@backstage-community/plugin-code-coverage-backend 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +0 -62
- package/dist/index.cjs.js +0 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -31
- package/dist/plugin.cjs.js +9 -3
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/service/CodeCoverageDatabase.cjs.js +2 -2
- package/dist/service/CodeCoverageDatabase.cjs.js.map +1 -1
- package/dist/service/CoverageUtils.cjs.js +2 -2
- package/dist/service/CoverageUtils.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +1 -3
- package/dist/service/router.cjs.js.map +1 -1
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @backstage-community/plugin-code-coverage-backend
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 208e250: Updated dependency `@types/uuid` to `^10.0.0`.
|
|
8
|
+
|
|
9
|
+
## 0.6.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 02cdb81: **BREAKING** Removed support for the legacy backend system. Please refer to the [README](https://github.com/backstage/community-plugins/blob/main/workspaces/code-coverage/plugins/code-coverage-backend/README.md) for instructions on how to use the new backend system.
|
|
14
|
+
|
|
15
|
+
Removed usages and references of `@backstage/backend-common`
|
|
16
|
+
|
|
3
17
|
## 0.5.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -9,68 +9,6 @@ This is the backend part of the `code-coverage` plugin. It takes care of process
|
|
|
9
9
|
yarn --cwd packages/backend add @backstage-community/plugin-code-coverage-backend
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
First create a `codecoverage.ts` file here: `packages/backend/src/plugins`. Now add the following as its content:
|
|
13
|
-
|
|
14
|
-
```diff
|
|
15
|
-
diff --git a/packages/backend/src/plugins/codecoverage.ts b/packages/backend/src/plugins/codecoverage.ts
|
|
16
|
-
--- /dev/null
|
|
17
|
-
+++ b/packages/backend/src/plugins/codecoverage.ts
|
|
18
|
-
@@ -0,0 +1,15 @@
|
|
19
|
-
+import { createRouter } from '@backstage-community/plugin-code-coverage-backend';
|
|
20
|
-
+import { Router } from 'express';
|
|
21
|
-
+import { PluginEnvironment } from '../types';
|
|
22
|
-
+
|
|
23
|
-
+export default async function createPlugin(
|
|
24
|
-
+ env: PluginEnvironment,
|
|
25
|
-
+): Promise<Router> {
|
|
26
|
-
+ return await createRouter({
|
|
27
|
-
+ config: env.config,
|
|
28
|
-
+ discovery: env.discovery,
|
|
29
|
-
+ database: env.database,
|
|
30
|
-
+ urlReader: env.reader,
|
|
31
|
-
+ logger: env.logger,
|
|
32
|
-
+ });
|
|
33
|
-
+}
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Finally we need to load the plugin in `packages/backend/src/index.ts`, make the following edits:
|
|
38
|
-
|
|
39
|
-
```diff
|
|
40
|
-
diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts
|
|
41
|
-
--- a/packages/backend/src/index.ts
|
|
42
|
-
+++ b/packages/backend/src/index.ts
|
|
43
|
-
@@ -28,6 +28,7 @@ import scaffolder from './plugins/scaffolder';
|
|
44
|
-
import proxy from './plugins/proxy';
|
|
45
|
-
import techdocs from './plugins/techdocs';
|
|
46
|
-
import search from './plugins/search';
|
|
47
|
-
+import codeCoverage from './plugins/codecoverage';
|
|
48
|
-
import { PluginEnvironment } from './types';
|
|
49
|
-
import { ServerPermissionClient } from '@backstage/plugin-permission-node';
|
|
50
|
-
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
|
|
51
|
-
@@ -85,6 +86,9 @@ async function main() {
|
|
52
|
-
const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs'));
|
|
53
|
-
const searchEnv = useHotMemoize(module, () => createEnv('search'));
|
|
54
|
-
const appEnv = useHotMemoize(module, () => createEnv('app'));
|
|
55
|
-
+ const codeCoverageEnv = useHotMemoize(module, () =>
|
|
56
|
-
+ createEnv('code-coverage'),
|
|
57
|
-
+ );
|
|
58
|
-
|
|
59
|
-
const apiRouter = Router();
|
|
60
|
-
apiRouter.use('/catalog', await catalog(catalogEnv));
|
|
61
|
-
@@ -93,6 +97,7 @@ async function main() {
|
|
62
|
-
apiRouter.use('/techdocs', await techdocs(techdocsEnv));
|
|
63
|
-
apiRouter.use('/proxy', await proxy(proxyEnv));
|
|
64
|
-
apiRouter.use('/search', await search(searchEnv));
|
|
65
|
-
+ apiRouter.use('/code-coverage', await codeCoverage(codeCoverageEnv));
|
|
66
|
-
|
|
67
|
-
apiRouter.use(notFoundHandler());
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## New Backend System
|
|
71
|
-
|
|
72
|
-
The code coverage backend plugin has support for the [new backend system](https://backstage.io/docs/backend-system/), here's how you can set that up:
|
|
73
|
-
|
|
74
12
|
In your `packages/backend/src/index.ts` make the following changes:
|
|
75
13
|
|
|
76
14
|
```diff
|
package/dist/index.cjs.js
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var router = require('./service/router.cjs.js');
|
|
6
5
|
var plugin = require('./plugin.cjs.js');
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
exports.createRouter = router.createRouter;
|
|
11
9
|
exports.default = plugin.codeCoveragePlugin;
|
|
12
10
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,34 +1,4 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import { CatalogApi } from '@backstage/catalog-client';
|
|
3
|
-
import { Config } from '@backstage/config';
|
|
4
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
5
|
-
import { DiscoveryService, DatabaseService, UrlReaderService, LoggerService, AuthService, HttpAuthService } from '@backstage/backend-plugin-api';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @deprecated Please migrate to the new backend system as this will be removed in the future.
|
|
9
|
-
*
|
|
10
|
-
* Options for {@link createRouter}.
|
|
11
|
-
*
|
|
12
|
-
* @public
|
|
13
|
-
*/
|
|
14
|
-
interface RouterOptions {
|
|
15
|
-
config: Config;
|
|
16
|
-
discovery: DiscoveryService;
|
|
17
|
-
database: DatabaseService;
|
|
18
|
-
urlReader: UrlReaderService;
|
|
19
|
-
logger: LoggerService;
|
|
20
|
-
catalogApi?: CatalogApi;
|
|
21
|
-
auth?: AuthService;
|
|
22
|
-
httpAuth?: HttpAuthService;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* @deprecated Please migrate to the new backend system as this will be removed in the future.
|
|
26
|
-
*
|
|
27
|
-
* Creates a code-coverage plugin backend router.
|
|
28
|
-
*
|
|
29
|
-
* @public
|
|
30
|
-
*/
|
|
31
|
-
declare function createRouter(options: RouterOptions): Promise<express.Router>;
|
|
32
2
|
|
|
33
3
|
/**
|
|
34
4
|
* Code coverage backend plugin
|
|
@@ -37,4 +7,4 @@ declare function createRouter(options: RouterOptions): Promise<express.Router>;
|
|
|
37
7
|
*/
|
|
38
8
|
declare const codeCoveragePlugin: _backstage_backend_plugin_api.BackendFeature;
|
|
39
9
|
|
|
40
|
-
export {
|
|
10
|
+
export { codeCoveragePlugin as default };
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -13,7 +13,9 @@ const codeCoveragePlugin = backendPluginApi.createBackendPlugin({
|
|
|
13
13
|
urlReader: backendPluginApi.coreServices.urlReader,
|
|
14
14
|
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
15
15
|
discovery: backendPluginApi.coreServices.discovery,
|
|
16
|
-
database: backendPluginApi.coreServices.database
|
|
16
|
+
database: backendPluginApi.coreServices.database,
|
|
17
|
+
auth: backendPluginApi.coreServices.auth,
|
|
18
|
+
httpAuth: backendPluginApi.coreServices.httpAuth
|
|
17
19
|
},
|
|
18
20
|
async init({
|
|
19
21
|
config,
|
|
@@ -21,7 +23,9 @@ const codeCoveragePlugin = backendPluginApi.createBackendPlugin({
|
|
|
21
23
|
urlReader,
|
|
22
24
|
httpRouter,
|
|
23
25
|
discovery,
|
|
24
|
-
database
|
|
26
|
+
database,
|
|
27
|
+
auth,
|
|
28
|
+
httpAuth
|
|
25
29
|
}) {
|
|
26
30
|
httpRouter.use(
|
|
27
31
|
await router.createRouter({
|
|
@@ -29,7 +33,9 @@ const codeCoveragePlugin = backendPluginApi.createBackendPlugin({
|
|
|
29
33
|
logger,
|
|
30
34
|
urlReader,
|
|
31
35
|
discovery,
|
|
32
|
-
database
|
|
36
|
+
database,
|
|
37
|
+
auth,
|
|
38
|
+
httpAuth
|
|
33
39
|
})
|
|
34
40
|
);
|
|
35
41
|
httpRouter.addAuthPolicy({
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * Code coverage backend plugin\n *\n * @public\n */\nexport const codeCoveragePlugin = createBackendPlugin({\n pluginId: 'code-coverage',\n register(env) {\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n urlReader: coreServices.urlReader,\n httpRouter: coreServices.httpRouter,\n discovery: coreServices.discovery,\n database: coreServices.database,\n },\n async init({\n config,\n logger,\n urlReader,\n httpRouter,\n discovery,\n database,\n }) {\n httpRouter.use(\n await createRouter({\n config,\n logger,\n urlReader,\n discovery,\n database,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","createRouter"],"mappings":";;;;;AA0BO,MAAM,qBAAqBA,oCAAoB,CAAA;AAAA,EACpD,QAAU,EAAA,eAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,UAAUA,6BAAa,CAAA;AAAA,OACzB;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,MAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,UAAA;AAAA,QACA,SAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,MAAA;AAAA,YACA,MAAA;AAAA,YACA,SAAA;AAAA,YACA,SAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA;AAAA,SACR,CAAA;AAAA;AACH,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * Code coverage backend plugin\n *\n * @public\n */\nexport const codeCoveragePlugin = createBackendPlugin({\n pluginId: 'code-coverage',\n register(env) {\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n urlReader: coreServices.urlReader,\n httpRouter: coreServices.httpRouter,\n discovery: coreServices.discovery,\n database: coreServices.database,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n },\n async init({\n config,\n logger,\n urlReader,\n httpRouter,\n discovery,\n database,\n auth,\n httpAuth,\n }) {\n httpRouter.use(\n await createRouter({\n config,\n logger,\n urlReader,\n discovery,\n database,\n auth,\n httpAuth,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","createRouter"],"mappings":";;;;;AA0BO,MAAM,qBAAqBA,oCAAoB,CAAA;AAAA,EACpD,QAAU,EAAA,eAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,YAAYA,6BAAa,CAAA,UAAA;AAAA,QACzB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,MAAMA,6BAAa,CAAA,IAAA;AAAA,QACnB,UAAUA,6BAAa,CAAA;AAAA,OACzB;AAAA,MACA,MAAM,IAAK,CAAA;AAAA,QACT,MAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,UAAA;AAAA,QACA,SAAA;AAAA,QACA,QAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA,OACC,EAAA;AACD,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,mBAAa,CAAA;AAAA,YACjB,MAAA;AAAA,YACA,MAAA;AAAA,YACA,SAAA;AAAA,YACA,SAAA;AAAA,YACA,QAAA;AAAA,YACA,IAAA;AAAA,YACA;AAAA,WACD;AAAA,SACH;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA;AAAA,SACR,CAAA;AAAA;AACH,KACD,CAAA;AAAA;AAEL,CAAC;;;;"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var errors = require('@backstage/errors');
|
|
5
5
|
var catalogModel = require('@backstage/catalog-model');
|
|
6
6
|
var uuid = require('uuid');
|
|
7
7
|
var CoverageUtils = require('./CoverageUtils.cjs.js');
|
|
8
8
|
|
|
9
|
-
const migrationsDir =
|
|
9
|
+
const migrationsDir = backendPluginApi.resolvePackagePath(
|
|
10
10
|
"@backstage-community/plugin-code-coverage-backend",
|
|
11
11
|
"migrations"
|
|
12
12
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeCoverageDatabase.cjs.js","sources":["../../src/service/CodeCoverageDatabase.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n
|
|
1
|
+
{"version":3,"file":"CodeCoverageDatabase.cjs.js","sources":["../../src/service/CodeCoverageDatabase.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { NotFoundError } from '@backstage/errors';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport { aggregateCoverage } from './CoverageUtils';\nimport { JsonCodeCoverage, JsonCoverageHistory } from './types';\n\nexport type RawDbCoverageRow = {\n id: string;\n entity: string;\n coverage: string;\n};\n\nexport interface CodeCoverageStore {\n insertCodeCoverage(\n coverage: JsonCodeCoverage,\n ): Promise<{ codeCoverageId: string }>;\n getCodeCoverage(entity: string): Promise<JsonCodeCoverage>;\n getHistory(entity: string, limit: number): Promise<JsonCoverageHistory>;\n}\n\nconst migrationsDir = resolvePackagePath(\n '@backstage-community/plugin-code-coverage-backend',\n 'migrations',\n);\n\nexport class CodeCoverageDatabase implements CodeCoverageStore {\n static async create(database: DatabaseService): Promise<CodeCoverageStore> {\n const knex = await database.getClient();\n\n if (!database.migrations?.skip) {\n await knex.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return new CodeCoverageDatabase(knex);\n }\n\n constructor(private readonly db: Knex) {}\n\n async insertCodeCoverage(\n coverage: JsonCodeCoverage,\n ): Promise<{ codeCoverageId: string }> {\n const codeCoverageId = uuid();\n const entity = stringifyEntityRef({\n kind: coverage.entity.kind,\n namespace: coverage.entity.namespace,\n name: coverage.entity.name,\n });\n\n await this.db<RawDbCoverageRow>('code_coverage').insert({\n id: codeCoverageId,\n entity: entity,\n coverage: JSON.stringify(coverage),\n });\n\n return { codeCoverageId };\n }\n\n async getCodeCoverage(entity: string): Promise<JsonCodeCoverage> {\n const [result] = await this.db<RawDbCoverageRow>('code_coverage')\n .where({ entity: entity })\n .orderBy('index', 'desc')\n .limit(1)\n .select();\n\n if (!result) {\n throw new NotFoundError(\n `No coverage for entity '${JSON.stringify(entity)}' found`,\n );\n }\n\n try {\n return JSON.parse(result.coverage);\n } catch (error) {\n throw new Error(`Failed to parse coverage for '${entity}', ${error}`);\n }\n }\n\n async getHistory(\n entity: string,\n limit: number,\n ): Promise<JsonCoverageHistory> {\n const res = await this.db<RawDbCoverageRow>('code_coverage')\n .where({ entity: entity })\n .orderBy('index', 'desc')\n .limit(limit)\n .select();\n\n const history = res\n .map(r => JSON.parse(r.coverage))\n .map(c => aggregateCoverage(c));\n\n const entityName = parseEntityRef(entity);\n\n return {\n entity: {\n name: entityName.name,\n kind: entityName.kind,\n namespace: entityName.namespace,\n },\n history: history,\n };\n }\n}\n"],"names":["resolvePackagePath","uuid","stringifyEntityRef","NotFoundError","aggregateCoverage","parseEntityRef"],"mappings":";;;;;;;;AAwCA,MAAM,aAAgB,GAAAA,mCAAA;AAAA,EACpB,mDAAA;AAAA,EACA;AACF,CAAA;AAEO,MAAM,oBAAkD,CAAA;AAAA,EAa7D,YAA6B,EAAU,EAAA;AAAV,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA;AAAA;AAAW,EAZxC,aAAa,OAAO,QAAuD,EAAA;AACzE,IAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,SAAU,EAAA;AAEtC,IAAI,IAAA,CAAC,QAAS,CAAA,UAAA,EAAY,IAAM,EAAA;AAC9B,MAAM,MAAA,IAAA,CAAK,QAAQ,MAAO,CAAA;AAAA,QACxB,SAAW,EAAA;AAAA,OACZ,CAAA;AAAA;AAGH,IAAO,OAAA,IAAI,qBAAqB,IAAI,CAAA;AAAA;AACtC,EAIA,MAAM,mBACJ,QACqC,EAAA;AACrC,IAAA,MAAM,iBAAiBC,OAAK,EAAA;AAC5B,IAAA,MAAM,SAASC,+BAAmB,CAAA;AAAA,MAChC,IAAA,EAAM,SAAS,MAAO,CAAA,IAAA;AAAA,MACtB,SAAA,EAAW,SAAS,MAAO,CAAA,SAAA;AAAA,MAC3B,IAAA,EAAM,SAAS,MAAO,CAAA;AAAA,KACvB,CAAA;AAED,IAAA,MAAM,IAAK,CAAA,EAAA,CAAqB,eAAe,CAAA,CAAE,MAAO,CAAA;AAAA,MACtD,EAAI,EAAA,cAAA;AAAA,MACJ,MAAA;AAAA,MACA,QAAA,EAAU,IAAK,CAAA,SAAA,CAAU,QAAQ;AAAA,KAClC,CAAA;AAED,IAAA,OAAO,EAAE,cAAe,EAAA;AAAA;AAC1B,EAEA,MAAM,gBAAgB,MAA2C,EAAA;AAC/D,IAAM,MAAA,CAAC,MAAM,CAAI,GAAA,MAAM,KAAK,EAAqB,CAAA,eAAe,EAC7D,KAAM,CAAA,EAAE,QAAgB,CAAA,CACxB,QAAQ,OAAS,EAAA,MAAM,EACvB,KAAM,CAAA,CAAC,EACP,MAAO,EAAA;AAEV,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAA,MAAM,IAAIC,oBAAA;AAAA,QACR,CAA2B,wBAAA,EAAA,IAAA,CAAK,SAAU,CAAA,MAAM,CAAC,CAAA,OAAA;AAAA,OACnD;AAAA;AAGF,IAAI,IAAA;AACF,MAAO,OAAA,IAAA,CAAK,KAAM,CAAA,MAAA,CAAO,QAAQ,CAAA;AAAA,aAC1B,KAAO,EAAA;AACd,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,8BAAA,EAAiC,MAAM,CAAA,GAAA,EAAM,KAAK,CAAE,CAAA,CAAA;AAAA;AACtE;AACF,EAEA,MAAM,UACJ,CAAA,MAAA,EACA,KAC8B,EAAA;AAC9B,IAAA,MAAM,MAAM,MAAM,IAAA,CAAK,GAAqB,eAAe,CAAA,CACxD,MAAM,EAAE,MAAA,EAAgB,CAAA,CACxB,QAAQ,OAAS,EAAA,MAAM,EACvB,KAAM,CAAA,KAAK,EACX,MAAO,EAAA;AAEV,IAAA,MAAM,OAAU,GAAA,GAAA,CACb,GAAI,CAAA,CAAA,CAAA,KAAK,KAAK,KAAM,CAAA,CAAA,CAAE,QAAQ,CAAC,CAC/B,CAAA,GAAA,CAAI,CAAK,CAAA,KAAAC,+BAAA,CAAkB,CAAC,CAAC,CAAA;AAEhC,IAAM,MAAA,UAAA,GAAaC,4BAAe,MAAM,CAAA;AAExC,IAAO,OAAA;AAAA,MACL,MAAQ,EAAA;AAAA,QACN,MAAM,UAAW,CAAA,IAAA;AAAA,QACjB,MAAM,UAAW,CAAA,IAAA;AAAA,QACjB,WAAW,UAAW,CAAA;AAAA,OACxB;AAAA,MACA;AAAA,KACF;AAAA;AAEJ;;;;"}
|
|
@@ -43,8 +43,8 @@ class CoverageUtils {
|
|
|
43
43
|
}
|
|
44
44
|
async processCoveragePayload(entity, req) {
|
|
45
45
|
const enforceScmFiles = entity.metadata.annotations?.["backstage.io/code-coverage"] === "scm-only" || false;
|
|
46
|
-
let sourceLocation =
|
|
47
|
-
let vcs =
|
|
46
|
+
let sourceLocation = undefined;
|
|
47
|
+
let vcs = undefined;
|
|
48
48
|
let scmFiles = [];
|
|
49
49
|
if (enforceScmFiles) {
|
|
50
50
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CoverageUtils.cjs.js","sources":["../../src/service/CoverageUtils.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Request } from 'express';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport {\n Entity,\n getEntitySourceLocation,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { ScmIntegration, ScmIntegrations } from '@backstage/integration';\nimport { AggregateCoverage, FileEntry, JsonCodeCoverage } from './types';\nimport { UrlReaderService } from '@backstage/backend-plugin-api';\n\nexport const calculatePercentage = (\n available: number,\n covered: number,\n): number => {\n if (available === 0) {\n return 0;\n }\n return parseFloat(((covered / available) * 100).toFixed(2));\n};\n\nexport const aggregateCoverage = (c: JsonCodeCoverage): AggregateCoverage => {\n let availableLine = 0;\n let coveredLine = 0;\n let availableBranch = 0;\n let coveredBranch = 0;\n c.files.forEach(f => {\n availableLine += Object.keys(f.lineHits).length;\n coveredLine += Object.values(f.lineHits).filter(l => l > 0).length;\n\n availableBranch += Object.keys(f.branchHits)\n .map(b => parseInt(b, 10))\n .map((b: number) => f.branchHits[b].available)\n .filter(Boolean)\n .reduce((acc, curr) => acc + curr, 0);\n coveredBranch += Object.keys(f.branchHits)\n .map(b => parseInt(b, 10))\n .map((b: number) => f.branchHits[b].covered)\n .filter(Boolean)\n .reduce((acc, curr) => acc + curr, 0);\n });\n\n return {\n timestamp: c.metadata.generationTime,\n branch: {\n available: availableBranch,\n covered: coveredBranch,\n missed: availableBranch - coveredBranch,\n percentage: calculatePercentage(availableBranch, coveredBranch),\n },\n line: {\n available: availableLine,\n covered: coveredLine,\n missed: availableLine - coveredLine,\n percentage: calculatePercentage(availableLine, coveredLine),\n },\n };\n};\n\nexport class CoverageUtils {\n constructor(\n readonly scm: Partial<ScmIntegrations>,\n readonly urlReader: Partial<UrlReaderService>,\n ) {}\n\n async processCoveragePayload(\n entity: Entity,\n req: Request,\n ): Promise<{\n sourceLocation?: string;\n vcs?: ScmIntegration;\n scmFiles: string[];\n body: {};\n }> {\n const enforceScmFiles =\n entity.metadata.annotations?.['backstage.io/code-coverage'] ===\n 'scm-only' || false;\n\n let sourceLocation: string | undefined = undefined;\n let vcs: ScmIntegration | undefined = undefined;\n let scmFiles: string[] = [];\n\n if (enforceScmFiles) {\n try {\n const sl = getEntitySourceLocation(entity);\n sourceLocation = sl.target;\n } catch (e: unknown) {\n // TODO: logging\n }\n\n if (!sourceLocation) {\n throw new InputError(\n `No \"backstage.io/source-location\" annotation on entity ${stringifyEntityRef(\n entity,\n )}`,\n );\n }\n\n vcs = this.scm.byUrl?.(sourceLocation);\n if (!vcs) {\n throw new InputError(`Unable to determine SCM from ${sourceLocation}`);\n }\n\n const scmTree = await this.urlReader.readTree?.(sourceLocation);\n if (!scmTree) {\n throw new NotFoundError(`Unable to read tree from ${sourceLocation}`);\n }\n scmFiles = (await scmTree.files()).map(f => f.path);\n }\n\n const body = this.validateRequestBody(req);\n if (Object.keys(body).length === 0) {\n throw new InputError('Unable to parse body');\n }\n\n return {\n sourceLocation,\n vcs,\n scmFiles,\n body,\n };\n }\n\n async buildCoverage(\n entity: Entity,\n sourceLocation: string | undefined,\n vcs: ScmIntegration | undefined,\n files: FileEntry[],\n ): Promise<JsonCodeCoverage> {\n return {\n metadata: {\n vcs: {\n type: vcs?.type || 'unknown',\n location: sourceLocation || 'unknown',\n },\n generationTime: Date.now(),\n },\n entity: {\n name: entity.metadata.name,\n namespace: entity.metadata.namespace || 'default',\n kind: entity.kind,\n },\n files,\n };\n }\n\n validateRequestBody(req: Request) {\n const contentType = req.headers['content-type'];\n if (!contentType) {\n throw new InputError('Content-Type header missing');\n // text/xml or text/plain is allowed\n } else if (!contentType.match(/^text\\/xml|plain($|;)/)) {\n throw new InputError(\n `Content-Type header \"${contentType}\" not supported, expected \"text/xml\" or \"text/plain\" possibly followed by a charset`,\n );\n }\n const body = req.body;\n if (!body) {\n throw new InputError('Missing request body');\n }\n return body;\n }\n}\n"],"names":["getEntitySourceLocation","InputError","stringifyEntityRef","NotFoundError"],"mappings":";;;;;AA0Ba,MAAA,mBAAA,GAAsB,CACjC,SAAA,EACA,OACW,KAAA;AACX,EAAA,IAAI,cAAc,CAAG,EAAA;AACnB,IAAO,OAAA,CAAA;AAAA;AAET,EAAA,OAAO,YAAa,OAAU,GAAA,SAAA,GAAa,GAAK,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA;AAC5D;AAEa,MAAA,iBAAA,GAAoB,CAAC,CAA2C,KAAA;AAC3E,EAAA,IAAI,aAAgB,GAAA,CAAA;AACpB,EAAA,IAAI,WAAc,GAAA,CAAA;AAClB,EAAA,IAAI,eAAkB,GAAA,CAAA;AACtB,EAAA,IAAI,aAAgB,GAAA,CAAA;AACpB,EAAE,CAAA,CAAA,KAAA,CAAM,QAAQ,CAAK,CAAA,KAAA;AACnB,IAAA,aAAA,IAAiB,MAAO,CAAA,IAAA,CAAK,CAAE,CAAA,QAAQ,CAAE,CAAA,MAAA;AACzC,IAAe,WAAA,IAAA,MAAA,CAAO,OAAO,CAAE,CAAA,QAAQ,EAAE,MAAO,CAAA,CAAA,CAAA,KAAK,CAAI,GAAA,CAAC,CAAE,CAAA,MAAA;AAE5D,IAAA,eAAA,IAAmB,MAAO,CAAA,IAAA,CAAK,CAAE,CAAA,UAAU,CACxC,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,QAAA,CAAS,CAAG,EAAA,EAAE,CAAC,CAAA,CACxB,IAAI,CAAC,CAAA,KAAc,CAAE,CAAA,UAAA,CAAW,CAAC,CAAA,CAAE,SAAS,CAAA,CAC5C,MAAO,CAAA,OAAO,CACd,CAAA,MAAA,CAAO,CAAC,GAAA,EAAK,IAAS,KAAA,GAAA,GAAM,MAAM,CAAC,CAAA;AACtC,IAAA,aAAA,IAAiB,MAAO,CAAA,IAAA,CAAK,CAAE,CAAA,UAAU,CACtC,CAAA,GAAA,CAAI,CAAK,CAAA,KAAA,QAAA,CAAS,CAAG,EAAA,EAAE,CAAC,CAAA,CACxB,IAAI,CAAC,CAAA,KAAc,CAAE,CAAA,UAAA,CAAW,CAAC,CAAA,CAAE,OAAO,CAAA,CAC1C,MAAO,CAAA,OAAO,CACd,CAAA,MAAA,CAAO,CAAC,GAAA,EAAK,IAAS,KAAA,GAAA,GAAM,MAAM,CAAC,CAAA;AAAA,GACvC,CAAA;AAED,EAAO,OAAA;AAAA,IACL,SAAA,EAAW,EAAE,QAAS,CAAA,cAAA;AAAA,IACtB,MAAQ,EAAA;AAAA,MACN,SAAW,EAAA,eAAA;AAAA,MACX,OAAS,EAAA,aAAA;AAAA,MACT,QAAQ,eAAkB,GAAA,aAAA;AAAA,MAC1B,UAAA,EAAY,mBAAoB,CAAA,eAAA,EAAiB,aAAa;AAAA,KAChE;AAAA,IACA,IAAM,EAAA;AAAA,MACJ,SAAW,EAAA,aAAA;AAAA,MACX,OAAS,EAAA,WAAA;AAAA,MACT,QAAQ,aAAgB,GAAA,WAAA;AAAA,MACxB,UAAA,EAAY,mBAAoB,CAAA,aAAA,EAAe,WAAW;AAAA;AAC5D,GACF;AACF;AAEO,MAAM,aAAc,CAAA;AAAA,EACzB,WAAA,CACW,KACA,SACT,EAAA;AAFS,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AACA,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AAAA;AACR,EAEH,MAAM,sBACJ,CAAA,MAAA,EACA,GAMC,EAAA;AACD,IAAA,MAAM,kBACJ,MAAO,CAAA,QAAA,CAAS,WAAc,GAAA,4BAA4B,MACxD,UAAc,IAAA,KAAA;AAElB,IAAA,IAAI,cAAqC,GAAA,
|
|
1
|
+
{"version":3,"file":"CoverageUtils.cjs.js","sources":["../../src/service/CoverageUtils.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Request } from 'express';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport {\n Entity,\n getEntitySourceLocation,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { ScmIntegration, ScmIntegrations } from '@backstage/integration';\nimport { AggregateCoverage, FileEntry, JsonCodeCoverage } from './types';\nimport { UrlReaderService } from '@backstage/backend-plugin-api';\n\nexport const calculatePercentage = (\n available: number,\n covered: number,\n): number => {\n if (available === 0) {\n return 0;\n }\n return parseFloat(((covered / available) * 100).toFixed(2));\n};\n\nexport const aggregateCoverage = (c: JsonCodeCoverage): AggregateCoverage => {\n let availableLine = 0;\n let coveredLine = 0;\n let availableBranch = 0;\n let coveredBranch = 0;\n c.files.forEach(f => {\n availableLine += Object.keys(f.lineHits).length;\n coveredLine += Object.values(f.lineHits).filter(l => l > 0).length;\n\n availableBranch += Object.keys(f.branchHits)\n .map(b => parseInt(b, 10))\n .map((b: number) => f.branchHits[b].available)\n .filter(Boolean)\n .reduce((acc, curr) => acc + curr, 0);\n coveredBranch += Object.keys(f.branchHits)\n .map(b => parseInt(b, 10))\n .map((b: number) => f.branchHits[b].covered)\n .filter(Boolean)\n .reduce((acc, curr) => acc + curr, 0);\n });\n\n return {\n timestamp: c.metadata.generationTime,\n branch: {\n available: availableBranch,\n covered: coveredBranch,\n missed: availableBranch - coveredBranch,\n percentage: calculatePercentage(availableBranch, coveredBranch),\n },\n line: {\n available: availableLine,\n covered: coveredLine,\n missed: availableLine - coveredLine,\n percentage: calculatePercentage(availableLine, coveredLine),\n },\n };\n};\n\nexport class CoverageUtils {\n constructor(\n readonly scm: Partial<ScmIntegrations>,\n readonly urlReader: Partial<UrlReaderService>,\n ) {}\n\n async processCoveragePayload(\n entity: Entity,\n req: Request,\n ): Promise<{\n sourceLocation?: string;\n vcs?: ScmIntegration;\n scmFiles: string[];\n body: {};\n }> {\n const enforceScmFiles =\n entity.metadata.annotations?.['backstage.io/code-coverage'] ===\n 'scm-only' || false;\n\n let sourceLocation: string | undefined = undefined;\n let vcs: ScmIntegration | undefined = undefined;\n let scmFiles: string[] = [];\n\n if (enforceScmFiles) {\n try {\n const sl = getEntitySourceLocation(entity);\n sourceLocation = sl.target;\n } catch (e: unknown) {\n // TODO: logging\n }\n\n if (!sourceLocation) {\n throw new InputError(\n `No \"backstage.io/source-location\" annotation on entity ${stringifyEntityRef(\n entity,\n )}`,\n );\n }\n\n vcs = this.scm.byUrl?.(sourceLocation);\n if (!vcs) {\n throw new InputError(`Unable to determine SCM from ${sourceLocation}`);\n }\n\n const scmTree = await this.urlReader.readTree?.(sourceLocation);\n if (!scmTree) {\n throw new NotFoundError(`Unable to read tree from ${sourceLocation}`);\n }\n scmFiles = (await scmTree.files()).map(f => f.path);\n }\n\n const body = this.validateRequestBody(req);\n if (Object.keys(body).length === 0) {\n throw new InputError('Unable to parse body');\n }\n\n return {\n sourceLocation,\n vcs,\n scmFiles,\n body,\n };\n }\n\n async buildCoverage(\n entity: Entity,\n sourceLocation: string | undefined,\n vcs: ScmIntegration | undefined,\n files: FileEntry[],\n ): Promise<JsonCodeCoverage> {\n return {\n metadata: {\n vcs: {\n type: vcs?.type || 'unknown',\n location: sourceLocation || 'unknown',\n },\n generationTime: Date.now(),\n },\n entity: {\n name: entity.metadata.name,\n namespace: entity.metadata.namespace || 'default',\n kind: entity.kind,\n },\n files,\n };\n }\n\n validateRequestBody(req: Request) {\n const contentType = req.headers['content-type'];\n if (!contentType) {\n throw new InputError('Content-Type header missing');\n // text/xml or text/plain is allowed\n } else if (!contentType.match(/^text\\/xml|plain($|;)/)) {\n throw new InputError(\n `Content-Type header \"${contentType}\" not supported, expected \"text/xml\" or \"text/plain\" possibly followed by a charset`,\n );\n }\n const body = req.body;\n if (!body) {\n throw new InputError('Missing request body');\n }\n return body;\n }\n}\n"],"names":["getEntitySourceLocation","InputError","stringifyEntityRef","NotFoundError"],"mappings":"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"}
|
|
@@ -5,7 +5,6 @@ var Router = require('express-promise-router');
|
|
|
5
5
|
var BodyParser = require('body-parser');
|
|
6
6
|
var bodyParserXml = require('body-parser-xml');
|
|
7
7
|
var catalogClient = require('@backstage/catalog-client');
|
|
8
|
-
var backendCommon = require('@backstage/backend-common');
|
|
9
8
|
var errors = require('@backstage/errors');
|
|
10
9
|
var integration = require('@backstage/integration');
|
|
11
10
|
var CodeCoverageDatabase = require('./CodeCoverageDatabase.cjs.js');
|
|
@@ -24,12 +23,11 @@ var BodyParser__default = /*#__PURE__*/_interopDefaultCompat(BodyParser);
|
|
|
24
23
|
var bodyParserXml__default = /*#__PURE__*/_interopDefaultCompat(bodyParserXml);
|
|
25
24
|
|
|
26
25
|
const makeRouter = async (options) => {
|
|
27
|
-
const { config, logger, discovery, database, urlReader } = options;
|
|
26
|
+
const { config, logger, discovery, database, urlReader, auth, httpAuth } = options;
|
|
28
27
|
const codeCoverageDatabase = await CodeCoverageDatabase.CodeCoverageDatabase.create(database);
|
|
29
28
|
const codecovUrl = await discovery.getExternalBaseUrl("code-coverage");
|
|
30
29
|
const catalogApi = options.catalogApi ?? new catalogClient.CatalogClient({ discoveryApi: discovery });
|
|
31
30
|
const scm = integration.ScmIntegrations.fromConfig(config);
|
|
32
|
-
const { auth, httpAuth } = backendCommon.createLegacyAuthAdapters(options);
|
|
33
31
|
const bodySizeLimit = config.getOptionalString("codeCoverage.bodySizeLimit") ?? "100kb";
|
|
34
32
|
bodyParserXml__default.default(BodyParser__default.default);
|
|
35
33
|
const router = Router__default.default();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport BodyParser from 'body-parser';\nimport bodyParserXml from 'body-parser-xml';\nimport { CatalogApi, CatalogClient } from '@backstage/catalog-client';\nimport { createLegacyAuthAdapters } from '@backstage/backend-common';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { CodeCoverageDatabase } from './CodeCoverageDatabase';\nimport { aggregateCoverage, CoverageUtils } from './CoverageUtils';\nimport { Cobertura, Converter, Jacoco, Lcov } from './converter';\nimport { getEntitySourceLocation } from '@backstage/catalog-model';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\n\n/**\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n *\n * Options for {@link createRouter}.\n *\n * @public\n */\nexport interface RouterOptions {\n config: Config;\n discovery: DiscoveryService;\n database: DatabaseService;\n urlReader: UrlReaderService;\n logger: LoggerService;\n catalogApi?: CatalogApi;\n auth?: AuthService;\n httpAuth?: HttpAuthService;\n}\n\nexport interface CodeCoverageApi {\n name: string;\n}\n\nexport const makeRouter = async (\n options: RouterOptions,\n): Promise<express.Router> => {\n const { config, logger, discovery, database, urlReader } = options;\n\n const codeCoverageDatabase = await CodeCoverageDatabase.create(database);\n const codecovUrl = await discovery.getExternalBaseUrl('code-coverage');\n const catalogApi =\n options.catalogApi ?? new CatalogClient({ discoveryApi: discovery });\n const scm = ScmIntegrations.fromConfig(config);\n const { auth, httpAuth } = createLegacyAuthAdapters(options);\n\n const bodySizeLimit =\n config.getOptionalString('codeCoverage.bodySizeLimit') ?? '100kb';\n\n bodyParserXml(BodyParser);\n const router = Router();\n router.use(\n BodyParser.xml({\n limit: bodySizeLimit,\n }),\n );\n router.use(\n BodyParser.text({\n limit: bodySizeLimit,\n }),\n );\n router.use(express.json());\n\n const utils = new CoverageUtils(scm, urlReader);\n\n router.get('/health', async (_req, res) => {\n res.status(200).json({ status: 'ok' });\n });\n\n /**\n * /report?entity=component:default/mycomponent\n */\n router.get('/report', async (req, res) => {\n const { entity } = req.query;\n const entityLookup = await catalogApi.getEntityByRef(\n entity as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entityLookup) {\n throw new NotFoundError(`No entity found matching ${entity}`);\n }\n const stored = await codeCoverageDatabase.getCodeCoverage(entity as string);\n\n const aggregate = aggregateCoverage(stored);\n\n res.status(200).json({\n ...stored,\n aggregate: {\n line: aggregate.line,\n branch: aggregate.branch,\n },\n });\n });\n\n /**\n * /history?entity=component:default/mycomponent\n */\n router.get('/history', async (req, res) => {\n const { entity } = req.query;\n const entityLookup = await catalogApi.getEntityByRef(\n entity as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entityLookup) {\n throw new NotFoundError(`No entity found matching ${entity}`);\n }\n const { limit } = req.query;\n const history = await codeCoverageDatabase.getHistory(\n entity as string,\n parseInt(limit?.toString() || '10', 10),\n );\n\n res.status(200).json(history);\n });\n\n /**\n * /file-content?entity=component:default/mycomponent&path=src/some-file.go\n */\n router.get('/file-content', async (req, res) => {\n const { entity, path } = req.query;\n const entityLookup = await catalogApi.getEntityByRef(\n entity as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entityLookup) {\n throw new NotFoundError(`No entity found matching ${entity}`);\n }\n\n if (!path) {\n throw new InputError('Need path query parameter');\n }\n\n const sourceLocation = getEntitySourceLocation(entityLookup);\n\n if (!sourceLocation) {\n throw new InputError(\n `No \"backstage.io/source-location\" annotation on entity ${entity}`,\n );\n }\n\n const vcs = scm.byUrl(sourceLocation.target);\n if (!vcs) {\n throw new InputError(`Unable to determine SCM from ${sourceLocation}`);\n }\n\n const scmTree = await urlReader.readTree(sourceLocation.target);\n const scmFile = (await scmTree.files()).find(f => f.path === path);\n if (!scmFile) {\n res.status(404).json({\n message: \"Couldn't find file in SCM\",\n file: path,\n scm: vcs.title,\n });\n return;\n }\n const content = await scmFile?.content();\n if (!content) {\n res.status(400).json({\n message: \"Couldn't process content of file in SCM\",\n file: path,\n scm: vcs.title,\n });\n return;\n }\n\n const data = content.toString();\n res.status(200).contentType('text/plain').send(data);\n });\n\n /**\n * /report?entity=component:default/mycomponent&coverageType=cobertura\n */\n router.post('/report', async (req, res) => {\n const { entity: entityRef, coverageType } = req.query;\n const entity = await catalogApi.getEntityByRef(\n entityRef as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entity) {\n throw new NotFoundError(`No entity found matching ${entityRef}`);\n }\n\n let converter: Converter;\n if (!coverageType) {\n throw new InputError('Need coverageType query parameter');\n } else if (coverageType === 'jacoco') {\n converter = new Jacoco(logger);\n } else if (coverageType === 'cobertura') {\n converter = new Cobertura(logger);\n } else if (coverageType === 'lcov') {\n converter = new Lcov(logger);\n } else {\n throw new InputError(`Unsupported coverage type '${coverageType}`);\n }\n\n const { sourceLocation, vcs, scmFiles, body } =\n await utils.processCoveragePayload(entity, req);\n\n const files = converter.convert(body, scmFiles);\n if (!files || files.length === 0) {\n throw new InputError(`Unable to parse body as ${coverageType}`);\n }\n\n const coverage = await utils.buildCoverage(\n entity,\n sourceLocation,\n vcs,\n files,\n );\n await codeCoverageDatabase.insertCodeCoverage(coverage);\n\n res.status(201).json({\n links: [\n {\n rel: 'coverage',\n href: `${codecovUrl}/report?entity=${entityRef}`,\n },\n ],\n });\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n\n router.use(middleware.error());\n return router;\n};\n\n/**\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n *\n * Creates a code-coverage plugin backend router.\n *\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const logger = options.logger;\n\n logger.info('Initializing Code Coverage backend');\n\n return makeRouter(options);\n}\n"],"names":["CodeCoverageDatabase","CatalogClient","ScmIntegrations","createLegacyAuthAdapters","bodyParserXml","BodyParser","Router","express","CoverageUtils","NotFoundError","aggregateCoverage","InputError","getEntitySourceLocation","Jacoco","Cobertura","Lcov","MiddlewareFactory"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport BodyParser from 'body-parser';\nimport bodyParserXml from 'body-parser-xml';\nimport { CatalogApi, CatalogClient } from '@backstage/catalog-client';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { CodeCoverageDatabase } from './CodeCoverageDatabase';\nimport { aggregateCoverage, CoverageUtils } from './CoverageUtils';\nimport { Cobertura, Converter, Jacoco, Lcov } from './converter';\nimport { getEntitySourceLocation } from '@backstage/catalog-model';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\n\n/** @internal */\nexport interface RouterOptions {\n config: Config;\n discovery: DiscoveryService;\n database: DatabaseService;\n urlReader: UrlReaderService;\n logger: LoggerService;\n auth: AuthService;\n httpAuth: HttpAuthService;\n catalogApi?: CatalogApi;\n}\n\n/** @internal */\nexport interface CodeCoverageApi {\n name: string;\n}\n\n/** @internal */\nexport const makeRouter = async (\n options: RouterOptions,\n): Promise<express.Router> => {\n const { config, logger, discovery, database, urlReader, auth, httpAuth } =\n options;\n\n const codeCoverageDatabase = await CodeCoverageDatabase.create(database);\n const codecovUrl = await discovery.getExternalBaseUrl('code-coverage');\n const catalogApi =\n options.catalogApi ?? new CatalogClient({ discoveryApi: discovery });\n const scm = ScmIntegrations.fromConfig(config);\n\n const bodySizeLimit =\n config.getOptionalString('codeCoverage.bodySizeLimit') ?? '100kb';\n\n bodyParserXml(BodyParser);\n const router = Router();\n router.use(\n BodyParser.xml({\n limit: bodySizeLimit,\n }),\n );\n router.use(\n BodyParser.text({\n limit: bodySizeLimit,\n }),\n );\n router.use(express.json());\n\n const utils = new CoverageUtils(scm, urlReader);\n\n router.get('/health', async (_req, res) => {\n res.status(200).json({ status: 'ok' });\n });\n\n /**\n * /report?entity=component:default/mycomponent\n */\n router.get('/report', async (req, res) => {\n const { entity } = req.query;\n const entityLookup = await catalogApi.getEntityByRef(\n entity as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entityLookup) {\n throw new NotFoundError(`No entity found matching ${entity}`);\n }\n const stored = await codeCoverageDatabase.getCodeCoverage(entity as string);\n\n const aggregate = aggregateCoverage(stored);\n\n res.status(200).json({\n ...stored,\n aggregate: {\n line: aggregate.line,\n branch: aggregate.branch,\n },\n });\n });\n\n /**\n * /history?entity=component:default/mycomponent\n */\n router.get('/history', async (req, res) => {\n const { entity } = req.query;\n const entityLookup = await catalogApi.getEntityByRef(\n entity as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entityLookup) {\n throw new NotFoundError(`No entity found matching ${entity}`);\n }\n const { limit } = req.query;\n const history = await codeCoverageDatabase.getHistory(\n entity as string,\n parseInt(limit?.toString() || '10', 10),\n );\n\n res.status(200).json(history);\n });\n\n /**\n * /file-content?entity=component:default/mycomponent&path=src/some-file.go\n */\n router.get('/file-content', async (req, res) => {\n const { entity, path } = req.query;\n const entityLookup = await catalogApi.getEntityByRef(\n entity as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entityLookup) {\n throw new NotFoundError(`No entity found matching ${entity}`);\n }\n\n if (!path) {\n throw new InputError('Need path query parameter');\n }\n\n const sourceLocation = getEntitySourceLocation(entityLookup);\n\n if (!sourceLocation) {\n throw new InputError(\n `No \"backstage.io/source-location\" annotation on entity ${entity}`,\n );\n }\n\n const vcs = scm.byUrl(sourceLocation.target);\n if (!vcs) {\n throw new InputError(`Unable to determine SCM from ${sourceLocation}`);\n }\n\n const scmTree = await urlReader.readTree(sourceLocation.target);\n const scmFile = (await scmTree.files()).find(f => f.path === path);\n if (!scmFile) {\n res.status(404).json({\n message: \"Couldn't find file in SCM\",\n file: path,\n scm: vcs.title,\n });\n return;\n }\n const content = await scmFile?.content();\n if (!content) {\n res.status(400).json({\n message: \"Couldn't process content of file in SCM\",\n file: path,\n scm: vcs.title,\n });\n return;\n }\n\n const data = content.toString();\n res.status(200).contentType('text/plain').send(data);\n });\n\n /**\n * /report?entity=component:default/mycomponent&coverageType=cobertura\n */\n router.post('/report', async (req, res) => {\n const { entity: entityRef, coverageType } = req.query;\n const entity = await catalogApi.getEntityByRef(\n entityRef as string,\n await auth.getPluginRequestToken({\n onBehalfOf: await httpAuth.credentials(req),\n targetPluginId: 'catalog',\n }),\n );\n if (!entity) {\n throw new NotFoundError(`No entity found matching ${entityRef}`);\n }\n\n let converter: Converter;\n if (!coverageType) {\n throw new InputError('Need coverageType query parameter');\n } else if (coverageType === 'jacoco') {\n converter = new Jacoco(logger);\n } else if (coverageType === 'cobertura') {\n converter = new Cobertura(logger);\n } else if (coverageType === 'lcov') {\n converter = new Lcov(logger);\n } else {\n throw new InputError(`Unsupported coverage type '${coverageType}`);\n }\n\n const { sourceLocation, vcs, scmFiles, body } =\n await utils.processCoveragePayload(entity, req);\n\n const files = converter.convert(body, scmFiles);\n if (!files || files.length === 0) {\n throw new InputError(`Unable to parse body as ${coverageType}`);\n }\n\n const coverage = await utils.buildCoverage(\n entity,\n sourceLocation,\n vcs,\n files,\n );\n await codeCoverageDatabase.insertCodeCoverage(coverage);\n\n res.status(201).json({\n links: [\n {\n rel: 'coverage',\n href: `${codecovUrl}/report?entity=${entityRef}`,\n },\n ],\n });\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n\n router.use(middleware.error());\n return router;\n};\n\n/** @internal */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const logger = options.logger;\n\n logger.info('Initializing Code Coverage backend');\n\n return makeRouter(options);\n}\n"],"names":["CodeCoverageDatabase","CatalogClient","ScmIntegrations","bodyParserXml","BodyParser","Router","express","CoverageUtils","NotFoundError","aggregateCoverage","InputError","getEntitySourceLocation","Jacoco","Cobertura","Lcov","MiddlewareFactory"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-code-coverage-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "A Backstage backend plugin that helps you keep track of your code coverage",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin",
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"test": "backstage-cli package test"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@backstage/backend-common": "^0.25.0",
|
|
42
41
|
"@backstage/backend-defaults": "^0.7.0",
|
|
43
42
|
"@backstage/backend-plugin-api": "^1.1.1",
|
|
44
43
|
"@backstage/catalog-client": "^1.9.1",
|
|
@@ -60,7 +59,7 @@
|
|
|
60
59
|
"@backstage/cli": "^0.29.6",
|
|
61
60
|
"@types/body-parser-xml": "^2.0.2",
|
|
62
61
|
"@types/supertest": "^6.0.0",
|
|
63
|
-
"@types/uuid": "^
|
|
62
|
+
"@types/uuid": "^10.0.0",
|
|
64
63
|
"supertest": "^7.0.0",
|
|
65
64
|
"xml2js": "^0.6.0"
|
|
66
65
|
},
|