From d7a8c736f8db1350fae7c5b85138e6159784d050 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Fri, 14 Jun 2024 11:22:17 +0200 Subject: [PATCH] refactor: revert ScmAuthTokenOptions API change Signed-off-by: Benjamin Janssens --- .changeset/cool-stingrays-eat.md | 5 -- .changeset/seven-chefs-share.md | 5 -- packages/integration-react/api-report.md | 4 +- .../integration-react/src/api/ScmAuth.test.ts | 84 +++++++++++-------- packages/integration-react/src/api/ScmAuth.ts | 14 ++-- .../integration-react/src/api/ScmAuthApi.ts | 6 +- .../src/api/CatalogImportClient.test.ts | 13 --- .../src/api/CatalogImportClient.ts | 2 +- 8 files changed, 60 insertions(+), 73 deletions(-) delete mode 100644 .changeset/cool-stingrays-eat.md delete mode 100644 .changeset/seven-chefs-share.md diff --git a/.changeset/cool-stingrays-eat.md b/.changeset/cool-stingrays-eat.md deleted file mode 100644 index ba79391b49..0000000000 --- a/.changeset/cool-stingrays-eat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Updated `CatalogImportClient` to use the updated `ScmAuthTokenOptions` diff --git a/.changeset/seven-chefs-share.md b/.changeset/seven-chefs-share.md deleted file mode 100644 index 6fa031cafa..0000000000 --- a/.changeset/seven-chefs-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration-react': patch ---- - -Replaced property `url` of `ScmAuthTokenOptions` with property `host` diff --git a/packages/integration-react/api-report.md b/packages/integration-react/api-report.md index 9e30875e79..c1a2e34907 100644 --- a/packages/integration-react/api-report.md +++ b/packages/integration-react/api-report.md @@ -70,7 +70,7 @@ export class ScmAuth implements ScmAuthApi { }, ): ScmAuth; getCredentials(options: ScmAuthTokenOptions): Promise; - isHostSupported(host: string): boolean; + isUrlSupported(url: URL): boolean; static merge(...providers: ScmAuth[]): ScmAuthApi; } @@ -93,7 +93,7 @@ export interface ScmAuthTokenOptions extends AuthRequestOptions { gitlab?: string[]; }; }; - host: string; + url: string; } // @public diff --git a/packages/integration-react/src/api/ScmAuth.test.ts b/packages/integration-react/src/api/ScmAuth.test.ts index de5ad516d7..d252b95b85 100644 --- a/packages/integration-react/src/api/ScmAuth.test.ts +++ b/packages/integration-react/src/api/ScmAuth.test.ts @@ -37,7 +37,9 @@ describe('ScmAuth', () => { }), ); - await expect(api.getCredentials({ host: 'github.com' })).resolves.toEqual({ + await expect( + api.getCredentials({ url: 'https://github.com/backstage/backstage' }), + ).resolves.toEqual({ token: 'github-access-token', headers: { Authorization: 'Bearer github-access-token', @@ -45,7 +47,7 @@ describe('ScmAuth', () => { }); await expect( api.getCredentials({ - host: 'ghe.example.com', + url: 'https://ghe.example.com/backstage/backstage', additionalScope: { repoWrite: true, }, @@ -78,13 +80,13 @@ describe('ScmAuth', () => { const githubAuth = ScmAuth.forGithub(mockAuthApi); await expect( - githubAuth.getCredentials({ host: 'example.com' }), + githubAuth.getCredentials({ url: 'http://example.com' }), ).resolves.toMatchObject({ token: 'repo read:org read:user', }); await expect( githubAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { repoWrite: true }, }), ).resolves.toMatchObject({ @@ -93,13 +95,13 @@ describe('ScmAuth', () => { const gitlabAuth = ScmAuth.forGitlab(mockAuthApi); await expect( - gitlabAuth.getCredentials({ host: 'example.com' }), + gitlabAuth.getCredentials({ url: 'http://example.com' }), ).resolves.toMatchObject({ token: 'read_user read_api read_repository', }); await expect( gitlabAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { repoWrite: true }, }), ).resolves.toMatchObject({ @@ -108,14 +110,14 @@ describe('ScmAuth', () => { const azureAuth = ScmAuth.forAzure(mockAuthApi); await expect( - azureAuth.getCredentials({ host: 'example.com' }), + azureAuth.getCredentials({ url: 'http://example.com' }), ).resolves.toMatchObject({ token: '499b84ac-1321-427f-aa17-267ca6975798/vso.build 499b84ac-1321-427f-aa17-267ca6975798/vso.code 499b84ac-1321-427f-aa17-267ca6975798/vso.graph 499b84ac-1321-427f-aa17-267ca6975798/vso.project 499b84ac-1321-427f-aa17-267ca6975798/vso.profile', }); await expect( azureAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { repoWrite: true }, }), ).resolves.toMatchObject({ @@ -125,13 +127,13 @@ describe('ScmAuth', () => { const bitbucketAuth = ScmAuth.forBitbucket(mockAuthApi); await expect( - bitbucketAuth.getCredentials({ host: 'example.com' }), + bitbucketAuth.getCredentials({ url: 'http://example.com' }), ).resolves.toMatchObject({ token: 'account team pullrequest snippet issue', }); await expect( bitbucketAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { repoWrite: true }, }), ).resolves.toMatchObject({ @@ -150,7 +152,7 @@ describe('ScmAuth', () => { const githubAuth = ScmAuth.forGithub(mockAuthApi); await expect( githubAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { customScopes: { github: ['org:read', 'workflow'] }, }, @@ -162,7 +164,7 @@ describe('ScmAuth', () => { const gitlabAuth = ScmAuth.forGitlab(mockAuthApi); await expect( gitlabAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { customScopes: { gitlab: ['write_repository'] } }, }), ).resolves.toMatchObject({ @@ -172,7 +174,7 @@ describe('ScmAuth', () => { const azureAuth = ScmAuth.forAzure(mockAuthApi); await expect( azureAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { customScopes: { azure: ['499b84ac-1321-427f-aa17-267ca6975798/vso.org'], @@ -187,7 +189,7 @@ describe('ScmAuth', () => { const bitbucketAuth = ScmAuth.forBitbucket(mockAuthApi); await expect( bitbucketAuth.getCredentials({ - host: 'example.com', + url: 'http://example.com', additionalScope: { customScopes: { bitbucket: ['snippet:write', 'issue:write'] }, }, @@ -202,39 +204,47 @@ describe('ScmAuth', () => { getAccessToken: jest.fn(), }; - const expectHostSupport = (scm: ScmAuth, host: string) => { - expect(scm.isHostSupported(host)).toBe(true); - expect(scm.isHostSupported('not.supported.com')).toBe(false); + const expectUrlSupport = (scm: ScmAuth, url: string) => { + expect(scm.isUrlSupported(new URL(url))).toBe(true); + expect(scm.isUrlSupported(new URL('https://not.supported.com'))).toBe( + false, + ); }; - expectHostSupport(ScmAuth.forGithub(mockAuthApi), 'github.com'); - expectHostSupport(ScmAuth.forGitlab(mockAuthApi), 'gitlab.com'); - expectHostSupport(ScmAuth.forAzure(mockAuthApi, {}), 'dev.azure.com'); - expectHostSupport(ScmAuth.forBitbucket(mockAuthApi, {}), 'bitbucket.org'); - expectHostSupport( + expectUrlSupport(ScmAuth.forGithub(mockAuthApi), 'https://github.com'); + expectUrlSupport(ScmAuth.forGitlab(mockAuthApi), 'https://gitlab.com'); + expectUrlSupport( + ScmAuth.forAzure(mockAuthApi, {}), + 'https://dev.azure.com', + ); + expectUrlSupport( + ScmAuth.forBitbucket(mockAuthApi, {}), + 'https://bitbucket.org', + ); + expectUrlSupport( ScmAuth.forGithub(mockAuthApi, { host: 'example.com' }), - 'example.com', + 'https://example.com/abc', ); - expectHostSupport( + expectUrlSupport( ScmAuth.forGitlab(mockAuthApi, { host: 'example.com' }), - 'example.com', + 'http://example.com', ); - expectHostSupport( + expectUrlSupport( ScmAuth.forAzure(mockAuthApi, { host: 'example.com' }), - 'example.com', + 'https://example.com', ); - expectHostSupport( + expectUrlSupport( ScmAuth.forBitbucket(mockAuthApi, { host: 'example.com:8080' }), - 'example.com:8080', + 'https://example.com:8080', ); }); - it('should throw an error for unknown hosts', async () => { + it('should throw an error for unknown URLs', async () => { const emptyMux = ScmAuth.merge(); await expect( - emptyMux.getCredentials({ host: 'example.com' }), + emptyMux.getCredentials({ url: 'http://example.com' }), ).rejects.toThrow( - "No auth provider available for 'example.com', see https://backstage.io/link?scm-auth", + "No auth provider available for 'http://example.com', see https://backstage.io/link?scm-auth", ); const scmAuth = ScmAuth.merge( @@ -247,17 +257,17 @@ describe('ScmAuth', () => { }), ); await expect( - scmAuth.getCredentials({ host: 'example.com' }), + scmAuth.getCredentials({ url: 'http://example.com' }), ).resolves.toMatchObject({ token: 'token' }); await expect( - scmAuth.getCredentials({ host: 'not.example.com' }), + scmAuth.getCredentials({ url: 'http://not.example.com' }), ).rejects.toThrow( - "No auth provider available for 'not.example.com', see https://backstage.io/link?scm-auth", + "No auth provider available for 'http://not.example.com', see https://backstage.io/link?scm-auth", ); await expect( - scmAuth.getCredentials({ host: 'example.com:8080' }), + scmAuth.getCredentials({ url: 'http://example.com:8080' }), ).rejects.toThrow( - "No auth provider available for 'example.com:8080', see https://backstage.io/link?scm-auth", + "No auth provider available for 'http://example.com:8080', see https://backstage.io/link?scm-auth", ); }); }); diff --git a/packages/integration-react/src/api/ScmAuth.ts b/packages/integration-react/src/api/ScmAuth.ts index 05bb360d90..a22b15e400 100644 --- a/packages/integration-react/src/api/ScmAuth.ts +++ b/packages/integration-react/src/api/ScmAuth.ts @@ -49,11 +49,11 @@ class ScmAuthMux implements ScmAuthApi { async getCredentials( options: ScmAuthTokenOptions, ): Promise { - const { host } = options; - const provider = this.#providers.find(p => p.isHostSupported(host)); + const url = new URL(options.url); + const provider = this.#providers.find(p => p.isUrlSupported(url)); if (!provider) { throw new Error( - `No auth provider available for '${host}', see https://backstage.io/link?scm-auth`, + `No auth provider available for '${options.url}', see https://backstage.io/link?scm-auth`, ); } @@ -261,10 +261,10 @@ export class ScmAuth implements ScmAuthApi { } /** - * Checks whether the implementation is able to provide authentication for the given host. + * Checks whether the implementation is able to provide authentication for the given URL. */ - isHostSupported(host: string): boolean { - return host === this.#host; + isUrlSupported(url: URL): boolean { + return url.host === this.#host; } private getAdditionalScopesForProvider( @@ -283,7 +283,7 @@ export class ScmAuth implements ScmAuthApi { async getCredentials( options: ScmAuthTokenOptions, ): Promise { - const { host, additionalScope, ...restOptions } = options; + const { url, additionalScope, ...restOptions } = options; const scopes = this.#scopeMapping.default.slice(); if (additionalScope?.repoWrite) { diff --git a/packages/integration-react/src/api/ScmAuthApi.ts b/packages/integration-react/src/api/ScmAuthApi.ts index eafc630128..be65842bc1 100644 --- a/packages/integration-react/src/api/ScmAuthApi.ts +++ b/packages/integration-react/src/api/ScmAuthApi.ts @@ -27,11 +27,11 @@ import { */ export interface ScmAuthTokenOptions extends AuthRequestOptions { /** - * The host of the SCM resource to be accessed. + * The URL of the SCM resource to be accessed. * - * @example github.com + * @example https://github.com/backstage/backstage */ - host: string; + url: string; /** * Whether to request additional access scope. diff --git a/plugins/catalog-import/src/api/CatalogImportClient.test.ts b/plugins/catalog-import/src/api/CatalogImportClient.test.ts index 73b9d741b9..df44ec94c4 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.test.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.test.ts @@ -588,12 +588,6 @@ describe('CatalogImportClient', () => { 'https://github.com/backstage/backstage/blob/main/catalog-info.yaml', }); expect(catalogApi.validateEntity).toHaveBeenCalledTimes(1); - expect(scmAuthApi.getCredentials).toHaveBeenCalledWith({ - host: 'github.com', - additionalScope: { - repoWrite: true, - }, - }); expect( (new Octokit().git.createRef as any as jest.Mock).mock.calls[0][0], ).toEqual({ @@ -707,13 +701,6 @@ describe('CatalogImportClient', () => { }), ); - expect(scmAuthApi.getCredentials).toHaveBeenCalledWith({ - host: 'github.com', - additionalScope: { - repoWrite: true, - }, - }); - expect( (new Octokit().git.createRef as any as jest.Mock).mock.calls[0][0], ).toEqual( diff --git a/plugins/catalog-import/src/api/CatalogImportClient.ts b/plugins/catalog-import/src/api/CatalogImportClient.ts index 32bea5d7b4..cecb85f9a3 100644 --- a/plugins/catalog-import/src/api/CatalogImportClient.ts +++ b/plugins/catalog-import/src/api/CatalogImportClient.ts @@ -260,7 +260,7 @@ the component will become available.\n\nFor more information, read an \ } = options; const { token } = await this.scmAuthApi.getCredentials({ - host: new URL(repositoryUrl).host, + url: repositoryUrl, additionalScope: { repoWrite: true, },