WIP. Create action to publish on gitea server

Signed-off-by: cmoulliard <cmoulliard@redhat.com>
This commit is contained in:
cmoulliard
2023-12-15 15:23:26 +01:00
parent 211ec25212
commit f6426a32f9
4 changed files with 117 additions and 42 deletions
@@ -20,7 +20,7 @@ import yaml from 'yaml';
export const examples: TemplateExample[] = [
{
description:
'Initializes a Gitea repository of contents in workspace and publish it to Gitea with default configuration.',
'Initializes a Gitea repository using the content of the workspace and publish it to Gitea with default configuration.',
example: yaml.stringify({
steps: [
{
@@ -52,7 +52,7 @@ export const examples: TemplateExample[] = [
},
{
description:
'Initializes a Gitea repository with a default Branch, if not set defaults to master',
'Initializes a Gitea repository with a default Branch, if not set defaults to main',
example: yaml.stringify({
steps: [
{
@@ -61,7 +61,7 @@ export const examples: TemplateExample[] = [
name: 'Publish to Gitea',
input: {
repoUrl: 'gitea.com?repo=repo&owner=owner',
defaultBranch: 'staging',
defaultBranch: 'main',
},
},
],
@@ -14,36 +14,103 @@
* limitations under the License.
*/
import { PassThrough } from 'stream';
import { createAcmeExampleAction } from './gitea';
/* import {rest} from 'msw';*/
import { setupServer } from 'msw';
import { setupRequestMockHandlers } from '@backstage/backend-test-utils';
import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { createPublishGiteaAction } from './gitea';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
describe('acme:example', () => {
afterEach(() => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
commitAndPushRepo: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
};
});
describe('publish:gitea', () => {
const config = new ConfigReader({
integrations: {
gitea: [
{
host: 'gitea.com',
username: 'gitea_user',
password: 'gitea_password',
},
],
},
});
const description = 'for the lols';
const integrations = ScmIntegrations.fromConfig(config);
const action = createPublishGiteaAction({ integrations, config });
const mockContext = {
input: {
repoUrl: 'gitea.com?repo=repo',
description,
},
workspacePath: 'lol',
logger: getVoidLogger(),
logStream: new PassThrough(),
output: jest.fn(),
createTemporaryDirectory: jest.fn(),
};
const mockGitClient = {
createRepository: jest.fn(),
};
const server = setupServer();
setupRequestMockHandlers(server);
beforeEach(() => {
jest.resetAllMocks();
});
it('should call action', async () => {
const action = createAcmeExampleAction();
it('should throw an error when the repoUrl is not well formed', async () => {
await expect(
action.handler({
...mockContext,
input: { repoUrl: 'gitea.com?owner=o', description },
}),
).rejects.toThrow(/missing repo/);
});
const logger = getVoidLogger();
jest.spyOn(logger, 'info');
it('should throw if there is no integration config provided for missing.com host', async () => {
await expect(
action.handler({
...mockContext,
input: { repoUrl: 'missing.com?repo=repo', description },
}),
).rejects.toThrow(/No matching integration configuration/);
});
await action.handler({
input: {
myParameter: 'test',
},
workspacePath: '/tmp',
logger,
logStream: new PassThrough(),
output: jest.fn(),
createTemporaryDirectory() {
// Usage of mock-fs is recommended for testing of filesystem operations
throw new Error('Not implemented');
},
it('should throw if there is no repositoryId returned', async () => {
mockGitClient.createRepository.mockImplementation(() => ({
remoteUrl: 'https://gitea.com',
id: null,
}));
await action.handler(mockContext);
expect(initRepoAndPush).toHaveBeenCalledWith({
dir: mockContext.workspacePath,
remoteUrl: 'https://gitea.com',
defaultBranch: 'main',
auth: { username: 'gitea_user', password: 'gitea_password' },
logger: mockContext.logger,
commitMessage: 'initial commit',
gitAuthorInfo: {},
});
});
expect(logger.info).toHaveBeenCalledWith(
'Running example template with parameters: test',
);
afterEach(() => {
jest.resetAllMocks();
});
});
@@ -35,20 +35,19 @@ const createGiteaProject = async (
config: GiteaIntegrationConfig,
options: {
projectName: string;
parent: string;
// parent: string;
owner?: string;
description: string;
},
): Promise<void> => {
const { projectName, parent, owner, description } = options;
const { projectName, owner, description } = options;
const fetchOptions: RequestInit = {
method: 'PUT',
method: 'POST',
body: JSON.stringify({
parent,
name: projectName,
description,
owners: owner ? [owner] : [],
create_empty_commit: false,
owner,
}),
headers: {
...getGiteaRequestOptions(config).headers,
@@ -57,8 +56,10 @@ const createGiteaProject = async (
};
// TODO
// Create a repository in Gitea
// API request: https://gitea.com/api/swagger#/user/createCurrentUserRepo
const response: Response = await fetch(
`${config.baseUrl}/a/projects/${encodeURIComponent(projectName)}`,
`${config.baseUrl}/api/v1/user/repos`,
fetchOptions,
);
if (response.status !== 201) {
@@ -174,31 +175,34 @@ export function createPublishGiteaAction(options: {
sourcePath,
} = ctx.input;
const { repo, host, owner, workspace } = parseRepoUrl(
repoUrl,
integrations,
);
const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
const integrationConfig = integrations.gitea.byHost(host);
if (!integrationConfig) {
throw new InputError(
`No matching integration configuration for host ${host}, please check your integrations config`,
);
}
if (!workspace) {
throw new InputError(
`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`,
if (
!integrationConfig.config.username ||
!integrationConfig.config.password
) {
throw new Error(
'Credentials for Gitea integration required for this action.',
);
}
// TODO
// Check if the integration config includes a baseUrl
await createGiteaProject(integrationConfig.config, {
description,
owner: owner,
projectName: repo,
parent: workspace,
// parent: workspace,
});
const auth = {
username: integrationConfig.config.username!,
password: integrationConfig.config.password!,
@@ -212,7 +216,7 @@ export function createPublishGiteaAction(options: {
: config.getOptionalString('scaffolder.defaultAuthor.email'),
};
// TODO
const remoteUrl = `${integrationConfig.config.baseUrl}/a/${repo}`;
const remoteUrl = `${integrationConfig.config.baseUrl}/api/v1/user/${repo}`;
const commitResult = await initRepoAndPush({
dir: getRepoSourceDirectory(ctx.workspacePath, sourcePath),
remoteUrl,
@@ -92,6 +92,10 @@ export const parseRepoUrl = (
}
break;
}
case 'gitea': {
checkRequiredParams(parsed, 'repo');
break;
}
case 'gerrit': {
checkRequiredParams(parsed, 'repo');
break;