apex-code-coverage-transformer 2.6.0 → 2.7.0

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
@@ -5,6 +5,20 @@
5
5
 
6
6
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
7
7
 
8
+ ## [2.7.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.6.1...v2.7.0) (2025-01-15)
9
+
10
+
11
+ ### Features
12
+
13
+ * add async processing and sort files in report ([ef0c011](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/ef0c011895f378e7aedc5c6568b9b9ec0e9574bf))
14
+
15
+ ## [2.6.1](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.6.0...v2.6.1) (2025-01-15)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * fix default test command path in doc and provide defaults ([c8dc711](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/c8dc71177d3ed9cae8dc7a41b7843fdc9d09ad5d))
21
+
8
22
  ## [2.6.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.5.2...v2.6.0) (2025-01-12)
9
23
 
10
24
 
package/README.md CHANGED
@@ -9,6 +9,7 @@
9
9
  - [Install](#install)
10
10
  - [Who is the Plugin For?](#who-is-the-plugin-for)
11
11
  - [Creating Code Coverage Files with the Salesforce CLI](#creating-code-coverage-files-with-the-salesforce-cli)
12
+ - [Creating Code Coverage Files with SFDX Hardis](#creating-code-coverage-files-with-sfdx-hardis)
12
13
  - [What this Plugin fixes in the Salesforce CLI Coverage Reports](#what-this-plugin-fixes-in-the-salesforce-cli-coverage-reports)
13
14
  - [Command](#command)
14
15
  - [`sf acc-transformer transform`](#sf-acc-transformer-transform)
@@ -45,7 +46,7 @@ To create the code coverage JSON when deploying or validating, append `--coverag
45
46
  sf project deploy [start/validate] --coverage-formatters json --results-dir "coverage"
46
47
  ```
47
48
 
48
- To create the code coverage JSON when running tests directly in the org, append `--code-coverage --result-format json --output-dir "coverage"` to the `sf apex run test` or `sf apex get test` command. This will create the code coverage JSON in a folder named "coverage".
49
+ To create the code coverage JSON when running tests directly in the org, append `--code-coverage --result-format json --output-dir "coverage"` to the `sf apex run test` or `sf apex get test` command. This will create the code coverage JSON in this relative path - `coverage/test-result-codecoverage.json`
49
50
 
50
51
  ```
51
52
  sf apex run test --code-coverage --result-format json --output-dir "coverage"
@@ -54,6 +55,12 @@ sf apex get test --test-run-id <test run id> --code-coverage --result-format jso
54
55
 
55
56
  The code coverage JSONs created by the Salesforce CLI aren't accepted automatically for Salesforce DX repositories and needs to be converted using this plugin.
56
57
 
58
+ ## Creating Code Coverage Files with SFDX Hardis
59
+
60
+ This plugin can be used after running [sfdx-hardis](https://github.com/hardisgroupcom/sfdx-hardis) commands `hardis:project:deploy:smart` (only if `COVERAGE_FORMATTER_JSON=true` environment variable is defined) and `hardis:org:test:apex` assuming you have sfdx-hardis and this plugin installed.
61
+
62
+ Both hardis commands will create the code coverage JSON to transform here: `hardis-report/apex-coverage-results.json`. Provide this relative path as the `--coverage-json`/`-j` input for this plugin.
63
+
57
64
  ## What this Plugin fixes in the Salesforce CLI Coverage Reports
58
65
 
59
66
  1. The coverage reports created by this plugin will add correct file-paths per your Salesforce DX repository. Salesforce CLI coverage reports have the `no-map/` prefix hard-coded into their coverage reports. The coverage report created in this plugin will only contain Apex coverage results against files found in your Salesforce DX repository, allowing you to use these reports in external code quality tools like SonarQube.
@@ -105,38 +112,30 @@ EXAMPLES
105
112
 
106
113
  ## Hook
107
114
 
108
- A post-run hook has been configured if you elect to use it.
115
+ A post-run hook has been configured if you opt into using it by creating a `.apexcodecovtransformer.config.json` config file in the root of your repo. If the config file is found, the post-run hook will automatically run after the following commands:
109
116
 
110
- The post-run hook will automatically transform the code coverage JSON file after every Salesforce CLI deployment (`sf project deploy start`, `sf project deploy validate`, `sf project deploy report`, `sf project deploy resume` commands) and test run (`sf apex run test` and `sf apex get test` commands) if the JSON is found.
117
+ - `sf project deploy start`
118
+ - `sf project deploy validate`
119
+ - `sf project deploy report`
120
+ - `sf project deploy resume`
121
+ - `sf apex run test`
122
+ - `sf apex get test`
123
+ - `hardis:project:deploy:smart` (only if sfdx-hardis is installed and `COVERAGE_FORMATTER_JSON=true` environment variable is defined)
124
+ - `hardis:org:test:apex` (only if sfdx-hardis is installed)
111
125
 
112
- The hook requires you to create this file in the root of your repo: `.apexcodecovtransformer.config.json`
126
+ You can copy the sample [Salesforce CLI .apexcodecovtransformer.config.json](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/defaults/salesforce-cli/.apexcodecovtransformer.config.json), which assumes you are running the Salesforce CLI commands and specifying the `--results-dir`/`--output-dir` directory as "coverage". Update this sample with your desired output report path and format.
113
127
 
114
- The `.apexcodecovtransformer.config.json` should look like this:
128
+ You can copy the sample [SFDX Hardis .apexcodecovtransformer.config.json](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/defaults/sfdx-hardis/.apexcodecovtransformer.config.json), which assumes you are running the SFDX Hardis commands. Update this sample with your desired output report path and format.
115
129
 
116
- ```json
117
- {
118
- "deployCoverageJsonPath": "coverage/coverage/coverage.json",
119
- "testCoverageJsonPath": "coverage/test-coverage.json",
120
- "outputReportPath": "coverage.xml",
121
- "format": "sonar"
122
- }
123
- ```
130
+ The `.apexcodecovtransformer.config.json` follows this structure:
124
131
 
125
- - `deployCoverageJsonPath` is required to use the hook after deployments and should be the path to the code coverage JSON created by the Salesforce CLI deployment command. Recommend using a relative path.
126
- - `testCoverageJsonPath` is required to use the hook after test runs and should be the path to the code coverage JSON created by the Salesforce CLI test command. Recommend using a relative path.
132
+ - `deployCoverageJsonPath` is required to use the hook after deploy commands and should be the path to the code coverage JSON created by the Salesforce CLI/SFDX Hardis deploy command. Recommend using a relative path.
133
+ - `testCoverageJsonPath` is required to use the hook after test commands and should be the path to the code coverage JSON created by the Salesforce CLI/SFDX Hardis test command. Recommend using a relative path.
127
134
  - `outputReportPath` is optional and should be the path to the code coverage file created by this plugin. Recommend using a relative path. If this isn't provided, it will default to `coverage.[xml/info]` in the working directory.
128
135
  - `format` is optional and should be the intended output format for the code coverage file created by this plugin. Options are "sonar", "clover", "lcovonly", or "cobertura". If this isn't provided, it will default to "sonar".
129
136
 
130
137
  If the `.apexcodecovtransformer.config.json` file isn't found, the hook will be skipped.
131
138
 
132
- The post-run hook can also run after the [sfdx-hardis](https://github.com/hardisgroupcom/sfdx-hardis) commands `hardis:project:deploy:smart` (only if `COVERAGE_FORMATTER_JSON=true` environment variable is defined) and `hardis:org:test:apex` assuming you:
133
-
134
- - Install both plugins, apex-code-coverage-transformer and sfdx-hardis, with the Salesforce CLI
135
- - Create the `.apexcodecovtransformer.config.json` file in the root of your repo
136
- - Set `deployCoverageJsonPath` and `testCoverageJsonPath` in `.apexcodecovtransformer.config.json` to `hardis-report/apex-coverage-results.json`
137
-
138
- Since sfdx-hardis invokes Salesforce CLI commands, the hooks will fire twice per hardis command, once after the Salesforce CLI command and once after the sfdx-hardis command. The hook will end early without errors after the Salesforce CLI command and will run successfully after the sfdx-hardis command assuming the hardis report is found.
139
-
140
139
  ## Errors and Warnings
141
140
 
142
141
  Any file in the coverage JSON that isn't found in any package directory will result in this warning:
@@ -4,6 +4,7 @@ export function generateReport(coverageObj, format) {
4
4
  if (format === 'lcovonly') {
5
5
  if ('files' in coverageObj) {
6
6
  let lcovOutput = '';
7
+ coverageObj.files.sort((a, b) => a.sourceFile.localeCompare(b.sourceFile));
7
8
  for (const file of coverageObj.files) {
8
9
  lcovOutput += `TN:\nSF:${file.sourceFile}\n`;
9
10
  lcovOutput += 'FNF:0\nFNH:0\n';
@@ -19,6 +20,9 @@ export function generateReport(coverageObj, format) {
19
20
  }
20
21
  }
21
22
  const isHeadless = format === 'cobertura' || format === 'clover';
23
+ if ('files' in coverageObj) {
24
+ coverageObj.files.sort((a, b) => a.sourceFile.localeCompare(b.sourceFile));
25
+ }
22
26
  let xml = create(coverageObj).end({ prettyPrint: true, indent: ' ', headless: isHeadless });
23
27
  if (format === 'cobertura') {
24
28
  xml = `<?xml version="1.0" ?>\n<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">\n${xml}`;
@@ -1 +1 @@
1
- {"version":3,"file":"generateReport.js","sourceRoot":"","sources":["../../src/helpers/generateReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,UAAU,cAAc,CAC5B,WAAsG,EACtG,MAAc;IAEd,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC1B,IAAI,OAAO,IAAI,WAAW,EAAE,CAAC;YAC3B,IAAI,UAAU,GAAG,EAAE,CAAC;YACpB,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;gBACrC,UAAU,IAAI,WAAW,IAAI,CAAC,UAAU,IAAI,CAAC;gBAC7C,UAAU,IAAI,gBAAgB,CAAC;gBAE/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC9B,UAAU,IAAI,MAAM,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC;gBAC3D,CAAC;gBAED,UAAU,IAAI,MAAM,IAAI,CAAC,UAAU,IAAI,CAAC;gBACxC,UAAU,IAAI,MAAM,IAAI,CAAC,YAAY,IAAI,CAAC;gBAC1C,UAAU,IAAI,gBAAgB,CAAC;gBAC/B,UAAU,IAAI,iBAAiB,CAAC;YAClC,CAAC;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,QAAQ,CAAC;IACjE,IAAI,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAE7F,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QAC3B,GAAG,GAAG,8GAA8G,GAAG,EAAE,CAAC;IAC5H,CAAC;SAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,GAAG,GAAG,2CAA2C,GAAG,EAAE,CAAC;IACzD,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"generateReport.js","sourceRoot":"","sources":["../../src/helpers/generateReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,UAAU,cAAc,CAC5B,WAAsG,EACtG,MAAc;IAEd,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC1B,IAAI,OAAO,IAAI,WAAW,EAAE,CAAC;YAC3B,IAAI,UAAU,GAAG,EAAE,CAAC;YACpB,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;YAC3E,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;gBACrC,UAAU,IAAI,WAAW,IAAI,CAAC,UAAU,IAAI,CAAC;gBAC7C,UAAU,IAAI,gBAAgB,CAAC;gBAE/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC9B,UAAU,IAAI,MAAM,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC;gBAC3D,CAAC;gBAED,UAAU,IAAI,MAAM,IAAI,CAAC,UAAU,IAAI,CAAC;gBACxC,UAAU,IAAI,MAAM,IAAI,CAAC,YAAY,IAAI,CAAC;gBAC1C,UAAU,IAAI,gBAAgB,CAAC;gBAC/B,UAAU,IAAI,iBAAiB,CAAC;YAClC,CAAC;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,QAAQ,CAAC;IACjE,IAAI,OAAO,IAAI,WAAW,EAAE,CAAC;QAC3B,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAE7F,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QAC3B,GAAG,GAAG,8GAA8G,GAAG,EAAE,CAAC;IAC5H,CAAC;SAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,GAAG,GAAG,2CAA2C,GAAG,EAAE,CAAC;IACzD,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function getConcurrencyThreshold(): number;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+ import { availableParallelism } from 'node:os';
3
+ export function getConcurrencyThreshold() {
4
+ const AVAILABLE_PARALLELISM = availableParallelism ? availableParallelism() : Infinity;
5
+ return Math.min(AVAILABLE_PARALLELISM, 6);
6
+ }
7
+ //# sourceMappingURL=getConcurrencyThreshold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getConcurrencyThreshold.js","sourceRoot":"","sources":["../../src/helpers/getConcurrencyThreshold.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,UAAU,uBAAuB;IACrC,MAAM,qBAAqB,GAAW,oBAAoB,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE/F,OAAO,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC;AAC5C,CAAC"}
@@ -1,30 +1,37 @@
1
1
  'use strict';
2
2
  /* eslint-disable no-await-in-loop */
3
+ import async from 'async';
3
4
  import { getCoverageHandler } from '../handlers/getCoverageHandler.js';
4
5
  import { getPackageDirectories } from './getPackageDirectories.js';
5
6
  import { findFilePath } from './findFilePath.js';
6
7
  import { generateReport } from './generateReport.js';
7
8
  import { setCoveredLines } from './setCoveredLines.js';
9
+ import { getConcurrencyThreshold } from './getConcurrencyThreshold.js';
8
10
  export async function transformDeployCoverageReport(data, format) {
9
11
  const warnings = [];
10
12
  let filesProcessed = 0;
11
13
  const { repoRoot, packageDirectories } = await getPackageDirectories();
12
14
  const handler = getCoverageHandler(format);
13
- for (const fileName in data) {
14
- if (!Object.hasOwn(data, fileName))
15
- continue;
15
+ const processFile = async (fileName) => {
16
16
  const fileInfo = data[fileName];
17
17
  const formattedFileName = fileName.replace(/no-map[\\/]+/, '');
18
18
  const relativeFilePath = await findFilePath(formattedFileName, packageDirectories, repoRoot);
19
19
  if (!relativeFilePath) {
20
20
  warnings.push(`The file name ${formattedFileName} was not found in any package directory.`);
21
- continue;
21
+ return false;
22
22
  }
23
23
  const updatedLines = await setCoveredLines(relativeFilePath, repoRoot, fileInfo.s);
24
24
  fileInfo.s = updatedLines;
25
25
  handler.processFile(relativeFilePath, formattedFileName, fileInfo.s);
26
- filesProcessed++;
27
- }
26
+ return true;
27
+ };
28
+ const concurrencyLimit = getConcurrencyThreshold();
29
+ await async.mapLimit(Object.keys(data).filter((fileName) => Object.hasOwn(data, fileName)), concurrencyLimit, async (fileName) => {
30
+ const result = await processFile(fileName);
31
+ if (result) {
32
+ filesProcessed++;
33
+ }
34
+ });
28
35
  const coverageObj = handler.finalize();
29
36
  const xml = generateReport(coverageObj, format);
30
37
  return { xml, warnings, filesProcessed };
@@ -1 +1 @@
1
- {"version":3,"file":"transformDeployCoverageReport.js","sourceRoot":"","sources":["../../src/helpers/transformDeployCoverageReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,qCAAqC;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,IAAwB,EACxB,MAAc;IAEd,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3C,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC;YAAE,SAAS;QAE7C,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;QAE7F,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,iBAAiB,iBAAiB,0CAA0C,CAAC,CAAC;YAC5F,SAAS;QACX,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnF,QAAQ,CAAC,CAAC,GAAG,YAAY,CAAC;QAE1B,OAAO,CAAC,WAAW,CACjB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,CAAC,CAAC,CACX,CAAC;QACF,cAAc,EAAE,CAAC;IACnB,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEhD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"transformDeployCoverageReport.js","sourceRoot":"","sources":["../../src/helpers/transformDeployCoverageReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,qCAAqC;AAErC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,IAAwB,EACxB,MAAc;IAEd,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3C,MAAM,WAAW,GAAG,KAAK,EAAE,QAAgB,EAAoB,EAAE;QAC/D,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;QAE7F,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,iBAAiB,iBAAiB,0CAA0C,CAAC,CAAC;YAC5F,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnF,QAAQ,CAAC,CAAC,GAAG,YAAY,CAAC;QAE1B,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACrE,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,uBAAuB,EAAE,CAAC;IACnD,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,QAAgB,EAAE,EAAE;QACvI,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,MAAM,EAAE,CAAC;YACX,cAAc,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEhD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
@@ -1,32 +1,39 @@
1
1
  'use strict';
2
2
  /* eslint-disable no-await-in-loop */
3
+ import async from 'async';
3
4
  import { getCoverageHandler } from '../handlers/getCoverageHandler.js';
4
5
  import { getPackageDirectories } from './getPackageDirectories.js';
5
6
  import { findFilePath } from './findFilePath.js';
6
7
  import { generateReport } from './generateReport.js';
8
+ import { getConcurrencyThreshold } from './getConcurrencyThreshold.js';
7
9
  export async function transformTestCoverageReport(testCoverageData, format) {
8
10
  const warnings = [];
9
11
  let filesProcessed = 0;
10
12
  const { repoRoot, packageDirectories } = await getPackageDirectories();
11
13
  const handler = getCoverageHandler(format);
12
- let coverageData = testCoverageData;
13
- if (!Array.isArray(coverageData)) {
14
- coverageData = [coverageData]; // Ensure the data is an array
15
- }
16
- for (const data of coverageData) {
14
+ // Ensure testCoverageData is an array
15
+ const coverageData = Array.isArray(testCoverageData) ? testCoverageData : [testCoverageData];
16
+ const processFile = async (data) => {
17
17
  const name = data?.name;
18
18
  const lines = data?.lines;
19
19
  if (!name || !lines)
20
- continue;
20
+ return false;
21
21
  const formattedFileName = name.replace(/no-map[\\/]+/, '');
22
22
  const relativeFilePath = await findFilePath(formattedFileName, packageDirectories, repoRoot);
23
- if (relativeFilePath === undefined) {
23
+ if (!relativeFilePath) {
24
24
  warnings.push(`The file name ${formattedFileName} was not found in any package directory.`);
25
- continue;
25
+ return false;
26
26
  }
27
27
  handler.processFile(relativeFilePath, formattedFileName, lines);
28
- filesProcessed++;
29
- }
28
+ return true;
29
+ };
30
+ const concurrencyLimit = getConcurrencyThreshold();
31
+ await async.mapLimit(coverageData, concurrencyLimit, async (data) => {
32
+ const result = await processFile(data);
33
+ if (result) {
34
+ filesProcessed++;
35
+ }
36
+ });
30
37
  const coverageObj = handler.finalize();
31
38
  const xml = generateReport(coverageObj, format);
32
39
  return { xml, warnings, filesProcessed };
@@ -1 +1 @@
1
- {"version":3,"file":"transformTestCoverageReport.js","sourceRoot":"","sources":["../../src/helpers/transformTestCoverageReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,qCAAqC;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,gBAAoC,EACpC,MAAc;IAEd,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,YAAY,GAAG,gBAAgB,CAAC;IACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,8BAA8B;IAC/D,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC;QACxB,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC;QAE1B,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;YAAE,SAAS;QAE9B,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;QAE7F,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,iBAAiB,0CAA0C,CAAC,CAAC;YAC5F,SAAS;QACX,CAAC;QAED,OAAO,CAAC,WAAW,CACjB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,CACN,CAAC;QACF,cAAc,EAAE,CAAC;IACnB,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEhD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"transformTestCoverageReport.js","sourceRoot":"","sources":["../../src/helpers/transformTestCoverageReport.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AACb,qCAAqC;AAErC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,gBAAoC,EACpC,MAAc;IAEd,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,MAAM,qBAAqB,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3C,sCAAsC;IACtC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAE7F,MAAM,WAAW,GAAG,KAAK,EAAE,IAAsB,EAAoB,EAAE;QACrE,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC;QACxB,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC;QAE1B,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QAElC,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;QAE7F,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,iBAAiB,iBAAiB,0CAA0C,CAAC,CAAC;YAC5F,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,uBAAuB,EAAE,CAAC;IACnD,MAAM,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAsB,EAAE,EAAE;QACpF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,cAAc,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEhD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
package/oclif.lock CHANGED
@@ -2478,6 +2478,11 @@
2478
2478
  resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz"
2479
2479
  integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
2480
2480
 
2481
+ "@types/async@^3.2.24":
2482
+ version "3.2.24"
2483
+ resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.24.tgz#3a96351047575bbcf2340541b2d955a35339608f"
2484
+ integrity sha512-8iHVLHsCCOBKjCF2KwFe0p9Z3rfM9mL+sSP8btyR5vTjJRAqpBYD28/ZLgXPf0pjG1VxOvtCV/BgXkQbpSe8Hw==
2485
+
2481
2486
  "@types/chai@^4.3.14":
2482
2487
  version "4.3.20"
2483
2488
  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc"
@@ -3070,6 +3075,11 @@ async@^3.2.3:
3070
3075
  resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz"
3071
3076
  integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
3072
3077
 
3078
+ async@^3.2.6:
3079
+ version "3.2.6"
3080
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce"
3081
+ integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==
3082
+
3073
3083
  asynckit@^0.4.0:
3074
3084
  version "0.4.0"
3075
3085
  resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
@@ -8031,16 +8041,7 @@ stack-utils@^2.0.6:
8031
8041
  dependencies:
8032
8042
  escape-string-regexp "^2.0.0"
8033
8043
 
8034
- "string-width-cjs@npm:string-width@^4.2.0":
8035
- version "4.2.3"
8036
- resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
8037
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
8038
- dependencies:
8039
- emoji-regex "^8.0.0"
8040
- is-fullwidth-code-point "^3.0.0"
8041
- strip-ansi "^6.0.1"
8042
-
8043
- string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
8044
+ "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
8044
8045
  version "4.2.3"
8045
8046
  resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
8046
8047
  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -8148,14 +8149,7 @@ stringify-entities@^4.0.0:
8148
8149
  character-entities-html4 "^2.0.0"
8149
8150
  character-entities-legacy "^3.0.0"
8150
8151
 
8151
- "strip-ansi-cjs@npm:strip-ansi@^6.0.1":
8152
- version "6.0.1"
8153
- resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
8154
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
8155
- dependencies:
8156
- ansi-regex "^5.0.1"
8157
-
8158
- strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
8152
+ "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
8159
8153
  version "6.0.1"
8160
8154
  resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
8161
8155
  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -8914,7 +8908,7 @@ workerpool@^6.5.1:
8914
8908
  resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544"
8915
8909
  integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==
8916
8910
 
8917
- "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
8911
+ "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
8918
8912
  version "7.0.0"
8919
8913
  resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
8920
8914
  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -8932,15 +8926,6 @@ wrap-ansi@^6.2.0:
8932
8926
  string-width "^4.1.0"
8933
8927
  strip-ansi "^6.0.0"
8934
8928
 
8935
- wrap-ansi@^7.0.0:
8936
- version "7.0.0"
8937
- resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
8938
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
8939
- dependencies:
8940
- ansi-styles "^4.0.0"
8941
- string-width "^4.1.0"
8942
- strip-ansi "^6.0.0"
8943
-
8944
8929
  wrap-ansi@^8.1.0:
8945
8930
  version "8.1.0"
8946
8931
  resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"
@@ -85,5 +85,5 @@
85
85
  ]
86
86
  }
87
87
  },
88
- "version": "2.6.0"
88
+ "version": "2.7.0"
89
89
  }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "apex-code-coverage-transformer",
3
3
  "description": "Transforms the Apex code coverage JSON created during Salesforce deployments and test runs into SonarQube, Clover, LCovOnly, or Cobertura format.",
4
- "version": "2.6.0",
4
+ "version": "2.7.0",
5
5
  "dependencies": {
6
6
  "@oclif/core": "^4.0.37",
7
7
  "@salesforce/core": "^8.8.0",
8
8
  "@salesforce/sf-plugins-core": "^12.1.1",
9
+ "async": "^3.2.6",
9
10
  "xmlbuilder2": "^3.1.1"
10
11
  },
11
12
  "devDependencies": {
@@ -14,6 +15,7 @@
14
15
  "@oclif/plugin-command-snapshot": "^5.2.24",
15
16
  "@salesforce/cli-plugins-testkit": "^5.3.39",
16
17
  "@salesforce/dev-scripts": "^10.2.11",
18
+ "@types/async": "^3.2.24",
17
19
  "@types/node": "18",
18
20
  "eslint-plugin-sf-plugin": "^1.20.13",
19
21
  "husky": "^9.1.7",