refactor: revert ScmAuthTokenOptions API change

Signed-off-by: Benjamin Janssens <benji.janssens@gmail.com>
This commit is contained in:
Benjamin Janssens
2024-06-14 11:22:17 +02:00
parent e3d0da09dc
commit d7a8c736f8
8 changed files with 60 additions and 73 deletions
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-import': patch
---
Updated `CatalogImportClient` to use the updated `ScmAuthTokenOptions`
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/integration-react': patch
---
Replaced property `url` of `ScmAuthTokenOptions` with property `host`
+2 -2
View File
@@ -70,7 +70,7 @@ export class ScmAuth implements ScmAuthApi {
},
): ScmAuth;
getCredentials(options: ScmAuthTokenOptions): Promise<ScmAuthTokenResponse>;
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
@@ -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",
);
});
});
@@ -49,11 +49,11 @@ class ScmAuthMux implements ScmAuthApi {
async getCredentials(
options: ScmAuthTokenOptions,
): Promise<ScmAuthTokenResponse> {
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<ScmAuthTokenResponse> {
const { host, additionalScope, ...restOptions } = options;
const { url, additionalScope, ...restOptions } = options;
const scopes = this.#scopeMapping.default.slice();
if (additionalScope?.repoWrite) {
@@ -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.
@@ -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(
@@ -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,
},