@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-code-climate': minor
|
||||
---
|
||||
|
||||
Added Code Climate plugin
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint')],
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
# Code Climate Plugin
|
||||
|
||||
The Code Climate Plugin displays a few stats from the quality section from [Code Climate](https://codeclimate.com).
|
||||
|
||||

|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install the Code Climate Plugin:
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-code-climate
|
||||
```
|
||||
|
||||
2. Add the `EntityCodeClimateCard` to the EntityPage:
|
||||
|
||||
```jsx
|
||||
// packages/app/src/components/catalog/EntityPage.tsx
|
||||
|
||||
import { EntityCodeClimateCard } from '@backstage/plugin-code-climate';
|
||||
|
||||
const overviewContent = (
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
// ...
|
||||
<Grid item>
|
||||
<EntityCodeClimateCard />
|
||||
</Grid>
|
||||
// ...
|
||||
</Grid>
|
||||
);
|
||||
```
|
||||
|
||||
3. Add the proxy config:
|
||||
|
||||
```yaml
|
||||
# app-config.yaml
|
||||
|
||||
proxy:
|
||||
'/codeclimate/api':
|
||||
target: https://api.codeclimate.com/v1
|
||||
headers:
|
||||
Authorization: Token token=${CODECLIMATE_TOKEN}
|
||||
```
|
||||
|
||||
4. Create a new API access token (https://codeclimate.com/profile/tokens) and provide `CODECLIMATE_TOKEN` as an env variable.
|
||||
|
||||
5. Add the `codeclimate.com/repo-id` annotation to your `catalog-info.yaml` file:
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage
|
||||
description: |
|
||||
Backstage is an open-source developer portal that puts the developer experience first.
|
||||
annotations:
|
||||
codeclimate.com/repo-id: YOUR_REPO_ID
|
||||
spec:
|
||||
type: library
|
||||
owner: CNCF
|
||||
lifecycle: experimental
|
||||
```
|
||||
|
||||
### Demo Mode
|
||||
|
||||
The plugin provides a MockAPI that always returns dummy data instead of talking to the Code Climate backend.
|
||||
You can add it by overriding the `codeClimateApiRef`:
|
||||
|
||||
```ts
|
||||
// packages/app/src/apis.ts
|
||||
|
||||
import { createApiFactory } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
MockCodeClimateApi,
|
||||
codeClimateApiRef,
|
||||
} from '@backstage/plugin-code-climate';
|
||||
|
||||
export const apis = [
|
||||
// ...
|
||||
|
||||
createApiFactory(codeClimateApiRef, new MockCodeClimateApi()),
|
||||
];
|
||||
```
|
||||
@@ -0,0 +1,87 @@
|
||||
## API Report File for "@backstage/plugin-code-climate"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "CodeClimateApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export interface CodeClimateApi {
|
||||
// (undocumented)
|
||||
fetchData(repoID: string): Promise<CodeClimateData>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "codeClimateApiRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const codeClimateApiRef: ApiRef<CodeClimateApi>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "CodeClimateData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type CodeClimateData = {
|
||||
repoID: string;
|
||||
maintainability: {
|
||||
letter: string;
|
||||
value: string;
|
||||
};
|
||||
testCoverage: {
|
||||
letter: string;
|
||||
value: string;
|
||||
};
|
||||
numberOfCodeSmells: number;
|
||||
numberOfDuplication: number;
|
||||
numberOfOtherIssues: number;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "codeClimatePlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const codeClimatePlugin: BackstagePlugin<
|
||||
{
|
||||
root: RouteRef<undefined>;
|
||||
},
|
||||
{}
|
||||
>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "EntityCodeClimateCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const EntityCodeClimateCard: () => JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "MockCodeClimateApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export class MockCodeClimateApi implements CodeClimateApi {
|
||||
// (undocumented)
|
||||
fetchData(): Promise<CodeClimateData>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "mockData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const mockData: CodeClimateData;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ProductionCodeClimateApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export class ProductionCodeClimateApi implements CodeClimateApi {
|
||||
constructor(discoveryApi: DiscoveryApi);
|
||||
// (undocumented)
|
||||
fetchAllData(options: {
|
||||
apiUrl: string;
|
||||
repoID: string;
|
||||
snapshotID: string;
|
||||
testReportID: string;
|
||||
}): Promise<any>;
|
||||
// (undocumented)
|
||||
fetchData(repoID: string): Promise<CodeClimateData>;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2020 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';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { createDevApp, EntityGridItem } from '@backstage/dev-utils';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import {
|
||||
EntityCodeClimateCard,
|
||||
MockCodeClimateApi,
|
||||
CodeClimateApi,
|
||||
codeClimateApiRef,
|
||||
} from '../src';
|
||||
import { CODECLIMATE_REPO_ID_ANNOTATION } from '../src/plugin';
|
||||
import { Content, Header, Page } from '@backstage/core-components';
|
||||
|
||||
const entity = (name?: string) =>
|
||||
({
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
annotations: {
|
||||
[CODECLIMATE_REPO_ID_ANNOTATION]: name,
|
||||
},
|
||||
name: name,
|
||||
},
|
||||
} as Entity);
|
||||
|
||||
createDevApp()
|
||||
.registerApi({
|
||||
api: codeClimateApiRef,
|
||||
deps: {},
|
||||
factory: () =>
|
||||
({
|
||||
fetchData: async (repoID: string) => {
|
||||
switch (repoID) {
|
||||
case 'error':
|
||||
throw new Error('Error!');
|
||||
|
||||
case 'never':
|
||||
return new Promise(() => {});
|
||||
|
||||
case 'no-values':
|
||||
return undefined;
|
||||
|
||||
case 'with-values':
|
||||
return new MockCodeClimateApi().fetchData();
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
},
|
||||
} as CodeClimateApi),
|
||||
})
|
||||
.addPage({
|
||||
title: 'Cards',
|
||||
element: (
|
||||
<Page themeId="home">
|
||||
<Header title="Code Climate" />
|
||||
<Content>
|
||||
<Grid container>
|
||||
<EntityGridItem xs={12} md={6} entity={entity('error')}>
|
||||
<EntityCodeClimateCard />
|
||||
</EntityGridItem>
|
||||
<EntityGridItem xs={12} md={6} entity={entity('never')}>
|
||||
<EntityCodeClimateCard />
|
||||
</EntityGridItem>
|
||||
<EntityGridItem xs={12} md={6} entity={entity('no-values')}>
|
||||
<EntityCodeClimateCard />
|
||||
</EntityGridItem>
|
||||
<EntityGridItem xs={12} md={6} entity={entity('with-values')}>
|
||||
<EntityCodeClimateCard />
|
||||
</EntityGridItem>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
),
|
||||
})
|
||||
.render();
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "@backstage/plugin-code-climate",
|
||||
"version": "0.0.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.10.0",
|
||||
"@backstage/core-components": "^0.8.9",
|
||||
"@backstage/core-plugin-api": "^0.6.1",
|
||||
"@backstage/plugin-catalog-react": "^0.6.15",
|
||||
"@backstage/theme": "^0.2.15",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"humanize-duration": "^3.27.1",
|
||||
"luxon": "^2.0.2",
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-use": "^17.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.14.0",
|
||||
"@backstage/dev-utils": "^0.2.22",
|
||||
"@backstage/test-utils": "^0.2.5",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
"@types/humanize-duration": "^3.27.1",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/luxon": "^2.0.9",
|
||||
"@types/node": "^14.14.32",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"msw": "^0.35.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2020 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 { CodeClimateData } from './code-climate-data';
|
||||
import { createApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const codeClimateApiRef = createApiRef<CodeClimateApi>({
|
||||
id: 'plugin.code-climate.service',
|
||||
});
|
||||
|
||||
export interface CodeClimateApi {
|
||||
fetchData(repoID: string): Promise<CodeClimateData>;
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2020 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 type CodeClimateRepoData = {
|
||||
data: {
|
||||
id: string;
|
||||
type: string;
|
||||
attributes: {
|
||||
analysis_version: number;
|
||||
badge_token: string;
|
||||
branch: string;
|
||||
created_at: string;
|
||||
delegated_config_repo_id: string;
|
||||
diff_coverage_enforced: boolean;
|
||||
diff_coverage_threshold: number;
|
||||
enable_notifications: boolean;
|
||||
github_slug: string;
|
||||
human_name: string;
|
||||
last_activity_at: string;
|
||||
test_reporter_id: string | null;
|
||||
total_coverage_enforced: boolean;
|
||||
vcs_database_id: string;
|
||||
vcs_host: string;
|
||||
score: string | null;
|
||||
};
|
||||
relationships: {
|
||||
latest_default_branch_snapshot: {
|
||||
data: { id: string; type: string };
|
||||
};
|
||||
latest_default_branch_test_report: {
|
||||
data: { id: string; type: string };
|
||||
};
|
||||
account: {
|
||||
data: { id: string; type: string };
|
||||
};
|
||||
};
|
||||
links: {
|
||||
self: string;
|
||||
services: string;
|
||||
web_coverage: string;
|
||||
web_issues: string;
|
||||
maintainability_badge: string;
|
||||
test_coverage_badge: string;
|
||||
};
|
||||
meta: { permissions: { admin: boolean } };
|
||||
};
|
||||
};
|
||||
|
||||
export type CodeClimateMaintainabilityData = {
|
||||
data: {
|
||||
id: string;
|
||||
type: string;
|
||||
attributes: {
|
||||
commit_sha: string;
|
||||
committed_at: string;
|
||||
created_at: string;
|
||||
lines_of_code: number;
|
||||
ratings: [
|
||||
{
|
||||
path: string;
|
||||
letter: string;
|
||||
measure: {
|
||||
value: number;
|
||||
unit: string;
|
||||
meta: {
|
||||
remediation_time: { value: number; unit: string };
|
||||
implementation_time: {
|
||||
value: number;
|
||||
unit: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
pillar: string;
|
||||
},
|
||||
];
|
||||
gpa: string | null;
|
||||
worker_version: number;
|
||||
};
|
||||
meta: {
|
||||
issues_count: number;
|
||||
measures: {
|
||||
remediation: { value: number; unit: string };
|
||||
technical_debt_ratio: {
|
||||
value: number;
|
||||
unit: string;
|
||||
meta: {
|
||||
remediation_time: { value: number; unit: string };
|
||||
implementation_time: {
|
||||
value: number;
|
||||
unit: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type CodeClimateTestCoverageData = {
|
||||
data: {
|
||||
id: string;
|
||||
type: string;
|
||||
attributes: {
|
||||
branch: string;
|
||||
commit_sha: string;
|
||||
committed_at: string;
|
||||
covered_percent: number;
|
||||
lines_of_code: number;
|
||||
rating: {
|
||||
path: string;
|
||||
letter: string;
|
||||
measure: { value: number; unit: string };
|
||||
pillar: string;
|
||||
};
|
||||
received_at: string;
|
||||
state: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type CodeClimateIssuesData = {
|
||||
data: [
|
||||
{
|
||||
id: string;
|
||||
type: string;
|
||||
attributes: {
|
||||
categories: string[];
|
||||
check_name: string;
|
||||
constant_name: string;
|
||||
content: { body: string };
|
||||
description: string;
|
||||
engine_name: string;
|
||||
fingerprint: string;
|
||||
location: {
|
||||
path: string;
|
||||
end_line: number;
|
||||
start_line: number;
|
||||
};
|
||||
other_locations: string[];
|
||||
remediation_points: number;
|
||||
severity: string;
|
||||
};
|
||||
meta: { permissions: { manageable: boolean } };
|
||||
},
|
||||
];
|
||||
links: {
|
||||
self: string;
|
||||
next: string;
|
||||
last: string;
|
||||
};
|
||||
meta: { current_page: number; total_pages: number; total_count: number };
|
||||
};
|
||||
|
||||
export type CodeClimateData = {
|
||||
repoID: string;
|
||||
maintainability: {
|
||||
letter: string;
|
||||
value: string;
|
||||
};
|
||||
testCoverage: {
|
||||
letter: string;
|
||||
value: string;
|
||||
};
|
||||
numberOfCodeSmells: number;
|
||||
numberOfDuplication: number;
|
||||
numberOfOtherIssues: number;
|
||||
};
|
||||
|
||||
export type CodeClimateApiError = {
|
||||
detail: string;
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2020 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 * from './mock';
|
||||
export type { CodeClimateApi } from './code-climate-api';
|
||||
export { codeClimateApiRef } from './code-climate-api';
|
||||
export type { CodeClimateData } from './code-climate-data';
|
||||
export { ProductionCodeClimateApi } from './production-api';
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"data": {
|
||||
"id": "6b8cc37a64b741dd9d516119",
|
||||
"type": "snapshots",
|
||||
"attributes": {
|
||||
"commit_sha": "d670460b4b4aece5915caf5c68d12f560a9fe3e4",
|
||||
"committed_at": "2022-01-14T15:17:29.311Z",
|
||||
"created_at": "2022-01-31T10:07:40.415Z",
|
||||
"lines_of_code": 8854,
|
||||
"ratings": [
|
||||
{
|
||||
"path": "/",
|
||||
"letter": "B",
|
||||
"measure": {
|
||||
"value": 5.264879308188034,
|
||||
"unit": "percent",
|
||||
"meta": {
|
||||
"remediation_time": { "value": 7186.52, "unit": "minute" },
|
||||
"implementation_time": {
|
||||
"value": 136499.2353922225,
|
||||
"unit": "minute"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pillar": "Maintainability"
|
||||
}
|
||||
],
|
||||
"gpa": null,
|
||||
"worker_version": 69440
|
||||
},
|
||||
"meta": {
|
||||
"issues_count": 127,
|
||||
"measures": {
|
||||
"remediation": { "value": 7186.52, "unit": "minute" },
|
||||
"technical_debt_ratio": {
|
||||
"value": 5.264879308188034,
|
||||
"unit": "percent",
|
||||
"meta": {
|
||||
"remediation_time": { "value": 7186.52, "unit": "minute" },
|
||||
"implementation_time": {
|
||||
"value": 136499.2353922225,
|
||||
"unit": "minute"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"data": {
|
||||
"id": "6b8cc37a64b741dd9d516119",
|
||||
"type": "test_reports",
|
||||
"attributes": {
|
||||
"branch": "master",
|
||||
"commit_sha": "d670460b4b4aece5915caf5c68d12f560a9fe3e4",
|
||||
"committed_at": "2022-01-14T15:17:26.000Z",
|
||||
"covered_percent": 88.41059602649007,
|
||||
"lines_of_code": 8854,
|
||||
"rating": {
|
||||
"path": "/",
|
||||
"letter": "B",
|
||||
"measure": { "value": 88.41059602649007, "unit": "percent" },
|
||||
"pillar": "Test Coverage"
|
||||
},
|
||||
"received_at": "2022-01-14T15:25:38.352Z",
|
||||
"state": "done"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2020 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 { mockData } from './mock-api';
|
||||
export { MockCodeClimateApi } from './mock-api';
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2020 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 { CodeClimateData } from '../code-climate-data';
|
||||
import { CodeClimateApi } from '../code-climate-api';
|
||||
import maintainabilityMock from './code-climate-maintainability-mock.json';
|
||||
import testCoverageMock from './code-climate-test-coverage-mock.json';
|
||||
import { Duration } from 'luxon';
|
||||
import humanizeDuration from 'humanize-duration';
|
||||
|
||||
const maintainabilityData = maintainabilityMock.data.attributes.ratings[0];
|
||||
const testCoverageData = testCoverageMock.data.attributes.rating;
|
||||
|
||||
const maintainabilityValue: any = {};
|
||||
maintainabilityValue[
|
||||
maintainabilityData.measure.meta.implementation_time.unit
|
||||
] = maintainabilityData.measure.meta.implementation_time.value.toFixed();
|
||||
|
||||
export const mockData: CodeClimateData = {
|
||||
repoID: '6b8cc37a64b741dd9d516119',
|
||||
maintainability: {
|
||||
letter: maintainabilityData.letter,
|
||||
value: humanizeDuration(
|
||||
Duration.fromObject(maintainabilityValue).toMillis(),
|
||||
{ largest: 1 },
|
||||
),
|
||||
},
|
||||
testCoverage: {
|
||||
letter: testCoverageData.letter,
|
||||
value: testCoverageData.measure.value.toFixed(),
|
||||
},
|
||||
numberOfCodeSmells: 97,
|
||||
numberOfDuplication: 49,
|
||||
numberOfOtherIssues: 26,
|
||||
};
|
||||
|
||||
export class MockCodeClimateApi implements CodeClimateApi {
|
||||
fetchData(): Promise<CodeClimateData> {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => resolve(mockData), 800);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2020 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 {
|
||||
CodeClimateData,
|
||||
CodeClimateRepoData,
|
||||
CodeClimateMaintainabilityData,
|
||||
CodeClimateTestCoverageData,
|
||||
CodeClimateIssuesData,
|
||||
} from './code-climate-data';
|
||||
import { CodeClimateApi } from './code-climate-api';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { Duration } from 'luxon';
|
||||
import humanizeDuration from 'humanize-duration';
|
||||
|
||||
const pageQuery = encodeURIComponent('page[size]');
|
||||
const statusFilter = encodeURIComponent('filter[status][$in][]');
|
||||
const categoriesFilter = encodeURIComponent('filter[categories][$in][]');
|
||||
const basicIssuesOptions = `${pageQuery}=1&${statusFilter}=open&${statusFilter}=confirmed`;
|
||||
const codeSmellsQuery = `${basicIssuesOptions}&${categoriesFilter}=Complexity`;
|
||||
const duplicationQuery = `${basicIssuesOptions}&${categoriesFilter}=Duplication`;
|
||||
const otherIssuesQuery = `${basicIssuesOptions}&${categoriesFilter}=Bug%20Risk`;
|
||||
|
||||
export class ProductionCodeClimateApi implements CodeClimateApi {
|
||||
constructor(private readonly discoveryApi: DiscoveryApi) {}
|
||||
|
||||
async fetchAllData(options: {
|
||||
apiUrl: string;
|
||||
repoID: string;
|
||||
snapshotID: string;
|
||||
testReportID: string;
|
||||
}): Promise<any> {
|
||||
const { apiUrl, repoID, snapshotID, testReportID } = options;
|
||||
|
||||
const [
|
||||
maintainabilityResponse,
|
||||
testCoverageResponse,
|
||||
codeSmellsResponse,
|
||||
duplicationResponse,
|
||||
otherIssuesResponse,
|
||||
] = await Promise.all([
|
||||
await fetch(`${apiUrl}/repos/${repoID}/snapshots/${snapshotID}`),
|
||||
await fetch(`${apiUrl}/repos/${repoID}/test_reports/${testReportID}`),
|
||||
await fetch(
|
||||
`${apiUrl}/repos/${repoID}/snapshots/${snapshotID}/issues?${codeSmellsQuery}`,
|
||||
),
|
||||
await fetch(
|
||||
`${apiUrl}/repos/${repoID}/snapshots/${snapshotID}/issues?${duplicationQuery}`,
|
||||
),
|
||||
await fetch(
|
||||
`${apiUrl}/repos/${repoID}/snapshots/${snapshotID}/issues?${otherIssuesQuery}`,
|
||||
),
|
||||
]);
|
||||
|
||||
if (
|
||||
!maintainabilityResponse.ok ||
|
||||
!testCoverageResponse.ok ||
|
||||
!codeSmellsResponse.ok ||
|
||||
!duplicationResponse.ok ||
|
||||
!otherIssuesResponse.ok
|
||||
) {
|
||||
throw new Error('Failed fetching Code Climate info');
|
||||
}
|
||||
|
||||
const maintainabilityData = (
|
||||
(await maintainabilityResponse.json()) as CodeClimateMaintainabilityData
|
||||
).data.attributes.ratings[0];
|
||||
const testCoverageData = (
|
||||
(await testCoverageResponse.json()) as CodeClimateTestCoverageData
|
||||
).data.attributes.rating;
|
||||
const codeSmellsData = (
|
||||
(await codeSmellsResponse.json()) as CodeClimateIssuesData
|
||||
).meta.total_count;
|
||||
const duplicationData = (
|
||||
(await duplicationResponse.json()) as CodeClimateIssuesData
|
||||
).meta.total_count;
|
||||
const otherIssuesData = (
|
||||
(await otherIssuesResponse.json()) as CodeClimateIssuesData
|
||||
).meta.total_count;
|
||||
|
||||
return [
|
||||
maintainabilityData,
|
||||
testCoverageData,
|
||||
codeSmellsData,
|
||||
duplicationData,
|
||||
otherIssuesData,
|
||||
];
|
||||
}
|
||||
|
||||
async fetchData(repoID: string): Promise<CodeClimateData> {
|
||||
if (!repoID) {
|
||||
throw new Error('No Repo id found');
|
||||
}
|
||||
|
||||
const apiUrl = `${await this.discoveryApi.getBaseUrl(
|
||||
'proxy',
|
||||
)}/codeclimate/api`;
|
||||
|
||||
const repoResponse = await fetch(`${apiUrl}/repos/${repoID}`);
|
||||
|
||||
if (!repoResponse.ok) {
|
||||
throw new Error('Failed fetching Code Climate info');
|
||||
}
|
||||
|
||||
const repoData = ((await repoResponse.json()) as CodeClimateRepoData).data;
|
||||
const snapshotID =
|
||||
repoData.relationships.latest_default_branch_snapshot.data.id;
|
||||
const testReportID =
|
||||
repoData.relationships.latest_default_branch_test_report.data.id;
|
||||
|
||||
const [
|
||||
maintainabilityData,
|
||||
testCoverageData,
|
||||
codeSmellsData,
|
||||
duplicationData,
|
||||
otherIssuesData,
|
||||
] = await this.fetchAllData({
|
||||
apiUrl,
|
||||
repoID,
|
||||
snapshotID,
|
||||
testReportID,
|
||||
});
|
||||
|
||||
const maintainabilityValue: any = {};
|
||||
maintainabilityValue[
|
||||
maintainabilityData.measure.meta.implementation_time.unit
|
||||
] = maintainabilityData.measure.meta.implementation_time.value.toFixed();
|
||||
|
||||
return {
|
||||
repoID,
|
||||
maintainability: {
|
||||
letter: maintainabilityData.letter,
|
||||
value: humanizeDuration(
|
||||
Duration.fromObject(maintainabilityValue).toMillis(),
|
||||
{ largest: 1 },
|
||||
),
|
||||
},
|
||||
testCoverage: {
|
||||
letter: testCoverageData.letter,
|
||||
value: testCoverageData.measure.value.toFixed(),
|
||||
},
|
||||
numberOfCodeSmells: codeSmellsData,
|
||||
numberOfDuplication: duplicationData,
|
||||
numberOfOtherIssues: otherIssuesData,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2020 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 { InfoCard } from '@backstage/core-components';
|
||||
import { CodeClimateCardContents } from '../CodeClimateCardContents';
|
||||
|
||||
export const CodeClimateCard = () => (
|
||||
<InfoCard title="Code Climate Summary">
|
||||
<CodeClimateCardContents />
|
||||
</InfoCard>
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 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 { CodeClimateCard } from './CodeClimateCard';
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020 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 useAsync from 'react-use/lib/useAsync';
|
||||
import { codeClimateApiRef } from '../../api';
|
||||
import { CodeClimateTable } from '../CodeClimateTable';
|
||||
import { CODECLIMATE_REPO_ID_ANNOTATION } from '../../plugin';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
EmptyState,
|
||||
ErrorPanel,
|
||||
MissingAnnotationEmptyState,
|
||||
Progress,
|
||||
} from '@backstage/core-components';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
export const CodeClimateCardContents = () => {
|
||||
const { entity } = useEntity();
|
||||
const codeClimateApi = useApi(codeClimateApiRef);
|
||||
|
||||
const repoID =
|
||||
entity?.metadata.annotations?.[CODECLIMATE_REPO_ID_ANNOTATION] ?? '';
|
||||
|
||||
const { loading, value, error } = useAsync(
|
||||
() => codeClimateApi.fetchData(repoID),
|
||||
[codeClimateApi, repoID],
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (!repoID) {
|
||||
return (
|
||||
<MissingAnnotationEmptyState
|
||||
annotation={CODECLIMATE_REPO_ID_ANNOTATION}
|
||||
/>
|
||||
);
|
||||
} else if (error) {
|
||||
return <ErrorPanel error={error} />;
|
||||
} else if (!value) {
|
||||
return (
|
||||
<EmptyState
|
||||
missing="info"
|
||||
title="No information to display"
|
||||
description={`There is no Code Climate repo setup with id '${repoID}'.`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <CodeClimateTable codeClimateData={value} />;
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 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 { CodeClimateCardContents } from './CodeClimateCardContents';
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2020 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 { render } from '@testing-library/react';
|
||||
import { CodeClimateTable } from './CodeClimateTable';
|
||||
import { mockData } from '../../api/mock';
|
||||
import { ThemeProvider } from '@material-ui/core';
|
||||
import { lightTheme } from '@backstage/theme';
|
||||
|
||||
describe('CodeClimateTable', () => {
|
||||
it('should render values in a table', async () => {
|
||||
const table = await render(
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<CodeClimateTable codeClimateData={mockData} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
expect(await table.findByText('3 months')).toBeInTheDocument();
|
||||
expect(await table.findByText('88%')).toBeInTheDocument();
|
||||
expect(await table.findByText('97')).toBeInTheDocument();
|
||||
expect(await table.findByText('49')).toBeInTheDocument();
|
||||
expect(await table.findByText('26')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2020 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 { CodeClimateData } from '../../api';
|
||||
import { Link } from '@backstage/core-components';
|
||||
import { Box, makeStyles, Typography } from '@material-ui/core';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
const letterStyle = {
|
||||
color: 'white',
|
||||
border: 0,
|
||||
borderRadius: '3px',
|
||||
fontSize: '40px',
|
||||
padding: '5px 20px',
|
||||
};
|
||||
|
||||
const fontSize = {
|
||||
fontSize: '25px',
|
||||
};
|
||||
|
||||
const letterColor = (letter: string) => {
|
||||
if (letter === 'A') {
|
||||
return '#45d298';
|
||||
} else if (letter === 'B') {
|
||||
return '#a5d86e';
|
||||
} else if (letter === 'C') {
|
||||
return '#f1ce0c';
|
||||
} else if (letter === 'D') {
|
||||
return '#f29141';
|
||||
} else if (letter === 'F') {
|
||||
return '#df5869';
|
||||
}
|
||||
|
||||
return '#45d298';
|
||||
};
|
||||
|
||||
const useStyles = makeStyles<
|
||||
BackstageTheme,
|
||||
{
|
||||
maintainabilityLetter: string;
|
||||
testCoverageLetter: string;
|
||||
}
|
||||
>({
|
||||
spaceAround: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-around',
|
||||
},
|
||||
spaceBetween: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
maintainabilityLetterColor: {
|
||||
...letterStyle,
|
||||
backgroundColor: props => letterColor(props.maintainabilityLetter),
|
||||
},
|
||||
testCoverageLetterColor: {
|
||||
...letterStyle,
|
||||
backgroundColor: props => letterColor(props.testCoverageLetter),
|
||||
},
|
||||
fontSize: {
|
||||
...fontSize,
|
||||
},
|
||||
letterDetails: {
|
||||
...fontSize,
|
||||
paddingLeft: '10px',
|
||||
},
|
||||
paddingSides20: {
|
||||
padding: '0px 20px',
|
||||
},
|
||||
});
|
||||
|
||||
export const CodeClimateTable = ({
|
||||
codeClimateData,
|
||||
}: {
|
||||
codeClimateData: CodeClimateData;
|
||||
}) => {
|
||||
const {
|
||||
repoID,
|
||||
maintainability: {
|
||||
letter: maintainabilityLetter,
|
||||
value: maintainabilityValue,
|
||||
},
|
||||
testCoverage: { letter: testCoverageLetter, value: testCoverageValue },
|
||||
numberOfCodeSmells,
|
||||
numberOfDuplication,
|
||||
numberOfOtherIssues,
|
||||
} = codeClimateData;
|
||||
|
||||
const classes = useStyles({ maintainabilityLetter, testCoverageLetter });
|
||||
|
||||
if (!codeClimateData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.spaceAround}>
|
||||
<div>
|
||||
<Typography variant="h6" component="p">
|
||||
Maintainability
|
||||
</Typography>
|
||||
<div className={classes.spaceBetween}>
|
||||
<Typography
|
||||
className={classes.maintainabilityLetterColor}
|
||||
variant="body2"
|
||||
component="p"
|
||||
>
|
||||
{maintainabilityLetter}
|
||||
</Typography>
|
||||
<Link to={`https://codeclimate.com/repos/${repoID}`}>
|
||||
<Typography
|
||||
className={classes.letterDetails}
|
||||
variant="body2"
|
||||
component="p"
|
||||
>
|
||||
{maintainabilityValue}
|
||||
</Typography>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="h6" component="p">
|
||||
Test Coverage
|
||||
</Typography>
|
||||
<div className={classes.spaceBetween}>
|
||||
<Typography
|
||||
className={classes.testCoverageLetterColor}
|
||||
variant="body2"
|
||||
component="p"
|
||||
>
|
||||
{testCoverageLetter}
|
||||
</Typography>
|
||||
<Link to={`https://codeclimate.com/repos/${repoID}`}>
|
||||
<Typography
|
||||
className={classes.letterDetails}
|
||||
variant="body2"
|
||||
component="p"
|
||||
>
|
||||
{testCoverageValue}%
|
||||
</Typography>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Box className={classes.spaceAround} paddingTop="30px">
|
||||
<div>
|
||||
<Typography variant="h6" component="p">
|
||||
Code Smells:
|
||||
</Typography>
|
||||
<Link
|
||||
to={`https://codeclimate.com/repos/${repoID}/issues?category%5B%5D=complexity&status%5B%5D=&status%5B%5D=open&status%5B%5D=confirmed`}
|
||||
>
|
||||
<Typography
|
||||
className={classes.fontSize}
|
||||
variant="body2"
|
||||
component="p"
|
||||
>
|
||||
{numberOfCodeSmells}
|
||||
</Typography>
|
||||
</Link>
|
||||
</div>
|
||||
<Box paddingLeft="20" paddingRight="20">
|
||||
<Typography variant="h6" component="p">
|
||||
Duplication:
|
||||
</Typography>
|
||||
<Link
|
||||
to={`https://codeclimate.com/repos/${repoID}/issues?category%5B%5D=duplication&status%5B%5D=&status%5B%5D=open&status%5B%5D=confirmed`}
|
||||
>
|
||||
<Typography
|
||||
className={classes.fontSize}
|
||||
variant="body2"
|
||||
component="p"
|
||||
>
|
||||
{numberOfDuplication}
|
||||
</Typography>
|
||||
</Link>
|
||||
</Box>
|
||||
<div>
|
||||
<Typography variant="h6" component="p">
|
||||
Other Issues:
|
||||
</Typography>
|
||||
<Link
|
||||
to={`https://codeclimate.com/repos/${repoID}/issues?category%5B%5D=bugrisk&status%5B%5D=&status%5B%5D=open&status%5B%5D=confirmed`}
|
||||
>
|
||||
<Typography
|
||||
className={classes.fontSize}
|
||||
variant="body2"
|
||||
component="p"
|
||||
>
|
||||
{numberOfOtherIssues}
|
||||
</Typography>
|
||||
</Link>
|
||||
</div>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 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 { CodeClimateTable } from './CodeClimateTable';
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A Backstage plugin that integrates towards Code Climate
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export * from './api';
|
||||
export { codeClimatePlugin, EntityCodeClimateCard } from './plugin';
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2020 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 { codeClimatePlugin } from './plugin';
|
||||
|
||||
describe('codeclimate', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(codeClimatePlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2020 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 { ProductionCodeClimateApi, codeClimateApiRef } from './api';
|
||||
import {
|
||||
createApiFactory,
|
||||
createPlugin,
|
||||
createRouteRef,
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
createComponentExtension,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
export const CODECLIMATE_REPO_ID_ANNOTATION = 'codeclimate.com/repo-id';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
id: 'code-climate',
|
||||
});
|
||||
|
||||
export const codeClimatePlugin = createPlugin({
|
||||
id: 'code-climate',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: codeClimateApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
},
|
||||
factory: ({ discoveryApi }) => new ProductionCodeClimateApi(discoveryApi),
|
||||
}),
|
||||
],
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
},
|
||||
});
|
||||
|
||||
export const EntityCodeClimateCard = codeClimatePlugin.provide(
|
||||
createComponentExtension({
|
||||
name: 'EntityCodeClimateCard',
|
||||
component: {
|
||||
lazy: () =>
|
||||
import('./components/CodeClimateCard').then(m => m.CodeClimateCard),
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
|
||||
import '@testing-library/jest-dom';
|
||||
import 'cross-fetch/polyfill';
|
||||
@@ -5785,6 +5785,11 @@
|
||||
resolved "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.25.1.tgz#b6140d5fc00ff3917b3f521784abef4bc0387ccc"
|
||||
integrity sha512-WZU/4bb+lvzyDmZzjJtp++9mfKy6B3lH6gGISgkcz6SU8hMILKRM0vi08TxIsb0dQB4Gzo68MWLmctu6xqUi9g==
|
||||
|
||||
"@types/humanize-duration@^3.27.1":
|
||||
version "3.27.1"
|
||||
resolved "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.27.1.tgz#f14740d1f585a0a8e3f46359b62fda8b0eaa31e7"
|
||||
integrity sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==
|
||||
|
||||
"@types/inquirer@^7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz#92e6676efb67fa6925c69a2ee638f67a822952ac"
|
||||
@@ -5954,6 +5959,11 @@
|
||||
resolved "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.9.tgz#782a0edfa6d699191292c13168bd496cd66b87c6"
|
||||
integrity sha512-ZuzIc7aN+i2ZDMWIiSmMdubR9EMMSTdEzF6R+FckP4p6xdnOYKqknTo/k+xXQvciSXlNGIwA4OPU5X7JIFzYdA==
|
||||
|
||||
"@types/luxon@^2.0.9":
|
||||
version "2.0.9"
|
||||
resolved "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.9.tgz#782a0edfa6d699191292c13168bd496cd66b87c6"
|
||||
integrity sha512-ZuzIc7aN+i2ZDMWIiSmMdubR9EMMSTdEzF6R+FckP4p6xdnOYKqknTo/k+xXQvciSXlNGIwA4OPU5X7JIFzYdA==
|
||||
|
||||
"@types/mdast@^3.0.0", "@types/mdast@^3.0.3":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb"
|
||||
@@ -13948,7 +13958,7 @@ human-signals@^2.1.0:
|
||||
resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
|
||||
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
||||
|
||||
humanize-duration@^3.25.1, humanize-duration@^3.26.0, humanize-duration@^3.27.0:
|
||||
humanize-duration@^3.25.1, humanize-duration@^3.26.0, humanize-duration@^3.27.0, humanize-duration@^3.27.1:
|
||||
version "3.27.1"
|
||||
resolved "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.27.1.tgz#2cd4ea4b03bd92184aee6d90d77a8f3d7628df69"
|
||||
integrity sha512-jCVkMl+EaM80rrMrAPl96SGG4NRac53UyI1o/yAzebDntEY6K6/Fj2HOjdPg8omTqIe5Y0wPBai2q5xXrIbarA==
|
||||
|
||||
Reference in New Issue
Block a user