apex-code-coverage-transformer 1.7.0 → 1.7.2-beta.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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![NPM](https://img.shields.io/npm/v/apex-code-coverage-transformer.svg?label=apex-code-coverage-transformer)](https://www.npmjs.com/package/apex-code-coverage-transformer) [![Downloads/week](https://img.shields.io/npm/dw/apex-code-coverage-transformer.svg)](https://npmjs.org/package/apex-code-coverage-transformer) [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/LICENSE.md)
4
4
 
5
- The `apex-code-coverage-transformer` is a Salesforce CLI plugin to transform the Apex Code Coverage JSON files created during deployments into the Generic Test Coverage Format (XML). This format is accepted by static code analysis tools like SonarQube.
5
+ The `apex-code-coverage-transformer` is a Salesforce CLI plugin to transform the Apex Code Coverage JSON files created during deployments and test runs into the Generic Test Coverage Format (XML). This format is accepted by static code analysis tools like SonarQube.
6
6
 
7
7
  This plugin requires [git](https://git-scm.com/downloads) to be installed and that it can be called using the command `git`.
8
8
 
@@ -10,17 +10,21 @@ This plugin supports code coverage metrics created for Apex Classes and Apex Tri
10
10
 
11
11
  This plugin is intended for users who deploy their Apex codebase from a git-based repository and use SonarQube for code quality. This plugin will work if you run local tests or run all tests in an org, including tests that originate from installed managed and unlocked packages. SonarQube relies on file-paths to map code coverage to the files in their file explorer interface. Since files from managed and unlocked packages aren't retrieved into git-based Salesforce repositories, these files cannot be included in your SonarQube scans. If your Apex code coverage JSON output includes managed/unlocked package files, they will not be added to the coverage XML created by this plugin. A warning will be printed for each file not found in a package directory in your git repository. See [Errors and Warnings](https://github.com/mcarvin8/apex-code-coverage-transformer?tab=readme-ov-file#errors-and-warnings) for more information.
12
12
 
13
- To create the code coverage JSON during a Salesforce CLI deployment/validation, append `--coverage-formatters json --results-dir coverage` to the `sf project deploy` command:
13
+ To create the code coverage JSON during a Salesforce CLI deployment/validation, append `--coverage-formatters json --results-dir coverage` to the `sf project deploy` command. This will create a coverage JSON in this relative path - `coverage/coverage/coverage.json`.
14
14
 
15
15
  ```
16
16
  sf project deploy [start/validate] -x manifest/package.xml -l RunSpecifiedTests -t {testclasses} --verbose --coverage-formatters json --results-dir coverage
17
17
  ```
18
18
 
19
- This will create a coverage JSON in this relative path - `coverage/coverage/coverage.json`
19
+ To create the code coverage JSON when running tests directly in the org, append `-c -r json` to the `sf apex run test` command.
20
20
 
21
- This JSON isn't accepted by SonarQube automatically for git-based Salesforce repositories and needs to be converted using this plugin.
21
+ ```
22
+ sf apex run test -c -r json
23
+ ```
24
+
25
+ The code coverage JSONs created by the Salesforce CLI aren't accepted by SonarQube automatically for git-based Salesforce repositories and needs to be converted using this plugin.
22
26
 
23
- **Disclaimer**: Due to existing bugs with how the Salesforce CLI reports covered lines (see [5511](https://github.com/forcedotcom/salesforcedx-vscode/issues/5511) and [1568](https://github.com/forcedotcom/cli/issues/1568)), to add support for covered lines in this plugin, I had to add a function to re-number out-of-range covered lines the CLI may report (ex: line 100 in a 98-line Apex Class is reported back as covered by the Salesforce CLI deploy command). Salesforce's coverage result may also include extra lines as covered (ex: 120 lines are included in the coverage report for a 100 line file), so the coverage percentage may vary based on how many lines the API returns in the coverage report. Once Salesforce fixes the API to correctly return covered lines in the deploy command, this function will be removed.
27
+ **Disclaimer**: Due to existing bugs with how the Salesforce CLI reports covered lines during deployments (see [5511](https://github.com/forcedotcom/salesforcedx-vscode/issues/5511) and [1568](https://github.com/forcedotcom/cli/issues/1568)), to add support for covered lines in this plugin for deployment coverage files, I had to add a function to re-number out-of-range covered lines the CLI may report (ex: line 100 in a 98-line Apex Class is reported back as covered by the Salesforce CLI deploy command). Salesforce's coverage result may also include extra lines as covered (ex: 120 lines are included in the coverage report for a 100 line file), so the coverage percentage may vary based on how many lines the API returns in the coverage report. Once Salesforce fixes the API to correctly return covered lines in the deploy command, this function will be removed.
24
28
 
25
29
  ## Install
26
30
 
@@ -40,11 +44,12 @@ This command needs to be ran somewhere inside your Salesforce DX git repository,
40
44
 
41
45
  ```
42
46
  USAGE
43
- $ sf apex-code-coverage transformer transform -j <value> -x <value> [--json]
47
+ $ sf apex-code-coverage transformer transform -j <value> -x <value> -c <value> [--json]
44
48
 
45
49
  FLAGS
46
50
  -j, --coverage-json=<value> Path to the code coverage JSON file created by the Salesforce CLI deployment command.
47
- -x, --xml=<value> [default: coverage.xml] Path to code coverage XML file that will be created by this plugin.
51
+ -x, --xml=<value> [default: "coverage.xml"] Path to code coverage XML file that will be created by this plugin.
52
+ -c, --command=<value> [default: "deploy"] The type of Salesforce CLI command you are running. Valid options: "deploy" or "test".
48
53
 
49
54
  GLOBAL FLAGS
50
55
  --json Format output as json.
@@ -53,7 +58,7 @@ DESCRIPTION
53
58
  This plugin will convert the code coverage JSON file created by the Salesforce CLI during Apex deployments into an XML accepted by tools like SonarQube.
54
59
 
55
60
  EXAMPLES
56
- $ sf apex-code-coverage transformer transform -j "coverage.json" -x "coverage.xml"
61
+ $ sf apex-code-coverage transformer transform -j "coverage.json" -x "coverage.xml" -c "deploy"
57
62
  ```
58
63
 
59
64
  ## Hook
@@ -9,6 +9,7 @@ export default class TransformerTransform extends SfCommand<TransformerTransform
9
9
  static readonly flags: {
10
10
  'coverage-json': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
11
  xml: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
12
+ command: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
12
13
  };
13
14
  run(): Promise<TransformerTransformResult>;
14
15
  }
@@ -3,7 +3,8 @@ import { resolve } from 'node:path';
3
3
  import { writeFile, readFile } from 'node:fs/promises';
4
4
  import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
5
5
  import { Messages } from '@salesforce/core';
6
- import { convertToGenericCoverageReport } from '../../../helpers/convertToGenericCoverageReport.js';
6
+ import { transformDeployCoverageReport } from '../../../helpers/transformDeployCoverageReport.js';
7
+ import { transformTestCoverageReport } from '../../../helpers/transformTestCoverageReport.js';
7
8
  Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
8
9
  const messages = Messages.loadMessages('apex-code-coverage-transformer', 'transformer.transform');
9
10
  export default class TransformerTransform extends SfCommand {
@@ -24,14 +25,37 @@ export default class TransformerTransform extends SfCommand {
24
25
  exists: false,
25
26
  default: 'coverage.xml',
26
27
  }),
28
+ command: Flags.string({
29
+ summary: messages.getMessage('flags.command.summary'),
30
+ char: 'c',
31
+ required: true,
32
+ default: 'deploy',
33
+ options: ['deploy', 'test'],
34
+ }),
27
35
  };
28
36
  async run() {
29
37
  const { flags } = await this.parse(TransformerTransform);
30
38
  const jsonFilePath = resolve(flags['coverage-json']);
31
39
  const xmlFilePath = resolve(flags['xml']);
40
+ const commandType = flags['command'];
32
41
  const jsonData = await readFile(jsonFilePath, 'utf-8');
33
- const coverageData = JSON.parse(jsonData);
34
- const { xml: xmlData, warnings, filesProcessed } = await convertToGenericCoverageReport(coverageData);
42
+ let xmlData;
43
+ let warnings = [];
44
+ let filesProcessed = 0;
45
+ if (commandType === 'test') {
46
+ const coverageData = JSON.parse(jsonData);
47
+ const result = await transformTestCoverageReport(coverageData);
48
+ xmlData = result.xml;
49
+ warnings = result.warnings;
50
+ filesProcessed = result.filesProcessed;
51
+ }
52
+ else {
53
+ const coverageData = JSON.parse(jsonData);
54
+ const result = await transformDeployCoverageReport(coverageData);
55
+ xmlData = result.xml;
56
+ warnings = result.warnings;
57
+ filesProcessed = result.filesProcessed;
58
+ }
35
59
  // Print warnings if any
36
60
  if (warnings.length > 0) {
37
61
  warnings.forEach((warning) => {
@@ -1 +1 @@
1
- {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../../src/commands/apex-code-coverage/transformer/transform.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,8BAA8B,EAAE,MAAM,oDAAoD,CAAC;AAEpG,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,gCAAgC,EAAE,uBAAuB,CAAC,CAAC;AAMlG,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,SAAqC;IAC9E,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,MAAM,CAAU,KAAK,GAAG;QAC7B,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC;YAC1B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,6BAA6B,CAAC;YAC3D,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;SACb,CAAC;QACF,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC;YACd,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,mBAAmB,CAAC;YACjD,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,cAAc;SACxB,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACzD,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAiB,CAAC;QAC1D,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,8BAA8B,CAAC,YAAY,CAAC,CAAC;QAEtG,wBAAwB;QACxB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC;QAC9E,CAAC;QAED,MAAM,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,oCAAoC,WAAW,EAAE,CAAC,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC/B,CAAC"}
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../../src/commands/apex-code-coverage/transformer/transform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { DeployCoverageData } from './types.js';
2
+ export declare function transformDeployCoverageReport(data: DeployCoverageData): Promise<{
3
+ xml: string;
4
+ warnings: string[];
5
+ filesProcessed: number;
6
+ }>;
@@ -5,7 +5,7 @@ import { getPackageDirectories } from './getPackageDirectories.js';
5
5
  import { findFilePath } from './findFilePath.js';
6
6
  import { setCoveredLines } from './setCoveredLines.js';
7
7
  import { normalizePathToUnix } from './normalizePathToUnix.js';
8
- export async function convertToGenericCoverageReport(data) {
8
+ export async function transformDeployCoverageReport(data) {
9
9
  const coverageObj = { coverage: { '@version': '1', file: [] } };
10
10
  const warnings = [];
11
11
  let filesProcessed = 0;
@@ -14,7 +14,7 @@ export async function convertToGenericCoverageReport(data) {
14
14
  if (!Object.hasOwn(data, fileName))
15
15
  continue;
16
16
  const fileInfo = data[fileName];
17
- const formattedFileName = fileName.replace('no-map/', '');
17
+ const formattedFileName = fileName.replace(/no-map[\\/]+/, '');
18
18
  const relativeFilePath = await findFilePath(formattedFileName, packageDirectories, repoRoot);
19
19
  if (relativeFilePath === undefined) {
20
20
  warnings.push(`The file name ${formattedFileName} was not found in any package directory.`);
@@ -41,4 +41,4 @@ export async function convertToGenericCoverageReport(data) {
41
41
  const xml = create(coverageObj).end({ prettyPrint: true, indent: ' ' });
42
42
  return { xml, warnings, filesProcessed };
43
43
  }
44
- //# sourceMappingURL=convertToGenericCoverageReport.js.map
44
+ //# sourceMappingURL=transformDeployCoverageReport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformDeployCoverageReport.js","sourceRoot":"","sources":["../../src/helpers/transformDeployCoverageReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,qCAAqC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,IAAwB;IAExB,MAAM,WAAW,GAAmB,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC;IAChF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAW,CAAC,CAAC;IAC/B,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,EAAE,CAAC;IAEvE,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC;YAAE,SAAS;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAC/D,MAAM,gBAAgB,GAAG,MAAM,YAAY,CAAC,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QAC7F,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,iBAAiB,0CAA0C,CAAC,CAAC;YAC5F,SAAS;QACX,CAAC;QACD,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;aAC3C,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;aACpD,GAAG,CAAC,MAAM,CAAC,CAAC;QACf,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;aACzC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;aACpD,GAAG,CAAC,MAAM,CAAC,CAAC;QAEf,MAAM,OAAO,GAAe;YAC1B,OAAO,EAAE,mBAAmB,CAAC,gBAAgB,CAAC;YAC9C,WAAW,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,CAAC;gBACvD,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,OAAO;aACpB,CAAC,CAAC;SACJ,CAAC;QAEF,gGAAgG;QAChG,MAAM,eAAe,CAAC,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACzF,cAAc,EAAE,CAAC;QACjB,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { TestCoverageData } from './types.js';
2
+ export declare function transformTestCoverageReport(testCoverageData: TestCoverageData[]): Promise<{
3
+ xml: string;
4
+ warnings: string[];
5
+ filesProcessed: number;
6
+ }>;
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+ /* eslint-disable no-await-in-loop */
3
+ import { create } from 'xmlbuilder2';
4
+ import { getPackageDirectories } from './getPackageDirectories.js';
5
+ import { findFilePath } from './findFilePath.js';
6
+ import { normalizePathToUnix } from './normalizePathToUnix.js';
7
+ export async function transformTestCoverageReport(testCoverageData) {
8
+ const coverageObj = { coverage: { '@version': '1', file: [] } };
9
+ const warnings = [];
10
+ let filesProcessed = 0;
11
+ const { repoRoot, packageDirectories } = await getPackageDirectories();
12
+ if (!Array.isArray(testCoverageData)) {
13
+ testCoverageData = [testCoverageData];
14
+ }
15
+ for (const data of testCoverageData) {
16
+ const { name, lines } = data;
17
+ const formattedFileName = name.replace(/no-map[\\/]+/, '');
18
+ const relativeFilePath = await findFilePath(formattedFileName, packageDirectories, repoRoot);
19
+ if (relativeFilePath === undefined) {
20
+ warnings.push(`The file name ${formattedFileName} was not found in any package directory.`);
21
+ continue;
22
+ }
23
+ const fileObj = {
24
+ '@path': normalizePathToUnix(relativeFilePath),
25
+ lineToCover: [],
26
+ };
27
+ for (const [lineNumber, isCovered] of Object.entries(lines)) {
28
+ fileObj.lineToCover.push({
29
+ '@lineNumber': Number(lineNumber),
30
+ '@covered': `${isCovered === 1}`,
31
+ });
32
+ }
33
+ filesProcessed++;
34
+ coverageObj.coverage.file.push(fileObj);
35
+ }
36
+ const xml = create(coverageObj).end({ prettyPrint: true, indent: ' ' });
37
+ return { xml, warnings, filesProcessed };
38
+ }
39
+ //# sourceMappingURL=transformTestCoverageReport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformTestCoverageReport.js","sourceRoot":"","sources":["../../src/helpers/transformTestCoverageReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,qCAAqC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,gBAAoC;IAEpC,MAAM,WAAW,GAAmB,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC;IAChF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAW,CAAC,CAAC;IAC/B,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,EAAE,CAAC;IAEvE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACrC,gBAAgB,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QAC7B,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,gBAAgB,GAAG,MAAM,YAAY,CAAC,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QAC7F,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,iBAAiB,0CAA0C,CAAC,CAAC;YAC5F,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAe;YAC1B,OAAO,EAAE,mBAAmB,CAAC,gBAAgB,CAAC;YAC9C,WAAW,EAAE,EAAE;SAChB,CAAC;QAEF,KAAK,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5D,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;gBACvB,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC;gBACjC,UAAU,EAAE,GAAG,SAAS,KAAK,CAAC,EAAE;aACjC,CAAC,CAAC;QACL,CAAC;QACD,cAAc,EAAE,CAAC;QACjB,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
@@ -1,4 +1,4 @@
1
- export interface CoverageData {
1
+ export interface DeployCoverageData {
2
2
  [className: string]: {
3
3
  fnMap: Record<string, unknown>;
4
4
  branchMap: Record<string, unknown>;
@@ -18,6 +18,14 @@ export interface CoverageData {
18
18
  }>;
19
19
  };
20
20
  }
21
+ export interface TestCoverageData {
22
+ id: string;
23
+ name: string;
24
+ totalLines: number;
25
+ lines: Record<string, number>;
26
+ totalCovered: number;
27
+ coveredPercent: number;
28
+ }
21
29
  export interface SfdxProject {
22
30
  packageDirectories: Array<{
23
31
  path: string;
@@ -8,7 +8,7 @@ This plugin will convert the code coverage JSON file created by the Salesforce C
8
8
 
9
9
  # examples
10
10
 
11
- - `sf apex-code-coverage transformer transform -j "coverage.json" -x "coverage.xml"`
11
+ - `sf apex-code-coverage transformer transform -j "coverage.json" -x "coverage.xml" -c "deploy"`
12
12
 
13
13
  # flags.coverage-json.summary
14
14
 
@@ -17,3 +17,11 @@ Path to the code coverage JSON file created by the Salesforce CLI deployment com
17
17
  # flags.xml.summary
18
18
 
19
19
  Path to code coverage XML file that will be created by this plugin.
20
+
21
+ # flags.xml.summary
22
+
23
+ Path to code coverage XML file that will be created by this plugin.
24
+
25
+ # flags.command.summary
26
+
27
+ The type of Salesforce CLI command you are running.
@@ -5,7 +5,7 @@
5
5
  "args": {},
6
6
  "description": "This plugin will convert the code coverage JSON file created by the Salesforce CLI during Apex deployments into an XML accepted by tools like SonarQube.",
7
7
  "examples": [
8
- "`sf apex-code-coverage transformer transform -j \"coverage.json\" -x \"coverage.xml\"`"
8
+ "`sf apex-code-coverage transformer transform -j \"coverage.json\" -x \"coverage.xml\" -c \"deploy\"`"
9
9
  ],
10
10
  "flags": {
11
11
  "json": {
@@ -33,6 +33,20 @@
33
33
  "hasDynamicHelp": false,
34
34
  "multiple": false,
35
35
  "type": "option"
36
+ },
37
+ "command": {
38
+ "char": "c",
39
+ "name": "command",
40
+ "required": true,
41
+ "summary": "The type of Salesforce CLI command you are running.",
42
+ "default": "deploy",
43
+ "hasDynamicHelp": false,
44
+ "multiple": false,
45
+ "options": [
46
+ "deploy",
47
+ "test"
48
+ ],
49
+ "type": "option"
36
50
  }
37
51
  },
38
52
  "hasDynamicHelp": false,
@@ -63,5 +77,5 @@
63
77
  ]
64
78
  }
65
79
  },
66
- "version": "1.7.0"
80
+ "version": "1.7.2-beta.1"
67
81
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "apex-code-coverage-transformer",
3
3
  "description": "Transforms the Apex code coverage JSON created during Salesforce deployments into the Generic Test Coverage Format (XML).",
4
- "version": "1.7.0",
4
+ "version": "1.7.2-beta.1",
5
5
  "dependencies": {
6
6
  "@oclif/core": "^3.18.1",
7
7
  "@salesforce/core": "^6.4.7",
@@ -1,6 +0,0 @@
1
- import { CoverageData } from './types.js';
2
- export declare function convertToGenericCoverageReport(data: CoverageData): Promise<{
3
- xml: string;
4
- warnings: string[];
5
- filesProcessed: number;
6
- }>;
@@ -1 +0,0 @@
1
- {"version":3,"file":"convertToGenericCoverageReport.js","sourceRoot":"","sources":["../../src/helpers/convertToGenericCoverageReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,qCAAqC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,IAAkB;IAElB,MAAM,WAAW,GAAmB,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC;IAChF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAW,CAAC,CAAC;IAC/B,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,EAAE,CAAC;IAEvE,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC;YAAE,SAAS;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC1D,MAAM,gBAAgB,GAAG,MAAM,YAAY,CAAC,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QAC7F,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,iBAAiB,0CAA0C,CAAC,CAAC;YAC5F,SAAS;QACX,CAAC;QACD,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;aAC3C,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;aACpD,GAAG,CAAC,MAAM,CAAC,CAAC;QACf,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;aACzC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;aACpD,GAAG,CAAC,MAAM,CAAC,CAAC;QAEf,MAAM,OAAO,GAAe;YAC1B,OAAO,EAAE,mBAAmB,CAAC,gBAAgB,CAAC;YAC9C,WAAW,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,CAAC;gBACvD,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,OAAO;aACpB,CAAC,CAAC;SACJ,CAAC;QAEF,gGAAgG;QAChG,MAAM,eAAe,CAAC,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACzF,cAAc,EAAE,CAAC;QACjB,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}