Created Allure Plugin

Signed-off-by: Deepak Bhardwaj <deepak.bhardwaj@outlook.com>
This commit is contained in:
Deepak Bhardwaj
2021-08-23 19:03:54 +05:30
parent 56139cfd1e
commit 4e7c25ff66
17 changed files with 461 additions and 0 deletions
+3
View File
@@ -133,6 +133,9 @@ kafka:
brokers:
- localhost:9092
allure:
baseUrl: http://localhost:5050/allure-docker-service
integrations:
github:
- host: github.com
+1
View File
@@ -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",
@@ -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 = (
<EntityLayout.Route path="/todos" title="TODOs">
<EntityTodoContent />
</EntityLayout.Route>
<EntityLayout.Route path="/allure" title="Allure Report">
<EntityAllureReportContent />
</EntityLayout.Route>
</EntityLayoutWrapper>
);
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint')],
};
+47
View File
@@ -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: <ALLURE_SERVICE_BASE_URL> # 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 = (
<EntityLayoutWrapper>
...
+ <EntityLayout.Route path="/allure" title="Allure Report">
+ <EntityAllureReportContent />
+ </EntityLayout.Route>
</EntityLayoutWrapper>
);
```
+68
View File
@@ -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"
}
}
}
}
}
}
+24
View File
@@ -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<string>;
};
export const allureApiRef = createApiRef<AllureApi>({
id: 'allure-api',
});
+30
View File
@@ -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<string> {
const baseUrl = this.configApi.getString('allure.baseUrl');
return `${baseUrl}/projects/${projectId}/reports/latest/index.html`;
}
}
+17
View File
@@ -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';
@@ -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(
<ThemeProvider theme={lightTheme}>
<AllureReportComponent />
</ThemeProvider>,
);
expect(rendered.getByText('Welcome to allure!')).toBeInTheDocument();
});
});
@@ -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<AllureApi>(allureApiRef);
const allureProjectId = useAllureProjectId(props.entity);
const { value, loading } = useAsync(async () => {
const url = await allureApi.getReportUrl(allureProjectId);
return url;
});
if (loading) {
return <Progress />;
}
return (
<>
{!loading && (
<iframe
style={{
display: 'table',
width: '100%',
height: '100%',
}}
title="Allure Report"
src={value}
/>
)}
</>
);
};
export const AllureReportComponent = () => {
const { entity } = useEntity();
const isReportAvailable = isAllureReportAvailable(entity);
if (isReportAvailable) return <AllureReport entity={entity} />;
return (
<MissingAnnotationEmptyState annotation={ALLURE_PROJECT_ID_ANNOTATION} />
);
};
@@ -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';
@@ -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] ?? '';
};
+16
View File
@@ -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';
+22
View File
@@ -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();
});
});
+53
View File
@@ -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,
}),
);
+17
View File
@@ -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';