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 && (
+
+ )}
+ >
+ );
+};
+
+export const AllureReportComponent = () => {
+ const { entity } = useEntity();
+ const isReportAvailable = isAllureReportAvailable(entity);
+
+ if (isReportAvailable) return ;
+ return (
+
+ );
+};
diff --git a/plugins/allure/src/components/AllureReportComponent/index.ts b/plugins/allure/src/components/AllureReportComponent/index.ts
new file mode 100644
index 0000000000..7b2fab744b
--- /dev/null
+++ b/plugins/allure/src/components/AllureReportComponent/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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 { AllureReportComponent } from './AllureReportComponent';
diff --git a/plugins/allure/src/components/useAllureProjectId.ts b/plugins/allure/src/components/useAllureProjectId.ts
new file mode 100644
index 0000000000..d1bcf39b53
--- /dev/null
+++ b/plugins/allure/src/components/useAllureProjectId.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.
+ */
+import { Entity } from '@backstage/catalog-model';
+
+export const ALLURE_PROJECT_ID_ANNOTATION = 'allure/project-id';
+
+export const isAllureReportAvailable = (entity: Entity) =>
+ Boolean(entity.metadata.annotations?.[ALLURE_PROJECT_ID_ANNOTATION]);
+
+export const useAllureProjectId = (entity: Entity) => {
+ return entity?.metadata.annotations?.[ALLURE_PROJECT_ID_ANNOTATION] ?? '';
+};
diff --git a/plugins/allure/src/index.ts b/plugins/allure/src/index.ts
new file mode 100644
index 0000000000..016d33c2ff
--- /dev/null
+++ b/plugins/allure/src/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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 { allurePlugin, EntityAllureReportContent } from './plugin';
diff --git a/plugins/allure/src/plugin.test.ts b/plugins/allure/src/plugin.test.ts
new file mode 100644
index 0000000000..dab1088ad3
--- /dev/null
+++ b/plugins/allure/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 { allurePlugin } from './plugin';
+
+describe('allure', () => {
+ it('should export plugin', () => {
+ expect(allurePlugin).toBeDefined();
+ });
+});
diff --git a/plugins/allure/src/plugin.ts b/plugins/allure/src/plugin.ts
new file mode 100644
index 0000000000..3907707b18
--- /dev/null
+++ b/plugins/allure/src/plugin.ts
@@ -0,0 +1,53 @@
+/*
+ * 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 {
+ configApiRef,
+ createApiFactory,
+ createPlugin,
+ createRoutableExtension,
+ createRouteRef,
+} from '@backstage/core-plugin-api';
+import { AllureApiClient, allureApiRef } from './api';
+
+export const allureRouteRef = createRouteRef({
+ title: 'allure-report',
+});
+
+export const allurePlugin = createPlugin({
+ id: 'allure',
+ apis: [
+ createApiFactory({
+ api: allureApiRef,
+ deps: {
+ configApi: configApiRef,
+ },
+ factory: ({ configApi }) => new AllureApiClient({ configApi }),
+ }),
+ ],
+ routes: {
+ root: allureRouteRef,
+ },
+});
+
+export const EntityAllureReportContent = allurePlugin.provide(
+ createRoutableExtension({
+ component: () =>
+ import('./components/AllureReportComponent').then(
+ m => m.AllureReportComponent,
+ ),
+ mountPoint: allureRouteRef,
+ }),
+);
diff --git a/plugins/allure/src/setupTests.ts b/plugins/allure/src/setupTests.ts
new file mode 100644
index 0000000000..fc6dbd98f8
--- /dev/null
+++ b/plugins/allure/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';