From 090dfe65db7ba2f1a76cd009ab911cdfdae017be Mon Sep 17 00:00:00 2001 From: Carlo Colombo Date: Tue, 8 Jun 2021 14:47:21 +0200 Subject: [PATCH] Add supprt to enable LFS for hosted Bitbucket Signed-off-by: Carlo Colombo --- .changeset/lazy-cougars-rule.md | 5 ++ .../actions/builtin/publish/bitbucket.test.ts | 82 +++++++++++++++++++ .../actions/builtin/publish/bitbucket.ts | 43 +++++++++- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 .changeset/lazy-cougars-rule.md diff --git a/.changeset/lazy-cougars-rule.md b/.changeset/lazy-cougars-rule.md new file mode 100644 index 0000000000..cc6ec91bd5 --- /dev/null +++ b/.changeset/lazy-cougars-rule.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Adds support to enable LFS for hosted Bitbucket 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 40e7f613f2..f670cc715a 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 @@ -173,6 +173,88 @@ describe('publish:bitbucket', () => { }); }); + describe('LFS for hosted bitbucket', () => { + const repoCreationResponse = { + links: { + self: [ + { + href: 'https://bitbucket.mycompany.com/projects/project/repos/repo', + }, + ], + clone: [ + { + name: 'http', + href: 'https://bitbucket.mycompany.com/scm/project/repo', + }, + ], + }, + }; + + it('should call the correct APIs to enable LFS if requested and the host is hosted bitbucket', async () => { + expect.assertions(1); + server.use( + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/owner/repos', + (_, res, ctx) => { + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(repoCreationResponse), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/owner/repos/repo/enabled', + (req, res, ctx) => { + expect(req.headers.get('Authorization')).toBe('Bearer thing'); + return res(ctx.status(204)); + }, + ), + ); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + repoUrl: 'hosted.bitbucket.com?owner=owner&repo=repo', + enableLFS: true, + }, + }); + }); + + it('should report an error if enabling LFS fails', async () => { + server.use( + rest.post( + 'https://hosted.bitbucket.com/rest/api/1.0/projects/owner/repos', + (_, res, ctx) => { + return res( + ctx.status(201), + ctx.set('Content-Type', 'application/json'), + ctx.json(repoCreationResponse), + ); + }, + ), + rest.put( + 'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/owner/repos/repo/enabled', + (_, res, ctx) => { + return res(ctx.status(500)); + }, + ), + ); + + await expect( + action.handler({ + ...mockContext, + input: { + ...mockContext.input, + repoUrl: 'hosted.bitbucket.com?owner=owner&repo=repo', + enableLFS: true, + }, + }), + ).rejects.toThrow(/Failed to enable LFS/); + }); + }); + it('should call initAndPush with the correct values', 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 243e515b19..d543f4cdaa 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/bitbucket.ts @@ -156,6 +156,32 @@ const getAuthorizationHeader = (config: BitbucketIntegrationConfig) => { ); }; +const performEnableLFS = async (opts: { + authorization: string; + host: string; + owner: string; + repo: string; +}) => { + const { authorization, host, owner, repo } = opts; + + const options: RequestInit = { + method: 'PUT', + headers: { + Authorization: authorization, + }, + }; + + const { ok, status, statusText } = await fetch( + `https://${host}/rest/git-lfs/admin/projects/${owner}/repos/${repo}/enabled`, + options, + ); + + if (!ok) + throw new Error( + `Failed to enable LFS in the repository, ${status}: ${statusText}`, + ); +}; + export function createPublishBitbucketAction(options: { integrations: ScmIntegrationRegistry; }) { @@ -166,6 +192,7 @@ export function createPublishBitbucketAction(options: { description: string; repoVisibility: 'private' | 'public'; sourcePath?: string; + enableLFS: boolean; }>({ id: 'publish:bitbucket', description: @@ -193,6 +220,11 @@ export function createPublishBitbucketAction(options: { 'Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.', type: 'string', }, + enableLFS: { + title: + 'Enable LFS for the repository. Only available for hosted Bitbucket.', + type: 'boolean', + }, }, }, output: { @@ -210,7 +242,12 @@ export function createPublishBitbucketAction(options: { }, }, async handler(ctx) { - const { repoUrl, description, repoVisibility = 'private' } = ctx.input; + const { + repoUrl, + description, + repoVisibility = 'private', + enableLFS = false, + } = ctx.input; const { owner, repo, host } = parseRepoUrl(repoUrl); @@ -252,6 +289,10 @@ export function createPublishBitbucketAction(options: { logger: ctx.logger, }); + if (enableLFS && host !== 'bitbucket.org') { + await performEnableLFS({ authorization, host, owner, repo }); + } + ctx.output('remoteUrl', remoteUrl); ctx.output('repoContentsUrl', repoContentsUrl); },