diff --git a/.changeset/famous-sloths-tie.md b/.changeset/famous-sloths-tie.md new file mode 100644 index 0000000000..53932afab6 --- /dev/null +++ b/.changeset/famous-sloths-tie.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Getting credentials in the RepoUrlPicker now also works for targets without owner (e.g. Bitbucket Server). diff --git a/plugins/auth-backend/src/providers/bitbucketServer/provider.ts b/plugins/auth-backend/src/providers/bitbucketServer/provider.ts index fb8dd3d5b8..220f6db5cd 100644 --- a/plugins/auth-backend/src/providers/bitbucketServer/provider.ts +++ b/plugins/auth-backend/src/providers/bitbucketServer/provider.ts @@ -216,7 +216,7 @@ export class BitbucketServerAuthProvider implements OAuthHandlers { throw new Error(`Failed to retrieve the user '${username}'`); } - const user = (await userResponse.json()) as any; + const user = await userResponse.json(); const passportProfile = { provider: 'bitbucketServer', diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx index 1edb4fb940..c36374f939 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx @@ -38,6 +38,11 @@ describe('RepoUrlPicker', () => { integrations: [ { host: 'github.com', type: 'github', title: 'github.com' }, { host: 'dev.azure.com', type: 'azure', title: 'dev.azure.com' }, + { + host: 'server.bitbucket.org', + type: 'bitbucketServer', + title: 'server.bitbucket.org', + }, ], }), }; @@ -175,6 +180,65 @@ describe('RepoUrlPicker', () => { getByTestId('current-secrets').textContent!, ); + expect(currentSecrets).toEqual({ + secrets: { testKey: 'abc123' }, + }); + }); + it('should call the scmAuthApi with the correct params if only a project is set', async () => { + const SecretsComponent = () => { + const { secrets } = useTemplateSecrets(); + return ( +
{JSON.stringify({ secrets })}
+ ); + }; + const { getAllByRole, getByTestId } = await renderInTestApp( + + +
+ + + , + ); + + const [projectInput, repoInput] = getAllByRole('textbox'); + + await act(async () => { + fireEvent.change(projectInput, { target: { value: 'backstage' } }); + fireEvent.change(repoInput, { target: { value: 'repo123' } }); + + // need to wait for the debounce to finish + await new Promise(resolve => setTimeout(resolve, 600)); + }); + + expect(mockScmAuthApi.getCredentials).toHaveBeenCalledWith({ + url: 'https://server.bitbucket.org/backstage/repo123', + additionalScope: { + repoWrite: true, + }, + }); + + const currentSecrets = JSON.parse( + getByTestId('current-secrets').textContent!, + ); + expect(currentSecrets).toEqual({ secrets: { testKey: 'abc123' }, }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index 9cf61a5e40..9bd904de13 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -120,16 +120,17 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => { async () => { const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {}; + const workspace = state.owner ? state.owner : state.project; if ( !requestUserCredentials || - !(state.host && state.owner && state.repoName) + !(state.host && workspace && state.repoName) ) { return; } - const [encodedHost, encodedOwner, encodedRepoName] = [ + const [encodedHost, encodedWorkspace, encodedRepoName] = [ state.host, - state.owner, + workspace, state.repoName, ].map(encodeURIComponent); @@ -137,14 +138,14 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => { // so lets grab them using the scmAuthApi and pass through // any additional scopes from the ui:options const { token } = await scmAuthApi.getCredentials({ - url: `https://${encodedHost}/${encodedOwner}/${encodedRepoName}`, + url: `https://${encodedHost}/${encodedWorkspace}/${encodedRepoName}`, additionalScope: { repoWrite: true, customScopes: requestUserCredentials.additionalScopes, }, }); - // set the secret using the key provided in the the ui:options for use + // set the secret using the key provided in the ui:options for use // in the templating the manifest with ${{ secrets[secretsKey] }} setSecrets({ [requestUserCredentials.secretsKey]: token }); },