diff --git a/.changeset/loud-frogs-eat.md b/.changeset/loud-frogs-eat.md new file mode 100644 index 0000000000..dd1ab978f1 --- /dev/null +++ b/.changeset/loud-frogs-eat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Add examples for `gitlab:repo:push` scaffolder action & improve related tests diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.test.ts new file mode 100644 index 0000000000..d84181d398 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.test.ts @@ -0,0 +1,186 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createRootLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { createMockDirectory } from '@backstage/backend-test-utils'; +import { createGitlabRepoPushAction } from './gitlabRepoPush'; +import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; +import { examples } from './gitlabRepoPush.examples'; +import yaml from 'yaml'; + +createRootLogger(); + +const mockGitlabClient = { + Projects: { + create: jest.fn(), + show: jest.fn(async (_: any) => { + return { + default_branch: 'main', + }; + }), + }, + Branches: { + create: jest.fn(), + show: jest.fn(), + }, + Commits: { + create: jest.fn(async (_: any) => ({ + id: 'f8a2c9bd4e2915b0792b43235c779e82ddad54af', + })), + }, +}; + +jest.mock('@gitbeaker/node', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:repo:push', () => { + let instance: TemplateAction; + + const mockDir = createMockDirectory(); + const workspacePath = mockDir.resolve('workspace'); + + beforeEach(() => { + mockDir.clear(); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'token', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + instance = createGitlabRepoPushAction({ integrations }); + }); + + describe('Push changes to gitlab repository', () => { + it(`Should ${examples[0].description}`, async () => { + const input = yaml.parse(examples[0].example).steps[0].input; + mockDir.setContent({ + [workspacePath]: { + 'abcd.txt': 'Test message', + }, + }); + const ctx = createMockActionContext({ input, workspacePath }); + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'feature-branch', + 'Initial Commit', + [ + { + action: 'create', + filePath: 'abcd.txt', + content: 'VGVzdCBtZXNzYWdl', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'f8a2c9bd4e2915b0792b43235c779e82ddad54af', + ); + }); + }); + + describe('Push changes to gitlab repository with a specific source and target path', () => { + it(`Should ${examples[1].description}`, async () => { + const input = yaml.parse(examples[1].example).steps[0].input; + mockDir.setContent({ + [workspacePath]: { + 'abcd.txt': 'Test message', + source: { + 'abcd.txt': 'Test message', + }, + }, + }); + const ctx = createMockActionContext({ input, workspacePath }); + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'feature-branch', + 'Initial Commit', + [ + { + action: 'create', + filePath: 'abcd.txt', + content: 'VGVzdCBtZXNzYWdl', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'f8a2c9bd4e2915b0792b43235c779e82ddad54af', + ); + }); + }); + + describe('Push changes to gitlab repository with a specific commit action', () => { + it(`Should ${examples[2].description}`, async () => { + const input = yaml.parse(examples[2].example).steps[0].input; + mockDir.setContent({ + [workspacePath]: { + 'abcd.txt': 'Test message', + }, + }); + const ctx = createMockActionContext({ input, workspacePath }); + await instance.handler(ctx); + + expect(mockGitlabClient.Branches.create).toHaveBeenCalledTimes(0); + expect(mockGitlabClient.Commits.create).toHaveBeenCalledWith( + 'owner/repo', + 'feature-branch', + 'Initial Commit', + [ + { + action: 'update', + filePath: 'abcd.txt', + content: 'VGVzdCBtZXNzYWdl', + encoding: 'base64', + execute_filemode: false, + }, + ], + ); + expect(ctx.output).toHaveBeenCalledWith( + 'commitHash', + 'f8a2c9bd4e2915b0792b43235c779e82ddad54af', + ); + }); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.ts new file mode 100644 index 0000000000..56a59f25bc --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Push changes to gitlab repository with minimal changes', + example: yaml.stringify({ + steps: [ + { + id: 'pushChanges', + action: 'gitlab:repo:push', + name: 'Push changes to gitlab repository', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Initial Commit', + branchName: 'feature-branch', + }, + }, + ], + }), + }, + { + description: + 'Push changes to gitlab repository with a specific source and target path', + example: yaml.stringify({ + steps: [ + { + id: 'pushChanges', + action: 'gitlab:repo:push', + name: 'Push changes to gitlab repository', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Initial Commit', + branchName: 'feature-branch', + sourcePath: 'src', + targetPath: 'dest', + }, + }, + ], + }), + }, + { + description: + 'Push changes to gitlab repository with a specific commit action', + example: yaml.stringify({ + steps: [ + { + id: 'pushChanges', + action: 'gitlab:repo:push', + name: 'Push changes to gitlab repository', + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + commitMessage: 'Initial Commit', + branchName: 'feature-branch', + commitAction: 'update', + }, + }, + ], + }), + }, +]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts index 330d0f6f08..aae3b05c49 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts @@ -25,6 +25,7 @@ import { ScmIntegrationRegistry } from '@backstage/integration'; import { InputError } from '@backstage/errors'; import { resolveSafeChildPath } from '@backstage/backend-common'; import { createGitlabApi } from './helpers'; +import { examples } from './gitlabRepoPush.examples'; /** * Create a new action that commits into a gitlab repository. @@ -46,6 +47,7 @@ export const createGitlabRepoPushAction = (options: { commitAction?: 'create' | 'delete' | 'update'; }>({ id: 'gitlab:repo:push', + examples, schema: { input: { required: ['repoUrl', 'branchName', 'commitMessage'],