diff --git a/.changeset/fluffy-tomatoes-rescue.md b/.changeset/fluffy-tomatoes-rescue.md new file mode 100644 index 0000000000..4d446070a0 --- /dev/null +++ b/.changeset/fluffy-tomatoes-rescue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-gocd': patch +--- + +Add GoCD plugin for CI/CD. diff --git a/app-config.yaml b/app-config.yaml index 2837d97d2f..b43a229ae9 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -107,6 +107,13 @@ proxy: headers: Authorization: ${AIRFLOW_BASIC_AUTH_HEADER} + '/gocd': + target: https://your.gocd.instance.com/go/api + allowedMethods: ['GET'] + allowedHeaders: ['Authorization'] + headers: + Authorization: Basic ${GOCD_AUTH_CREDENTIALS} + organization: name: My Company @@ -450,3 +457,6 @@ azureDevOps: apacheAirflow: baseUrl: https://your.airflow.instance.com + +gocd: + baseUrl: https://your.gocd.instance.com diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index c3af6caf2d..26a8710820 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -204,6 +204,24 @@ browser when viewing that user. This annotation can be used on a [User entity](descriptor-format.md#kind-user) to note that it originated from that user on GitHub. +### gocd.org/pipelines + +```yaml +# Example: +metadata: + annotations: + gocd.org/pipelines: backstage,backstage-pr,backstage-builder +``` + +The value of this annotation is a comma-separated list of the GoCD pipeline +names to fetch CI/CD information for. + +The pipeline name is usually defined in the `gocd.yml` file for the pipeline +definition. + +Specifying this annotation will enable GoCD related features in Backstage for +that entity. + ### sentry.io/project-slug ```yaml diff --git a/microsite/data/plugins/gocd.yaml b/microsite/data/plugins/gocd.yaml new file mode 100644 index 0000000000..7bf24d75fd --- /dev/null +++ b/microsite/data/plugins/gocd.yaml @@ -0,0 +1,12 @@ +--- +title: GoCD +author: SoundCloud +authorUrl: https://github.com/soundcloud +category: CI/CD +description: GoCD is an open-source tool which is used in software development to help teams and organizations automate the continuous delivery of software. +documentation: https://github.com/backstage/backstage/tree/master/plugins/gocd +iconUrl: https://pics.freeicons.io/uploads/icons/png/13646383971540553613-512.png +npmPackageName: '@backstage/plugin-gocd' +tags: + - ci + - cd diff --git a/packages/app/package.json b/packages/app/package.json index bbfd903484..b83c43674b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -27,6 +27,7 @@ "@backstage/plugin-explore": "^0.3.24", "@backstage/plugin-gcp-projects": "^0.3.12", "@backstage/plugin-github-actions": "^0.4.30", + "@backstage/plugin-gocd": "^0.1.0", "@backstage/plugin-graphiql": "^0.2.26", "@backstage/plugin-home": "^0.4.9", "@backstage/plugin-jenkins": "^0.5.16", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 455cd188fb..60dc0dc979 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -129,6 +129,7 @@ import { EntityNewRelicDashboardContent, EntityNewRelicDashboardCard, } from '@backstage/plugin-newrelic-dashboard'; +import { EntityGoCdContent, isGoCdAvailable } from '@backstage/plugin-gocd'; import React, { ReactNode, useMemo, useState } from 'react'; @@ -185,6 +186,10 @@ export const cicdContent = ( + + + + diff --git a/plugins/gocd/.eslintrc.js b/plugins/gocd/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/plugins/gocd/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/plugins/gocd/README.md b/plugins/gocd/README.md new file mode 100644 index 0000000000..105d93e830 --- /dev/null +++ b/plugins/gocd/README.md @@ -0,0 +1,54 @@ +# GoCD + +Welcome to the GoCD plugin! + +- View recent GoCD Builds + +## Installation + +GoCD Plugin exposes an entity tab component named `EntityGoCdContent`. You can include it in the +[`EntityPage.tsx`](https://github.com/backstage/backstage/blob/master/packages/app/src/components/catalog/EntityPage.tsx)`: + +```tsx +// At the top imports +import { EntityGoCdContent } from '@backstage/plugin-gocd'; + +// Farther down at the component declaration +const componentEntityPage = ( + + {/* Place the following section where you want the tab to appear */} + + + +``` + +Now your plugin should be visible as a tab at the top of the entity pages, +specifically for components that are of the type `component`. +However, it warns of a missing `gocd.org/pipelines` annotation. + +Add the annotation to your component [catalog-info.yaml](https://github.com/backstage/backstage/blob/master/catalog-info.yaml). You can refer to multiple GoCD pipelines by defining their names separated by commas, as shown in the highlighted example below: + +```yaml +metadata: + annotations: + gocd.org/pipelines: '[,]' +``` + +The plugin requires to configure a GoCD API proxy with a `GOCD_AUTH_CREDENTIALS` for authentication in the [app-config.yaml](https://github.com/backstage/backstage/blob/master/app-config.yaml). Its value is an opaque token you can obtain directly from your GoCD instance, in the shape `base64(user + ':' + pass)`. For example, a user "root" and password "root" would become `base64('root:root') = cm9vdDpyb290`: + +```yaml +proxy: + '/gocd': + target: '/go/api' + allowedMethods: ['GET'] + allowedHeaders: ['Authorization'] + headers: + Authorization: Basic ${GOCD_AUTH_CREDENTIALS} +``` + +You should also include the `gocd` section to allow for the plugin to redirect back to GoCD pipelines in your deployed instance: + +```yaml +gocd: + baseUrl: +``` diff --git a/plugins/gocd/api-report.md b/plugins/gocd/api-report.md new file mode 100644 index 0000000000..de2c76e06b --- /dev/null +++ b/plugins/gocd/api-report.md @@ -0,0 +1,24 @@ +## API Report File for "@backstage/plugin-gocd" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { Entity } from '@backstage/catalog-model'; + +// @public +export const EntityGoCdContent: () => JSX.Element; + +// @public +export const GOCD_PIPELINES_ANNOTATION = 'gocd.org/pipelines'; + +// @public +export const gocdPlugin: BackstagePlugin<{}, {}>; + +// @public +export const isGoCdAvailable: (entity: Entity) => boolean; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/gocd/config.d.ts b/plugins/gocd/config.d.ts new file mode 100644 index 0000000000..6f4f4f3dc3 --- /dev/null +++ b/plugins/gocd/config.d.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2021 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. + */ +export interface Config { + /** Configurations for the GoCD plugin */ + gocd: { + /** + * The base url of the GoCD installation. + * @visibility frontend + */ + baseUrl: string; + }; +} diff --git a/plugins/gocd/dev/index.tsx b/plugins/gocd/dev/index.tsx new file mode 100644 index 0000000000..e821173774 --- /dev/null +++ b/plugins/gocd/dev/index.tsx @@ -0,0 +1,19 @@ +/* + * Copyright 2021 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 { createDevApp } from '@backstage/dev-utils'; +import { gocdPlugin } from '../src/plugin'; + +createDevApp().registerPlugin(gocdPlugin).render(); diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json new file mode 100644 index 0000000000..d07931916d --- /dev/null +++ b/plugins/gocd/package.json @@ -0,0 +1,68 @@ +{ + "name": "@backstage/plugin-gocd", + "description": "A Backstage plugin that integrates towards GoCD", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": false, + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/gocd" + }, + "scripts": { + "build": "backstage-cli plugin:build", + "start": "backstage-cli plugin:serve", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "diff": "backstage-cli plugin:diff", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/catalog-model": "^0.9.1", + "@backstage/core-components": "^0.8.3", + "@backstage/core-plugin-api": "^0.4.1", + "@backstage/errors": "^0.1.4", + "@backstage/plugin-catalog-react": "^0.6.0", + "@backstage/theme": "^0.2.14", + "@material-ui/core": "^4.12.2", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.57", + "lodash": "^4.17.21", + "luxon": "^2.0.2", + "qs": "^6.10.1", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.10.5", + "@backstage/core-app-api": "^0.3.1", + "@backstage/dev-utils": "^0.2.16", + "@backstage/test-utils": "^0.2.1", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^11.2.5", + "@testing-library/user-event": "^13.1.8", + "@types/jest": "^26.0.7", + "@types/lodash": "^4.14.173", + "@types/luxon": "^2.0.4", + "@types/node": "^14.14.32", + "cross-fetch": "^3.0.6", + "msw": "^0.35.0" + }, + "files": [ + "dist", + "config.d.ts" + ], + "configSchema": "config.d.ts" +} diff --git a/plugins/gocd/src/api/gocdApi.client.ts b/plugins/gocd/src/api/gocdApi.client.ts new file mode 100644 index 0000000000..1f4955a80d --- /dev/null +++ b/plugins/gocd/src/api/gocdApi.client.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2021 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 { GoCdApi } from './gocdApi'; +import { GoCdApiError, PipelineHistory } from './gocdApi.model'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { ResponseError } from '@backstage/errors'; + +export class GoCdClientApi implements GoCdApi { + constructor(private readonly discoveryApi: DiscoveryApi) {} + + async getPipelineHistory( + pipelineName: string, + ): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('proxy'); + const pipelineHistoryResponse = await fetch( + `${baseUrl}/gocd/pipelines/${pipelineName}/history`, + { + headers: { + Accept: 'application/vnd.go.cd+json', + }, + }, + ); + + if (!pipelineHistoryResponse.ok) { + throw await ResponseError.fromResponse(pipelineHistoryResponse); + } + + return await pipelineHistoryResponse.json(); + } +} diff --git a/plugins/gocd/src/api/gocdApi.model.ts b/plugins/gocd/src/api/gocdApi.model.ts new file mode 100644 index 0000000000..8bb9a481e6 --- /dev/null +++ b/plugins/gocd/src/api/gocdApi.model.ts @@ -0,0 +1,119 @@ +/* + * Copyright 2021 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. + */ +export interface GoCdApiError { + message: string; +} + +export interface PipelineHistory { + _links: Links; + pipelines: Pipeline[]; +} + +export interface Links { + next: Next; +} + +export interface Next { + href: string; +} + +export interface Pipeline { + name: string; + counter: number; + label: string; + natural_order?: number; + can_run?: boolean; + preparing_to_schedule?: boolean; + comment: string | null; + scheduled_date?: number; + build_cause?: BuildCause; + stages: Stage[]; +} + +export interface BuildCause { + trigger_message: string; + trigger_forced: boolean; + approver: string; + material_revisions: MaterialRevision[]; +} + +export interface MaterialRevision { + changed: boolean; + material: Material; + modifications: Modification[]; +} + +export interface Material { + name: string; + fingerprint: string; + type: string; + description: string; +} + +export interface Modification { + revision: string; + modified_time: number; + user_name: string; + comment: string | null; + email_address: string | null; +} + +export interface Stage { + result?: string; + status: string; + rerun_of_counter?: number | null; + name: string; + counter: string; + scheduled: boolean; + approval_type?: string | null; + approved_by?: string | null; + operate_permission?: boolean; + can_run?: boolean; + jobs: Job[]; +} + +export interface Job { + name: string; + scheduled_date?: number; + state: string; + result: string; +} + +export enum GoCdBuildResultStatus { + running, + successful, + warning, + aborted, + error, + pending, +} + +export interface GoCdBuildStageResult { + status: GoCdBuildResultStatus; + text: string; +} + +export interface GoCdBuildResult { + id: number; + source: string; + stages: GoCdBuildStageResult[]; + buildSlug: string; + message: string; + pipeline: string; + author: string | undefined; + commitHash: string; + triggerTime: number | undefined; +} diff --git a/plugins/gocd/src/api/gocdApi.ts b/plugins/gocd/src/api/gocdApi.ts new file mode 100644 index 0000000000..a9883a0c66 --- /dev/null +++ b/plugins/gocd/src/api/gocdApi.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2021 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 { GoCdApiError, PipelineHistory } from './gocdApi.model'; + +export interface GoCdApi { + getPipelineHistory( + pipelineName: string, + ): Promise; +} diff --git a/plugins/gocd/src/components/GoCdBuildsComponent/GoCdBuildsComponent.test.tsx b/plugins/gocd/src/components/GoCdBuildsComponent/GoCdBuildsComponent.test.tsx new file mode 100644 index 0000000000..7f16f40a6a --- /dev/null +++ b/plugins/gocd/src/components/GoCdBuildsComponent/GoCdBuildsComponent.test.tsx @@ -0,0 +1,60 @@ +/* + * Copyright 2021 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 React from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { ConfigReader } from '@backstage/core-app-api'; +import { ConfigApi, configApiRef } from '@backstage/core-plugin-api'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { renderWithEffects, TestApiProvider } from '@backstage/test-utils'; +import { GoCdBuildsComponent } from './GoCdBuildsComponent'; +import { gocdApiRef } from '../../plugin'; +import { GoCdApi } from '../../api/gocdApi'; + +const mockApiClient: GoCdApi = { + getPipelineHistory: jest.fn(async () => ({ + _links: { next: { href: 'some-href' } }, + pipelines: [], + })), +}; + +describe('GoCdArtifactsComponent', () => { + const configApi: ConfigApi = new ConfigReader({ + gocd: { + baseUrl: 'gocd.baseurl.com', + }, + }); + const entityValue = { entity: { metadata: {} } as Entity }; + + const renderComponent = () => + renderWithEffects( + + + + + , + ); + + it('should display an empty state if an app annotation is missing', async () => { + const rendered = await renderComponent(); + + expect(await rendered.findByText('Missing Annotation')).toBeInTheDocument(); + }); +}); diff --git a/plugins/gocd/src/components/GoCdBuildsComponent/GoCdBuildsComponent.tsx b/plugins/gocd/src/components/GoCdBuildsComponent/GoCdBuildsComponent.tsx new file mode 100644 index 0000000000..46e5d09260 --- /dev/null +++ b/plugins/gocd/src/components/GoCdBuildsComponent/GoCdBuildsComponent.tsx @@ -0,0 +1,132 @@ +/* + * Copyright 2021 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 React, { useState } from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { + Content, + ContentHeader, + MissingAnnotationEmptyState, + EmptyState, + Page, +} from '@backstage/core-components'; +import { useApi, configApiRef } from '@backstage/core-plugin-api'; +import { useAsync } from 'react-use'; +import { gocdApiRef } from '../../plugin'; +import { GoCdBuildsTable } from '../GoCdBuildsTable/GoCdBuildsTable'; +import { GoCdApiError, PipelineHistory } from '../../api/gocdApi.model'; +import { Item, Select } from '../Select'; + +/** + * Constant storing GoCD pipelines annotation. + * + * @public + */ +export const GOCD_PIPELINES_ANNOTATION = 'gocd.org/pipelines'; + +/** + * Returns true if GoCD annotation is present in the given entity. + * + * @public + */ +export const isGoCdAvailable = (entity: Entity): boolean => + Boolean(entity.metadata.annotations?.[GOCD_PIPELINES_ANNOTATION]); + +export const GoCdBuildsComponent = (): JSX.Element => { + const { entity } = useEntity(); + const config = useApi(configApiRef); + const rawPipelines: string[] | undefined = ( + entity.metadata.annotations?.[GOCD_PIPELINES_ANNOTATION] as + | string + | undefined + ) + ?.split(',') + .map(p => p.trim()); + const gocdApi = useApi(gocdApiRef); + + const [selectedPipeline, setSelectedPipeline] = useState( + rawPipelines ? rawPipelines[0] : '', + ); + + const { + value: pipelineHistory, + loading, + error, + } = useAsync(async (): Promise => { + return await gocdApi.getPipelineHistory(selectedPipeline); + }, [selectedPipeline]); + + const onSelectedPipelineChanged = (pipeline: string) => { + setSelectedPipeline(pipeline); + }; + + const getSelectionItems = (pipelines: string[]): Item[] => { + return pipelines.map(p => ({ label: p, value: p })); + }; + + function isError( + apiResult: PipelineHistory | GoCdApiError | undefined, + ): apiResult is GoCdApiError { + return (apiResult as GoCdApiError)?.message !== undefined; + } + + if (!rawPipelines) { + return ( + + ); + } + + if (isError(pipelineHistory)) { + return ( + + ); + } + + if (!loading && !pipelineHistory) { + return ( + + ); + } + + return ( + + + + + {renderItems(items)} + + + ); +}; diff --git a/plugins/gocd/src/components/Select/index.ts b/plugins/gocd/src/components/Select/index.ts new file mode 100644 index 0000000000..1503c54cdf --- /dev/null +++ b/plugins/gocd/src/components/Select/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 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. + */ +export { SelectComponent as Select } from './Select'; +export type { Item } from './Select'; diff --git a/plugins/gocd/src/extensions.ts b/plugins/gocd/src/extensions.ts new file mode 100644 index 0000000000..55624c9d7e --- /dev/null +++ b/plugins/gocd/src/extensions.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2021 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 { gocdPlugin } from './plugin'; +import { createComponentExtension } from '@backstage/core-plugin-api'; + +/** + * GoCD builds table component. + * + * @public + */ +export const EntityGoCdContent = gocdPlugin.provide( + createComponentExtension({ + name: 'EntityGoCdContent', + component: { + lazy: () => + import('./components/GoCdBuildsComponent').then( + m => m.GoCdBuildsComponent, + ), + }, + }), +); diff --git a/plugins/gocd/src/index.ts b/plugins/gocd/src/index.ts new file mode 100644 index 0000000000..c92e899546 --- /dev/null +++ b/plugins/gocd/src/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2021 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. + */ +export { gocdPlugin } from './plugin'; +export { EntityGoCdContent } from './extensions'; +export { + GOCD_PIPELINES_ANNOTATION, + isGoCdAvailable, +} from './components/GoCdBuildsComponent'; diff --git a/plugins/gocd/src/plugin.test.ts b/plugins/gocd/src/plugin.test.ts new file mode 100644 index 0000000000..02b52a00b6 --- /dev/null +++ b/plugins/gocd/src/plugin.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2021 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 { gocdPlugin } from './plugin'; + +describe('gocd', () => { + it('should export plugin', () => { + expect(gocdPlugin).toBeDefined(); + }); +}); diff --git a/plugins/gocd/src/plugin.ts b/plugins/gocd/src/plugin.ts new file mode 100644 index 0000000000..01081978f4 --- /dev/null +++ b/plugins/gocd/src/plugin.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2021 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 { GoCdClientApi } from './api/gocdApi.client'; +import { GoCdApi } from './api/gocdApi'; +import { + discoveryApiRef, + createApiRef, + createApiFactory, + createPlugin, +} from '@backstage/core-plugin-api'; + +export const gocdApiRef = createApiRef({ + id: 'plugin.gocd.service', +}); + +/** + * Plugin definition. + * + * @public + */ +export const gocdPlugin = createPlugin({ + id: 'gocd', + apis: [ + createApiFactory({ + api: gocdApiRef, + deps: { discoveryApi: discoveryApiRef }, + factory: ({ discoveryApi }) => { + return new GoCdClientApi(discoveryApi); + }, + }), + ], +}); diff --git a/plugins/gocd/src/routes.ts b/plugins/gocd/src/routes.ts new file mode 100644 index 0000000000..71e431c040 --- /dev/null +++ b/plugins/gocd/src/routes.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2021 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 { createRouteRef } from '@backstage/core-plugin-api'; + +export const rootRouteRef = createRouteRef({ + id: 'gocd', +}); diff --git a/plugins/gocd/src/setupTests.ts b/plugins/gocd/src/setupTests.ts new file mode 100644 index 0000000000..fc6dbd98f8 --- /dev/null +++ b/plugins/gocd/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 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 '@testing-library/jest-dom'; +import 'cross-fetch/polyfill';