diff --git a/app-config.yaml b/app-config.yaml index 1eca3664b7..26cf080ca3 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -16,7 +16,16 @@ backend: # See README.md in the proxy-backend plugin for information on the configuration format proxy: - '/circleci/api': https://circleci.com/api/v1.1 + '/circleci/api': + target: https://circleci.com/api/v1.1 + changeOrigin: true + pathRewrite: + '^/proxy/circleci/api/': '/' + headers: + Circle-Token: + $secret: + env: CIRCLECI_AUTH_TOKEN + '/jenkins/api': target: http://localhost:8080 headers: diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index b5824d3869..b0c1892d34 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@backstage/core": "^0.1.1-alpha.21", + "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", diff --git a/plugins/circleci/src/api/index.ts b/plugins/circleci/src/api/index.ts index 64a33e4c13..da4c811812 100644 --- a/plugins/circleci/src/api/index.ts +++ b/plugins/circleci/src/api/index.ts @@ -42,8 +42,8 @@ export class CircleCIApi { this.apiUrl = apiUrl; } - async retry(buildNumber: number, options: CircleCIOptions) { - return postBuildActions(options.token, buildNumber, BuildAction.RETRY, { + async retry(buildNumber: number, options: Partial) { + return postBuildActions('', buildNumber, BuildAction.RETRY, { circleHost: this.apiUrl, ...options.vcs, }); @@ -51,9 +51,9 @@ export class CircleCIApi { async getBuilds( { limit = 10, offset = 0 }: { limit: number; offset: number }, - options: CircleCIOptions, + options: Partial, ) { - return getBuildSummaries(options.token, { + return getBuildSummaries('', { options: { limit, offset, @@ -64,12 +64,12 @@ export class CircleCIApi { }); } - async getUser(options: CircleCIOptions) { - return getMe(options.token, { circleHost: this.apiUrl, ...options }); + async getUser(options: Partial) { + return getMe('', { circleHost: this.apiUrl, ...options }); } - async getBuild(buildNumber: number, options: CircleCIOptions) { - return getFullBuild(options.token, buildNumber, { + async getBuild(buildNumber: number, options: Partial) { + return getFullBuild('', buildNumber, { circleHost: this.apiUrl, ...options.vcs, }); diff --git a/plugins/circleci/src/state/useBuildWithSteps.ts b/plugins/circleci/src/state/useBuildWithSteps.ts index 8fa7fa896d..c169b8fe63 100644 --- a/plugins/circleci/src/state/useBuildWithSteps.ts +++ b/plugins/circleci/src/state/useBuildWithSteps.ts @@ -14,31 +14,35 @@ * limitations under the License. */ import { errorApiRef, useApi } from '@backstage/core'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import { useAsyncRetry } from 'react-use'; -import { circleCIApiRef, GitType } from '../api/index'; +import { circleCIApiRef } from '../api/index'; import { useAsyncPolling } from './useAsyncPolling'; -import { useSettings } from './useSettings'; +import { useProjectSlugFromEntity, mapVcsType } from './useBuilds'; const INTERVAL_AMOUNT = 1500; export function useBuildWithSteps(buildId: number) { - const [{ token, repo, owner }] = useSettings(); + const { vcs, repo, owner } = useProjectSlugFromEntity(); const api = useApi(circleCIApiRef); const errorApi = useApi(errorApiRef); + const vcsOption = useMemo( + () => ({ + owner: owner, + repo: repo, + type: mapVcsType(vcs), + }), + [owner, repo, vcs], + ); + const getBuildWithSteps = useCallback(async () => { - if (owner === '' || repo === '' || token === '') { + if (owner === '' || repo === '' || vcs === '') { return Promise.reject('No credentials provided'); } try { const options = { - token: token, - vcs: { - owner: owner, - repo: repo, - type: GitType.GITHUB, - }, + vcs: vcsOption, }; const build = await api.getBuild(buildId, options); return Promise.resolve(build); @@ -46,17 +50,12 @@ export function useBuildWithSteps(buildId: number) { errorApi.post(e); return Promise.reject(e); } - }, [token, owner, repo, buildId, api, errorApi]); + }, [vcsOption, buildId, api, errorApi]); // eslint-disable-line react-hooks/exhaustive-deps const restartBuild = async () => { try { await api.retry(buildId, { - token: token, - vcs: { - owner: owner, - repo: repo, - type: GitType.GITHUB, - }, + vcs: vcsOption, }); } catch (e) { errorApi.post(e); diff --git a/plugins/circleci/src/state/useBuilds.ts b/plugins/circleci/src/state/useBuilds.ts index 282ef68f12..2a4aed7fd6 100644 --- a/plugins/circleci/src/state/useBuilds.ts +++ b/plugins/circleci/src/state/useBuilds.ts @@ -18,8 +18,9 @@ import { BuildSummary, GitType } from 'circleci-api'; import { useCallback, useEffect, useState } from 'react'; import { useAsyncRetry } from 'react-use'; import { circleCIApiRef } from '../api/index'; -import type { CITableBuildInfo } from '../pages/BuildsPage/lib/CITable'; -import { useSettings } from './useSettings'; +import type { CITableBuildInfo } from '../components/BuildsPage/lib/CITable'; +import { useEntity } from '@backstage/plugin-catalog'; +import { CIRCLECI_ANNOTATION } from '../constants'; const makeReadableStatus = (status: string | undefined) => { if (!status) return ''; @@ -68,8 +69,25 @@ export const transform = ( }); }; +export const useProjectSlugFromEntity = () => { + const { entity } = useEntity(); + const [vcs, owner, repo] = ( + entity.metadata.annotations?.[CIRCLECI_ANNOTATION] ?? '' + ).split('/'); + return { vcs, owner, repo }; +}; + +export function mapVcsType(vcs: string): GitType { + switch (vcs) { + case 'github': + return GitType.GITHUB; + default: + return GitType.BITBUCKET; + } +} + export function useBuilds() { - const [{ repo, owner, token }] = useSettings(); + const { repo, owner, vcs } = useProjectSlugFromEntity(); const api = useApi(circleCIApiRef); const errorApi = useApi(errorApiRef); @@ -79,7 +97,7 @@ export function useBuilds() { const getBuilds = useCallback( async ({ limit, offset }: { limit: number; offset: number }) => { - if (owner === '' || repo === '' || token === '') { + if (owner === '' || repo === '' || vcs === '') { return Promise.reject('No credentials provided'); } @@ -87,11 +105,10 @@ export function useBuilds() { return await api.getBuilds( { limit, offset }, { - token: token, vcs: { owner: owner, repo: repo, - type: GitType.GITHUB, + type: mapVcsType(vcs), }, }, ); @@ -100,13 +117,12 @@ export function useBuilds() { return Promise.reject(e); } }, - [repo, token, owner, api, errorApi], + [repo, owner, vcs, api, errorApi], ); const restartBuild = async (buildId: number) => { try { await api.retry(buildId, { - token: token, vcs: { owner: owner, repo: repo,