From 21ddf605221eb3109cdf795bae1e2b1bfdaa11c1 Mon Sep 17 00:00:00 2001 From: Benjamin Janssens Date: Thu, 13 Jun 2024 11:51:57 +0200 Subject: [PATCH] feat: add endpoint for bitbucket autocomplete in scaffolder Signed-off-by: Benjamin Janssens --- plugins/scaffolder-backend/package.json | 1 + .../src/service/autocomplete.ts | 79 +++++++++++++++++++ .../scaffolder-backend/src/service/router.ts | 24 ++++++ yarn.lock | 1 + 4 files changed, 105 insertions(+) create mode 100644 plugins/scaffolder-backend/src/service/autocomplete.ts diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 4060529421..af6625c8b8 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -70,6 +70,7 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", diff --git a/plugins/scaffolder-backend/src/service/autocomplete.ts b/plugins/scaffolder-backend/src/service/autocomplete.ts new file mode 100644 index 0000000000..034a201450 --- /dev/null +++ b/plugins/scaffolder-backend/src/service/autocomplete.ts @@ -0,0 +1,79 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; + +export async function handleBitbucketCloudRequest( + token: string, + resource: string, + parameters: Record, +): Promise { + const client = BitbucketCloudClient.fromConfig({ + host: 'bitbucket.org', + apiBaseUrl: 'https://api.bitbucket.org/2.0', + accessToken: token, + }); + + switch (resource) { + case 'workspaces': { + const result: string[] = []; + + for await (const page of client.listWorkspaces().iteratePages()) { + const slugs = [...page.values!].map(p => p.slug!); + result.push(...slugs); + } + + return result; + } + case 'projects': { + if (!parameters.workspace) + throw new InputError('Missing workspace query parameter'); + + const result: string[] = []; + + for await (const page of client + .listProjectsByWorkspace(parameters.workspace) + .iteratePages()) { + const keys = [...page.values!].map(p => p.key!); + result.push(...keys); + } + + return result; + } + case 'repositories': { + if (!parameters.workspace || !parameters.project) + throw new InputError( + 'Missing workspace and/or project query parameter', + ); + + const result: string[] = []; + + for await (const page of client + .listRepositoriesByWorkspace(parameters.workspace, { + q: `project.key="${parameters.project}"`, + }) + .iteratePages()) { + const slugs = [...page.values!].map(p => p.slug!); + result.push(...slugs); + } + + return result; + } + default: + throw new InputError(`Invalid resource: ${resource}`); + } +} diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 384b9f5340..dbccd6ddb5 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -94,6 +94,7 @@ import { } from '@backstage/plugin-auth-node'; import { InternalTaskSecrets } from '../scaffolder/tasks/types'; import { checkPermission } from '../util/checkPermissions'; +import { handleBitbucketCloudRequest } from './autocomplete'; /** * @@ -771,6 +772,29 @@ export async function createRouter( base64Content: file.content.toString('base64'), })), }); + }) + .get('/v2/autocomplete/:provider/:resource', async (req, res) => { + const { token, ...query } = req.query; + const { provider, resource } = req.params; + + if (!token) throw new InputError('Missing token query parameter'); + + let result: string[]; + + switch (provider) { + case 'bitbucketCloud': { + result = await handleBitbucketCloudRequest( + token as string, + resource, + query as Record, + ); + break; + } + default: + throw new InputError(`Unsupported provider: ${provider}`); + } + + res.status(200).json(result); }); const app = express(); diff --git a/yarn.lock b/yarn.lock index 1719070c2f..7f44f1559c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7093,6 +7093,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" + "@backstage/plugin-bitbucket-cloud-common": "workspace:^" "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" "@backstage/plugin-permission-common": "workspace:^"