diff --git a/app-config.yaml b/app-config.yaml index 9f365becef..c5c4a23bdd 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -133,6 +133,9 @@ kafka: brokers: - localhost:9092 +allure: + baseUrl: http://localhost:5050/allure-docker-service + integrations: github: - host: github.com diff --git a/packages/app/package.json b/packages/app/package.json index 78ebe32e25..a5407abe09 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -10,6 +10,7 @@ "@backstage/core-components": "^0.3.2", "@backstage/core-plugin-api": "^0.1.6", "@backstage/integration-react": "^0.1.7", + "@backstage/plugin-allure": "^0.1.0", "@backstage/plugin-api-docs": "^0.6.6", "@backstage/plugin-badges": "^0.2.7", "@backstage/plugin-catalog": "^0.6.12", diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index d84a7341bc..89bc39952f 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -110,6 +110,7 @@ import { } from '@roadiehq/backstage-plugin-travis-ci'; import { EntityCodeCoverageContent } from '@backstage/plugin-code-coverage'; import { EmptyState } from '@backstage/core-components'; +import { EntityAllureReportContent } from '@backstage/plugin-allure'; const EntityLayoutWrapper = (props: { children?: ReactNode }) => { const [badgesDialogOpen, setBadgesDialogOpen] = useState(false); @@ -356,6 +357,10 @@ const serviceEntityPage = ( + + + + ); diff --git a/plugins/allure/.eslintrc.js b/plugins/allure/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/plugins/allure/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/plugins/allure/README.md b/plugins/allure/README.md new file mode 100644 index 0000000000..d28fe913b1 --- /dev/null +++ b/plugins/allure/README.md @@ -0,0 +1,47 @@ +# Allure + +Welcome to the Backstage Allure plugin. This plugin add an entity service page to display Allure test reports related to the service. + +## Install + +Run the below command from the `app` package directory. + +```shell +yarn add @backstage/plugin-allure +``` + +alternatively, you can execute below command from the root directory of your Backstage app. + +```shell +yarn workspace app add @backstage/plugin-allure +``` + +## Configure + +### Configure Allure service + +Add below configuration in the `app-config.yaml`. + +```yaml +allure: + baseUrl: # Example: http://localhost:5050/allure-docker-service +``` + +### Setup entity service page + +Add `EntityAllureReportContent` in the `EntityPage.tsx` like below: + +```diff ++ import { EntityAllureReportContent } from '@backstage/plugin-allure'; + +... + +const serviceEntityPage = ( + + ... ++ ++ ++ + +); +``` diff --git a/plugins/allure/package.json b/plugins/allure/package.json new file mode 100644 index 0000000000..81a37ed996 --- /dev/null +++ b/plugins/allure/package.json @@ -0,0 +1,68 @@ +{ + "name": "@backstage/plugin-allure", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "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.0", + "@backstage/core-components": "^0.3.2", + "@backstage/core-plugin-api": "^0.1.6", + "@backstage/plugin-catalog-react": "^0.4.3", + "@backstage/theme": "^0.2.10", + "@material-ui/core": "^4.12.2", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.45", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "react-router-dom": "6.0.0-beta.0", + "react-use": "^17.2.4" + }, + "devDependencies": { + "@backstage/cli": "^0.7.9", + "@backstage/core-app-api": "^0.1.9", + "@backstage/dev-utils": "^0.2.7", + "@backstage/test-utils": "^0.1.17", + "@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/node": "^14.14.32", + "cross-fetch": "^3.0.6", + "msw": "^0.29.0" + }, + "files": [ + "dist" + ], + "configSchema": { + "$schema": "https://backstage.io/schema/config-v1", + "title": "@backstage/allure", + "type": "object", + "properties": { + "allure": { + "type": "object", + "properties": { + "baseUrl": { + "type": "string", + "visibility": "frontend" + } + } + } + } + } +} diff --git a/plugins/allure/src/api/AllureApi.ts b/plugins/allure/src/api/AllureApi.ts new file mode 100644 index 0000000000..a926da03d0 --- /dev/null +++ b/plugins/allure/src/api/AllureApi.ts @@ -0,0 +1,24 @@ +/* + * 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 { createApiRef } from '@backstage/core-plugin-api'; + +export type AllureApi = { + getReportUrl(projectId: string): Promise; +}; + +export const allureApiRef = createApiRef({ + id: 'allure-api', +}); diff --git a/plugins/allure/src/api/AllureApiClient.ts b/plugins/allure/src/api/AllureApiClient.ts new file mode 100644 index 0000000000..698713c837 --- /dev/null +++ b/plugins/allure/src/api/AllureApiClient.ts @@ -0,0 +1,30 @@ +/* + * 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 { ConfigApi } from '@backstage/core-plugin-api'; +import { AllureApi } from './AllureApi'; + +export class AllureApiClient implements AllureApi { + readonly configApi: ConfigApi; + + constructor(options: { configApi: ConfigApi }) { + this.configApi = options.configApi; + } + + async getReportUrl(projectId: string): Promise { + const baseUrl = this.configApi.getString('allure.baseUrl'); + return `${baseUrl}/projects/${projectId}/reports/latest/index.html`; + } +} diff --git a/plugins/allure/src/api/index.ts b/plugins/allure/src/api/index.ts new file mode 100644 index 0000000000..1c1adb1db2 --- /dev/null +++ b/plugins/allure/src/api/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 { allureApiRef } from './AllureApi'; +export { AllureApiClient } from './AllureApiClient'; diff --git a/plugins/allure/src/components/AllureReportComponent/AllureReportComponent.test.tsx b/plugins/allure/src/components/AllureReportComponent/AllureReportComponent.test.tsx new file mode 100644 index 0000000000..38fa4c0923 --- /dev/null +++ b/plugins/allure/src/components/AllureReportComponent/AllureReportComponent.test.tsx @@ -0,0 +1,44 @@ +/* + * 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 { AllureReportComponent } from './AllureReportComponent'; +import { ThemeProvider } from '@material-ui/core'; +import { lightTheme } from '@backstage/theme'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { msw, renderInTestApp } from '@backstage/test-utils'; + +describe('ExampleComponent', () => { + const server = setupServer(); + // Enable sane handlers for network requests + msw.setupDefaultHandlers(server); + + // setup mock response + beforeEach(() => { + server.use( + rest.get('/*', (_, res, ctx) => res(ctx.status(200), ctx.json({}))), + ); + }); + + it('should render', async () => { + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('Welcome to allure!')).toBeInTheDocument(); + }); +}); diff --git a/plugins/allure/src/components/AllureReportComponent/AllureReportComponent.tsx b/plugins/allure/src/components/AllureReportComponent/AllureReportComponent.tsx new file mode 100644 index 0000000000..c59284b3ef --- /dev/null +++ b/plugins/allure/src/components/AllureReportComponent/AllureReportComponent.tsx @@ -0,0 +1,70 @@ +/* + * 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 { useApi } from '@backstage/core-plugin-api'; +import { allureApiRef } from '../../api'; +import { AllureApi } from '../../api/AllureApi'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { + ALLURE_PROJECT_ID_ANNOTATION, + isAllureReportAvailable, + useAllureProjectId, +} from '../useAllureProjectId'; +import { + MissingAnnotationEmptyState, + Progress, +} from '@backstage/core-components'; +import { useAsync } from 'react-use'; +import { Entity } from '@backstage/catalog-model'; + +const AllureReport = (props: { entity: Entity }) => { + const allureApi = useApi(allureApiRef); + + const allureProjectId = useAllureProjectId(props.entity); + const { value, loading } = useAsync(async () => { + const url = await allureApi.getReportUrl(allureProjectId); + return url; + }); + + if (loading) { + return ; + } + return ( + <> + {!loading && ( +