diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts index 64d73d498f..748a869205 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.examples.ts @@ -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', }, }, ], diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts index bd40b68603..52a29e2bbc 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.test.ts @@ -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(); }); }); diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts index a740b4938e..18e15fc191 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts @@ -35,20 +35,19 @@ const createGiteaProject = async ( config: GiteaIntegrationConfig, options: { projectName: string; - parent: string; + // parent: string; owner?: string; description: string; }, ): Promise => { - 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, diff --git a/plugins/scaffolder-node/src/actions/util.ts b/plugins/scaffolder-node/src/actions/util.ts index 327cfa9c2f..7f7121ef16 100644 --- a/plugins/scaffolder-node/src/actions/util.ts +++ b/plugins/scaffolder-node/src/actions/util.ts @@ -92,6 +92,10 @@ export const parseRepoUrl = ( } break; } + case 'gitea': { + checkRequiredParams(parsed, 'repo'); + break; + } case 'gerrit': { checkRequiredParams(parsed, 'repo'); break;