From 921e3ca569c7a81a20ab2b5e9c271ef822a1efae Mon Sep 17 00:00:00 2001 From: Chase Rutherford-Jenkins Date: Tue, 29 Jun 2021 22:10:56 -0700 Subject: [PATCH 1/5] use configured git author in scaffolder actions Co-authored-by: Himanshu Mishra Signed-off-by: Chase Rutherford-Jenkins --- app-config.yaml | 5 +++ plugins/scaffolder-backend/api-report.md | 5 +++ plugins/scaffolder-backend/config.d.ts | 9 ++++ .../actions/builtin/createBuiltinActions.ts | 8 +++- .../actions/builtin/publish/azure.test.ts | 23 +++++----- .../actions/builtin/publish/azure.ts | 10 ++++- .../actions/builtin/publish/bitbucket.test.ts | 43 ++++++++++--------- .../actions/builtin/publish/bitbucket.ts | 10 ++++- .../actions/builtin/publish/github.test.ts | 24 ++++++----- .../actions/builtin/publish/github.ts | 10 ++++- .../actions/builtin/publish/gitlab.test.ts | 37 ++++++++-------- .../actions/builtin/publish/gitlab.ts | 10 ++++- .../src/scaffolder/stages/publish/helpers.ts | 12 +++++- .../scaffolder-backend/src/service/router.ts | 1 + 14 files changed, 139 insertions(+), 68 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index e3ab12587e..c0bea41b34 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -250,6 +250,11 @@ catalog: target: ../catalog-model/examples/acme-corp.yaml scaffolder: + # Use to customize commit author info used when new components are created + # git: + # author: + # name: Scaffolder + # email: scaffolder@backstage.io github: token: ${GITHUB_TOKEN} visibility: public # or 'internal' or 'private' diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 7528388a47..21c6e03b0f 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -116,6 +116,7 @@ export const createBuiltinActions: (options: { integrations: ScmIntegrations; catalogClient: CatalogApi; templaters: TemplaterBuilder; + config: Config; }) => TemplateAction[]; // @public (undocumented) @@ -155,11 +156,13 @@ export function createLegacyActions(options: Options): TemplateAction[]; // @public (undocumented) export function createPublishAzureAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }): TemplateAction; // @public (undocumented) export function createPublishBitbucketAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }): TemplateAction; // @public @@ -168,6 +171,7 @@ export function createPublishFileAction(): TemplateAction; // @public (undocumented) export function createPublishGithubAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }): TemplateAction; // @public (undocumented) @@ -176,6 +180,7 @@ export const createPublishGithubPullRequestAction: ({ integrations, clientFactor // @public (undocumented) export function createPublishGitlabAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }): TemplateAction; // @public (undocumented) diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index 971c3036d6..07602b649a 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -17,6 +17,15 @@ export interface Config { /** Configuration options for the scaffolder plugin */ scaffolder?: { + git?: { + /** + * The commit author info used when new components are created. + */ + author?: { + name?: string; + email?: string; + }; + }; github?: { [key: string]: string; /** diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index 46b8db72b4..b3757571ff 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -17,6 +17,7 @@ import { UrlReader } from '@backstage/backend-common'; import { CatalogApi } from '@backstage/catalog-client'; import { ScmIntegrations } from '@backstage/integration'; +import { Config } from '@backstage/config'; import { TemplaterBuilder } from '../../stages'; import { createCatalogRegisterAction, @@ -41,8 +42,9 @@ export const createBuiltinActions = (options: { integrations: ScmIntegrations; catalogClient: CatalogApi; templaters: TemplaterBuilder; + config: Config; }) => { - const { reader, integrations, templaters, catalogClient } = options; + const { reader, integrations, templaters, catalogClient, config } = options; return [ createFetchPlainAction({ @@ -56,18 +58,22 @@ export const createBuiltinActions = (options: { }), createPublishGithubAction({ integrations, + config, }), createPublishGithubPullRequestAction({ integrations, }), createPublishGitlabAction({ integrations, + config, }), createPublishBitbucketAction({ integrations, + config, }), createPublishAzureAction({ integrations, + config, }), createDebugLogAction(), createCatalogRegisterAction({ catalogClient, integrations }), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts index d3cb4ccafc..6a1c8fdc55 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts @@ -28,17 +28,17 @@ import { PassThrough } from 'stream'; import { initRepoAndPush } from '../../../stages/publish/helpers'; describe('publish:azure', () => { - const integrations = ScmIntegrations.fromConfig( - new ConfigReader({ - integrations: { - azure: [ - { host: 'dev.azure.com', token: 'tokenlols' }, - { host: 'myazurehostnotoken.com' }, - ], - }, - }), - ); - const action = createPublishAzureAction({ integrations }); + const config = new ConfigReader({ + integrations: { + azure: [ + { host: 'dev.azure.com', token: 'tokenlols' }, + { host: 'myazurehostnotoken.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createPublishAzureAction({ integrations, config }); const mockContext = { input: { repoUrl: 'dev.azure.com?repo=repo&owner=owner&organization=org', @@ -187,6 +187,7 @@ describe('publish:azure', () => { defaultBranch: 'master', auth: { username: 'notempty', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts index eb1b0522c6..677abc3a08 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts @@ -21,11 +21,13 @@ import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/Git import { getPersonalAccessTokenHandler, WebApi } from 'azure-devops-node-api'; import { getRepoSourceDirectory, parseRepoUrl } from './util'; import { createTemplateAction } from '../../createTemplateAction'; +import { Config } from '@backstage/config'; export function createPublishAzureAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }) { - const { integrations } = options; + const { integrations, config } = options; return createTemplateAction<{ repoUrl: string; @@ -123,6 +125,11 @@ export function createPublishAzureAction(options: { // so it's just the base path I think const repoContentsUrl = remoteUrl; + const gitAuthorInfo = { + name: config.getOptionalString('scaffolder.git.author.name'), + email: config.getOptionalString('scaffolder.git.author.email'), + }; + await initRepoAndPush({ dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), remoteUrl, @@ -132,6 +139,7 @@ export function createPublishAzureAction(options: { password: integrationConfig.config.token, }, logger: ctx.logger, + gitAuthorInfo, }); ctx.output('remoteUrl', remoteUrl); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts index 16b84737a7..f173959aa0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts @@ -26,27 +26,27 @@ import { PassThrough } from 'stream'; import { initRepoAndPush } from '../../../stages/publish/helpers'; describe('publish:bitbucket', () => { - const integrations = ScmIntegrations.fromConfig( - new ConfigReader({ - integrations: { - bitbucket: [ - { - host: 'bitbucket.org', - token: 'tokenlols', - }, - { - host: 'hosted.bitbucket.com', - token: 'thing', - apiBaseUrl: 'https://hosted.bitbucket.com/rest/api/1.0', - }, - { - host: 'notoken.bitbucket.com', - }, - ], - }, - }), - ); - const action = createPublishBitbucketAction({ integrations }); + const config = new ConfigReader({ + integrations: { + bitbucket: [ + { + host: 'bitbucket.org', + token: 'tokenlols', + }, + { + host: 'hosted.bitbucket.com', + token: 'thing', + apiBaseUrl: 'https://hosted.bitbucket.com/rest/api/1.0', + }, + { + host: 'notoken.bitbucket.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createPublishBitbucketAction({ integrations, config }); const mockContext = { input: { repoUrl: 'bitbucket.org?repo=repo&owner=owner', @@ -331,6 +331,7 @@ describe('publish:bitbucket', () => { defaultBranch: 'main', auth: { username: 'x-token-auth', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts index 295f4d1574..b05b51a7eb 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts @@ -23,6 +23,7 @@ import fetch from 'cross-fetch'; import { initRepoAndPush } from '../../../stages/publish/helpers'; import { createTemplateAction } from '../../createTemplateAction'; import { getRepoSourceDirectory, parseRepoUrl } from './util'; +import { Config } from '@backstage/config'; const createBitbucketCloudRepository = async (opts: { owner: string; @@ -184,8 +185,9 @@ const performEnableLFS = async (opts: { export function createPublishBitbucketAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }) { - const { integrations } = options; + const { integrations, config } = options; return createTemplateAction<{ repoUrl: string; @@ -284,6 +286,11 @@ export function createPublishBitbucketAction(options: { apiBaseUrl, }); + const gitAuthorInfo = { + name: config.getOptionalString('scaffolder.git.author.name'), + email: config.getOptionalString('scaffolder.git.author.email'), + }; + await initRepoAndPush({ dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), remoteUrl, @@ -297,6 +304,7 @@ export function createPublishBitbucketAction(options: { }, defaultBranch, logger: ctx.logger, + gitAuthorInfo, }); if (enableLFS && host !== 'bitbucket.org') { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts index 910fa27b46..058168d666 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts @@ -25,17 +25,17 @@ import { initRepoAndPush } from '../../../stages/publish/helpers'; import { when } from 'jest-when'; describe('publish:github', () => { - const integrations = ScmIntegrations.fromConfig( - new ConfigReader({ - integrations: { - github: [ - { host: 'github.com', token: 'tokenlols' }, - { host: 'ghe.github.com' }, - ], - }, - }), - ); - const action = createPublishGithubAction({ integrations }); + const config = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createPublishGithubAction({ integrations, config }); const mockContext = { input: { repoUrl: 'github.com?repo=repo&owner=owner', @@ -178,6 +178,7 @@ describe('publish:github', () => { defaultBranch: 'master', auth: { username: 'x-access-token', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); @@ -207,6 +208,7 @@ describe('publish:github', () => { defaultBranch: 'main', auth: { username: 'x-access-token', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts index 7dd790cb62..f14dd817b0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -25,14 +25,16 @@ import { } from '../../../stages/publish/helpers'; import { getRepoSourceDirectory, parseRepoUrl } from './util'; import { createTemplateAction } from '../../createTemplateAction'; +import { Config } from '@backstage/config'; type Permission = 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; type Collaborator = { access: Permission; username: string }; export function createPublishGithubAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }) { - const { integrations } = options; + const { integrations, config } = options; const credentialsProviders = new Map( integrations.github.list().map(integration => { @@ -248,6 +250,11 @@ export function createPublishGithubAction(options: { const remoteUrl = newRepo.clone_url; const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`; + const gitAuthorInfo = { + name: config.getOptionalString('scaffolder.git.author.name'), + email: config.getOptionalString('scaffolder.git.author.email'), + }; + await initRepoAndPush({ dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), remoteUrl, @@ -257,6 +264,7 @@ export function createPublishGithubAction(options: { password: token, }, logger: ctx.logger, + gitAuthorInfo, }); try { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts index 67064efde7..427056454c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts @@ -24,24 +24,24 @@ import { PassThrough } from 'stream'; import { initRepoAndPush } from '../../../stages/publish/helpers'; describe('publish:gitlab', () => { - const integrations = ScmIntegrations.fromConfig( - new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - token: 'tokenlols', - apiBaseUrl: 'https://api.gitlab.com', - }, - { - host: 'hosted.gitlab.com', - apiBaseUrl: 'https://api.hosted.gitlab.com', - }, - ], - }, - }), - ); - const action = createPublishGitlabAction({ integrations }); + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createPublishGitlabAction({ integrations, config }); const mockContext = { input: { repoUrl: 'gitlab.com?repo=repo&owner=owner', @@ -166,6 +166,7 @@ describe('publish:gitlab', () => { remoteUrl: 'http://mockurl.git', auth: { username: 'oauth2', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts index 57c7fdf752..6d7384294d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -20,11 +20,13 @@ import { Gitlab } from '@gitbeaker/node'; import { initRepoAndPush } from '../../../stages/publish/helpers'; import { getRepoSourceDirectory, parseRepoUrl } from './util'; import { createTemplateAction } from '../../createTemplateAction'; +import { Config } from '@backstage/config'; export function createPublishGitlabAction(options: { integrations: ScmIntegrationRegistry; + config: Config; }) { - const { integrations } = options; + const { integrations, config } = options; return createTemplateAction<{ repoUrl: string; @@ -121,6 +123,11 @@ export function createPublishGitlabAction(options: { const remoteUrl = (http_url_to_repo as string).replace(/\.git$/, ''); const repoContentsUrl = `${remoteUrl}/-/blob/master`; + const gitAuthorInfo = { + name: config.getOptionalString('scaffolder.git.author.name'), + email: config.getOptionalString('scaffolder.git.author.email'), + }; + await initRepoAndPush({ dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), remoteUrl: http_url_to_repo as string, @@ -130,6 +137,7 @@ export function createPublishGitlabAction(options: { password: integrationConfig.config.token, }, logger: ctx.logger, + gitAuthorInfo, }); ctx.output('remoteUrl', remoteUrl); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts index dff0feb5f2..c974c466d4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts @@ -25,12 +25,14 @@ export async function initRepoAndPush({ auth, logger, defaultBranch = 'master', + gitAuthorInfo, }: { dir: string; remoteUrl: string; auth: { username: string; password: string }; logger: Logger; defaultBranch?: string; + gitAuthorInfo?: { name?: string; email?: string }; }): Promise { const git = Git.fromAuth({ username: auth.username, @@ -53,11 +55,17 @@ export async function initRepoAndPush({ await git.add({ dir, filepath }); } + // use provided info if possible, otherwise use fallbacks + const authorInfo = { + name: gitAuthorInfo?.name ?? 'Scaffolder', + email: gitAuthorInfo?.email ?? 'scaffolder@backstage.io', + }; + await git.commit({ dir, message: 'Initial commit', - author: { name: 'Scaffolder', email: 'scaffolder@backstage.io' }, - committer: { name: 'Scaffolder', email: 'scaffolder@backstage.io' }, + author: authorInfo, + committer: authorInfo, }); await git.addRemote({ diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index b0142d4b02..17304aefb1 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -129,6 +129,7 @@ export async function createRouter( catalogClient, templaters, reader, + config, }), ]; From b1aca39abe11bc22f0908fecf2d53dc95a1b58c5 Mon Sep 17 00:00:00 2001 From: Chase Rutherford-Jenkins Date: Fri, 2 Jul 2021 17:11:32 -0500 Subject: [PATCH 2/5] incorporate naming feedback; add tests Signed-off-by: Chase Rutherford-Jenkins --- app-config.yaml | 9 ++- plugins/scaffolder-backend/config.d.ts | 14 ++-- .../actions/builtin/publish/azure.test.ts | 39 +++++++++++ .../actions/builtin/publish/azure.ts | 4 +- .../actions/builtin/publish/bitbucket.test.ts | 69 +++++++++++++++++++ .../actions/builtin/publish/bitbucket.ts | 4 +- .../actions/builtin/publish/github.test.ts | 47 +++++++++++++ .../actions/builtin/publish/github.ts | 4 +- .../actions/builtin/publish/gitlab.test.ts | 47 +++++++++++++ .../actions/builtin/publish/gitlab.ts | 4 +- 10 files changed, 220 insertions(+), 21 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index c0bea41b34..b50de963ed 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -250,11 +250,10 @@ catalog: target: ../catalog-model/examples/acme-corp.yaml scaffolder: - # Use to customize commit author info used when new components are created - # git: - # author: - # name: Scaffolder - # email: scaffolder@backstage.io + # Use to customize default commit author info used when new components are created + # defaultAuthor: + # name: Scaffolder + # email: scaffolder@backstage.io github: token: ${GITHUB_TOKEN} visibility: public # or 'internal' or 'private' diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index 07602b649a..795fe5b112 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -17,14 +17,12 @@ export interface Config { /** Configuration options for the scaffolder plugin */ scaffolder?: { - git?: { - /** - * The commit author info used when new components are created. - */ - author?: { - name?: string; - email?: string; - }; + /** + * The commit author info used when new components are created. + */ + defaultAuthor?: { + name?: string; + email?: string; }; github?: { [key: string]: string; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts index 6a1c8fdc55..b5c9bdcd89 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts @@ -191,6 +191,45 @@ describe('publish:azure', () => { }); }); + it('should call initRepoAndPush with the configured defaultAuthor', async () => { + const customAuthorConfig = new ConfigReader({ + integrations: { + azure: [ + { host: 'dev.azure.com', token: 'tokenlols' }, + { host: 'myazurehostnotoken.com' }, + ], + }, + scaffolder: { + defaultAuthor: { + name: 'Test', + email: 'example@example.com', + }, + }, + }); + + const customAuthorIntegrations = ScmIntegrations.fromConfig( + customAuthorConfig, + ); + const customAuthorAction = createPublishAzureAction({ + integrations: customAuthorIntegrations, + config: customAuthorConfig, + }); + + mockGitClient.createRepository.mockImplementation(() => ({ + remoteUrl: 'https://dev.azure.com/organization/project/_git/repo', + })); + + await customAuthorAction.handler(mockContext); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://dev.azure.com/organization/project/_git/repo', + auth: { username: 'notempty', password: 'tokenlols' }, + logger: mockContext.logger, + gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, + }); + }); + it('should call output with the remoteUrl and the repoContentsUrl', async () => { mockGitClient.createRepository.mockImplementation(() => ({ remoteUrl: 'https://dev.azure.com/organization/project/_git/repo', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts index 677abc3a08..8b8f6ce3e5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.ts @@ -126,8 +126,8 @@ export function createPublishAzureAction(options: { const repoContentsUrl = remoteUrl; const gitAuthorInfo = { - name: config.getOptionalString('scaffolder.git.author.name'), - email: config.getOptionalString('scaffolder.git.author.email'), + name: config.getOptionalString('scaffolder.defaultAuthor.name'), + email: config.getOptionalString('scaffolder.defaultAuthor.email'), }; await initRepoAndPush({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts index f173959aa0..6a72cf1bc3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts @@ -335,6 +335,75 @@ describe('publish:bitbucket', () => { }); }); + it('should call initAndPush with the configured defaultAuthor', async () => { + const customAuthorConfig = new ConfigReader({ + integrations: { + bitbucket: [ + { + host: 'bitbucket.org', + token: 'tokenlols', + }, + { + host: 'hosted.bitbucket.com', + token: 'thing', + apiBaseUrl: 'https://hosted.bitbucket.com/rest/api/1.0', + }, + { + host: 'notoken.bitbucket.com', + }, + ], + }, + scaffolder: { + defaultAuthor: { + name: 'Test', + email: 'example@example.com', + }, + }, + }); + + const customAuthorIntegrations = ScmIntegrations.fromConfig( + customAuthorConfig, + ); + const customAuthorAction = createPublishBitbucketAction({ + integrations: customAuthorIntegrations, + config: customAuthorConfig, + }); + + server.use( + rest.post( + 'https://api.bitbucket.org/2.0/repositories/owner/repo', + (_, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + links: { + html: { + href: 'https://bitbucket.org/owner/repo', + }, + clone: [ + { + name: 'https', + href: 'https://bitbucket.org/owner/cloneurl', + }, + ], + }, + }), + ), + ), + ); + + await customAuthorAction.handler(mockContext); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://bitbucket.org/owner/cloneurl', + auth: { username: 'x-token-auth', password: 'tokenlols' }, + logger: mockContext.logger, + gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, + }); + }); + it('should call outputs with the correct urls', async () => { server.use( rest.post( diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts index b05b51a7eb..1dc80f370c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts @@ -287,8 +287,8 @@ export function createPublishBitbucketAction(options: { }); const gitAuthorInfo = { - name: config.getOptionalString('scaffolder.git.author.name'), - email: config.getOptionalString('scaffolder.git.author.email'), + name: config.getOptionalString('scaffolder.defaultAuthor.name'), + email: config.getOptionalString('scaffolder.defaultAuthor.email'), }; await initRepoAndPush({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts index 058168d666..0b277c4739 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts @@ -212,6 +212,53 @@ describe('publish:github', () => { }); }); + it('should call initRepoAndPush with the configured defaultAuthor', async () => { + const customAuthorConfig = new ConfigReader({ + integrations: { + github: [ + { host: 'github.com', token: 'tokenlols' }, + { host: 'ghe.github.com' }, + ], + }, + scaffolder: { + defaultAuthor: { + name: 'Test', + email: 'example@example.com', + }, + }, + }); + + const customAuthorIntegrations = ScmIntegrations.fromConfig( + customAuthorConfig, + ); + const customAuthorAction = createPublishGithubAction({ + integrations: customAuthorIntegrations, + config: customAuthorConfig, + }); + + mockGithubClient.users.getByUsername.mockResolvedValue({ + data: { type: 'User' }, + }); + + mockGithubClient.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await customAuthorAction.handler(mockContext); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'https://github.com/clone/url.git', + defaultBranch: 'master', + auth: { username: 'x-access-token', password: 'tokenlols' }, + logger: mockContext.logger, + gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, + }); + }); + it('should add access for the team when it starts with the owner', async () => { mockGithubClient.users.getByUsername.mockResolvedValue({ data: { type: 'User' }, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts index f14dd817b0..9f693a96d8 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -251,8 +251,8 @@ export function createPublishGithubAction(options: { const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`; const gitAuthorInfo = { - name: config.getOptionalString('scaffolder.git.author.name'), - email: config.getOptionalString('scaffolder.git.author.email'), + name: config.getOptionalString('scaffolder.defaultAuthor.name'), + email: config.getOptionalString('scaffolder.defaultAuthor.email'), }; await initRepoAndPush({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts index 427056454c..08ab87c271 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts @@ -170,6 +170,53 @@ describe('publish:gitlab', () => { }); }); + it('should call initRepoAndPush with the configured defaultAuthor', async () => { + const customAuthorConfig = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + scaffolder: { + defaultAuthor: { + name: 'Test', + email: 'example@example.com', + }, + }, + }); + + const customAuthorIntegrations = ScmIntegrations.fromConfig( + customAuthorConfig, + ); + const customAuthorAction = createPublishGitlabAction({ + integrations: customAuthorIntegrations, + config: customAuthorConfig, + }); + + mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); + mockGitlabClient.Projects.create.mockResolvedValue({ + http_url_to_repo: 'http://mockurl.git', + }); + + await customAuthorAction.handler(mockContext); + + expect(initRepoAndPush).toHaveBeenCalledWith({ + dir: mockContext.workspacePath, + remoteUrl: 'http://mockurl.git', + auth: { username: 'oauth2', password: 'tokenlols' }, + logger: mockContext.logger, + gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, + }); + }); + it('should call output with the remoteUrl and repoContentsUrl', async () => { mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts index 6d7384294d..1cd77ebe2a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -124,8 +124,8 @@ export function createPublishGitlabAction(options: { const repoContentsUrl = `${remoteUrl}/-/blob/master`; const gitAuthorInfo = { - name: config.getOptionalString('scaffolder.git.author.name'), - email: config.getOptionalString('scaffolder.git.author.email'), + name: config.getOptionalString('scaffolder.defaultAuthor.name'), + email: config.getOptionalString('scaffolder.defaultAuthor.email'), }; await initRepoAndPush({ From 7cad18e2f039e71161af7aa582f1fd758b7d2546 Mon Sep 17 00:00:00 2001 From: Chase Rutherford-Jenkins Date: Tue, 6 Jul 2021 20:45:10 -0500 Subject: [PATCH 3/5] add changeset Signed-off-by: Chase Rutherford-Jenkins --- .changeset/moody-garlics-whisper.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .changeset/moody-garlics-whisper.md diff --git a/.changeset/moody-garlics-whisper.md b/.changeset/moody-garlics-whisper.md new file mode 100644 index 0000000000..b2867bc016 --- /dev/null +++ b/.changeset/moody-garlics-whisper.md @@ -0,0 +1,24 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Adding `config: Config` as a required argument to `createBuiltinActions` and downstream methods in order to support configuration of the default git author used for Scaffolder commits. + +The affected methods are: + +- `createBuiltinActions` +- `createPublishGithubAction` +- `createPublishGitlabAction` +- `createPublishBitbucketAction` +- `createPublishAzureAction` + +Call sites to these methods will need to be migrated to include the new `config` argument. See `createRouter` in `plugins/scaffolder-backend/src/service/router.ts` for an example of adding this new argument. + +To configure the default git author, use the `defaultAuthor` key under `scaffolder` in `app-config.yaml`: + +```yaml +scaffolder: + defaultAuthor: + name: Example + email: example@example.com +``` From 3c19f1230f28d2465a83410fca6ed9dadbb9e9c0 Mon Sep 17 00:00:00 2001 From: Chase Rutherford-Jenkins Date: Tue, 6 Jul 2021 21:15:14 -0500 Subject: [PATCH 4/5] update tests Signed-off-by: Chase Rutherford-Jenkins --- .../src/scaffolder/actions/builtin/publish/azure.test.ts | 2 ++ .../src/scaffolder/actions/builtin/publish/bitbucket.test.ts | 2 ++ .../src/scaffolder/actions/builtin/publish/gitlab.test.ts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts index b5c9bdcd89..1dc29ea763 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/azure.test.ts @@ -165,6 +165,7 @@ describe('publish:azure', () => { defaultBranch: 'master', auth: { username: 'notempty', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); @@ -226,6 +227,7 @@ describe('publish:azure', () => { remoteUrl: 'https://dev.azure.com/organization/project/_git/repo', auth: { username: 'notempty', password: 'tokenlols' }, logger: mockContext.logger, + defaultBranch: 'master', gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts index 6a72cf1bc3..0e5f8df72b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.test.ts @@ -289,6 +289,7 @@ describe('publish:bitbucket', () => { defaultBranch: 'master', auth: { username: 'x-token-auth', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); @@ -400,6 +401,7 @@ describe('publish:bitbucket', () => { remoteUrl: 'https://bitbucket.org/owner/cloneurl', auth: { username: 'x-token-auth', password: 'tokenlols' }, logger: mockContext.logger, + defaultBranch: 'master', gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts index 08ab87c271..25a129d905 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.test.ts @@ -143,6 +143,7 @@ describe('publish:gitlab', () => { remoteUrl: 'http://mockurl.git', auth: { username: 'oauth2', password: 'tokenlols' }, logger: mockContext.logger, + gitAuthorInfo: {}, }); }); @@ -213,6 +214,7 @@ describe('publish:gitlab', () => { remoteUrl: 'http://mockurl.git', auth: { username: 'oauth2', password: 'tokenlols' }, logger: mockContext.logger, + defaultBranch: 'master', gitAuthorInfo: { name: 'Test', email: 'example@example.com' }, }); }); From b254ebff8176b7464166414814016f4c4e61eefb Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Wed, 7 Jul 2021 10:43:11 +0200 Subject: [PATCH 5/5] Update moody-garlics-whisper.md Signed-off-by: Ben Lambert --- .changeset/moody-garlics-whisper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/moody-garlics-whisper.md b/.changeset/moody-garlics-whisper.md index b2867bc016..b9683e4637 100644 --- a/.changeset/moody-garlics-whisper.md +++ b/.changeset/moody-garlics-whisper.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder-backend': minor --- Adding `config: Config` as a required argument to `createBuiltinActions` and downstream methods in order to support configuration of the default git author used for Scaffolder commits.