From 8e554c649a9bfe447894f14efe9f152a479f7734 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 6 Apr 2021 13:53:17 +0100 Subject: [PATCH 01/12] support GitHub enterprise and hosted GitHub on GithubDeployments plugin Signed-off-by: Andrew Johnson --- plugins/github-deployments/package.json | 3 + plugins/github-deployments/src/api/index.ts | 32 +++++++++++ .../components/GithubDeploymentsCard.test.tsx | 57 ++++++++++++++++++- .../src/components/GithubDeploymentsCard.tsx | 13 ++++- plugins/github-deployments/src/plugin.ts | 10 +++- 5 files changed, 108 insertions(+), 7 deletions(-) diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index b8761c1385..528d660ea8 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -22,6 +22,9 @@ "dependencies": { "@backstage/catalog-model": "^0.7.4", "@backstage/core": "^0.7.3", + "@backstage/errors": "^0.1.1", + "@backstage/integration": "^0.5.1", + "@backstage/integration-react": "^0.1.1", "@backstage/plugin-catalog-react": "^0.1.3", "@backstage/theme": "^0.2.5", "@material-ui/core": "^4.11.0", diff --git a/plugins/github-deployments/src/api/index.ts b/plugins/github-deployments/src/api/index.ts index ca69ac3853..f239af9ef8 100644 --- a/plugins/github-deployments/src/api/index.ts +++ b/plugins/github-deployments/src/api/index.ts @@ -14,8 +14,33 @@ * limitations under the License. */ import { createApiRef, OAuthApi } from '@backstage/core'; +import { InputError } from '@backstage/errors'; +import { ScmIntegrationRegistry } from '@backstage/integration'; import { graphql } from '@octokit/graphql'; +const getBaseUrl = ( + scmIntegrationsApi: ScmIntegrationRegistry, + host?: string, +): string => { + if (!host) { + return 'https://api.github.com'; + } + + const integrationConfig = scmIntegrationsApi.github.byHost(host); + + if (!integrationConfig) { + throw new InputError( + `No matching GitHub integration configuration for host ${host}, please check your integrations config`, + ); + } + + if (!integrationConfig.config.apiBaseUrl) { + throw new InputError(`No apiBaseUrl available for host ${host}`); + } + + return integrationConfig.config.apiBaseUrl; +}; + export type GithubDeployment = { environment: string; state: string; @@ -28,6 +53,7 @@ export type GithubDeployment = { export interface GithubDeploymentsApi { listDeployments(options: { + host?: string; owner: string; repo: string; last: number; @@ -41,6 +67,7 @@ export const githubDeploymentsApiRef = createApiRef({ export type Options = { githubAuthApi: OAuthApi; + scmIntegrationsApi: ScmIntegrationRegistry; }; const deploymentsQuery = ` @@ -71,19 +98,24 @@ export type QueryResponse = { export class GithubDeploymentsApiClient implements GithubDeploymentsApi { private readonly githubAuthApi: OAuthApi; + private readonly scmIntegrationsApi: ScmIntegrationRegistry; constructor(options: Options) { this.githubAuthApi = options.githubAuthApi; + this.scmIntegrationsApi = options.scmIntegrationsApi; } async listDeployments(options: { owner: string; repo: string; last: number; + host?: string; }): Promise { + const baseUrl = getBaseUrl(this.scmIntegrationsApi, options.host); const token = await this.githubAuthApi.getAccessToken(['repo']); const graphQLWithAuth = graphql.defaults({ + baseUrl, headers: { authorization: `token ${token}`, }, diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index e20183f1d6..db0092caa8 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -39,6 +39,7 @@ import { import { setupServer } from 'msw/node'; import { graphql } from 'msw'; +import { ScmIntegrations } from '@backstage/integration'; jest.mock('@backstage/plugin-catalog-react', () => ({ useEntity: () => { @@ -48,7 +49,20 @@ jest.mock('@backstage/plugin-catalog-react', () => ({ const errorApiMock = { post: jest.fn(), error$: jest.fn() }; -const configApi: ConfigApi = new ConfigReader({}); +const configApi: ConfigApi = new ConfigReader({ + integrations: { + github: [ + { + host: 'missing-api-base-url.com', + }, + { + host: 'my-github.com', + apiBaseUrl: 'https://api.my-github.com', + }, + ], + }, +}); +const scmIntegrationsApi = ScmIntegrations.fromConfig(configApi); const githubAuthApi: OAuthApi = { getAccessToken: async _ => 'access_token', }; @@ -56,7 +70,10 @@ const githubAuthApi: OAuthApi = { const apis = ApiRegistry.from([ [configApiRef, configApi], [errorApiRef, errorApiMock], - [githubDeploymentsApiRef, new GithubDeploymentsApiClient({ githubAuthApi })], + [ + githubDeploymentsApiRef, + new GithubDeploymentsApiClient({ scmIntegrationsApi, githubAuthApi }), + ], ]); describe('github-deployments', () => { @@ -159,5 +176,41 @@ describe('github-deployments', () => { ).toBeInTheDocument(); expect(await rendered.findByText('failure')).toBeInTheDocument(); }); + + it('shows error when host does not exist', async () => { + worker.use( + graphql.query('deployments', (_, res, ctx) => + res(ctx.data(responseStub)), + ), + ); + + const rendered = await renderInTestApp( + + + , + ); + + expect(await rendered.findByText( + 'Warning: No matching GitHub integration configuration for host unknown-host.com, please check your integrations config', + )).toBeInTheDocument(); + }); + + it('shows error when baseApiURL does not exist forr host', async () => { + worker.use( + graphql.query('deployments', (_, res, ctx) => + res(ctx.data(responseStub)), + ), + ); + + const rendered = await renderInTestApp( + + + , + ); + + expect(await rendered.findByText( + 'Warning: No apiBaseUrl available for host missing-api-base-url.com', + )).toBeInTheDocument(); + }); }); }); diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index 99dfba560a..691c63fcc3 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -29,9 +29,11 @@ import { import GithubDeploymentsTable from './GithubDeploymentsTable/GithubDeploymentsTable'; const GithubDeploymentsComponent = ({ + host, projectSlug, last, }: { + host?: string; projectSlug: string; last: number; }) => { @@ -39,7 +41,7 @@ const GithubDeploymentsComponent = ({ const [owner, repo] = projectSlug.split('/'); const { loading, value, error, retry: reload } = useAsyncRetry( - async () => await api.listDeployments({ owner, repo, last }), + async () => await api.listDeployments({ host, owner, repo, last }), ); if (error) { @@ -55,7 +57,13 @@ const GithubDeploymentsComponent = ({ ); }; -export const GithubDeploymentsCard = ({ last }: { last?: number }) => { +export const GithubDeploymentsCard = ({ + last, + host, +}: { + last?: number; + host?: string; +}) => { const { entity } = useEntity(); return !isGithubDeploymentsAvailable(entity) ? ( @@ -66,6 +74,7 @@ export const GithubDeploymentsCard = ({ last }: { last?: number }) => { entity?.metadata.annotations?.[GITHUB_PROJECT_SLUG_ANNOTATION] || '' } last={last || 10} + host={host} /> ); }; diff --git a/plugins/github-deployments/src/plugin.ts b/plugins/github-deployments/src/plugin.ts index 3707b1cf68..943d5e0bc6 100644 --- a/plugins/github-deployments/src/plugin.ts +++ b/plugins/github-deployments/src/plugin.ts @@ -19,6 +19,7 @@ import { createPlugin, githubAuthApiRef, } from '@backstage/core'; +import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { githubDeploymentsApiRef, GithubDeploymentsApiClient } from './api'; export const githubDeploymentsPlugin = createPlugin({ @@ -26,9 +27,12 @@ export const githubDeploymentsPlugin = createPlugin({ apis: [ createApiFactory({ api: githubDeploymentsApiRef, - deps: { githubAuthApi: githubAuthApiRef }, - factory: ({ githubAuthApi }) => - new GithubDeploymentsApiClient({ githubAuthApi }), + deps: { + scmIntegrationsApi: scmIntegrationsApiRef, + githubAuthApi: githubAuthApiRef, + }, + factory: ({ scmIntegrationsApi, githubAuthApi }) => + new GithubDeploymentsApiClient({ scmIntegrationsApi, githubAuthApi }), }), ], }); From f5a916c497671f9f47b44eb6ff56a3fa018c1104 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 6 Apr 2021 14:00:58 +0100 Subject: [PATCH 02/12] changeset and typo Signed-off-by: Andrew Johnson --- .changeset/smooth-vans-travel.md | 5 +++++ .../src/components/GithubDeploymentsCard.test.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/smooth-vans-travel.md diff --git a/.changeset/smooth-vans-travel.md b/.changeset/smooth-vans-travel.md new file mode 100644 index 0000000000..0038c35e8e --- /dev/null +++ b/.changeset/smooth-vans-travel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-deployments': patch +--- + +Support for GitHub Enterprise with GithubDeploymentsPlugin diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index db0092caa8..a671e6a847 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -195,7 +195,7 @@ describe('github-deployments', () => { )).toBeInTheDocument(); }); - it('shows error when baseApiURL does not exist forr host', async () => { + it('shows error when baseApiURL does not exist for host', async () => { worker.use( graphql.query('deployments', (_, res, ctx) => res(ctx.data(responseStub)), From 612a9c03399b74b9cad0f6d0c444f21548b78e19 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 6 Apr 2021 14:06:57 +0100 Subject: [PATCH 03/12] update readme Signed-off-by: Andrew Johnson --- plugins/github-deployments/README.md | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/plugins/github-deployments/README.md b/plugins/github-deployments/README.md index 174d1bc8c7..64ae9c66ca 100644 --- a/plugins/github-deployments/README.md +++ b/plugins/github-deployments/README.md @@ -60,3 +60,33 @@ spec: owner: CNCF lifecycle: experimental ``` + +### Self-hosted / Enterprise GitHub + +1. Add the `host` and `apiBaseUrl` to your `app-config.yaml` + +```yaml +# app-config.yaml + +integrations: + github: + - host: 'your-github-host.com' + apiBaseUrl: 'https://api.your-github-host.com' +``` + +2. Pass the host into the `EntityGithubDeploymentsCard` + +```typescript +// packages/app/src/components/catalog/EntityPage.tsx + +import { EntityGithubDeploymentsCard } from '@backstage/plugin-github-deployments'; + +const OverviewContent = () => ( + + // ... + + + + // ... + +); \ No newline at end of file From b4c269777b383e096ed7daae2559dcf234c95dde Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 6 Apr 2021 14:11:19 +0100 Subject: [PATCH 04/12] prettier Signed-off-by: Andrew Johnson --- plugins/github-deployments/README.md | 5 +++-- .../components/GithubDeploymentsCard.test.tsx | 16 ++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/plugins/github-deployments/README.md b/plugins/github-deployments/README.md index 64ae9c66ca..42f550059c 100644 --- a/plugins/github-deployments/README.md +++ b/plugins/github-deployments/README.md @@ -85,8 +85,9 @@ const OverviewContent = () => ( // ... - + // ... -); \ No newline at end of file +); +``` diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index a671e6a847..d7bc0dfcc8 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -190,9 +190,11 @@ describe('github-deployments', () => { , ); - expect(await rendered.findByText( - 'Warning: No matching GitHub integration configuration for host unknown-host.com, please check your integrations config', - )).toBeInTheDocument(); + expect( + await rendered.findByText( + 'Warning: No matching GitHub integration configuration for host unknown-host.com, please check your integrations config', + ), + ).toBeInTheDocument(); }); it('shows error when baseApiURL does not exist for host', async () => { @@ -208,9 +210,11 @@ describe('github-deployments', () => { , ); - expect(await rendered.findByText( - 'Warning: No apiBaseUrl available for host missing-api-base-url.com', - )).toBeInTheDocument(); + expect( + await rendered.findByText( + 'Warning: No apiBaseUrl available for host missing-api-base-url.com', + ), + ).toBeInTheDocument(); }); }); }); From c05da9a5d9bb07ee0c21483d0c3960f8c23f2be9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 8 Apr 2021 12:18:34 +0100 Subject: [PATCH 05/12] use location from entity Signed-off-by: Andrew Johnson --- plugins/github-deployments/src/api/index.ts | 49 +++-- .../components/GithubDeploymentsCard.test.tsx | 208 ++++++++++++------ .../src/components/GithubDeploymentsCard.tsx | 23 +- plugins/github-deployments/src/mocks/mocks.ts | 7 +- 4 files changed, 188 insertions(+), 99 deletions(-) diff --git a/plugins/github-deployments/src/api/index.ts b/plugins/github-deployments/src/api/index.ts index f239af9ef8..31e3defa47 100644 --- a/plugins/github-deployments/src/api/index.ts +++ b/plugins/github-deployments/src/api/index.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { parseLocationReference } from '@backstage/catalog-model'; import { createApiRef, OAuthApi } from '@backstage/core'; import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; @@ -20,25 +21,29 @@ import { graphql } from '@octokit/graphql'; const getBaseUrl = ( scmIntegrationsApi: ScmIntegrationRegistry, - host?: string, + location?: string, ): string => { - if (!host) { + if (!location) { return 'https://api.github.com'; } - const integrationConfig = scmIntegrationsApi.github.byHost(host); + const config = scmIntegrationsApi.github.byUrl( + parseLocationReference(location).target, + ); - if (!integrationConfig) { + if (!config) { throw new InputError( - `No matching GitHub integration configuration for host ${host}, please check your integrations config`, + `No matching GitHub integration configuration for location ${location}, please check your integrations config`, ); } - if (!integrationConfig.config.apiBaseUrl) { - throw new InputError(`No apiBaseUrl available for host ${host}`); + if (!config.config.apiBaseUrl) { + throw new InputError( + `No apiBaseUrl available for location ${location}, please check your integrations config`, + ); } - return integrationConfig.config.apiBaseUrl; + return config?.config.apiBaseUrl; }; export type GithubDeployment = { @@ -51,13 +56,17 @@ export type GithubDeployment = { }; }; +type QueryOptions = { + owner: string; + repo: string; + last: number; +}; + export interface GithubDeploymentsApi { - listDeployments(options: { - host?: string; - owner: string; - repo: string; - last: number; - }): Promise; + listDeployments( + options: QueryOptions, + location?: string, + ): Promise; } export const githubDeploymentsApiRef = createApiRef({ @@ -105,13 +114,11 @@ export class GithubDeploymentsApiClient implements GithubDeploymentsApi { this.scmIntegrationsApi = options.scmIntegrationsApi; } - async listDeployments(options: { - owner: string; - repo: string; - last: number; - host?: string; - }): Promise { - const baseUrl = getBaseUrl(this.scmIntegrationsApi, options.host); + async listDeployments( + options: QueryOptions, + location?: string, + ): Promise { + const baseUrl = getBaseUrl(this.scmIntegrationsApi, location); const token = await this.githubAuthApi.getAccessToken(['repo']); const graphQLWithAuth = graphql.defaults({ diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index d7bc0dfcc8..040a9b6571 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -40,10 +40,13 @@ import { import { setupServer } from 'msw/node'; import { graphql } from 'msw'; import { ScmIntegrations } from '@backstage/integration'; +import { Entity } from '@backstage/catalog-model'; + +let entity: { entity: Entity }; jest.mock('@backstage/plugin-catalog-react', () => ({ useEntity: () => { - return entityStub; + return entity; }, })); @@ -53,15 +56,24 @@ const configApi: ConfigApi = new ConfigReader({ integrations: { github: [ { - host: 'missing-api-base-url.com', + host: 'my-github-1.com', + apiBaseUrl: 'https://api.my-github-1.com', }, { - host: 'my-github.com', - apiBaseUrl: 'https://api.my-github.com', + host: 'my-github-2.com', + apiBaseUrl: 'https://api.my-github-2.com', + }, + { + host: 'my-github-3.com', }, ], }, }); + +const GRAPHQL_GITHUB_API = graphql.link('https://api.github.com/graphql'); +const GRAPHQL_CUSTOM_API_1 = graphql.link('https://api.github-1.com/graphql'); +const GRAPHQL_CUSTOM_API_2 = graphql.link('https://api.github-2.com/graphql'); + const scmIntegrationsApi = ScmIntegrations.fromConfig(configApi); const githubAuthApi: OAuthApi = { getAccessToken: async _ => 'access_token', @@ -76,11 +88,36 @@ const apis = ApiRegistry.from([ ], ]); +const assertFetchedData = async () => { + const rendered = await renderInTestApp( + + + , + ); + + expect(await rendered.findByText('GitHub Deployments')).toBeInTheDocument(); + + expect(await rendered.findByText('active')).toBeInTheDocument(); + expect(await rendered.findByText('prd')).toBeInTheDocument(); + expect(await rendered.findByText('12345')).toHaveAttribute( + 'href', + 'https://exampleapi.com/123456789', + ); + + expect(await rendered.findByText('pending')).toBeInTheDocument(); + expect(await rendered.findByText('lab')).toBeInTheDocument(); + expect(await rendered.findByText('54321')).toHaveAttribute( + 'href', + 'https://exampleapi.com/543212345', + ); +}; + describe('github-deployments', () => { const worker = setupServer(); msw.setupDefaultHandlers(worker); beforeEach(() => { + worker.resetHandlers(); jest.resetAllMocks(); }); @@ -91,40 +128,27 @@ describe('github-deployments', () => { }); describe('GithubDeploymentsCard', () => { - it('should display fetched data', async () => { + beforeEach(() => { + entity = entityStub; + entity.entity.metadata.annotations = { + 'github.com/project-slug': 'org/repo', + }; + }); + + it('displays fetched data using default github api', async () => { worker.use( - graphql.query('deployments', (_, res, ctx) => + GRAPHQL_GITHUB_API.query('deployments', (_, res, ctx) => res(ctx.data(responseStub)), ), ); - const rendered = await renderInTestApp( - - - , - ); - - expect( - await rendered.findByText('GitHub Deployments'), - ).toBeInTheDocument(); - expect(await rendered.findByText('active')).toBeInTheDocument(); - expect(await rendered.findByText('prd')).toBeInTheDocument(); - expect(await rendered.findByText('12345')).toHaveAttribute( - 'href', - 'https://exampleapi.com/123456789', - ); - - expect(await rendered.findByText('pending')).toBeInTheDocument(); - expect(await rendered.findByText('lab')).toBeInTheDocument(); - expect(await rendered.findByText('54321')).toHaveAttribute( - 'href', - 'https://exampleapi.com/543212345', - ); + await assertFetchedData(); + expect.assertions(7); }); it('should display empty state when no data', async () => { worker.use( - graphql.query('deployments', (_, res, ctx) => + GRAPHQL_GITHUB_API.query('deployments', (_, res, ctx) => res(ctx.data(noDataResponseStub)), ), ); @@ -145,7 +169,7 @@ describe('github-deployments', () => { it('should shows new data on reload', async () => { worker.use( - graphql.query('deployments', (_, res, ctx) => + GRAPHQL_GITHUB_API.query('deployments', (_, res, ctx) => res(ctx.data(responseStub)), ), ); @@ -163,7 +187,7 @@ describe('github-deployments', () => { worker.resetHandlers(); worker.use( - graphql.query('deployments', (_, res, ctx) => + GRAPHQL_GITHUB_API.query('deployments', (_, res, ctx) => res(ctx.data(refreshedResponseStub)), ), ); @@ -177,44 +201,102 @@ describe('github-deployments', () => { expect(await rendered.findByText('failure')).toBeInTheDocument(); }); - it('shows error when host does not exist', async () => { - worker.use( - graphql.query('deployments', (_, res, ctx) => - res(ctx.data(responseStub)), - ), - ); + describe('entity with source location', () => { + beforeEach(() => { + entity = entityStub; + entity.entity.metadata.annotations = { + 'github.com/project-slug': 'org/repo', + 'backstage.io/source-location': + 'url:https://my-github-1.com/org/repo', + }; + }); - const rendered = await renderInTestApp( - - - , - ); + it('should fetch data using custom api', async () => { + const customAPI = graphql.link('https://api.my-github-1.com/graphql'); - expect( - await rendered.findByText( - 'Warning: No matching GitHub integration configuration for host unknown-host.com, please check your integrations config', - ), - ).toBeInTheDocument(); + worker.use( + customAPI.query('deployments', (_, res, ctx) => + res(ctx.data(responseStub)), + ), + ); + + await assertFetchedData(); + expect.assertions(7); + }); }); - it('shows error when baseApiURL does not exist for host', async () => { - worker.use( - graphql.query('deployments', (_, res, ctx) => - res(ctx.data(responseStub)), - ), - ); + describe('entity with managed by location', () => { + beforeEach(() => { + entity = entityStub; + entity.entity.metadata.annotations = { + 'github.com/project-slug': 'org/repo', + 'backstage.io/managed-by-location': + 'url:https://my-github-2.com/org/repo', + }; + }); - const rendered = await renderInTestApp( - - - , - ); + it('should fetch data using custom api', async () => { + const customAPI = graphql.link('https://api.my-github-2.com/graphql'); - expect( - await rendered.findByText( - 'Warning: No apiBaseUrl available for host missing-api-base-url.com', - ), - ).toBeInTheDocument(); + worker.use( + customAPI.query('deployments', (_, res, ctx) => + res(ctx.data(responseStub)), + ), + ); + + await assertFetchedData(); + expect.assertions(7); + }); + }); + + describe('entity with location without baseApiURL', () => { + beforeEach(() => { + entity = entityStub; + entity.entity.metadata.annotations = { + 'github.com/project-slug': 'org/repo', + 'backstage.io/managed-by-location': + 'url:https://my-github-3.com/org/repo', + }; + }); + + it('shows error when no matching github host', async () => { + const rendered = await renderInTestApp( + + + , + ); + + expect( + await rendered.findByText( + 'Warning: No apiBaseUrl available for location url:https://my-github-3.com/org/repo, please check your integrations config', + ), + ).toBeInTheDocument(); + }); + }); + + describe('entity with location without matching host', () => { + beforeEach(() => { + entity = entityStub; + entity.entity.metadata.annotations = { + 'github.com/project-slug': 'org/repo', + 'backstage.io/managed-by-location': + 'url:https://my-github-unknown.com/org/repo', + }; + }); + + it('shows error when no matching github host', async () => { + const rendered = await renderInTestApp( + + + , + ); + + expect( + await rendered.findByText( + 'Warning: No matching GitHub integration configuration for location url:https://my-github-unknown.com/org/repo, please check your integrations config', + ), + ).toBeInTheDocument(); + }); }); }); }); diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index 691c63fcc3..f7ba6293ee 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -27,21 +27,25 @@ import { isGithubDeploymentsAvailable, } from '../Router'; import GithubDeploymentsTable from './GithubDeploymentsTable/GithubDeploymentsTable'; +import { + LOCATION_ANNOTATION, + SOURCE_LOCATION_ANNOTATION, +} from '@backstage/catalog-model'; const GithubDeploymentsComponent = ({ - host, projectSlug, last, + location, }: { - host?: string; projectSlug: string; last: number; + location?: string; }) => { const api = useApi(githubDeploymentsApiRef); const [owner, repo] = projectSlug.split('/'); const { loading, value, error, retry: reload } = useAsyncRetry( - async () => await api.listDeployments({ host, owner, repo, last }), + async () => await api.listDeployments({ owner, repo, last }, location), ); if (error) { @@ -57,14 +61,11 @@ const GithubDeploymentsComponent = ({ ); }; -export const GithubDeploymentsCard = ({ - last, - host, -}: { - last?: number; - host?: string; -}) => { +export const GithubDeploymentsCard = ({ last }: { last?: number }) => { const { entity } = useEntity(); + const location = + entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION] || + entity?.metadata.annotations?.[LOCATION_ANNOTATION]; return !isGithubDeploymentsAvailable(entity) ? ( @@ -74,7 +75,7 @@ export const GithubDeploymentsCard = ({ entity?.metadata.annotations?.[GITHUB_PROJECT_SLUG_ANNOTATION] || '' } last={last || 10} - host={host} + location={location} /> ); }; diff --git a/plugins/github-deployments/src/mocks/mocks.ts b/plugins/github-deployments/src/mocks/mocks.ts index f636a08558..9e10e6c289 100644 --- a/plugins/github-deployments/src/mocks/mocks.ts +++ b/plugins/github-deployments/src/mocks/mocks.ts @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; import { QueryResponse } from '../api'; -export const entityStub = { +export const entityStub: { entity: Entity } = { entity: { metadata: { namespace: 'default', - annotations: { - 'github.com/project-slug': 'org/repo', - }, + annotations: {}, name: 'sample-service', description: 'Sample service', uid: 'g0h33dd9-56h7-835b-b63v-7x5da3j64851', From ebce9fdbeef552544540a0c304c6aa85860d5524 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 8 Apr 2021 12:30:13 +0100 Subject: [PATCH 06/12] update test Signed-off-by: Andrew Johnson --- plugins/github-deployments/src/api/index.ts | 20 +++++--- .../components/GithubDeploymentsCard.test.tsx | 50 ++++++++++++++----- .../src/components/GithubDeploymentsCard.tsx | 15 +++--- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/plugins/github-deployments/src/api/index.ts b/plugins/github-deployments/src/api/index.ts index 31e3defa47..221eb3be8a 100644 --- a/plugins/github-deployments/src/api/index.ts +++ b/plugins/github-deployments/src/api/index.ts @@ -21,15 +21,19 @@ import { graphql } from '@octokit/graphql'; const getBaseUrl = ( scmIntegrationsApi: ScmIntegrationRegistry, - location?: string, + locations: string[], ): string => { - if (!location) { + const targets = locations + .map(parseLocationReference) + .filter(location => location.type === 'url') + .map(location => location.target); + + if (targets.length === 0) { return 'https://api.github.com'; } - const config = scmIntegrationsApi.github.byUrl( - parseLocationReference(location).target, - ); + const location = targets[0]; + const config = scmIntegrationsApi.github.byUrl(location); if (!config) { throw new InputError( @@ -65,7 +69,7 @@ type QueryOptions = { export interface GithubDeploymentsApi { listDeployments( options: QueryOptions, - location?: string, + location: string[], ): Promise; } @@ -116,9 +120,9 @@ export class GithubDeploymentsApiClient implements GithubDeploymentsApi { async listDeployments( options: QueryOptions, - location?: string, + locations: string[], ): Promise { - const baseUrl = getBaseUrl(this.scmIntegrationsApi, location); + const baseUrl = getBaseUrl(this.scmIntegrationsApi, locations); const token = await this.githubAuthApi.getAccessToken(['repo']); const graphQLWithAuth = graphql.defaults({ diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index 040a9b6571..d2f6b1c4b6 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -71,8 +71,12 @@ const configApi: ConfigApi = new ConfigReader({ }); const GRAPHQL_GITHUB_API = graphql.link('https://api.github.com/graphql'); -const GRAPHQL_CUSTOM_API_1 = graphql.link('https://api.github-1.com/graphql'); -const GRAPHQL_CUSTOM_API_2 = graphql.link('https://api.github-2.com/graphql'); +const GRAPHQL_CUSTOM_API_1 = graphql.link( + 'https://api.my-github-1.com/graphql', +); +const GRAPHQL_CUSTOM_API_2 = graphql.link( + 'https://api.my-github-2.com/graphql', +); const scmIntegrationsApi = ScmIntegrations.fromConfig(configApi); const githubAuthApi: OAuthApi = { @@ -167,7 +171,7 @@ describe('github-deployments', () => { ).toBeInTheDocument(); }); - it('should shows new data on reload', async () => { + it('should show new data on reload', async () => { worker.use( GRAPHQL_GITHUB_API.query('deployments', (_, res, ctx) => res(ctx.data(responseStub)), @@ -212,10 +216,8 @@ describe('github-deployments', () => { }); it('should fetch data using custom api', async () => { - const customAPI = graphql.link('https://api.my-github-1.com/graphql'); - worker.use( - customAPI.query('deployments', (_, res, ctx) => + GRAPHQL_CUSTOM_API_1.query('deployments', (_, res, ctx) => res(ctx.data(responseStub)), ), ); @@ -236,10 +238,8 @@ describe('github-deployments', () => { }); it('should fetch data using custom api', async () => { - const customAPI = graphql.link('https://api.my-github-2.com/graphql'); - worker.use( - customAPI.query('deployments', (_, res, ctx) => + GRAPHQL_CUSTOM_API_2.query('deployments', (_, res, ctx) => res(ctx.data(responseStub)), ), ); @@ -259,7 +259,7 @@ describe('github-deployments', () => { }; }); - it('shows error when no matching github host', async () => { + it('shows no apiBaseUrl error', async () => { const rendered = await renderInTestApp( @@ -268,7 +268,7 @@ describe('github-deployments', () => { expect( await rendered.findByText( - 'Warning: No apiBaseUrl available for location url:https://my-github-3.com/org/repo, please check your integrations config', + 'Warning: No apiBaseUrl available for location https://my-github-3.com/org/repo, please check your integrations config', ), ).toBeInTheDocument(); }); @@ -284,7 +284,7 @@ describe('github-deployments', () => { }; }); - it('shows error when no matching github host', async () => { + it('shows no matching host error', async () => { const rendered = await renderInTestApp( @@ -293,10 +293,34 @@ describe('github-deployments', () => { expect( await rendered.findByText( - 'Warning: No matching GitHub integration configuration for location url:https://my-github-unknown.com/org/repo, please check your integrations config', + 'Warning: No matching GitHub integration configuration for location https://my-github-unknown.com/org/repo, please check your integrations config', ), ).toBeInTheDocument(); }); }); + + describe('entity with non url location', () => { + beforeEach(() => { + entity = entityStub; + entity.entity.metadata.annotations = { + 'github.com/project-slug': 'org/repo', + 'backstage.io/source-location': + 'some-other-managed-location:my-favourite-location/org/repo', + 'backstage.io/managed-by-location': + 'file:my-favourite-file/org/repo.yaml', + }; + }); + + it('displays fetched data using default github api', async () => { + worker.use( + GRAPHQL_GITHUB_API.query('deployments', (_, res, ctx) => + res(ctx.data(responseStub)), + ), + ); + + await assertFetchedData(); + expect.assertions(7); + }); + }); }); }); diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index f7ba6293ee..eccab4089a 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -35,17 +35,17 @@ import { const GithubDeploymentsComponent = ({ projectSlug, last, - location, + locations, }: { projectSlug: string; last: number; - location?: string; + locations: string[]; }) => { const api = useApi(githubDeploymentsApiRef); const [owner, repo] = projectSlug.split('/'); const { loading, value, error, retry: reload } = useAsyncRetry( - async () => await api.listDeployments({ owner, repo, last }, location), + async () => await api.listDeployments({ owner, repo, last }, locations), ); if (error) { @@ -63,9 +63,10 @@ const GithubDeploymentsComponent = ({ export const GithubDeploymentsCard = ({ last }: { last?: number }) => { const { entity } = useEntity(); - const location = - entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION] || - entity?.metadata.annotations?.[LOCATION_ANNOTATION]; + const locations = [ + entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], + entity?.metadata.annotations?.[LOCATION_ANNOTATION], + ].filter(location => location !== undefined) as string[]; return !isGithubDeploymentsAvailable(entity) ? ( @@ -75,7 +76,7 @@ export const GithubDeploymentsCard = ({ last }: { last?: number }) => { entity?.metadata.annotations?.[GITHUB_PROJECT_SLUG_ANNOTATION] || '' } last={last || 10} - location={location} + locations={locations} /> ); }; From 2842e953f42d2df618c80aa8281221692b484f93 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 8 Apr 2021 16:37:22 +0100 Subject: [PATCH 07/12] as per feedback Signed-off-by: Andrew Johnson --- .changeset/smooth-vans-travel.md | 2 +- plugins/github-deployments/README.md | 21 +++---------------- plugins/github-deployments/package.json | 8 +++---- plugins/github-deployments/src/api/index.ts | 14 ++++++++----- .../src/components/GithubDeploymentsCard.tsx | 2 +- 5 files changed, 18 insertions(+), 29 deletions(-) diff --git a/.changeset/smooth-vans-travel.md b/.changeset/smooth-vans-travel.md index 0038c35e8e..eb074c8ecf 100644 --- a/.changeset/smooth-vans-travel.md +++ b/.changeset/smooth-vans-travel.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-github-deployments': patch +'@backstage/plugin-github-deployments': minor --- Support for GitHub Enterprise with GithubDeploymentsPlugin diff --git a/plugins/github-deployments/README.md b/plugins/github-deployments/README.md index 42f550059c..e1f3d7c2c0 100644 --- a/plugins/github-deployments/README.md +++ b/plugins/github-deployments/README.md @@ -63,6 +63,9 @@ spec: ### Self-hosted / Enterprise GitHub +The plugin will try to use `backstage.io/source-location` or `backstage.io/managed-by-location` +annotations to figure out the location of the source code. + 1. Add the `host` and `apiBaseUrl` to your `app-config.yaml` ```yaml @@ -73,21 +76,3 @@ integrations: - host: 'your-github-host.com' apiBaseUrl: 'https://api.your-github-host.com' ``` - -2. Pass the host into the `EntityGithubDeploymentsCard` - -```typescript -// packages/app/src/components/catalog/EntityPage.tsx - -import { EntityGithubDeploymentsCard } from '@backstage/plugin-github-deployments'; - -const OverviewContent = () => ( - - // ... - - - - // ... - -); -``` diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 528d660ea8..39c7577bb5 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.4", - "@backstage/core": "^0.7.3", + "@backstage/catalog-model": "^0.7.6", + "@backstage/core": "^0.7.4", "@backstage/errors": "^0.1.1", "@backstage/integration": "^0.5.1", "@backstage/integration-react": "^0.1.1", @@ -37,9 +37,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.6.6", + "@backstage/cli": "^0.6.7", "@backstage/dev-utils": "^0.1.13", - "@backstage/test-utils": "^0.1.9", + "@backstage/test-utils": "^0.1.10", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/github-deployments/src/api/index.ts b/plugins/github-deployments/src/api/index.ts index 221eb3be8a..0deb586e6d 100644 --- a/plugins/github-deployments/src/api/index.ts +++ b/plugins/github-deployments/src/api/index.ts @@ -60,16 +60,20 @@ export type GithubDeployment = { }; }; -type QueryOptions = { +type QueryParams = { owner: string; repo: string; last: number; }; +type QueryOptions = { + locations: string[]; +}; + export interface GithubDeploymentsApi { listDeployments( + params: QueryParams, options: QueryOptions, - location: string[], ): Promise; } @@ -119,10 +123,10 @@ export class GithubDeploymentsApiClient implements GithubDeploymentsApi { } async listDeployments( + params: QueryParams, options: QueryOptions, - locations: string[], ): Promise { - const baseUrl = getBaseUrl(this.scmIntegrationsApi, locations); + const baseUrl = getBaseUrl(this.scmIntegrationsApi, options.locations); const token = await this.githubAuthApi.getAccessToken(['repo']); const graphQLWithAuth = graphql.defaults({ @@ -134,7 +138,7 @@ export class GithubDeploymentsApiClient implements GithubDeploymentsApi { const response: QueryResponse = await graphQLWithAuth( deploymentsQuery, - options, + params, ); return response.repository?.deployments?.nodes?.reverse() || []; } diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index eccab4089a..fb433338fa 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -45,7 +45,7 @@ const GithubDeploymentsComponent = ({ const [owner, repo] = projectSlug.split('/'); const { loading, value, error, retry: reload } = useAsyncRetry( - async () => await api.listDeployments({ owner, repo, last }, locations), + async () => await api.listDeployments({ owner, repo, last }, { locations }), ); if (error) { From 6b4b3c89e30c7452ce00c0aa1e41c8b17b38ff5f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 16 Apr 2021 17:39:29 +0100 Subject: [PATCH 08/12] prettier Signed-off-by: Andrew Johnson --- .../src/components/GithubDeploymentsCard.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index f68e57ed73..cae8313422 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -210,7 +210,7 @@ describe('github-deployments', () => { ).toBeInTheDocument(); expect(await rendered.findByText('failure')).toBeInTheDocument(); }); - + it('should display extra columns', async () => { worker.use( graphql.query('deployments', (_, res, ctx) => From cb7a25f778687fef1a77949d6faccfe51abbd9a1 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 7 May 2021 15:32:16 +0100 Subject: [PATCH 09/12] as per comments Signed-off-by: Andrew Johnson --- .changeset/smooth-vans-travel.md | 2 +- plugins/github-deployments/src/api/index.ts | 38 +++++++------------ .../components/GithubDeploymentsCard.test.tsx | 15 +++----- .../src/components/GithubDeploymentsCard.tsx | 12 +++--- 4 files changed, 27 insertions(+), 40 deletions(-) diff --git a/.changeset/smooth-vans-travel.md b/.changeset/smooth-vans-travel.md index eb074c8ecf..0038c35e8e 100644 --- a/.changeset/smooth-vans-travel.md +++ b/.changeset/smooth-vans-travel.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-github-deployments': minor +'@backstage/plugin-github-deployments': patch --- Support for GitHub Enterprise with GithubDeploymentsPlugin diff --git a/plugins/github-deployments/src/api/index.ts b/plugins/github-deployments/src/api/index.ts index 3a348f2b56..23a381f771 100644 --- a/plugins/github-deployments/src/api/index.ts +++ b/plugins/github-deployments/src/api/index.ts @@ -21,29 +21,28 @@ import { graphql } from '@octokit/graphql'; const getBaseUrl = ( scmIntegrationsApi: ScmIntegrationRegistry, - locations: string[], + host: string | undefined, ): string => { - const targets = locations - .map(parseLocationReference) - .filter(location => location.type === 'url') - .map(location => location.target); - - if (targets.length === 0) { + if (host === undefined) { return 'https://api.github.com'; } - const location = targets[0]; - const config = scmIntegrationsApi.github.byUrl(location); + const location = parseLocationReference(host); + if (location.type !== 'github') { + return 'https://api.github.com'; + } + + const config = scmIntegrationsApi.github.byHost(location.target); if (!config) { throw new InputError( - `No matching GitHub integration configuration for location ${location}, please check your integrations config`, + `No matching GitHub integration configuration for host ${host}, please check your integrations config`, ); } if (!config.config.apiBaseUrl) { throw new InputError( - `No apiBaseUrl available for location ${location}, please check your integrations config`, + `No apiBaseUrl available for host ${host}, please check your integrations config`, ); } @@ -65,20 +64,14 @@ export type GithubDeployment = { }; type QueryParams = { + host: string | undefined; owner: string; repo: string; last: number; }; -type QueryOptions = { - locations: string[]; -}; - export interface GithubDeploymentsApi { - listDeployments( - params: QueryParams, - options: QueryOptions, - ): Promise; + listDeployments(params: QueryParams): Promise; } export const githubDeploymentsApiRef = createApiRef({ @@ -130,11 +123,8 @@ export class GithubDeploymentsApiClient implements GithubDeploymentsApi { this.scmIntegrationsApi = options.scmIntegrationsApi; } - async listDeployments( - params: QueryParams, - options: QueryOptions, - ): Promise { - const baseUrl = getBaseUrl(this.scmIntegrationsApi, options.locations); + async listDeployments(params: QueryParams): Promise { + const baseUrl = getBaseUrl(this.scmIntegrationsApi, params.host); const token = await this.githubAuthApi.getAccessToken(['repo']); const graphQLWithAuth = graphql.defaults({ diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index cae8313422..5914e4b422 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -250,8 +250,7 @@ describe('github-deployments', () => { entity = entityStub; entity.entity.metadata.annotations = { 'github.com/project-slug': 'org/repo', - 'backstage.io/source-location': - 'url:https://my-github-1.com/org/repo', + 'backstage.io/source-location': 'github:my-github-1.com', }; }); @@ -272,8 +271,7 @@ describe('github-deployments', () => { entity = entityStub; entity.entity.metadata.annotations = { 'github.com/project-slug': 'org/repo', - 'backstage.io/managed-by-location': - 'url:https://my-github-2.com/org/repo', + 'backstage.io/managed-by-location': 'github:my-github-2.com', }; }); @@ -294,8 +292,7 @@ describe('github-deployments', () => { entity = entityStub; entity.entity.metadata.annotations = { 'github.com/project-slug': 'org/repo', - 'backstage.io/managed-by-location': - 'url:https://my-github-3.com/org/repo', + 'backstage.io/managed-by-location': 'github:my-github-3.com', }; }); @@ -308,7 +305,7 @@ describe('github-deployments', () => { expect( await rendered.findByText( - 'Warning: No apiBaseUrl available for location https://my-github-3.com/org/repo, please check your integrations config', + 'Warning: No apiBaseUrl available for host github:my-github-3.com, please check your integrations config', ), ).toBeInTheDocument(); }); @@ -320,7 +317,7 @@ describe('github-deployments', () => { entity.entity.metadata.annotations = { 'github.com/project-slug': 'org/repo', 'backstage.io/managed-by-location': - 'url:https://my-github-unknown.com/org/repo', + 'github:my-github-unknown.com/org/repo', }; }); @@ -333,7 +330,7 @@ describe('github-deployments', () => { expect( await rendered.findByText( - 'Warning: No matching GitHub integration configuration for location https://my-github-unknown.com/org/repo, please check your integrations config', + 'Warning: No matching GitHub integration configuration for host github:my-github-unknown.com/org/repo, please check your integrations config', ), ).toBeInTheDocument(); }); diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index 959926683f..b7f2e7b1ba 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -37,18 +37,18 @@ const GithubDeploymentsComponent = ({ projectSlug, last, columns, - locations, + host, }: { projectSlug: string; last: number; - locations: string[]; columns: TableColumn[]; + host: string | undefined; }) => { const api = useApi(githubDeploymentsApiRef); const [owner, repo] = projectSlug.split('/'); const { loading, value, error, retry: reload } = useAsyncRetry( - async () => await api.listDeployments({ owner, repo, last }, { locations }), + async () => await api.listDeployments({ host, owner, repo, last }), ); if (error) { @@ -73,10 +73,10 @@ export const GithubDeploymentsCard = ({ columns?: TableColumn[]; }) => { const { entity } = useEntity(); - const locations = [ + const host: string | undefined = [ entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], entity?.metadata.annotations?.[LOCATION_ANNOTATION], - ].filter(location => location !== undefined) as string[]; + ].filter(Boolean)[0]; return !isGithubDeploymentsAvailable(entity) ? ( @@ -86,7 +86,7 @@ export const GithubDeploymentsCard = ({ entity?.metadata.annotations?.[GITHUB_PROJECT_SLUG_ANNOTATION] || '' } last={last || 10} - locations={locations} + host={host} columns={columns || GithubDeploymentsTable.defaultDeploymentColumns} /> ); From e7e9e93f5730ccbda905d388b382f3a7fe16c1a6 Mon Sep 17 00:00:00 2001 From: Andrew Johnson <57673895+anderoo@users.noreply.github.com> Date: Wed, 12 May 2021 09:41:25 +0100 Subject: [PATCH 10/12] Update GithubDeploymentsCard.tsx Signed-off-by: anderoo --- .../src/components/GithubDeploymentsCard.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index b7f2e7b1ba..4cb01f04a8 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -73,10 +73,8 @@ export const GithubDeploymentsCard = ({ columns?: TableColumn[]; }) => { const { entity } = useEntity(); - const host: string | undefined = [ - entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], - entity?.metadata.annotations?.[LOCATION_ANNOTATION], - ].filter(Boolean)[0]; + const [host] = [entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], + entity?.metadata.annotations?.[LOCATION_ANNOTATION]].filter(Boolean); return !isGithubDeploymentsAvailable(entity) ? ( From d8e24a7ae30f5a7bf1d9b7aa3b50cb78d490302b Mon Sep 17 00:00:00 2001 From: Andrew Johnson <57673895+anderoo@users.noreply.github.com> Date: Wed, 12 May 2021 09:46:29 +0100 Subject: [PATCH 11/12] Update GithubDeploymentsCard.test.tsx Signed-off-by: anderoo --- .../components/GithubDeploymentsCard.test.tsx | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index 5914e4b422..4af0c0096e 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -336,7 +336,31 @@ describe('github-deployments', () => { }); }); - describe('entity with non url location', () => { + describe('entity with url location type', () => { + beforeEach(() => { + entity = entityStub; + entity.entity.metadata.annotations = { + 'github.com/project-slug': 'org/repo', + 'backstage.io/source-location': + 'url:my-favourite-url-location/org/repo', + 'backstage.io/managed-by-location': + 'url:my-favourite-url-location/org/repo', + }; + }); + + it('displays fetched data using default github api', async () => { + worker.use( + GRAPHQL_GITHUB_API.query('deployments', (_, res, ctx) => + res(ctx.data(responseStub)), + ), + ); + + await assertFetchedData(); + expect.assertions(7); + }); + }); + + describe('entity with other location types', () => { beforeEach(() => { entity = entityStub; entity.entity.metadata.annotations = { From b23260677a7000355bfc849a5c2781554713e947 Mon Sep 17 00:00:00 2001 From: anderoo Date: Wed, 12 May 2021 10:09:56 +0100 Subject: [PATCH 12/12] prettier Signed-off-by: anderoo --- .../src/components/GithubDeploymentsCard.test.tsx | 2 +- .../src/components/GithubDeploymentsCard.tsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx index 4af0c0096e..bec60c47bc 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.test.tsx @@ -359,7 +359,7 @@ describe('github-deployments', () => { expect.assertions(7); }); }); - + describe('entity with other location types', () => { beforeEach(() => { entity = entityStub; diff --git a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx index 4cb01f04a8..a13c205084 100644 --- a/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx +++ b/plugins/github-deployments/src/components/GithubDeploymentsCard.tsx @@ -73,8 +73,10 @@ export const GithubDeploymentsCard = ({ columns?: TableColumn[]; }) => { const { entity } = useEntity(); - const [host] = [entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], - entity?.metadata.annotations?.[LOCATION_ANNOTATION]].filter(Boolean); + const [host] = [ + entity?.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION], + entity?.metadata.annotations?.[LOCATION_ANNOTATION], + ].filter(Boolean); return !isGithubDeploymentsAvailable(entity) ? (