From 2ea30b685225b24dbb1128f879c95a8ee0ed6521 Mon Sep 17 00:00:00 2001 From: Max Morton Date: Fri, 11 Nov 2022 10:27:08 -0800 Subject: [PATCH 1/9] Update GitlabUrlReader to support API and Artifact URLs Signed-off-by: Max Morton --- .../src/reading/GitlabUrlReader.test.ts | 82 +++++++++++++++++++ .../src/reading/GitlabUrlReader.ts | 67 ++++++++++++++- 2 files changed, 148 insertions(+), 1 deletion(-) diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index 29ef3f4ce8..d88c6d8fb9 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -573,4 +573,86 @@ describe('GitlabUrlReader', () => { ).rejects.toThrow(NotModifiedError); }); }); + + describe('getGitlabFetchUrl', () => { + beforeEach(() => { + worker.use( + rest.get( + '*/api/v4/projects/group%2Fsubgroup%2Fproject', + (_, res, ctx) => res(ctx.status(200), ctx.json({ id: 12345 })), + ), + ); + }); + it('should fall back to getGitLabFileFetchUrl for blob urls', async () => { + await expect( + gitlabProcessor.getGitlabFetchUrl( + 'https://gitlab.com/group/subgroup/project/-/blob/branch/my/path/to/file.yaml', + ), + ).resolves.toEqual( + 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + ); + }); + it('should work for job artifact urls', async () => { + await expect( + gitlabProcessor.getGitlabFetchUrl( + 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ), + ).resolves.toEqual( + 'https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ); + }); + it('should pass API urls naively', async () => { + const apiUrl = 'https://gitlab.com/api/v4/my/api/path'; + await expect(gitlabProcessor.getGitlabFetchUrl(apiUrl)).resolves.toEqual( + apiUrl, + ); + }); + it('should fail on unfamiliar or non-Gitlab urls', async () => { + await expect( + gitlabProcessor.getGitlabFetchUrl( + 'https://gitlab.com/some/random/endpoint', + ), + ).rejects.toThrow('Please provide full path to yaml file from GitLab'); + }); + }); + + describe('getGitlabArtfiactFetchUrl', () => { + beforeEach(() => { + worker.use( + rest.get( + '*/api/v4/projects/group%2Fsubgroup%2Fproject', + (_, res, ctx) => res(ctx.status(200), ctx.json({ id: 12345 })), + ), + ); + worker.use( + rest.get( + '*/api/v4/projects/groupA%2Fsubgroup%2Fproject', + (_, res, ctx) => res(ctx.status(404)), + ), + ); + }); + it('should reject urls that are not for the job artifacts API', async () => { + await expect( + gitlabProcessor.getGitlabArtifactFetchUrl( + 'https://gitlab.com/some/url', + ), + ).rejects.toThrow('Unable to process url as an GitLab artifact'); + }); + it('should work for job artifact urls', async () => { + await expect( + gitlabProcessor.getGitlabFetchUrl( + 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ), + ).resolves.toEqual( + 'https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ); + }); + it('errors in mapping the project ID should be captured', async () => { + await expect( + gitlabProcessor.getGitlabFetchUrl( + 'https://gitlab.com/groupA/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ), + ).rejects.toThrow(/^Unable to translate GitLab artifact URL:/); + }); + }); }); diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts index eaa15a7208..f704901650 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.ts @@ -73,7 +73,7 @@ export class GitlabUrlReader implements UrlReader { options?: ReadUrlOptions, ): Promise { const { etag, signal } = options ?? {}; - const builtUrl = await getGitLabFileFetchUrl(url, this.integration.config); + const builtUrl = await this.getGitlabFetchUrl(url); let response: Response; try { @@ -256,4 +256,69 @@ export class GitlabUrlReader implements UrlReader { const { host, token } = this.integration.config; return `gitlab{host=${host},authed=${Boolean(token)}}`; } + + async getGitlabFetchUrl(target: string): Promise { + // If the target is a raw API url then trust that no parsing is needed + if (target.includes('/api/v4/')) { + return target; + } + // If the target is for a job artifact then go down that path + if (target.includes('/-/jobs/artifacts/')) { + return this.getGitlabArtifactFetchUrl(target).then(value => + value.toString(), + ); + } + // Default to the old behavior of assuming the url is for a file + return getGitLabFileFetchUrl(target, this.integration.config); + } + + // convert urls of the form: + // https://example.com///-/jobs/artifacts//raw/?job= + // to urls of the form: + // https://example.com/api/v4/projects/:id/jobs/artifacts/:ref_name/raw/*artifact_path?job= + async getGitlabArtifactFetchUrl(target: string): Promise { + const url = new URL(target); + if (!url.pathname.includes('/-/jobs/artifacts/')) { + throw new Error('Unable to process url as an GitLab artifact'); + } + try { + const [namespaceAndProject, ref] = + url.pathname.split('/-/jobs/artifacts/'); + const projectPath = new URL(url); + projectPath.pathname = namespaceAndProject; + const projectId = await this.resolveProjectToId(projectPath); + const relativePath = getGitLabIntegrationRelativePath( + this.integration.config, + ); + url.pathname = `${relativePath}/api/v4/projects/${projectId}/jobs/artifacts/${ref}`; + return url; + } catch (e) { + throw new Error( + `Unable to translate GitLab artifact URL: ${target}, ${e}`, + ); + } + } + + private async resolveProjectToId(pathToProject: URL): Promise { + let project = pathToProject.pathname; + // Check relative path exist and remove it if so + const relativePath = getGitLabIntegrationRelativePath( + this.integration.config, + ); + if (relativePath) { + project = project.replace(relativePath, ''); + } + // Trim an initial / if it exists + project = project.replace(/^\//, ''); + const result = await fetch( + `${ + pathToProject.origin + }${relativePath}/api/v4/projects/${encodeURIComponent(project)}`, + ); + const data = await result.json(); + if (!result.ok) { + throw new Error(`Gitlab error: ${data.error}, ${data.error_description}`); + } + return Number(data.id); + } } From 6b82598bd82e09ff2979e93aed3d77def54881cd Mon Sep 17 00:00:00 2001 From: Max Morton Date: Fri, 11 Nov 2022 11:17:50 -0800 Subject: [PATCH 2/9] Add changeset Signed-off-by: Max Morton --- .changeset/rich-balloons-leave.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rich-balloons-leave.md diff --git a/.changeset/rich-balloons-leave.md b/.changeset/rich-balloons-leave.md new file mode 100644 index 0000000000..b77524b396 --- /dev/null +++ b/.changeset/rich-balloons-leave.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Added the ability to understand Job Artifact URLs and raw API URLs to the GitLab integration From b7cda00d33ef431fddc39ff75e421d4b962ff6e0 Mon Sep 17 00:00:00 2001 From: Max Morton Date: Mon, 14 Nov 2022 09:14:23 -0800 Subject: [PATCH 3/9] add api-report Signed-off-by: Max Morton --- packages/backend-common/api-report.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index e8dbd8d150..69d94053b3 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -458,6 +458,10 @@ export class GitlabUrlReader implements UrlReader { // (undocumented) static factory: ReaderFactory; // (undocumented) + getGitlabArtifactFetchUrl(target: string): Promise; + // (undocumented) + getGitlabFetchUrl(target: string): Promise; + // (undocumented) read(url: string): Promise; // (undocumented) readTree(url: string, options?: ReadTreeOptions): Promise; From 468cd24becb97e3ce79c97acb8bff350af6870a8 Mon Sep 17 00:00:00 2001 From: Max Morton Date: Thu, 17 Nov 2022 09:05:46 -0800 Subject: [PATCH 4/9] Revert "add api-report" This reverts commit b7cda00d33ef431fddc39ff75e421d4b962ff6e0. Signed-off-by: Max Morton --- packages/backend-common/api-report.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index 69d94053b3..e8dbd8d150 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -458,10 +458,6 @@ export class GitlabUrlReader implements UrlReader { // (undocumented) static factory: ReaderFactory; // (undocumented) - getGitlabArtifactFetchUrl(target: string): Promise; - // (undocumented) - getGitlabFetchUrl(target: string): Promise; - // (undocumented) read(url: string): Promise; // (undocumented) readTree(url: string, options?: ReadTreeOptions): Promise; From fb6b4036474c9f5073b77bb68f753d8136328217 Mon Sep 17 00:00:00 2001 From: Max Morton Date: Thu, 17 Nov 2022 09:11:59 -0800 Subject: [PATCH 5/9] Make functions private Signed-off-by: Max Morton --- .../src/reading/GitlabUrlReader.test.ts | 18 +++++++++--------- .../src/reading/GitlabUrlReader.ts | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index d88c6d8fb9..8bf0328432 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -585,7 +585,7 @@ describe('GitlabUrlReader', () => { }); it('should fall back to getGitLabFileFetchUrl for blob urls', async () => { await expect( - gitlabProcessor.getGitlabFetchUrl( + (gitlabProcessor as any).getGitlabFetchUrl( 'https://gitlab.com/group/subgroup/project/-/blob/branch/my/path/to/file.yaml', ), ).resolves.toEqual( @@ -594,7 +594,7 @@ describe('GitlabUrlReader', () => { }); it('should work for job artifact urls', async () => { await expect( - gitlabProcessor.getGitlabFetchUrl( + (gitlabProcessor as any).getGitlabFetchUrl( 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', ), ).resolves.toEqual( @@ -603,13 +603,13 @@ describe('GitlabUrlReader', () => { }); it('should pass API urls naively', async () => { const apiUrl = 'https://gitlab.com/api/v4/my/api/path'; - await expect(gitlabProcessor.getGitlabFetchUrl(apiUrl)).resolves.toEqual( - apiUrl, - ); + await expect( + (gitlabProcessor as any).getGitlabFetchUrl(apiUrl) + ).resolves.toEqual(apiUrl,); }); it('should fail on unfamiliar or non-Gitlab urls', async () => { await expect( - gitlabProcessor.getGitlabFetchUrl( + (gitlabProcessor as any).getGitlabFetchUrl( 'https://gitlab.com/some/random/endpoint', ), ).rejects.toThrow('Please provide full path to yaml file from GitLab'); @@ -633,14 +633,14 @@ describe('GitlabUrlReader', () => { }); it('should reject urls that are not for the job artifacts API', async () => { await expect( - gitlabProcessor.getGitlabArtifactFetchUrl( + (gitlabProcessor as any).getGitlabArtifactFetchUrl( 'https://gitlab.com/some/url', ), ).rejects.toThrow('Unable to process url as an GitLab artifact'); }); it('should work for job artifact urls', async () => { await expect( - gitlabProcessor.getGitlabFetchUrl( + (gitlabProcessor as any).getGitlabFetchUrl( 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', ), ).resolves.toEqual( @@ -649,7 +649,7 @@ describe('GitlabUrlReader', () => { }); it('errors in mapping the project ID should be captured', async () => { await expect( - gitlabProcessor.getGitlabFetchUrl( + (gitlabProcessor as any).getGitlabFetchUrl( 'https://gitlab.com/groupA/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', ), ).rejects.toThrow(/^Unable to translate GitLab artifact URL:/); diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts index f704901650..3455de6f20 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.ts @@ -257,7 +257,7 @@ export class GitlabUrlReader implements UrlReader { return `gitlab{host=${host},authed=${Boolean(token)}}`; } - async getGitlabFetchUrl(target: string): Promise { + private async getGitlabFetchUrl(target: string): Promise { // If the target is a raw API url then trust that no parsing is needed if (target.includes('/api/v4/')) { return target; @@ -276,7 +276,7 @@ export class GitlabUrlReader implements UrlReader { // https://example.com///-/jobs/artifacts//raw/?job= // to urls of the form: // https://example.com/api/v4/projects/:id/jobs/artifacts/:ref_name/raw/*artifact_path?job= - async getGitlabArtifactFetchUrl(target: string): Promise { + private async getGitlabArtifactFetchUrl(target: string): Promise { const url = new URL(target); if (!url.pathname.includes('/-/jobs/artifacts/')) { throw new Error('Unable to process url as an GitLab artifact'); From 15841df6df40eb7bcb56f7c36f11680d3f2fe4a4 Mon Sep 17 00:00:00 2001 From: Max Morton Date: Thu, 17 Nov 2022 10:21:39 -0800 Subject: [PATCH 6/9] remove naive /api/v4 querying Signed-off-by: Max Morton --- packages/backend-common/src/reading/GitlabUrlReader.test.ts | 6 ------ packages/backend-common/src/reading/GitlabUrlReader.ts | 4 ---- 2 files changed, 10 deletions(-) diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index 8bf0328432..caf82f2f9e 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -601,12 +601,6 @@ describe('GitlabUrlReader', () => { 'https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', ); }); - it('should pass API urls naively', async () => { - const apiUrl = 'https://gitlab.com/api/v4/my/api/path'; - await expect( - (gitlabProcessor as any).getGitlabFetchUrl(apiUrl) - ).resolves.toEqual(apiUrl,); - }); it('should fail on unfamiliar or non-Gitlab urls', async () => { await expect( (gitlabProcessor as any).getGitlabFetchUrl( diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts index 3455de6f20..f54e045857 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.ts @@ -258,10 +258,6 @@ export class GitlabUrlReader implements UrlReader { } private async getGitlabFetchUrl(target: string): Promise { - // If the target is a raw API url then trust that no parsing is needed - if (target.includes('/api/v4/')) { - return target; - } // If the target is for a job artifact then go down that path if (target.includes('/-/jobs/artifacts/')) { return this.getGitlabArtifactFetchUrl(target).then(value => From f766f6f5d511f4c3a5c8e1b087d376c7fdfb3a2f Mon Sep 17 00:00:00 2001 From: Max Morton Date: Thu, 17 Nov 2022 11:06:58 -0800 Subject: [PATCH 7/9] update changeset Signed-off-by: Max Morton --- .changeset/rich-balloons-leave.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/rich-balloons-leave.md b/.changeset/rich-balloons-leave.md index b77524b396..bb6832a681 100644 --- a/.changeset/rich-balloons-leave.md +++ b/.changeset/rich-balloons-leave.md @@ -2,4 +2,4 @@ '@backstage/backend-common': patch --- -Added the ability to understand Job Artifact URLs and raw API URLs to the GitLab integration +Added the ability to understand Job Artifact URLs to the GitLab integration From f1fb8d1d5ec90483b2902078293cfb8e7a8b810b Mon Sep 17 00:00:00 2001 From: Max Morton Date: Thu, 17 Nov 2022 13:55:01 -0800 Subject: [PATCH 8/9] test pathname instead of raw string Signed-off-by: Max Morton --- .../src/reading/GitlabUrlReader.test.ts | 38 +++++-------------- .../src/reading/GitlabUrlReader.ts | 24 ++++++------ 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index caf82f2f9e..4c612b4350 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -585,32 +585,22 @@ describe('GitlabUrlReader', () => { }); it('should fall back to getGitLabFileFetchUrl for blob urls', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl( - 'https://gitlab.com/group/subgroup/project/-/blob/branch/my/path/to/file.yaml', - ), - ).resolves.toEqual( - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - ); + (gitlabProcessor as any).getGitlabFetchUrl('https://gitlab.com/group/subgroup/project/-/blob/branch/my/path/to/file.yaml'), + ).resolves.toEqual('https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch'); }); it('should work for job artifact urls', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl( - 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', - ), - ).resolves.toEqual( - 'https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', - ); + (gitlabProcessor as any).getGitlabFetchUrl('https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob'), + ).resolves.toEqual('https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob'); }); it('should fail on unfamiliar or non-Gitlab urls', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl( - 'https://gitlab.com/some/random/endpoint', - ), + (gitlabProcessor as any).getGitlabFetchUrl('https://gitlab.com/some/random/endpoint'), ).rejects.toThrow('Please provide full path to yaml file from GitLab'); }); }); - describe('getGitlabArtfiactFetchUrl', () => { + describe('getGitlabArtifactFetchUrl', () => { beforeEach(() => { worker.use( rest.get( @@ -627,25 +617,17 @@ describe('GitlabUrlReader', () => { }); it('should reject urls that are not for the job artifacts API', async () => { await expect( - (gitlabProcessor as any).getGitlabArtifactFetchUrl( - 'https://gitlab.com/some/url', - ), + (gitlabProcessor as any).getGitlabArtifactFetchUrl(new URL('https://gitlab.com/some/url')) ).rejects.toThrow('Unable to process url as an GitLab artifact'); }); it('should work for job artifact urls', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl( - 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', - ), - ).resolves.toEqual( - 'https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', - ); + (gitlabProcessor as any).getGitlabArtifactFetchUrl(new URL('https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob')) + ).resolves.toEqual(new URL('https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob')); }); it('errors in mapping the project ID should be captured', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl( - 'https://gitlab.com/groupA/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', - ), + (gitlabProcessor as any).getGitlabArtifactFetchUrl(new URL('https://gitlab.com/groupA/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob')) ).rejects.toThrow(/^Unable to translate GitLab artifact URL:/); }); }); diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts index f54e045857..7b89f00f47 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.ts @@ -259,8 +259,9 @@ export class GitlabUrlReader implements UrlReader { private async getGitlabFetchUrl(target: string): Promise { // If the target is for a job artifact then go down that path - if (target.includes('/-/jobs/artifacts/')) { - return this.getGitlabArtifactFetchUrl(target).then(value => + const targetUrl = new URL(target); + if (targetUrl.pathname.includes('/-/jobs/artifacts/')) { + return this.getGitlabArtifactFetchUrl(targetUrl).then(value => value.toString(), ); } @@ -272,22 +273,19 @@ export class GitlabUrlReader implements UrlReader { // https://example.com///-/jobs/artifacts//raw/?job= // to urls of the form: // https://example.com/api/v4/projects/:id/jobs/artifacts/:ref_name/raw/*artifact_path?job= - private async getGitlabArtifactFetchUrl(target: string): Promise { - const url = new URL(target); - if (!url.pathname.includes('/-/jobs/artifacts/')) { + private async getGitlabArtifactFetchUrl(target: URL): Promise { + if (!target.pathname.includes('/-/jobs/artifacts/')) { throw new Error('Unable to process url as an GitLab artifact'); } try { - const [namespaceAndProject, ref] = - url.pathname.split('/-/jobs/artifacts/'); - const projectPath = new URL(url); + const [namespaceAndProject, ref] = target.pathname.split('/-/jobs/artifacts/'); + const projectPath = new URL(target); projectPath.pathname = namespaceAndProject; const projectId = await this.resolveProjectToId(projectPath); - const relativePath = getGitLabIntegrationRelativePath( - this.integration.config, - ); - url.pathname = `${relativePath}/api/v4/projects/${projectId}/jobs/artifacts/${ref}`; - return url; + const relativePath = getGitLabIntegrationRelativePath(this.integration.config); + const newUrl = new URL(target); + newUrl.pathname = `${relativePath}/api/v4/projects/${projectId}/jobs/artifacts/${ref}`; + return newUrl; } catch (e) { throw new Error( `Unable to translate GitLab artifact URL: ${target}, ${e}`, From 6d0f1d2474a0a23961eb211aadd91a64a1dea17a Mon Sep 17 00:00:00 2001 From: Max Morton Date: Fri, 18 Nov 2022 09:33:07 -0800 Subject: [PATCH 9/9] prettier run Signed-off-by: Max Morton --- .../src/reading/GitlabUrlReader.test.ts | 42 +++++++++++++++---- .../src/reading/GitlabUrlReader.ts | 7 +++- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index 4c612b4350..18f00d9f68 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -585,17 +585,27 @@ describe('GitlabUrlReader', () => { }); it('should fall back to getGitLabFileFetchUrl for blob urls', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl('https://gitlab.com/group/subgroup/project/-/blob/branch/my/path/to/file.yaml'), - ).resolves.toEqual('https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch'); + (gitlabProcessor as any).getGitlabFetchUrl( + 'https://gitlab.com/group/subgroup/project/-/blob/branch/my/path/to/file.yaml', + ), + ).resolves.toEqual( + 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + ); }); it('should work for job artifact urls', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl('https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob'), - ).resolves.toEqual('https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob'); + (gitlabProcessor as any).getGitlabFetchUrl( + 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ), + ).resolves.toEqual( + 'https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ); }); it('should fail on unfamiliar or non-Gitlab urls', async () => { await expect( - (gitlabProcessor as any).getGitlabFetchUrl('https://gitlab.com/some/random/endpoint'), + (gitlabProcessor as any).getGitlabFetchUrl( + 'https://gitlab.com/some/random/endpoint', + ), ).rejects.toThrow('Please provide full path to yaml file from GitLab'); }); }); @@ -617,17 +627,31 @@ describe('GitlabUrlReader', () => { }); it('should reject urls that are not for the job artifacts API', async () => { await expect( - (gitlabProcessor as any).getGitlabArtifactFetchUrl(new URL('https://gitlab.com/some/url')) + (gitlabProcessor as any).getGitlabArtifactFetchUrl( + new URL('https://gitlab.com/some/url'), + ), ).rejects.toThrow('Unable to process url as an GitLab artifact'); }); it('should work for job artifact urls', async () => { await expect( - (gitlabProcessor as any).getGitlabArtifactFetchUrl(new URL('https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob')) - ).resolves.toEqual(new URL('https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob')); + (gitlabProcessor as any).getGitlabArtifactFetchUrl( + new URL( + 'https://gitlab.com/group/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ), + ), + ).resolves.toEqual( + new URL( + 'https://gitlab.com/api/v4/projects/12345/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ), + ); }); it('errors in mapping the project ID should be captured', async () => { await expect( - (gitlabProcessor as any).getGitlabArtifactFetchUrl(new URL('https://gitlab.com/groupA/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob')) + (gitlabProcessor as any).getGitlabArtifactFetchUrl( + new URL( + 'https://gitlab.com/groupA/subgroup/project/-/jobs/artifacts/branch/raw/my/path/to/file.yaml?job=myJob', + ), + ), ).rejects.toThrow(/^Unable to translate GitLab artifact URL:/); }); }); diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts index 7b89f00f47..522e81cd2f 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.ts @@ -278,11 +278,14 @@ export class GitlabUrlReader implements UrlReader { throw new Error('Unable to process url as an GitLab artifact'); } try { - const [namespaceAndProject, ref] = target.pathname.split('/-/jobs/artifacts/'); + const [namespaceAndProject, ref] = + target.pathname.split('/-/jobs/artifacts/'); const projectPath = new URL(target); projectPath.pathname = namespaceAndProject; const projectId = await this.resolveProjectToId(projectPath); - const relativePath = getGitLabIntegrationRelativePath(this.integration.config); + const relativePath = getGitLabIntegrationRelativePath( + this.integration.config, + ); const newUrl = new URL(target); newUrl.pathname = `${relativePath}/api/v4/projects/${projectId}/jobs/artifacts/${ref}`; return newUrl;