From e3a11945eaa1fda3b29791d248d35228f17c028f Mon Sep 17 00:00:00 2001 From: Alan Crosswell Date: Fri, 29 Jan 2021 17:34:51 -0500 Subject: [PATCH 1/6] Add repoVisibility for GitLab repos --- .../scaffolder/stages/publish/gitlab.test.ts | 26 ++++++++++++------- .../src/scaffolder/stages/publish/gitlab.ts | 20 +++++++++++--- .../scaffolder/stages/publish/publishers.ts | 19 ++++++++++---- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts index 368f1bb29f..61c8480efb 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.test.ts @@ -54,11 +54,14 @@ describe('GitLab Publisher', () => { describe('publish: createRemoteInGitLab', () => { it('should use gitbeaker to create a repo in a namespace if the namespace property is set', async () => { - const publisher = await GitlabPublisher.fromConfig({ - host: 'gitlab.com', - token: 'fake-token', - baseUrl: 'https://gitlab.hosted.com', - }); + const publisher = await GitlabPublisher.fromConfig( + { + host: 'gitlab.com', + token: 'fake-token', + baseUrl: 'https://gitlab.hosted.com', + }, + { repoVisibility: 'public' }, + ); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 42, @@ -88,6 +91,7 @@ describe('GitLab Publisher', () => { expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ namespace_id: 42, name: 'test', + visibility: 'public', }); expect(initRepoAndPush).toHaveBeenCalledWith({ dir: resultPath, @@ -98,10 +102,13 @@ describe('GitLab Publisher', () => { }); it('should use gitbeaker to create a repo in the authed user if the namespace property is not set', async () => { - const publisher = await GitlabPublisher.fromConfig({ - host: 'gitlab.com', - token: 'fake-token', - }); + const publisher = await GitlabPublisher.fromConfig( + { + host: 'gitlab.com', + token: 'fake-token', + }, + { repoVisibility: 'public' }, + ); mockGitlabClient.Namespaces.show.mockResolvedValue({}); mockGitlabClient.Users.current.mockResolvedValue({ @@ -128,6 +135,7 @@ describe('GitLab Publisher', () => { expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ namespace_id: 21, name: 'test', + visibility: 'public', }); expect(initRepoAndPush).toHaveBeenCalledWith({ dir: resultPath, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts index ace5791b1f..4b10d653da 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts @@ -22,18 +22,31 @@ import parseGitUrl from 'git-url-parse'; import path from 'path'; import { GitLabIntegrationConfig } from '@backstage/integration'; +export type RepoVisibilityOptions = 'private' | 'internal' | 'public'; + export class GitlabPublisher implements PublisherBase { - static async fromConfig(config: GitLabIntegrationConfig) { + static async fromConfig( + config: GitLabIntegrationConfig, + { repoVisibility }: { repoVisibility: RepoVisibilityOptions }, + ) { if (!config.token) { return undefined; } const client = new Gitlab({ host: config.baseUrl, token: config.token }); - return new GitlabPublisher({ token: config.token, client }); + return new GitlabPublisher({ + token: config.token, + client, + repoVisibility, + }); } constructor( - private readonly config: { token: string; client: GitlabClient }, + private readonly config: { + token: string; + client: GitlabClient; + repoVisibility: RepoVisibilityOptions; + }, ) {} async publish({ @@ -85,6 +98,7 @@ export class GitlabPublisher implements PublisherBase { const project = (await this.config.client.Projects.create({ namespace_id: targetNamespace, name: name, + visibility: this.config.repoVisibility, })) as { http_url_to_repo: string }; return project?.http_url_to_repo; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts index 79eb3b7708..ac8a87ef8d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts @@ -98,7 +98,13 @@ export class Publishers implements PublisherBuilder { } for (const integration of scm.gitlab.list()) { - const publisher = await GitlabPublisher.fromConfig(integration.config); + const repoVisibility = (config.getOptionalString( + 'scaffolder.gitlab.visibility', + ) ?? 'public') as RepoVisibilityOptions; + + const publisher = await GitlabPublisher.fromConfig(integration.config, { + repoVisibility, + }); if (publisher) { publishers.register(integration.config.host, publisher); @@ -107,10 +113,13 @@ export class Publishers implements PublisherBuilder { publishers.register( integration.config.host, - await GitlabPublisher.fromConfig({ - token: config.getOptionalString('scaffolder.gitlab.token') ?? '', - host: integration.config.host, - }), + await GitlabPublisher.fromConfig( + { + token: config.getOptionalString('scaffolder.gitlab.token') ?? '', + host: integration.config.host, + }, + { repoVisibility }, + ), ); } } From a4e526dfe38909c672fb870867f2c51de475902a Mon Sep 17 00:00:00 2001 From: Alan Crosswell Date: Sat, 30 Jan 2021 09:31:53 -0500 Subject: [PATCH 2/6] Bitbucket repo visibility --- .../stages/publish/bitbucket.test.ts | 24 +++++---- .../scaffolder/stages/publish/bitbucket.ts | 11 +++- .../scaffolder/stages/publish/publishers.ts | 52 +++++++++++++------ 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.test.ts index 419c81ea7e..4cf5e83ba3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.test.ts @@ -63,11 +63,14 @@ describe('Bitbucket Publisher', () => { ), ); - const publisher = await BitbucketPublisher.fromConfig({ - host: 'bitbucket.org', - username: 'fake-user', - appPassword: 'fake-token', - }); + const publisher = await BitbucketPublisher.fromConfig( + { + host: 'bitbucket.org', + username: 'fake-user', + appPassword: 'fake-token', + }, + { repoVisibility: 'private' }, + ); const result = await publisher.publish({ values: { @@ -122,10 +125,13 @@ describe('Bitbucket Publisher', () => { ), ); - const publisher = await BitbucketPublisher.fromConfig({ - host: 'bitbucket.mycompany.com', - token: 'fake-token', - }); + const publisher = await BitbucketPublisher.fromConfig( + { + host: 'bitbucket.mycompany.com', + token: 'fake-token', + }, + { repoVisibility: 'private' }, + ); const result = await publisher.publish({ values: { diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.ts index 2a274144ff..373920c005 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.ts @@ -21,17 +21,23 @@ import { BitbucketIntegrationConfig } from '@backstage/integration'; import parseGitUrl from 'git-url-parse'; import path from 'path'; +export type RepoVisibilityOptions = 'private' | 'public'; + // TODO(blam): We should probably start to use a bitbucket client here that we can change // the baseURL to point at on-prem or public bitbucket versions like we do for // github and ghe. There's to much logic and not enough types here for us to say that this way is better than using // a supported bitbucket client if one exists. export class BitbucketPublisher implements PublisherBase { - static async fromConfig(config: BitbucketIntegrationConfig) { + static async fromConfig( + config: BitbucketIntegrationConfig, + { repoVisibility }: { repoVisibility: RepoVisibilityOptions }, + ) { return new BitbucketPublisher({ host: config.host, token: config.token, appPassword: config.appPassword, username: config.username, + repoVisibility, }); } @@ -41,6 +47,7 @@ export class BitbucketPublisher implements PublisherBase { token?: string; appPassword?: string; username?: string; + repoVisibility: RepoVisibilityOptions; }, ) {} @@ -101,6 +108,7 @@ export class BitbucketPublisher implements PublisherBase { body: JSON.stringify({ scm: 'git', description: description, + is_private: this.config.repoVisibility === 'private', }), headers: { Authorization: `Basic ${buffer.toString('base64')}`, @@ -144,6 +152,7 @@ export class BitbucketPublisher implements PublisherBase { body: JSON.stringify({ name: name, description: description, + is_private: this.config.repoVisibility === 'private', }), headers: { Authorization: `Bearer ${this.config.token}`, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts index ac8a87ef8d..30201e6dca 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts @@ -16,10 +16,19 @@ import { Config } from '@backstage/config'; import { PublisherBase, PublisherBuilder } from './types'; -import { GithubPublisher, RepoVisibilityOptions } from './github'; -import { GitlabPublisher } from './gitlab'; +import { + GithubPublisher, + RepoVisibilityOptions as GithubRepoVisibilityOptions, +} from './github'; +import { + GitlabPublisher, + RepoVisibilityOptions as GitlabRepoVisibilityOptions, +} from './gitlab'; import { AzurePublisher } from './azure'; -import { BitbucketPublisher } from './bitbucket'; +import { + BitbucketPublisher, + RepoVisibilityOptions as BitbucketRepoVisibilityOptions, +} from './bitbucket'; import { Logger } from 'winston'; import { ScmIntegrations } from '@backstage/integration'; @@ -74,7 +83,7 @@ export class Publishers implements PublisherBuilder { for (const integration of scm.github.list()) { const repoVisibility = (config.getOptionalString( 'scaffolder.github.visibility', - ) ?? 'public') as RepoVisibilityOptions; + ) ?? 'public') as GithubRepoVisibilityOptions; const publisher = await GithubPublisher.fromConfig(integration.config, { repoVisibility, @@ -100,7 +109,7 @@ export class Publishers implements PublisherBuilder { for (const integration of scm.gitlab.list()) { const repoVisibility = (config.getOptionalString( 'scaffolder.gitlab.visibility', - ) ?? 'public') as RepoVisibilityOptions; + ) ?? 'public') as GitlabRepoVisibilityOptions; const publisher = await GitlabPublisher.fromConfig(integration.config, { repoVisibility, @@ -125,7 +134,16 @@ export class Publishers implements PublisherBuilder { } for (const integration of scm.bitbucket.list()) { - const publisher = await BitbucketPublisher.fromConfig(integration.config); + const repoVisibility = (config.getOptionalString( + 'scaffolder.bitbucket.visibility', + ) ?? 'public') as BitbucketRepoVisibilityOptions; + + const publisher = await BitbucketPublisher.fromConfig( + integration.config, + { + repoVisibility, + }, + ); if (publisher) { publishers.register(integration.config.host, publisher); @@ -134,15 +152,19 @@ export class Publishers implements PublisherBuilder { publishers.register( integration.config.host, - await BitbucketPublisher.fromConfig({ - token: config.getOptionalString('scaffolder.bitbucket.token') ?? '', - username: - config.getOptionalString('scaffolder.bitbucket.username') ?? '', - appPassword: - config.getOptionalString('scaffolder.bitbucket.appPassword') ?? - '', - host: integration.config.host, - }), + await BitbucketPublisher.fromConfig( + { + token: + config.getOptionalString('scaffolder.bitbucket.token') ?? '', + username: + config.getOptionalString('scaffolder.bitbucket.username') ?? '', + appPassword: + config.getOptionalString('scaffolder.bitbucket.appPassword') ?? + '', + host: integration.config.host, + }, + { repoVisibility }, + ), ); } } From 2d56971596819d7160d881b1b65502f3d14c7f0a Mon Sep 17 00:00:00 2001 From: Alan Crosswell Date: Sat, 30 Jan 2021 10:25:41 -0500 Subject: [PATCH 3/6] add scaffolder visibility config for GitLab and BitBucket --- app-config.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app-config.yaml b/app-config.yaml index f71649659b..763dd0c258 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -243,6 +243,7 @@ scaffolder: baseUrl: https://gitlab.com token: $env: GITLAB_TOKEN + visibility: public # or 'internal' or 'private' azure: baseUrl: https://dev.azure.com/{your-organization} api: @@ -255,6 +256,7 @@ scaffolder: $env: BITBUCKET_USERNAME token: $env: BITBUCKET_TOKEN + visibility: public # or or 'private' auth: environment: development From 529d16d278f3996a517d55d8be3fafa2f84063df Mon Sep 17 00:00:00 2001 From: Alan Crosswell Date: Sat, 30 Jan 2021 10:26:26 -0500 Subject: [PATCH 4/6] changeset --- .changeset/sour-gorillas-fail.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .changeset/sour-gorillas-fail.md diff --git a/.changeset/sour-gorillas-fail.md b/.changeset/sour-gorillas-fail.md new file mode 100644 index 0000000000..c6394ed76e --- /dev/null +++ b/.changeset/sour-gorillas-fail.md @@ -0,0 +1,23 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +# Repo visibility for GitLab and BitBucket repos + +**NOTE: This changes default repo visibility from `private` to `public` for GitLab and BitBucket** which +is consistent with the GitHub default. If you were counting on `private` visibility, you'll need to update +your scaffolder config to use `private`. + +This adds repo visibility feature parity with GitHub for GitLab and BitBucket. + +To configure the repo visibility, set scaffolder._type_.visibility as in this example: + +```yaml +scaffolder: + github: + visibility: private # 'public' or 'internal' or 'private' (default is 'public') + gitlab: + visibility: public # 'public' or 'internal' or 'private' (default is 'public') + bitbucket: + visibility: public # 'public' or 'private' (default is 'public') +``` From c3609ebb44f8a28cca7d6696743e824960e67b31 Mon Sep 17 00:00:00 2001 From: Alan Crosswell Date: Mon, 1 Feb 2021 10:26:33 -0500 Subject: [PATCH 5/6] add visibility to schema --- plugins/scaffolder-backend/config.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index 28e2515471..55ed959edc 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -19,9 +19,11 @@ export interface Config { scaffolder?: { github?: { [key: string]: string; + visiblity?: string; }; gitlab?: { api: { [key: string]: string }; + visiblity?: string; }; azure?: { baseUrl: string; @@ -29,6 +31,7 @@ export interface Config { }; bitbucket?: { api: { [key: string]: string }; + visiblity?: string; }; }; } From 2bf3ad4ce56f6ddecc20e6d2386be44d1485d658 Mon Sep 17 00:00:00 2001 From: Alan Crosswell Date: Mon, 1 Feb 2021 11:45:38 -0500 Subject: [PATCH 6/6] better document the config options --- plugins/scaffolder-backend/config.d.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index 55ed959edc..3b31b4f951 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -19,11 +19,17 @@ export interface Config { scaffolder?: { github?: { [key: string]: string; - visiblity?: string; + /** + * The visibility to set on created repositories. + */ + visiblity?: 'public' | 'internal' | 'private'; }; gitlab?: { api: { [key: string]: string }; - visiblity?: string; + /** + * The visibility to set on created repositories. + */ + visiblity?: 'public' | 'internal' | 'private'; }; azure?: { baseUrl: string; @@ -31,7 +37,10 @@ export interface Config { }; bitbucket?: { api: { [key: string]: string }; - visiblity?: string; + /** + * The visibility to set on created repositories. + */ + visiblity?: 'public' | 'private'; }; }; }