apex-code-coverage-transformer 2.22.0 → 2.23.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 +14 -0
- package/README.md +46 -14
- package/lib/commands/acc-transformer/transform.d.ts +1 -1
- package/lib/commands/acc-transformer/transform.js +1 -0
- package/lib/commands/acc-transformer/transform.js.map +1 -1
- package/lib/handlers/BaseHandler.js +4 -3
- package/lib/handlers/BaseHandler.js.map +1 -1
- package/lib/transformers/coverageDataMerger.d.ts +3 -0
- package/lib/transformers/coverageDataMerger.js +38 -0
- package/lib/transformers/coverageDataMerger.js.map +1 -0
- package/lib/transformers/coverageProcessor.d.ts +6 -0
- package/lib/transformers/coverageProcessor.js +87 -0
- package/lib/transformers/coverageProcessor.js.map +1 -0
- package/lib/transformers/coverageTransformer.d.ts +3 -6
- package/lib/transformers/coverageTransformer.js +21 -108
- package/lib/transformers/coverageTransformer.js.map +1 -1
- package/lib/utils/globMatcher.d.ts +3 -0
- package/lib/utils/globMatcher.js +57 -0
- package/lib/utils/globMatcher.js.map +1 -0
- package/lib/utils/readJson.d.ts +1 -0
- package/lib/utils/readJson.js +12 -0
- package/lib/utils/readJson.js.map +1 -0
- package/lib/utils/types.d.ts +13 -0
- package/messages/transformer.transform.md +2 -1
- package/oclif.manifest.json +5 -4
- package/package.json +2 -3
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.23.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.22.1...v2.23.0) (2026-06-17)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* support multiple coverage JSON inputs with union merge ([#317](https://github.com/mcarvin8/apex-code-coverage-transformer/issues/317)) ([43ccda6](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/43ccda6c2542cbb0be36faba37682a23b76758b8))
|
|
14
|
+
|
|
15
|
+
## [2.22.1](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.22.0...v2.22.1) (2026-06-15)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **deps:** replace minimatch with in-house glob matcher ([#312](https://github.com/mcarvin8/apex-code-coverage-transformer/issues/312)) ([c1ec8c8](https://github.com/mcarvin8/apex-code-coverage-transformer/commit/c1ec8c81673f47bf22f2cbe68294ce75a59d0873))
|
|
21
|
+
|
|
8
22
|
## [2.22.0](https://github.com/mcarvin8/apex-code-coverage-transformer/compare/v2.21.0...v2.22.0) (2026-06-12)
|
|
9
23
|
|
|
10
24
|
|
package/README.md
CHANGED
|
@@ -69,6 +69,9 @@ sf plugins install apex-code-coverage-transformer@latest
|
|
|
69
69
|
|
|
70
70
|
# Multiple formats at once
|
|
71
71
|
sf acc-transformer transform -j "coverage/test-result-codecoverage.json" -f "sonar" -f "cobertura" -f "jacoco"
|
|
72
|
+
|
|
73
|
+
# Merge multiple coverage JSONs of the same type (e.g. two deploy runs)
|
|
74
|
+
sf acc-transformer transform -j "coverage/coverage/coverage.json" -j "coverage2/coverage/coverage.json" -r "coverage.xml" -f "sonar"
|
|
72
75
|
```
|
|
73
76
|
|
|
74
77
|
3. **Upload to your tool** — see [CI/CD Integration](#cicd-integration).
|
|
@@ -111,11 +114,16 @@ Works with [sfdx-hardis](https://github.com/hardisgroupcom/sfdx-hardis):
|
|
|
111
114
|
|
|
112
115
|
```
|
|
113
116
|
USAGE
|
|
114
|
-
$ sf acc-transformer transform -j <value
|
|
115
|
-
|
|
117
|
+
$ sf acc-transformer transform -j <value>... [-r <value>] [-f <value>] [-i <value>] [-e <value>]
|
|
118
|
+
[--min-coverage <value>] [--max-annotations <value>] [--json]
|
|
116
119
|
|
|
117
120
|
FLAGS
|
|
118
|
-
-j, --coverage-json=<value
|
|
121
|
+
-j, --coverage-json=<value>... Path to a code coverage JSON from deploy or test. Repeat to merge
|
|
122
|
+
multiple files. When the same Apex file appears in more than one
|
|
123
|
+
input, covered lines are unioned across all inputs — if a line is
|
|
124
|
+
covered in any input it is counted as covered in the final report,
|
|
125
|
+
even if it is uncovered in others. All files must be the same type
|
|
126
|
+
(deploy or test).
|
|
119
127
|
-r, --output-report=<value> Output path (e.g. coverage.xml). Default: coverage.[xml|info] by format.
|
|
120
128
|
-f, --format=<value> Output format (repeat for multiple). Default: sonar.
|
|
121
129
|
Multiple formats append to filename, e.g. coverage-sonar.xml.
|
|
@@ -154,18 +162,34 @@ Use `-f` / `--format` to choose the output format. Multiple `-f` values produce
|
|
|
154
162
|
|
|
155
163
|
### Shared setup (GitHub Actions)
|
|
156
164
|
|
|
157
|
-
All GitHub Actions examples below assume these steps run first:
|
|
165
|
+
All GitHub Actions examples below assume these steps run first for deployments (update `sf project deploy start` command to `sf apex run test` to invoke tests directly in an org):
|
|
158
166
|
|
|
159
167
|
```yaml
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
|
|
168
|
+
jobs:
|
|
169
|
+
deploy:
|
|
170
|
+
runs-on: ubuntu-latest
|
|
171
|
+
steps:
|
|
172
|
+
- name: Checkout
|
|
173
|
+
uses: actions/checkout@v4
|
|
174
|
+
with:
|
|
175
|
+
fetch-depth: 0
|
|
176
|
+
|
|
177
|
+
- name: Set up Node.js
|
|
178
|
+
uses: actions/setup-node@v4
|
|
179
|
+
with:
|
|
180
|
+
node-version: '20'
|
|
181
|
+
|
|
182
|
+
- name: Install Salesforce CLI
|
|
183
|
+
run: npm install -g @salesforce/cli@latest
|
|
184
|
+
|
|
185
|
+
- name: Install Apex Code Coverage Transformer plugin
|
|
186
|
+
run: echo y | sf plugins install apex-code-coverage-transformer
|
|
187
|
+
|
|
188
|
+
- name: Authenticate to Salesforce
|
|
189
|
+
run: sf org login sfdx-url --sfdx-url-file ${{ secrets.SFDX_AUTH_URL }} --alias ci-org
|
|
190
|
+
|
|
191
|
+
- name: Deploy with Apex Tests
|
|
192
|
+
run: sf project deploy start --test-level RunLocalTests --coverage-formatters json --results-dir "coverage"
|
|
169
193
|
```
|
|
170
194
|
|
|
171
195
|
### Codecov
|
|
@@ -295,6 +319,8 @@ Create `.apexcodecovtransformer.config.json` in the project root to transform co
|
|
|
295
319
|
- `sf hardis project deploy smart` (if sfdx-hardis installed and `COVERAGE_FORMATTER_JSON=true`)
|
|
296
320
|
- `sf hardis org test apex` (if sfdx-hardis installed)
|
|
297
321
|
|
|
322
|
+
> **Note:** The hook fires once per command and always processes a single coverage JSON. It cannot merge multiple inputs. If you need to merge coverage from multiple runs (e.g. split test batches), run the `sf acc-transformer transform` command manually with multiple `-j` flags after all runs complete.
|
|
323
|
+
|
|
298
324
|
Sample configs: [Salesforce CLI](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/defaults/salesforce-cli/.apexcodecovtransformer.config.json), [SFDX Hardis](https://raw.githubusercontent.com/mcarvin8/apex-code-coverage-transformer/main/defaults/sfdx-hardis/.apexcodecovtransformer.config.json).
|
|
299
325
|
|
|
300
326
|
| Key | Required | Description |
|
|
@@ -330,6 +356,12 @@ Resolve by renaming one of the files or using `--ignore-package-directory` to ex
|
|
|
330
356
|
Warning: None of the files listed in the coverage JSON were processed. The coverage report will be empty.
|
|
331
357
|
```
|
|
332
358
|
|
|
359
|
+
**Mixed coverage types** — All `-j` inputs must be the same type (either all deploy or all test):
|
|
360
|
+
|
|
361
|
+
```
|
|
362
|
+
Error (1): All coverage JSON files must be the same type (deploy or test).
|
|
363
|
+
```
|
|
364
|
+
|
|
333
365
|
**Unknown JSON structure** — Input is not from deploy or test coverage:
|
|
334
366
|
|
|
335
367
|
```
|
|
@@ -372,4 +404,4 @@ The coverage report has been written to: coverage.xml
|
|
|
372
404
|
|
|
373
405
|
## License
|
|
374
406
|
|
|
375
|
-
[MIT](
|
|
407
|
+
[MIT](LICENSE.md)
|
|
@@ -5,7 +5,7 @@ export default class TransformerTransform extends SfCommand<TransformerTransform
|
|
|
5
5
|
static readonly description: string;
|
|
6
6
|
static readonly examples: string[];
|
|
7
7
|
static readonly flags: {
|
|
8
|
-
'coverage-json': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'coverage-json': import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
'output-report': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
format: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
'ignore-package-directory': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -15,6 +15,7 @@ export default class TransformerTransform extends SfCommand {
|
|
|
15
15
|
summary: messages.getMessage('flags.coverage-json.summary'),
|
|
16
16
|
char: 'j',
|
|
17
17
|
required: true,
|
|
18
|
+
multiple: true,
|
|
18
19
|
}),
|
|
19
20
|
'output-report': Flags.file({
|
|
20
21
|
summary: messages.getMessage('flags.output-report.summary'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/commands/acc-transformer/transform.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/commands/acc-transformer/transform.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,10 +27,11 @@ export class BaseHandler {
|
|
|
27
27
|
*/
|
|
28
28
|
// eslint-disable-next-line class-methods-use-this
|
|
29
29
|
extractLinesByStatus(lines, covered) {
|
|
30
|
-
|
|
30
|
+
const filtered = Object.entries(lines)
|
|
31
31
|
.filter(([, hits]) => (covered ? hits > 0 : hits === 0))
|
|
32
|
-
.map(([line]) => Number(line))
|
|
33
|
-
|
|
32
|
+
.map(([line]) => Number(line));
|
|
33
|
+
// Stryker disable next-line MethodExpression,ArithmeticOperator -- equivalent mutants: Object.entries already returns integer keys ascending; a+b never negative so insertion sort never swaps
|
|
34
|
+
return filtered.sort((a, b) => a - b);
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
37
|
* Get covered and uncovered line numbers from a lines record.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseHandler.js","sourceRoot":"","sources":["../../src/handlers/BaseHandler.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAkBb;;;GAGG;AACH,MAAM,OAAgB,WAAW;IAC/B;;;;;OAKG;IACH,kDAAkD;IACxC,iBAAiB,CAAC,KAA6B;QAMvD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAChF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5E,MAAM,UAAU,GAAG,cAAc,GAAG,YAAY,CAAC;QACjD,MAAM,QAAQ,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC;IAChE,CAAC;IAED;;;;;;OAMG;IACH,kDAAkD;IACxC,oBAAoB,CAAC,KAA6B,EAAE,OAAgB;QAC5E,
|
|
1
|
+
{"version":3,"file":"BaseHandler.js","sourceRoot":"","sources":["../../src/handlers/BaseHandler.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAkBb;;;GAGG;AACH,MAAM,OAAgB,WAAW;IAC/B;;;;;OAKG;IACH,kDAAkD;IACxC,iBAAiB,CAAC,KAA6B;QAMvD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAChF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5E,MAAM,UAAU,GAAG,cAAc,GAAG,YAAY,CAAC;QACjD,MAAM,QAAQ,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC;IAChE,CAAC;IAED;;;;;;OAMG;IACH,kDAAkD;IACxC,oBAAoB,CAAC,KAA6B,EAAE,OAAgB;QAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aACnC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;aACvD,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACjC,+LAA+L;QAC/L,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxC,CAAC;IAED;;;;;OAKG;IACO,sBAAsB,CAAC,KAA6B;QAI5D,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC;YAC/C,SAAS,EAAE,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC;SACnD,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,kDAAkD;IACxC,UAAU,CAAyE,KAAU;QACrG,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACzB,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/D,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/D,OAAO,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;CAsBF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
export function mergeDeployCoverageData(inputs) {
|
|
3
|
+
const merged = {};
|
|
4
|
+
for (const input of inputs) {
|
|
5
|
+
for (const [className, fileInfo] of Object.entries(input)) {
|
|
6
|
+
if (!merged[className]) {
|
|
7
|
+
merged[className] = { ...fileInfo, s: { ...fileInfo.s } };
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
for (const [line, hit] of Object.entries(fileInfo.s)) {
|
|
11
|
+
merged[className].s[line] = Math.max(merged[className].s[line] ?? 0, hit);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return merged;
|
|
17
|
+
}
|
|
18
|
+
export function mergeTestCoverageData(inputs) {
|
|
19
|
+
const byName = new Map();
|
|
20
|
+
for (const input of inputs) {
|
|
21
|
+
for (const entry of input) {
|
|
22
|
+
if (!byName.has(entry.name)) {
|
|
23
|
+
byName.set(entry.name, { ...entry, lines: { ...entry.lines } });
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const existing = byName.get(entry.name);
|
|
27
|
+
for (const [line, hit] of Object.entries(entry.lines)) {
|
|
28
|
+
existing.lines[line] = Math.max(existing.lines[line] ?? 0, hit);
|
|
29
|
+
}
|
|
30
|
+
existing.totalLines = Object.keys(existing.lines).length;
|
|
31
|
+
existing.totalCovered = Object.values(existing.lines).filter((v) => v === 1).length;
|
|
32
|
+
existing.coveredPercent = existing.totalLines > 0 ? (existing.totalCovered / existing.totalLines) * 100 : 0;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return [...byName.values()];
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=coverageDataMerger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverageDataMerger.js","sourceRoot":"","sources":["../../src/transformers/coverageDataMerger.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAIb,MAAM,UAAU,uBAAuB,CAAC,MAA4B;IAClE,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvB,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC;YAC5D,CAAC;iBAAM,CAAC;gBACN,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrD,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAA4B;IAChE,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAE,CAAC;gBACzC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;oBACtD,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;gBAClE,CAAC;gBACD,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;gBACzD,QAAQ,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;gBACpF,QAAQ,CAAC,cAAc,GAAG,QAAQ,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9G,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { getCoverageHandler } from '../handlers/getHandler.js';
|
|
2
|
+
import { DeployCoverageData, TestCoverageData, CoverageProcessingContext, LineTotals, ProcessResult } from '../utils/types.js';
|
|
3
|
+
export declare function createHandlers(formats: string[]): Map<string, ReturnType<typeof getCoverageHandler>>;
|
|
4
|
+
export declare function countLines(lines: Record<string, number>): LineTotals;
|
|
5
|
+
export declare function processDeployCoverage(data: DeployCoverageData, context: CoverageProcessingContext): Promise<ProcessResult>;
|
|
6
|
+
export declare function processTestCoverage(data: TestCoverageData[], context: CoverageProcessingContext): Promise<ProcessResult>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
'use strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { matchesGlob } from '../utils/globMatcher.js';
|
|
6
|
+
import { getCoverageHandler } from '../handlers/getHandler.js';
|
|
7
|
+
import { findFilePath } from '../utils/findFilePath.js';
|
|
8
|
+
import { setCoveredLines } from '../utils/setCoveredLines.js';
|
|
9
|
+
import { mapLimit } from '../utils/mapLimit.js';
|
|
10
|
+
export function createHandlers(formats) {
|
|
11
|
+
const handlers = new Map();
|
|
12
|
+
for (const format of formats) {
|
|
13
|
+
handlers.set(format, getCoverageHandler(format));
|
|
14
|
+
}
|
|
15
|
+
return handlers;
|
|
16
|
+
}
|
|
17
|
+
function hasSourceContent(result) {
|
|
18
|
+
return typeof result === 'object' && result !== null && 'sourceContent' in result;
|
|
19
|
+
}
|
|
20
|
+
async function readSourceFile(absolutePath) {
|
|
21
|
+
try {
|
|
22
|
+
return await readFile(absolutePath, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function countLines(lines) {
|
|
29
|
+
const totalLines = Object.keys(lines).length;
|
|
30
|
+
const coveredLines = Object.values(lines).filter((v) => v === 1).length;
|
|
31
|
+
return { totalLines, coveredLines };
|
|
32
|
+
}
|
|
33
|
+
export async function processDeployCoverage(data, context) {
|
|
34
|
+
let processed = 0;
|
|
35
|
+
let totalLines = 0;
|
|
36
|
+
let coveredLines = 0;
|
|
37
|
+
await mapLimit(Object.keys(data), context.concurrencyLimit, async (fileName) => {
|
|
38
|
+
const fileInfo = data[fileName];
|
|
39
|
+
const formattedName = fileName.replace(/no-map[\\/]+/, '');
|
|
40
|
+
const path = findFilePath(formattedName, context.filePathCache);
|
|
41
|
+
if (!path) {
|
|
42
|
+
context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (context.excludePatterns.some((pattern) => matchesGlob(path, pattern, { matchBase: true }))) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const setCoveredResult = await setCoveredLines(path, context.repoRoot, fileInfo.s, context.handlers.has('html'));
|
|
49
|
+
const updatedLines = hasSourceContent(setCoveredResult) ? setCoveredResult.updatedLines : setCoveredResult;
|
|
50
|
+
const sourceContent = hasSourceContent(setCoveredResult) ? setCoveredResult.sourceContent : undefined;
|
|
51
|
+
fileInfo.s = updatedLines;
|
|
52
|
+
const counts = countLines(updatedLines);
|
|
53
|
+
totalLines += counts.totalLines;
|
|
54
|
+
coveredLines += counts.coveredLines;
|
|
55
|
+
for (const handler of context.handlers.values()) {
|
|
56
|
+
handler.processFile(path, formattedName, updatedLines, sourceContent);
|
|
57
|
+
}
|
|
58
|
+
processed++;
|
|
59
|
+
});
|
|
60
|
+
return { processed, totalLines, coveredLines };
|
|
61
|
+
}
|
|
62
|
+
export async function processTestCoverage(data, context) {
|
|
63
|
+
let processed = 0;
|
|
64
|
+
let totalLines = 0;
|
|
65
|
+
let coveredLines = 0;
|
|
66
|
+
await mapLimit(data, context.concurrencyLimit, async (entry) => {
|
|
67
|
+
const formattedName = entry.name.replace(/no-map[\\/]+/, '');
|
|
68
|
+
const path = findFilePath(formattedName, context.filePathCache);
|
|
69
|
+
if (!path) {
|
|
70
|
+
context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (context.excludePatterns.some((pattern) => matchesGlob(path, pattern, { matchBase: true }))) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const counts = countLines(entry.lines);
|
|
77
|
+
totalLines += counts.totalLines;
|
|
78
|
+
coveredLines += counts.coveredLines;
|
|
79
|
+
const sourceContent = context.handlers.has('html') ? await readSourceFile(join(context.repoRoot, path)) : undefined;
|
|
80
|
+
for (const handler of context.handlers.values()) {
|
|
81
|
+
handler.processFile(path, formattedName, entry.lines, sourceContent);
|
|
82
|
+
}
|
|
83
|
+
processed++;
|
|
84
|
+
});
|
|
85
|
+
return { processed, totalLines, coveredLines };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=coverageProcessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverageProcessor.js","sourceRoot":"","sources":["../../src/transformers/coverageProcessor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
excludePatterns?: string[];
|
|
5
|
-
};
|
|
6
|
-
export declare function transformCoverageReport(jsonFilePath: string, outputReportPath: string, formats: string[], ignoreDirs: string[], options?: TransformOptions): Promise<{
|
|
1
|
+
import { TransformOptions } from '../utils/types.js';
|
|
2
|
+
export { TransformOptions };
|
|
3
|
+
export declare function transformCoverageReport(jsonFilePaths: string[], outputReportPath: string, formats: string[], ignoreDirs: string[], options?: TransformOptions): Promise<{
|
|
7
4
|
finalPaths: string[];
|
|
8
5
|
warnings: string[];
|
|
9
6
|
lineRate: number;
|
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
|
-
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { minimatch } from 'minimatch';
|
|
5
|
-
import { getCoverageHandler } from '../handlers/getHandler.js';
|
|
2
|
+
'use strict';
|
|
6
3
|
import { getPackageDirectories } from '../utils/getPackageDirectories.js';
|
|
7
|
-
import { findFilePath } from '../utils/findFilePath.js';
|
|
8
4
|
import { buildFilePathCache } from '../utils/buildFilePathCache.js';
|
|
9
|
-
import { setCoveredLines } from '../utils/setCoveredLines.js';
|
|
10
5
|
import { getConcurrencyThreshold } from '../utils/getConcurrencyThreshold.js';
|
|
11
6
|
import { checkCoverageDataType } from '../utils/setCoverageDataType.js';
|
|
12
|
-
import {
|
|
7
|
+
import { tryReadJson } from '../utils/readJson.js';
|
|
13
8
|
import { generateAndWriteReport } from './reportGenerator.js';
|
|
14
|
-
|
|
9
|
+
import { mergeDeployCoverageData, mergeTestCoverageData } from './coverageDataMerger.js';
|
|
10
|
+
import { createHandlers, processDeployCoverage, processTestCoverage } from './coverageProcessor.js';
|
|
11
|
+
export async function transformCoverageReport(jsonFilePaths, outputReportPath, formats, ignoreDirs, options) {
|
|
15
12
|
const warnings = [];
|
|
16
13
|
const finalPaths = [];
|
|
17
14
|
const formatAmount = formats.length;
|
|
18
|
-
const
|
|
19
|
-
|
|
15
|
+
const jsonDataItems = await Promise.all(jsonFilePaths.map((p) => tryReadJson(p, warnings)));
|
|
16
|
+
const validData = jsonDataItems.filter((d) => d !== null);
|
|
17
|
+
if (validData.length === 0)
|
|
20
18
|
return { finalPaths: [outputReportPath], warnings, lineRate: 0 };
|
|
21
|
-
const
|
|
19
|
+
const parsedItems = validData.map((d) => JSON.parse(d));
|
|
20
|
+
const types = parsedItems.map(checkCoverageDataType);
|
|
21
|
+
if (types.some((t) => t === 'Unknown')) {
|
|
22
|
+
throw new Error('The provided JSON does not match a known coverage data format from the Salesforce deploy or test command.');
|
|
23
|
+
}
|
|
24
|
+
const uniqueTypes = [...new Set(types)];
|
|
25
|
+
if (uniqueTypes.length > 1) {
|
|
26
|
+
throw new Error('All coverage JSON files must be the same type (deploy or test).');
|
|
27
|
+
}
|
|
28
|
+
const commandType = uniqueTypes[0];
|
|
22
29
|
const { repoRoot, packageDirectories } = await getPackageDirectories(ignoreDirs);
|
|
23
30
|
const handlers = createHandlers(formats);
|
|
24
|
-
const commandType = checkCoverageDataType(parsedData);
|
|
25
31
|
const concurrencyLimit = getConcurrencyThreshold();
|
|
26
32
|
// Build file path cache upfront to avoid O(n*m) directory traversals
|
|
27
33
|
const { cache: filePathCache, warnings: cacheWarnings } = await buildFilePathCache(packageDirectories, repoRoot);
|
|
@@ -35,16 +41,9 @@ export async function transformCoverageReport(jsonFilePath, outputReportPath, fo
|
|
|
35
41
|
filePathCache,
|
|
36
42
|
excludePatterns: options?.excludePatterns ?? [],
|
|
37
43
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
else if (commandType === 'TestCoverageData') {
|
|
43
|
-
processResult = await processTestCoverage(parsedData, context);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
throw new Error('The provided JSON does not match a known coverage data format from the Salesforce deploy or test command.');
|
|
47
|
-
}
|
|
44
|
+
const processResult = commandType === 'DeployCoverageData'
|
|
45
|
+
? await processDeployCoverage(mergeDeployCoverageData(parsedItems), context)
|
|
46
|
+
: await processTestCoverage(mergeTestCoverageData(parsedItems), context);
|
|
48
47
|
if (processResult.processed === 0) {
|
|
49
48
|
warnings.push('None of the files listed in the coverage JSON were processed. The coverage report will be empty.');
|
|
50
49
|
}
|
|
@@ -60,90 +59,4 @@ export async function transformCoverageReport(jsonFilePath, outputReportPath, fo
|
|
|
60
59
|
}
|
|
61
60
|
return { finalPaths, warnings, lineRate };
|
|
62
61
|
}
|
|
63
|
-
function hasSourceContent(result) {
|
|
64
|
-
return typeof result === 'object' && result !== null && 'sourceContent' in result;
|
|
65
|
-
}
|
|
66
|
-
async function readSourceFile(absolutePath) {
|
|
67
|
-
try {
|
|
68
|
-
return await readFile(absolutePath, 'utf-8');
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
async function tryReadJson(path, warnings) {
|
|
75
|
-
try {
|
|
76
|
-
return await readFile(path, 'utf-8');
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
warnings.push(`Failed to read ${path}. Confirm file exists.`);
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function createHandlers(formats) {
|
|
84
|
-
const handlers = new Map();
|
|
85
|
-
for (const format of formats) {
|
|
86
|
-
handlers.set(format, getCoverageHandler(format));
|
|
87
|
-
}
|
|
88
|
-
return handlers;
|
|
89
|
-
}
|
|
90
|
-
function countLines(lines) {
|
|
91
|
-
const totalLines = Object.keys(lines).length;
|
|
92
|
-
const coveredLines = Object.values(lines).filter((v) => v === 1).length;
|
|
93
|
-
return { totalLines, coveredLines };
|
|
94
|
-
}
|
|
95
|
-
async function processDeployCoverage(data, context) {
|
|
96
|
-
let processed = 0;
|
|
97
|
-
let totalLines = 0;
|
|
98
|
-
let coveredLines = 0;
|
|
99
|
-
await mapLimit(Object.keys(data), context.concurrencyLimit, async (fileName) => {
|
|
100
|
-
const fileInfo = data[fileName];
|
|
101
|
-
const formattedName = fileName.replace(/no-map[\\/]+/, '');
|
|
102
|
-
const path = findFilePath(formattedName, context.filePathCache);
|
|
103
|
-
if (!path) {
|
|
104
|
-
context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (context.excludePatterns.some((pattern) => minimatch(path, pattern, { matchBase: true }))) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const setCoveredResult = await setCoveredLines(path, context.repoRoot, fileInfo.s, context.handlers.has('html'));
|
|
111
|
-
const updatedLines = hasSourceContent(setCoveredResult) ? setCoveredResult.updatedLines : setCoveredResult;
|
|
112
|
-
const sourceContent = hasSourceContent(setCoveredResult) ? setCoveredResult.sourceContent : undefined;
|
|
113
|
-
fileInfo.s = updatedLines;
|
|
114
|
-
const counts = countLines(updatedLines);
|
|
115
|
-
totalLines += counts.totalLines;
|
|
116
|
-
coveredLines += counts.coveredLines;
|
|
117
|
-
for (const handler of context.handlers.values()) {
|
|
118
|
-
handler.processFile(path, formattedName, updatedLines, sourceContent);
|
|
119
|
-
}
|
|
120
|
-
processed++;
|
|
121
|
-
});
|
|
122
|
-
return { processed, totalLines, coveredLines };
|
|
123
|
-
}
|
|
124
|
-
async function processTestCoverage(data, context) {
|
|
125
|
-
let processed = 0;
|
|
126
|
-
let totalLines = 0;
|
|
127
|
-
let coveredLines = 0;
|
|
128
|
-
await mapLimit(data, context.concurrencyLimit, async (entry) => {
|
|
129
|
-
const formattedName = entry.name.replace(/no-map[\\/]+/, '');
|
|
130
|
-
const path = findFilePath(formattedName, context.filePathCache);
|
|
131
|
-
if (!path) {
|
|
132
|
-
context.warnings.push(`The file name ${formattedName} was not found in any package directory.`);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (context.excludePatterns.some((pattern) => minimatch(path, pattern, { matchBase: true }))) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
const counts = countLines(entry.lines);
|
|
139
|
-
totalLines += counts.totalLines;
|
|
140
|
-
coveredLines += counts.coveredLines;
|
|
141
|
-
const sourceContent = context.handlers.has('html') ? await readSourceFile(join(context.repoRoot, path)) : undefined;
|
|
142
|
-
for (const handler of context.handlers.values()) {
|
|
143
|
-
handler.processFile(path, formattedName, entry.lines, sourceContent);
|
|
144
|
-
}
|
|
145
|
-
processed++;
|
|
146
|
-
});
|
|
147
|
-
return { processed, totalLines, coveredLines };
|
|
148
|
-
}
|
|
149
62
|
//# sourceMappingURL=coverageTransformer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverageTransformer.js","sourceRoot":"","sources":["../../src/transformers/coverageTransformer.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,
|
|
1
|
+
{"version":3,"file":"coverageTransformer.js","sourceRoot":"","sources":["../../src/transformers/coverageTransformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
function parseCharClass(pattern, start) {
|
|
3
|
+
let j = start + 1;
|
|
4
|
+
let cls = '[';
|
|
5
|
+
// Stryker disable next-line ConditionalExpression,EqualityOperator -- equivalent mutant: undefined !== '!' so bounds check is undetectable via char comparison
|
|
6
|
+
if (j < pattern.length && pattern[j] === '!') {
|
|
7
|
+
cls += '^';
|
|
8
|
+
j++;
|
|
9
|
+
}
|
|
10
|
+
// Stryker disable next-line ConditionalExpression,EqualityOperator -- equivalent mutant: undefined !== ']' so bounds check is undetectable via char comparison
|
|
11
|
+
if (j < pattern.length && pattern[j] === ']') {
|
|
12
|
+
cls += '\\]';
|
|
13
|
+
j++;
|
|
14
|
+
}
|
|
15
|
+
// Stryker disable next-line EqualityOperator -- equivalent mutant: extra iteration appends undefined to cls but unmatched-[ path still returns \\[
|
|
16
|
+
while (j < pattern.length && pattern[j] !== ']') {
|
|
17
|
+
cls += pattern[j++];
|
|
18
|
+
}
|
|
19
|
+
if (j < pattern.length) {
|
|
20
|
+
return { fragment: cls + ']', advance: j + 1 - start };
|
|
21
|
+
}
|
|
22
|
+
// unmatched '[', treat as literal
|
|
23
|
+
return { fragment: '\\[', advance: 1 };
|
|
24
|
+
}
|
|
25
|
+
function parseDoubleStar(pattern, i) {
|
|
26
|
+
if (pattern[i + 2] === '/') {
|
|
27
|
+
return { fragment: '(.*\\/)?', advance: 3 };
|
|
28
|
+
}
|
|
29
|
+
return { fragment: '.*', advance: 2 };
|
|
30
|
+
}
|
|
31
|
+
function nextToken(pattern, i) {
|
|
32
|
+
const c = pattern[i];
|
|
33
|
+
if (c === '*' && pattern[i + 1] === '*')
|
|
34
|
+
return parseDoubleStar(pattern, i);
|
|
35
|
+
if (c === '*')
|
|
36
|
+
return { fragment: '[^/]*', advance: 1 };
|
|
37
|
+
if (c === '?')
|
|
38
|
+
return { fragment: '[^/]', advance: 1 };
|
|
39
|
+
if (c === '[')
|
|
40
|
+
return parseCharClass(pattern, i);
|
|
41
|
+
return { fragment: c.replace(/[.+^${}()|\\]/g, '\\$&'), advance: 1 };
|
|
42
|
+
}
|
|
43
|
+
function globToRegex(pattern) {
|
|
44
|
+
let re = '';
|
|
45
|
+
let i = 0;
|
|
46
|
+
while (i < pattern.length) {
|
|
47
|
+
const { fragment, advance } = nextToken(pattern, i);
|
|
48
|
+
re += fragment;
|
|
49
|
+
i += advance;
|
|
50
|
+
}
|
|
51
|
+
return new RegExp('^' + re + '$');
|
|
52
|
+
}
|
|
53
|
+
export function matchesGlob(filePath, pattern, options) {
|
|
54
|
+
const subject = options?.matchBase && !pattern.includes('/') ? basename(filePath) : filePath;
|
|
55
|
+
return globToRegex(pattern).test(subject);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=globMatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globMatcher.js","sourceRoot":"","sources":["../../src/utils/globMatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function tryReadJson(path: string, warnings: string[]): Promise<string | null>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
export async function tryReadJson(path, warnings) {
|
|
4
|
+
try {
|
|
5
|
+
return await readFile(path, 'utf-8');
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
warnings.push(`Failed to read ${path}. Confirm file exists.`);
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=readJson.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readJson.js","sourceRoot":"","sources":["../../src/utils/readJson.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,QAAkB;IAChE,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,CAAC,IAAI,CAAC,kBAAkB,IAAI,wBAAwB,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/lib/utils/types.d.ts
CHANGED
|
@@ -44,6 +44,19 @@ export type CoverageProcessingContext = {
|
|
|
44
44
|
filePathCache: Map<string, string>;
|
|
45
45
|
excludePatterns: string[];
|
|
46
46
|
};
|
|
47
|
+
export type CoverageInput = DeployCoverageData | TestCoverageData[];
|
|
48
|
+
export type LineTotals = {
|
|
49
|
+
totalLines: number;
|
|
50
|
+
coveredLines: number;
|
|
51
|
+
};
|
|
52
|
+
export type ProcessResult = {
|
|
53
|
+
processed: number;
|
|
54
|
+
} & LineTotals;
|
|
55
|
+
export type TransformOptions = {
|
|
56
|
+
minCoverage?: number;
|
|
57
|
+
maxAnnotations?: number;
|
|
58
|
+
excludePatterns?: string[];
|
|
59
|
+
};
|
|
47
60
|
type SonarLine = {
|
|
48
61
|
'@lineNumber': number;
|
|
49
62
|
'@covered': boolean;
|
|
@@ -15,10 +15,11 @@ Transform Salesforce Apex code coverage JSONs created during deployments and tes
|
|
|
15
15
|
- `sf acc-transformer transform -j "coverage.json" -r "coverage.md" -f "markdown"`
|
|
16
16
|
- `sf acc-transformer transform -j "coverage.json" -r "coverage.txt" -f "github-actions"`
|
|
17
17
|
- `sf acc-transformer transform -j "coverage.json" -i "force-app"`
|
|
18
|
+
- `sf acc-transformer transform -j "coverage1.json" -j "coverage2.json" -r "coverage.xml" -f "sonar"`
|
|
18
19
|
|
|
19
20
|
# flags.coverage-json.summary
|
|
20
21
|
|
|
21
|
-
Path to
|
|
22
|
+
Path to a code coverage JSON file created by the Salesforce CLI deploy or test command. Repeat the flag to merge multiple files. When the same Apex file appears in multiple inputs, covered lines are unioned across all inputs — if a line is covered in any input it is counted as covered in the final report, even if it is uncovered in others.
|
|
22
23
|
|
|
23
24
|
# flags.output-report.summary
|
|
24
25
|
|
package/oclif.manifest.json
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"`sf acc-transformer transform -j \"coverage.json\" -r \"coverage.info\" -f \"lcovonly\"`",
|
|
12
12
|
"`sf acc-transformer transform -j \"coverage.json\" -r \"coverage.md\" -f \"markdown\"`",
|
|
13
13
|
"`sf acc-transformer transform -j \"coverage.json\" -r \"coverage.txt\" -f \"github-actions\"`",
|
|
14
|
-
"`sf acc-transformer transform -j \"coverage.json\" -i \"force-app\"`"
|
|
14
|
+
"`sf acc-transformer transform -j \"coverage.json\" -i \"force-app\"`",
|
|
15
|
+
"`sf acc-transformer transform -j \"coverage1.json\" -j \"coverage2.json\" -r \"coverage.xml\" -f \"sonar\"`"
|
|
15
16
|
],
|
|
16
17
|
"flags": {
|
|
17
18
|
"json": {
|
|
@@ -33,9 +34,9 @@
|
|
|
33
34
|
"char": "j",
|
|
34
35
|
"name": "coverage-json",
|
|
35
36
|
"required": true,
|
|
36
|
-
"summary": "Path to
|
|
37
|
+
"summary": "Path to a code coverage JSON file created by the Salesforce CLI deploy or test command. Repeat the flag to merge multiple files. When the same Apex file appears in multiple inputs, covered lines are unioned across all inputs — if a line is covered in any input it is counted as covered in the final report, even if it is uncovered in others.",
|
|
37
38
|
"hasDynamicHelp": false,
|
|
38
|
-
"multiple":
|
|
39
|
+
"multiple": true,
|
|
39
40
|
"type": "option"
|
|
40
41
|
},
|
|
41
42
|
"output-report": {
|
|
@@ -130,5 +131,5 @@
|
|
|
130
131
|
]
|
|
131
132
|
}
|
|
132
133
|
},
|
|
133
|
-
"version": "2.
|
|
134
|
+
"version": "2.23.0"
|
|
134
135
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apex-code-coverage-transformer",
|
|
3
3
|
"description": "Transform Salesforce Apex code coverage JSONs into other formats accepted by SonarQube, GitHub, GitLab, Azure, Bitbucket, etc.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.23.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@oclif/core": "4.8.3",
|
|
7
7
|
"@salesforce/core": "8.26.3",
|
|
8
8
|
"@salesforce/sf-plugins-core": "12.2.6",
|
|
9
|
-
"fast-xml-builder": "1.2.0"
|
|
10
|
-
"minimatch": "10.2.5"
|
|
9
|
+
"fast-xml-builder": "1.2.0"
|
|
11
10
|
},
|
|
12
11
|
"devDependencies": {
|
|
13
12
|
"@commitlint/cli": "19.8.1",
|