@backstage-community/plugin-code-coverage-backend 0.2.32 → 0.2.33

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @backstage-community/plugin-code-coverage-backend
2
2
 
3
+ ## 0.2.33
4
+
5
+ ### Patch Changes
6
+
7
+ - 1a94274: version:bump to v1.29.1
8
+
3
9
  ## 0.2.32
4
10
 
5
11
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -60,8 +60,7 @@ class CoverageUtils {
60
60
  this.urlReader = urlReader;
61
61
  }
62
62
  async processCoveragePayload(entity, req) {
63
- var _a, _b, _c, _d, _e;
64
- const enforceScmFiles = ((_a = entity.metadata.annotations) == null ? void 0 : _a["backstage.io/code-coverage"]) === "scm-only" || false;
63
+ const enforceScmFiles = entity.metadata.annotations?.["backstage.io/code-coverage"] === "scm-only" || false;
65
64
  let sourceLocation = void 0;
66
65
  let vcs = void 0;
67
66
  let scmFiles = [];
@@ -78,11 +77,11 @@ class CoverageUtils {
78
77
  )}`
79
78
  );
80
79
  }
81
- vcs = (_c = (_b = this.scm).byUrl) == null ? void 0 : _c.call(_b, sourceLocation);
80
+ vcs = this.scm.byUrl?.(sourceLocation);
82
81
  if (!vcs) {
83
82
  throw new errors.InputError(`Unable to determine SCM from ${sourceLocation}`);
84
83
  }
85
- const scmTree = await ((_e = (_d = this.urlReader).readTree) == null ? void 0 : _e.call(_d, sourceLocation));
84
+ const scmTree = await this.urlReader.readTree?.(sourceLocation);
86
85
  if (!scmTree) {
87
86
  throw new errors.NotFoundError(`Unable to read tree from ${sourceLocation}`);
88
87
  }
@@ -103,7 +102,7 @@ class CoverageUtils {
103
102
  return {
104
103
  metadata: {
105
104
  vcs: {
106
- type: (vcs == null ? void 0 : vcs.type) || "unknown",
105
+ type: vcs?.type || "unknown",
107
106
  location: sourceLocation || "unknown"
108
107
  },
109
108
  generationTime: Date.now()
@@ -142,9 +141,8 @@ class CodeCoverageDatabase {
142
141
  this.db = db;
143
142
  }
144
143
  static async create(database) {
145
- var _a;
146
144
  const knex = await database.getClient();
147
- if (!((_a = database.migrations) == null ? void 0 : _a.skip)) {
145
+ if (!database.migrations?.skip) {
148
146
  await knex.migrate.latest({
149
147
  directory: migrationsDir
150
148
  });
@@ -205,9 +203,8 @@ class Cobertura {
205
203
  * @param scmFiles - list of files that are committed to SCM
206
204
  */
207
205
  convert(xml, scmFiles) {
208
- var _a, _b;
209
- const ppc = (_a = xml.coverage.packages) == null ? void 0 : _a.flatMap((p) => p.package).filter(Boolean).flatMap((p) => p.classes);
210
- const pc = (_b = xml.coverage.package) == null ? void 0 : _b.filter(Boolean).flatMap((p) => p.classes);
206
+ const ppc = xml.coverage.packages?.flatMap((p) => p.package).filter(Boolean).flatMap((p) => p.classes);
207
+ const pc = xml.coverage.package?.filter(Boolean).flatMap((p) => p.classes);
211
208
  const classes = [ppc, pc].flat().filter(Boolean).flatMap((c) => c.class).filter(Boolean);
212
209
  const jscov = [];
213
210
  classes.forEach((c) => {
@@ -264,9 +261,8 @@ class Cobertura {
264
261
  * @param clz - class coverage information
265
262
  */
266
263
  extractLines(clz) {
267
- var _a;
268
264
  const classLines = clz.lines.flatMap((l) => l.line);
269
- const methodLines = (_a = clz.methods) == null ? void 0 : _a.flatMap((m) => m.method).filter(Boolean).flatMap((m) => m.lines).filter(Boolean).flatMap((l) => l.line).filter(
265
+ const methodLines = clz.methods?.flatMap((m) => m.method).filter(Boolean).flatMap((m) => m.lines).filter(Boolean).flatMap((l) => l.line).filter(
270
266
  ({ $: methodLine }) => classLines.some(
271
267
  ({ $: classLine }) => methodLine.number === classLine.number
272
268
  ) === false
@@ -333,9 +329,8 @@ class Jacoco {
333
329
  return jscov;
334
330
  }
335
331
  extractLines(sourcefile) {
336
- var _a;
337
332
  const parsed = [];
338
- (_a = sourcefile.line) == null ? void 0 : _a.forEach((l) => {
333
+ sourcefile.line?.forEach((l) => {
339
334
  parsed.push({
340
335
  number: parseInt(l.$.nr, 10),
341
336
  missed_instructions: parseInt(l.$.mi, 10),
@@ -410,8 +405,7 @@ class Lcov {
410
405
  * @param value - line coverage information
411
406
  */
412
407
  processLineHit(currentFile, value) {
413
- if (!currentFile)
414
- return;
408
+ if (!currentFile) return;
415
409
  const [lineNumber, hits] = value.split(",");
416
410
  currentFile.lineHits[Number(lineNumber)] = Number(hits);
417
411
  }
@@ -422,8 +416,7 @@ class Lcov {
422
416
  * @param value - branch coverage information
423
417
  */
424
418
  processBranchHit(currentFile, value) {
425
- if (!currentFile)
426
- return;
419
+ if (!currentFile) return;
427
420
  const [lineNumber, , , hits] = value.split(",");
428
421
  const lineNumberNum = Number(lineNumber);
429
422
  const isHit = Number(hits) > 0;
@@ -440,14 +433,13 @@ class Lcov {
440
433
  }
441
434
 
442
435
  const makeRouter = async (options) => {
443
- var _a, _b;
444
436
  const { config, logger, discovery, database, urlReader } = options;
445
437
  const codeCoverageDatabase = await CodeCoverageDatabase.create(database);
446
438
  const codecovUrl = await discovery.getExternalBaseUrl("code-coverage");
447
- const catalogApi = (_a = options.catalogApi) != null ? _a : new catalogClient.CatalogClient({ discoveryApi: discovery });
439
+ const catalogApi = options.catalogApi ?? new catalogClient.CatalogClient({ discoveryApi: discovery });
448
440
  const scm = integration.ScmIntegrations.fromConfig(config);
449
441
  const { auth, httpAuth } = backendCommon.createLegacyAuthAdapters(options);
450
- const bodySizeLimit = (_b = config.getOptionalString("codeCoverage.bodySizeLimit")) != null ? _b : "100kb";
442
+ const bodySizeLimit = config.getOptionalString("codeCoverage.bodySizeLimit") ?? "100kb";
451
443
  bodyParserXml__default.default(BodyParser__default.default);
452
444
  const router = Router__default.default();
453
445
  router.use(
@@ -502,7 +494,7 @@ const makeRouter = async (options) => {
502
494
  const { limit } = req.query;
503
495
  const history = await codeCoverageDatabase.getHistory(
504
496
  entity,
505
- parseInt((limit == null ? void 0 : limit.toString()) || "10", 10)
497
+ parseInt(limit?.toString() || "10", 10)
506
498
  );
507
499
  res.status(200).json(history);
508
500
  });
@@ -541,7 +533,7 @@ const makeRouter = async (options) => {
541
533
  });
542
534
  return;
543
535
  }
544
- const content = await (scmFile == null ? void 0 : scmFile.content());
536
+ const content = await scmFile?.content();
545
537
  if (!content) {
546
538
  res.status(400).json({
547
539
  message: "Couldn't process content of file in SCM",
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/service/CoverageUtils.ts","../src/service/CodeCoverageDatabase.ts","../src/service/converter/cobertura.ts","../src/service/converter/jacoco.ts","../src/service/converter/lcov.ts","../src/service/router.ts","../src/plugin.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 { UrlReader } from '@backstage/backend-common';\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';\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<UrlReader>,\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","/*\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 PluginDatabaseManager,\n resolvePackagePath,\n} from '@backstage/backend-common';\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(\n database: PluginDatabaseManager,\n ): 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","/*\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 { BranchHit, FileEntry } from '../types';\nimport { CoberturaXML, InnerClass, LineHit } from './types';\nimport { Converter } from './Converter';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class Cobertura implements Converter {\n constructor(readonly logger: LoggerService) {\n this.logger = logger;\n }\n\n /**\n * convert cobertura into shared json coverage format\n *\n * @param xml - cobertura xml object\n * @param scmFiles - list of files that are committed to SCM\n */\n convert(xml: CoberturaXML, scmFiles: string[]): FileEntry[] {\n const ppc = xml.coverage.packages\n ?.flatMap(p => p.package)\n .filter(Boolean)\n .flatMap(p => p.classes);\n const pc = xml.coverage.package?.filter(Boolean).flatMap(p => p.classes);\n\n const classes = [ppc, pc]\n .flat()\n .filter(Boolean)\n .flatMap(c => c.class)\n .filter(Boolean);\n const jscov: Array<FileEntry> = [];\n\n classes.forEach(c => {\n const packageAndFilename = c.$.filename;\n const lines = this.extractLines(c);\n const lineHits: Record<number, number> = {};\n const branchHits: Record<number, BranchHit> = {};\n\n lines.forEach(l => {\n if (!lineHits[l.number]) {\n lineHits[l.number] = 0;\n }\n lineHits[l.number] += l.hits;\n if (l.branch && l['condition-coverage']) {\n const bh = this.parseBranch(l['condition-coverage']);\n if (bh) {\n branchHits[l.number] = bh;\n }\n }\n });\n\n const currentFile = scmFiles\n .map(f => f.trimEnd())\n .find(f => f.endsWith(packageAndFilename));\n this.logger.debug(`matched ${packageAndFilename} to ${currentFile}`);\n if (\n scmFiles.length === 0 ||\n (Object.keys(lineHits).length > 0 && currentFile)\n ) {\n jscov.push({\n filename: currentFile || packageAndFilename,\n branchHits: branchHits,\n lineHits: lineHits,\n });\n }\n });\n\n return jscov;\n }\n\n /**\n * Parses branch coverage information from condition-coverage\n *\n * @param condition - condition-coverage value from line coverage\n */\n private parseBranch(condition: string): BranchHit | null {\n const pattern = /[0-9\\.]+\\%\\s\\(([0-9]+)\\/([0-9]+)\\)/;\n const match = condition.match(pattern);\n if (!match) {\n return null;\n }\n const covered = parseInt(match[1], 10);\n const available = parseInt(match[2], 10);\n return {\n covered: covered,\n missed: available - covered,\n available: available,\n };\n }\n\n /**\n * Extract line hits from a class coverage entry\n *\n * @param clz - class coverage information\n */\n private extractLines(clz: InnerClass): Array<LineHit> {\n const classLines = clz.lines.flatMap(l => l.line);\n const methodLines = clz.methods\n ?.flatMap(m => m.method)\n .filter(Boolean)\n .flatMap(m => m.lines)\n .filter(Boolean)\n .flatMap(l => l.line)\n .filter(\n ({ $: methodLine }) =>\n classLines.some(\n ({ $: classLine }) => methodLine.number === classLine.number,\n ) === false,\n );\n const lines = [classLines, methodLines].flat().filter(Boolean);\n const lineHits = lines.map(l => {\n return {\n number: parseInt(l.$.number as unknown as string, 10),\n hits: parseInt(l.$.hits as unknown as string, 10),\n 'condition-coverage': l.$['condition-coverage'],\n branch: l.$.branch,\n };\n });\n return lineHits;\n }\n}\n","/*\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 { BranchHit, FileEntry } from '../types';\nimport { JacocoSourceFile, JacocoXML } from './types';\nimport { Converter } from './Converter';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype ParsedLine = {\n number: number;\n missed_instructions: number;\n covered_instructions: number;\n missed_branches: number;\n covered_branches: number;\n};\n\nexport class Jacoco implements Converter {\n constructor(readonly logger: LoggerService) {\n this.logger = logger;\n }\n\n /**\n * Converts jacoco into shared json coverage format\n *\n * @param xml - jacoco xml object\n * @param scmFiles - list of files that are committed to SCM\n */\n convert(xml: JacocoXML, scmFiles: Array<string>): Array<FileEntry> {\n const jscov: Array<FileEntry> = [];\n xml.report.package.forEach(r => {\n const packageName = r.$.name;\n r.sourcefile.forEach(sf => {\n const fileName = sf.$.name;\n const lines = this.extractLines(sf);\n const lineHits: Record<number, number> = {};\n const branchHits: Record<number, BranchHit> = {};\n lines.forEach(l => {\n if (!lineHits[l.number]) {\n lineHits[l.number] = 0;\n }\n lineHits[l.number] += l.covered_instructions;\n const ab = l.covered_branches + l.missed_branches;\n if (ab > 0) {\n branchHits[l.number] = {\n covered: l.covered_branches,\n missed: l.missed_branches,\n available: ab,\n };\n }\n });\n\n const packageAndFilename = `${packageName}/${fileName}`;\n const currentFile = scmFiles\n .map(f => f.trimEnd())\n .find(f => f.endsWith(packageAndFilename));\n this.logger.debug(`matched ${packageAndFilename} to ${currentFile}`);\n if (\n scmFiles.length === 0 ||\n (Object.keys(lineHits).length > 0 && currentFile)\n ) {\n jscov.push({\n filename: currentFile || packageAndFilename,\n branchHits: branchHits,\n lineHits: lineHits,\n });\n }\n });\n });\n\n return jscov;\n }\n\n private extractLines(sourcefile: JacocoSourceFile): ParsedLine[] {\n const parsed: ParsedLine[] = [];\n\n sourcefile.line?.forEach(l => {\n parsed.push({\n number: parseInt(l.$.nr, 10),\n missed_instructions: parseInt(l.$.mi, 10),\n covered_instructions: parseInt(l.$.ci, 10),\n missed_branches: parseInt(l.$.mb, 10),\n covered_branches: parseInt(l.$.cb, 10),\n });\n });\n\n return parsed;\n }\n}\n","/*\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 { FileEntry } from '../types';\nimport { Converter } from './Converter';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class Lcov implements Converter {\n constructor(readonly logger: LoggerService) {\n this.logger = logger;\n }\n\n /**\n * convert lcov into shared json coverage format\n *\n * @param raw - raw lcov report\n * @param scmFiles - list of files that are committed to SCM\n */\n convert(raw: string, scmFiles: string[]): FileEntry[] {\n const lines = raw.split(/\\r?\\n/);\n const jscov: Array<FileEntry> = [];\n let currentFile: FileEntry | null = null;\n\n lines.forEach(line => {\n const [section, value] = line.split(':');\n\n switch (section) {\n // If the line starts with SF, it's a new file\n case 'SF':\n currentFile = this.processNewFile(value, scmFiles);\n break;\n // If the line starts with DA, it's a line hit\n case 'DA':\n this.processLineHit(currentFile, value);\n break;\n // If the line starts with BRDA, it's a branch line\n case 'BRDA':\n this.processBranchHit(currentFile, value);\n break;\n // If the line starts with end_of_record, it's the end of current file\n case 'end_of_record':\n if (currentFile) {\n jscov.push(currentFile);\n currentFile = null;\n }\n break;\n default:\n break;\n }\n });\n\n return jscov;\n }\n\n /**\n * Parses a new file entry\n *\n * @param file - file name from coverage report\n * @param scmFiles - list of files that are committed to SCM\n */\n private processNewFile(file: string, scmFiles: string[]): FileEntry | null {\n const filename = scmFiles.map(f => f.trimEnd()).find(f => file.endsWith(f));\n\n this.logger.debug(`matched ${file} to ${filename}`);\n\n if (scmFiles.length === 0 || filename) {\n return {\n filename: filename || file,\n lineHits: {},\n branchHits: {},\n };\n }\n\n return null;\n }\n\n /**\n * Parses line coverage information\n *\n * @param currentFile - current file entry\n * @param value - line coverage information\n */\n private processLineHit(currentFile: FileEntry | null, value: string): void {\n if (!currentFile) return;\n\n const [lineNumber, hits] = value.split(',');\n currentFile.lineHits[Number(lineNumber)] = Number(hits);\n }\n\n /**\n * Parses branch coverage information\n *\n * @param currentFile - current file entry\n * @param value - branch coverage information\n */\n private processBranchHit(currentFile: FileEntry | null, value: string): void {\n if (!currentFile) return;\n\n const [lineNumber, , , hits] = value.split(',');\n const lineNumberNum = Number(lineNumber);\n const isHit = Number(hits) > 0;\n const branch = currentFile.branchHits[lineNumberNum] || {\n covered: 0,\n available: 0,\n missed: 0,\n };\n\n branch.available++;\n branch.covered += isHit ? 1 : 0;\n branch.missed += isHit ? 0 : 1;\n\n currentFile.branchHits[lineNumberNum] = branch;\n }\n}\n","/*\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 {\n createLegacyAuthAdapters,\n errorHandler,\n PluginDatabaseManager,\n PluginEndpointDiscovery,\n UrlReader,\n} 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 HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Options for {@link createRouter}.\n *\n * @public\n */\nexport interface RouterOptions {\n config: Config;\n discovery: PluginEndpointDiscovery;\n database: PluginDatabaseManager;\n urlReader: UrlReader;\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 router.use(errorHandler());\n return router;\n};\n\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","/*\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: 'codeCoverage',\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":["getEntitySourceLocation","InputError","stringifyEntityRef","NotFoundError","resolvePackagePath","uuid","parseEntityRef","CatalogClient","ScmIntegrations","createLegacyAuthAdapters","bodyParserXml","BodyParser","Router","express","errorHandler","createBackendPlugin","coreServices"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/service/CoverageUtils.ts","../src/service/CodeCoverageDatabase.ts","../src/service/converter/cobertura.ts","../src/service/converter/jacoco.ts","../src/service/converter/lcov.ts","../src/service/router.ts","../src/plugin.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 { UrlReader } from '@backstage/backend-common';\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';\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<UrlReader>,\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","/*\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 PluginDatabaseManager,\n resolvePackagePath,\n} from '@backstage/backend-common';\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(\n database: PluginDatabaseManager,\n ): 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","/*\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 { BranchHit, FileEntry } from '../types';\nimport { CoberturaXML, InnerClass, LineHit } from './types';\nimport { Converter } from './Converter';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class Cobertura implements Converter {\n constructor(readonly logger: LoggerService) {\n this.logger = logger;\n }\n\n /**\n * convert cobertura into shared json coverage format\n *\n * @param xml - cobertura xml object\n * @param scmFiles - list of files that are committed to SCM\n */\n convert(xml: CoberturaXML, scmFiles: string[]): FileEntry[] {\n const ppc = xml.coverage.packages\n ?.flatMap(p => p.package)\n .filter(Boolean)\n .flatMap(p => p.classes);\n const pc = xml.coverage.package?.filter(Boolean).flatMap(p => p.classes);\n\n const classes = [ppc, pc]\n .flat()\n .filter(Boolean)\n .flatMap(c => c.class)\n .filter(Boolean);\n const jscov: Array<FileEntry> = [];\n\n classes.forEach(c => {\n const packageAndFilename = c.$.filename;\n const lines = this.extractLines(c);\n const lineHits: Record<number, number> = {};\n const branchHits: Record<number, BranchHit> = {};\n\n lines.forEach(l => {\n if (!lineHits[l.number]) {\n lineHits[l.number] = 0;\n }\n lineHits[l.number] += l.hits;\n if (l.branch && l['condition-coverage']) {\n const bh = this.parseBranch(l['condition-coverage']);\n if (bh) {\n branchHits[l.number] = bh;\n }\n }\n });\n\n const currentFile = scmFiles\n .map(f => f.trimEnd())\n .find(f => f.endsWith(packageAndFilename));\n this.logger.debug(`matched ${packageAndFilename} to ${currentFile}`);\n if (\n scmFiles.length === 0 ||\n (Object.keys(lineHits).length > 0 && currentFile)\n ) {\n jscov.push({\n filename: currentFile || packageAndFilename,\n branchHits: branchHits,\n lineHits: lineHits,\n });\n }\n });\n\n return jscov;\n }\n\n /**\n * Parses branch coverage information from condition-coverage\n *\n * @param condition - condition-coverage value from line coverage\n */\n private parseBranch(condition: string): BranchHit | null {\n const pattern = /[0-9\\.]+\\%\\s\\(([0-9]+)\\/([0-9]+)\\)/;\n const match = condition.match(pattern);\n if (!match) {\n return null;\n }\n const covered = parseInt(match[1], 10);\n const available = parseInt(match[2], 10);\n return {\n covered: covered,\n missed: available - covered,\n available: available,\n };\n }\n\n /**\n * Extract line hits from a class coverage entry\n *\n * @param clz - class coverage information\n */\n private extractLines(clz: InnerClass): Array<LineHit> {\n const classLines = clz.lines.flatMap(l => l.line);\n const methodLines = clz.methods\n ?.flatMap(m => m.method)\n .filter(Boolean)\n .flatMap(m => m.lines)\n .filter(Boolean)\n .flatMap(l => l.line)\n .filter(\n ({ $: methodLine }) =>\n classLines.some(\n ({ $: classLine }) => methodLine.number === classLine.number,\n ) === false,\n );\n const lines = [classLines, methodLines].flat().filter(Boolean);\n const lineHits = lines.map(l => {\n return {\n number: parseInt(l.$.number as unknown as string, 10),\n hits: parseInt(l.$.hits as unknown as string, 10),\n 'condition-coverage': l.$['condition-coverage'],\n branch: l.$.branch,\n };\n });\n return lineHits;\n }\n}\n","/*\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 { BranchHit, FileEntry } from '../types';\nimport { JacocoSourceFile, JacocoXML } from './types';\nimport { Converter } from './Converter';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype ParsedLine = {\n number: number;\n missed_instructions: number;\n covered_instructions: number;\n missed_branches: number;\n covered_branches: number;\n};\n\nexport class Jacoco implements Converter {\n constructor(readonly logger: LoggerService) {\n this.logger = logger;\n }\n\n /**\n * Converts jacoco into shared json coverage format\n *\n * @param xml - jacoco xml object\n * @param scmFiles - list of files that are committed to SCM\n */\n convert(xml: JacocoXML, scmFiles: Array<string>): Array<FileEntry> {\n const jscov: Array<FileEntry> = [];\n xml.report.package.forEach(r => {\n const packageName = r.$.name;\n r.sourcefile.forEach(sf => {\n const fileName = sf.$.name;\n const lines = this.extractLines(sf);\n const lineHits: Record<number, number> = {};\n const branchHits: Record<number, BranchHit> = {};\n lines.forEach(l => {\n if (!lineHits[l.number]) {\n lineHits[l.number] = 0;\n }\n lineHits[l.number] += l.covered_instructions;\n const ab = l.covered_branches + l.missed_branches;\n if (ab > 0) {\n branchHits[l.number] = {\n covered: l.covered_branches,\n missed: l.missed_branches,\n available: ab,\n };\n }\n });\n\n const packageAndFilename = `${packageName}/${fileName}`;\n const currentFile = scmFiles\n .map(f => f.trimEnd())\n .find(f => f.endsWith(packageAndFilename));\n this.logger.debug(`matched ${packageAndFilename} to ${currentFile}`);\n if (\n scmFiles.length === 0 ||\n (Object.keys(lineHits).length > 0 && currentFile)\n ) {\n jscov.push({\n filename: currentFile || packageAndFilename,\n branchHits: branchHits,\n lineHits: lineHits,\n });\n }\n });\n });\n\n return jscov;\n }\n\n private extractLines(sourcefile: JacocoSourceFile): ParsedLine[] {\n const parsed: ParsedLine[] = [];\n\n sourcefile.line?.forEach(l => {\n parsed.push({\n number: parseInt(l.$.nr, 10),\n missed_instructions: parseInt(l.$.mi, 10),\n covered_instructions: parseInt(l.$.ci, 10),\n missed_branches: parseInt(l.$.mb, 10),\n covered_branches: parseInt(l.$.cb, 10),\n });\n });\n\n return parsed;\n }\n}\n","/*\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 { FileEntry } from '../types';\nimport { Converter } from './Converter';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\nexport class Lcov implements Converter {\n constructor(readonly logger: LoggerService) {\n this.logger = logger;\n }\n\n /**\n * convert lcov into shared json coverage format\n *\n * @param raw - raw lcov report\n * @param scmFiles - list of files that are committed to SCM\n */\n convert(raw: string, scmFiles: string[]): FileEntry[] {\n const lines = raw.split(/\\r?\\n/);\n const jscov: Array<FileEntry> = [];\n let currentFile: FileEntry | null = null;\n\n lines.forEach(line => {\n const [section, value] = line.split(':');\n\n switch (section) {\n // If the line starts with SF, it's a new file\n case 'SF':\n currentFile = this.processNewFile(value, scmFiles);\n break;\n // If the line starts with DA, it's a line hit\n case 'DA':\n this.processLineHit(currentFile, value);\n break;\n // If the line starts with BRDA, it's a branch line\n case 'BRDA':\n this.processBranchHit(currentFile, value);\n break;\n // If the line starts with end_of_record, it's the end of current file\n case 'end_of_record':\n if (currentFile) {\n jscov.push(currentFile);\n currentFile = null;\n }\n break;\n default:\n break;\n }\n });\n\n return jscov;\n }\n\n /**\n * Parses a new file entry\n *\n * @param file - file name from coverage report\n * @param scmFiles - list of files that are committed to SCM\n */\n private processNewFile(file: string, scmFiles: string[]): FileEntry | null {\n const filename = scmFiles.map(f => f.trimEnd()).find(f => file.endsWith(f));\n\n this.logger.debug(`matched ${file} to ${filename}`);\n\n if (scmFiles.length === 0 || filename) {\n return {\n filename: filename || file,\n lineHits: {},\n branchHits: {},\n };\n }\n\n return null;\n }\n\n /**\n * Parses line coverage information\n *\n * @param currentFile - current file entry\n * @param value - line coverage information\n */\n private processLineHit(currentFile: FileEntry | null, value: string): void {\n if (!currentFile) return;\n\n const [lineNumber, hits] = value.split(',');\n currentFile.lineHits[Number(lineNumber)] = Number(hits);\n }\n\n /**\n * Parses branch coverage information\n *\n * @param currentFile - current file entry\n * @param value - branch coverage information\n */\n private processBranchHit(currentFile: FileEntry | null, value: string): void {\n if (!currentFile) return;\n\n const [lineNumber, , , hits] = value.split(',');\n const lineNumberNum = Number(lineNumber);\n const isHit = Number(hits) > 0;\n const branch = currentFile.branchHits[lineNumberNum] || {\n covered: 0,\n available: 0,\n missed: 0,\n };\n\n branch.available++;\n branch.covered += isHit ? 1 : 0;\n branch.missed += isHit ? 0 : 1;\n\n currentFile.branchHits[lineNumberNum] = branch;\n }\n}\n","/*\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 {\n createLegacyAuthAdapters,\n errorHandler,\n PluginDatabaseManager,\n PluginEndpointDiscovery,\n UrlReader,\n} 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 HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Options for {@link createRouter}.\n *\n * @public\n */\nexport interface RouterOptions {\n config: Config;\n discovery: PluginEndpointDiscovery;\n database: PluginDatabaseManager;\n urlReader: UrlReader;\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 router.use(errorHandler());\n return router;\n};\n\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","/*\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: 'codeCoverage',\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":["getEntitySourceLocation","InputError","stringifyEntityRef","NotFoundError","resolvePackagePath","uuid","parseEntityRef","CatalogClient","ScmIntegrations","createLegacyAuthAdapters","bodyParserXml","BodyParser","Router","express","errorHandler","createBackendPlugin","coreServices"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -32,6 +32,6 @@ declare function createRouter(options: RouterOptions): Promise<express.Router>;
32
32
  *
33
33
  * @public
34
34
  */
35
- declare const codeCoveragePlugin: () => _backstage_backend_plugin_api.BackendFeature;
35
+ declare const codeCoveragePlugin: _backstage_backend_plugin_api.BackendFeatureCompat;
36
36
 
37
37
  export { type RouterOptions, createRouter, codeCoveragePlugin as default };
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@backstage-community/plugin-code-coverage-backend",
3
- "version": "0.2.32",
3
+ "version": "0.2.33",
4
4
  "description": "A Backstage backend plugin that helps you keep track of your code coverage",
5
5
  "backstage": {
6
- "role": "backend-plugin"
6
+ "role": "backend-plugin",
7
+ "pluginId": "code-coverage",
8
+ "pluginPackages": [
9
+ "@backstage-community/plugin-code-coverage",
10
+ "@backstage-community/plugin-code-coverage-backend"
11
+ ]
7
12
  },
8
13
  "publishConfig": {
9
14
  "access": "public",
@@ -33,13 +38,13 @@
33
38
  "test": "backstage-cli package test"
34
39
  },
35
40
  "dependencies": {
36
- "@backstage/backend-common": "^0.21.7",
37
- "@backstage/backend-plugin-api": "^0.6.17",
38
- "@backstage/catalog-client": "^1.6.4",
39
- "@backstage/catalog-model": "^1.4.5",
41
+ "@backstage/backend-common": "^0.23.3",
42
+ "@backstage/backend-plugin-api": "^0.7.0",
43
+ "@backstage/catalog-client": "^1.6.5",
44
+ "@backstage/catalog-model": "^1.5.0",
40
45
  "@backstage/config": "^1.2.0",
41
46
  "@backstage/errors": "^1.2.4",
42
- "@backstage/integration": "^1.10.0",
47
+ "@backstage/integration": "^1.13.0",
43
48
  "@types/express": "^4.17.6",
44
49
  "body-parser": "^1.20.0",
45
50
  "body-parser-xml": "^2.0.5",
@@ -50,8 +55,8 @@
50
55
  "yn": "^4.0.0"
51
56
  },
52
57
  "devDependencies": {
53
- "@backstage/backend-test-utils": "^0.3.7",
54
- "@backstage/cli": "^0.26.3",
58
+ "@backstage/backend-test-utils": "^0.4.4",
59
+ "@backstage/cli": "^0.26.11",
55
60
  "@types/body-parser-xml": "^2.0.2",
56
61
  "@types/supertest": "^2.0.8",
57
62
  "@types/uuid": "^9.0.0",