diff --git a/.changeset/wise-snakes-sleep.md b/.changeset/wise-snakes-sleep.md new file mode 100644 index 0000000000..ca51972f57 --- /dev/null +++ b/.changeset/wise-snakes-sleep.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +--- + +Implemented discovery on project-level to shift Bitbucket Cloud API limits diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts index aa00f937d8..489578e853 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.test.ts @@ -312,6 +312,22 @@ describe('BitbucketCloudEntityProvider', () => { ); server.use( + rest.get( + `https://api.bitbucket.org/2.0/workspaces/test-ws/projects`, + (_req, res, ctx) => { + const response = { + values: [ + { + key: 'TEST', + }, + { + key: 'TEST2', + }, + ], + }; + return res(ctx.json(response)); + }, + ), rest.get( `https://api.bitbucket.org/2.0/workspaces/test-ws/search/code`, (_req, res, ctx) => { @@ -447,6 +463,27 @@ describe('BitbucketCloudEntityProvider', () => { }, locationKey: 'bitbucketCloud-provider:myProvider', }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': `url:${url}`, + 'backstage.io/managed-by-origin-location': `url:${url}`, + 'bitbucket.org/repo-url': + 'https://bitbucket.org/test-ws/test-repo2', + }, + name: 'generated-7c2e6263b6cc2d14e69fd4d029afba601ad6dc3b', + }, + spec: { + presence: 'required', + target: `${url}`, + type: 'url', + }, + }, + locationKey: 'bitbucketCloud-provider:myProvider', + }, ]; expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); @@ -505,11 +542,31 @@ describe('BitbucketCloudEntityProvider', () => { })[0]; server.use( + rest.get( + `https://api.bitbucket.org/2.0/workspaces/test-ws/projects`, + (_req, res, ctx) => { + const response = { + values: [ + { + key: 'TEST', + }, + { + key: 'TEST2', + }, + ], + }; + return res(ctx.json(response)); + }, + ), rest.get( `https://api.bitbucket.org/2.0/workspaces/test-ws/search/code`, (req, res, ctx) => { const query = req.url.searchParams.get('search_query'); - if (!query || !query.includes('repo:test-repo')) { + if ( + !query || + !query.includes('repo:test-repo') || + !query.includes('project:TEST') + ) { return res(ctx.json({ values: [] })); } @@ -586,6 +643,10 @@ describe('BitbucketCloudEntityProvider', () => { entity: addedModule, locationKey: 'bitbucketCloud-provider:myProvider', }, + { + entity: addedModule, + locationKey: 'bitbucketCloud-provider:myProvider', + }, ]; const removedEntities = [ { diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts index b439f391ca..6c2de0ac10 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts @@ -323,6 +323,28 @@ export class BitbucketCloudEntityProvider implements EntityProvider { catalogPath.lastIndexOf('/') + 1, ); + const optRepoFilter = repoSlug ? ` repo:${repoSlug}` : ''; + const query = `"${catalogFilename}" path:${catalogPath}${optRepoFilter}`; + + const projects = this.client + .listProjectsByWorkspace(workspace) + .iterateResults(); + + let results: IngestionTarget[] = []; + + for await (const project of projects) { + const projectQuery = `${query} project:${project.key}`; + const result = await this.processQuery(workspace, projectQuery); + results = results.concat(result); + } + + return results; + } + + private async processQuery( + workspace: string, + query: string, + ): Promise { // load all fields relevant for creating refs later, but not more const fields = [ // exclude code/content match details @@ -338,8 +360,7 @@ export class BitbucketCloudEntityProvider implements EntityProvider { // ...except the one we need '+values.file.commit.repository.links.html.href', ].join(','); - const optRepoFilter = repoSlug ? ` repo:${repoSlug}` : ''; - const query = `"${catalogFilename}" path:${catalogPath}${optRepoFilter}`; + const searchResults = this.client .searchCode(workspace, query, { fields }) .iterateResults();