diff --git a/.changeset/eleven-lamps-hide.md b/.changeset/eleven-lamps-hide.md new file mode 100644 index 0000000000..809de25c82 --- /dev/null +++ b/.changeset/eleven-lamps-hide.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': patch +--- + +Fix default branch API url for custom hosted Bitbucket server diff --git a/packages/backend-common/src/reading/BitbucketUrlReader.test.ts b/packages/backend-common/src/reading/BitbucketUrlReader.test.ts index 9661368b5e..6265718571 100644 --- a/packages/backend-common/src/reading/BitbucketUrlReader.test.ts +++ b/packages/backend-common/src/reading/BitbucketUrlReader.test.ts @@ -126,12 +126,12 @@ describe('BitbucketUrlReader', () => { ), ), rest.get( - 'https://api.bitbucket.mycompany.net/rest/api/1.0/repositories/backstage/mock/commits/some-branch', + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/commits', (_, res, ctx) => res( ctx.status(200), ctx.json({ - values: [{ hash: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }], + values: [{ id: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }], }), ), ), diff --git a/packages/backend-common/src/reading/BitbucketUrlReader.ts b/packages/backend-common/src/reading/BitbucketUrlReader.ts index e9727e04cf..86dd7e32b0 100644 --- a/packages/backend-common/src/reading/BitbucketUrlReader.ts +++ b/packages/backend-common/src/reading/BitbucketUrlReader.ts @@ -161,13 +161,18 @@ export class BitbucketUrlReader implements UrlReader { } private async getLastCommitShortHash(url: string): Promise { - const { name: repoName, owner: project, ref } = parseGitUrl(url); + const { resource, name: repoName, owner: project, ref } = parseGitUrl(url); let branch = ref; if (!branch) { branch = await getBitbucketDefaultBranch(url, this.config); } - const commitsApiUrl = `${this.config.apiBaseUrl}/repositories/${project}/${repoName}/commits/${branch}`; + + const isHosted = resource === 'bitbucket.org'; + // Bitbucket Server https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp222 + const commitsApiUrl = isHosted + ? `${this.config.apiBaseUrl}/repositories/${project}/${repoName}/commits/${branch}` + : `${this.config.apiBaseUrl}/projects/${project}/repos/${repoName}/commits`; const commitsResponse = await fetch( commitsApiUrl, @@ -182,14 +187,26 @@ export class BitbucketUrlReader implements UrlReader { } const commits = await commitsResponse.json(); - if ( - commits && - commits.values && - commits.values.length > 0 && - commits.values[0].hash - ) { - return commits.values[0].hash.substring(0, 12); + if (isHosted) { + if ( + commits && + commits.values && + commits.values.length > 0 && + commits.values[0].hash + ) { + return commits.values[0].hash.substring(0, 12); + } + } else { + if ( + commits && + commits.values && + commits.values.length > 0 && + commits.values[0].id + ) { + return commits.values[0].id.substring(0, 12); + } } + throw new Error(`Failed to read response from ${commitsApiUrl}`); } } diff --git a/packages/integration/src/bitbucket/core.test.ts b/packages/integration/src/bitbucket/core.test.ts index 39707976fe..1287ab4d66 100644 --- a/packages/integration/src/bitbucket/core.test.ts +++ b/packages/integration/src/bitbucket/core.test.ts @@ -116,7 +116,7 @@ describe('bitbucket core', () => { }; worker.use( rest.get( - 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches/default', + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/default-branch', (_, res, ctx) => res( ctx.status(200), @@ -144,7 +144,7 @@ describe('bitbucket core', () => { }; worker.use( rest.get( - 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches/default', + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/default-branch', (_, res, ctx) => res( ctx.status(200), @@ -231,7 +231,7 @@ describe('bitbucket core', () => { }; worker.use( rest.get( - 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches/default', + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/default-branch', (_, res, ctx) => res( ctx.status(200), diff --git a/packages/integration/src/bitbucket/core.ts b/packages/integration/src/bitbucket/core.ts index ae61df497d..f5235d8189 100644 --- a/packages/integration/src/bitbucket/core.ts +++ b/packages/integration/src/bitbucket/core.ts @@ -31,9 +31,10 @@ export async function getBitbucketDefaultBranch( const { name: repoName, owner: project, resource } = parseGitUrl(url); const isHosted = resource === 'bitbucket.org'; + // Bitbucket Server https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp184 const branchUrl = isHosted ? `${config.apiBaseUrl}/repositories/${project}/${repoName}` - : `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/branches/default`; + : `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/default-branch`; const response = await fetch(branchUrl, getBitbucketRequestOptions(config)); if (!response.ok) { @@ -50,7 +51,10 @@ export async function getBitbucketDefaultBranch( defaultBranch = displayId; } if (!defaultBranch) { - throw new Error(`Failed to read default branch from ${branchUrl}`); + throw new Error( + `Failed to read default branch from ${branchUrl}. ` + + `Response ${response.status} ${response.json()}`, + ); } return defaultBranch; }