xcodebuild-axi 0.1.10 → 0.1.11
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 +75 -1
- package/README.md +23 -34
- package/dist/src/commands/coverage.d.ts +13 -2
- package/dist/src/commands/coverage.js +314 -7
- package/dist/src/commands/coverage.js.map +1 -1
- package/dist/src/commands/result.d.ts +11 -3
- package/dist/src/commands/result.js +367 -6
- package/dist/src/commands/result.js.map +1 -1
- package/dist/src/surface.js +11 -55
- package/dist/src/surface.js.map +1 -1
- package/dist/src/toon.d.ts +2 -0
- package/dist/src/toon.js +15 -0
- package/dist/src/toon.js.map +1 -1
- package/dist/src/xccov.d.ts +94 -0
- package/dist/src/xccov.js +178 -2
- package/dist/src/xccov.js.map +1 -1
- package/dist/src/xcodebuild.d.ts +18 -0
- package/dist/src/xcodebuild.js +38 -1
- package/dist/src/xcodebuild.js.map +1 -1
- package/dist/src/xcresult.d.ts +102 -0
- package/dist/src/xcresult.js +122 -0
- package/dist/src/xcresult.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,79 @@ Notable changes to `xcodebuild-axi`. Versions follow
|
|
|
4
4
|
[semver](https://semver.org/); the format follows
|
|
5
5
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [0.1.11] - 2026-09-21
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`result --export <what>` gets files out of a bundle**: `attachments`,
|
|
12
|
+
`diagnostics`, `metrics`, or `evaluations`. A UI test's screenshots, the
|
|
13
|
+
diagnostics report `test --diagnostics` collects, and the CSVs behind a
|
|
14
|
+
performance measurement were all in the bundle and reachable only by shelling
|
|
15
|
+
out to `xcresulttool`.
|
|
16
|
+
|
|
17
|
+
It writes under `~/Library/Caches/xcodebuild-axi/exports/` by default, or
|
|
18
|
+
wherever `--to` says — never into the working tree, so asking what is in a CI
|
|
19
|
+
artifact cannot dirty the checkout it sits in. `--test`, `--filter '*.png'`
|
|
20
|
+
and `--failures` narrow what comes out, and each is **refused** where it does
|
|
21
|
+
not apply rather than ignored: a diagnostics report covers the whole run, so
|
|
22
|
+
`--test` beside it would answer a different question than the one asked.
|
|
23
|
+
|
|
24
|
+
The report is what landed and where, with each exported file tied back to the
|
|
25
|
+
test that produced it — a screenshot's filename is a UUID, and the manifest
|
|
26
|
+
is the only thing that makes it findable. `xcresulttool` narrates an
|
|
27
|
+
attachment export with one "Skipped export for <test>: no matching
|
|
28
|
+
attachments" per test, which is dropped.
|
|
29
|
+
|
|
30
|
+
- **`result --against <baseline.xcresult>`** answers the question CI actually
|
|
31
|
+
asks — not "did this run fail" but "did it fail in a way the last one did
|
|
32
|
+
not". It reports the counts on both sides and their direction
|
|
33
|
+
(`failures: 0 → 1 (+1 -0)`), then the tests that newly fail, the ones that
|
|
34
|
+
now pass, the ones added and removed, and any new warning. A failure the
|
|
35
|
+
baseline did not have is listed first, because it is the only part of a
|
|
36
|
+
comparison that stops a merge.
|
|
37
|
+
|
|
38
|
+
Two bundles with nothing in common — a build against a test run — get an
|
|
39
|
+
explicit answer saying so. `xcresulttool` prints a bare `null` there, which
|
|
40
|
+
is otherwise indistinguishable from a clean comparison.
|
|
41
|
+
|
|
42
|
+
- **`result <a> <b> [...] --merge`** combines the bundles of a sharded test run
|
|
43
|
+
into one, which is the only way that run gets a single verdict. The merged
|
|
44
|
+
bundle is read back and reported from, rather than described from its
|
|
45
|
+
inputs. It lands under `~/Library/Caches` unless `--to` says otherwise, and a
|
|
46
|
+
`--to` that already exists is refused rather than written over — the bundle
|
|
47
|
+
under our own cache directory is ours to clear, one the caller named is not.
|
|
48
|
+
|
|
49
|
+
With these two, **`xcresulttool` coverage is 81% of its leaves** and every
|
|
50
|
+
remaining one is deprecated by Xcode or superseded here.
|
|
51
|
+
|
|
52
|
+
- **`coverage` sees everything `xccov` sees.** Five leaves, and the command's
|
|
53
|
+
path argument now also takes an `.xccovreport` or an `.xccovarchive`:
|
|
54
|
+
|
|
55
|
+
- `--functions <file>` is per-function coverage, which is where an uncovered
|
|
56
|
+
branch finally gets a name. A file at 60% says a test is missing; it does
|
|
57
|
+
not say which one.
|
|
58
|
+
- `--lines <file>` is how many times each line ran, read out of the archive
|
|
59
|
+
rather than the report. Consecutive lines that never ran collapse into one
|
|
60
|
+
range — a 400-line file was 400 rows to find the eight that matter.
|
|
61
|
+
- `--against <path>` answers "did coverage drop" from two bundles this tool
|
|
62
|
+
wrote, reporting which way it moved overall and then per file, worst
|
|
63
|
+
first.
|
|
64
|
+
- `--merge` combines the coverage of a sharded run. `xccov merge` takes
|
|
65
|
+
report/archive **pairs** rather than result bundles, so each bundle is
|
|
66
|
+
unpacked with `xcresulttool export coverage` first — that two-step is the
|
|
67
|
+
reason merging coverage across shards is something people give up on.
|
|
68
|
+
|
|
69
|
+
With them, **`xccov` coverage is 100%** and companion coverage overall is
|
|
70
|
+
43.7%.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- `xccov`'s refusals are no longer wrapped in NSError. A bad path came back as
|
|
75
|
+
`Error: Error Domain=XCCovErrorDomain Code=0 "Failed to load result bundle"
|
|
76
|
+
UserInfo={NSLocalizedDescription=Failed to load result bundle,
|
|
77
|
+
NSUnderlyingError=0x… {…}}` — 400 characters around a five-word answer that
|
|
78
|
+
was already in there.
|
|
79
|
+
|
|
7
80
|
## [0.1.10] - 2026-09-21
|
|
8
81
|
|
|
9
82
|
### Added
|
|
@@ -370,7 +443,8 @@ First release.
|
|
|
370
443
|
- 100% of the 117 options `xcodebuild -help` lists are covered, declared in
|
|
371
444
|
`src/surface.ts` and checked against the installed Xcode in CI.
|
|
372
445
|
|
|
373
|
-
[unreleased]: https://github.com/alexrrouse/xcodebuild-axi/compare/v0.1.
|
|
446
|
+
[unreleased]: https://github.com/alexrrouse/xcodebuild-axi/compare/v0.1.11...HEAD
|
|
447
|
+
[0.1.11]: https://github.com/alexrrouse/xcodebuild-axi/compare/v0.1.10...v0.1.11
|
|
374
448
|
[0.1.10]: https://github.com/alexrrouse/xcodebuild-axi/compare/v0.1.9...v0.1.10
|
|
375
449
|
[0.1.9]: https://github.com/alexrrouse/xcodebuild-axi/compare/v0.1.8...v0.1.9
|
|
376
450
|
[0.1.8]: https://github.com/alexrrouse/xcodebuild-axi/compare/v0.1.7...v0.1.8
|
package/README.md
CHANGED
|
@@ -204,44 +204,33 @@ The one action left out is `installsrc` — it copies sources into `SRCROOT` as
|
|
|
204
204
|
|
|
205
205
|
### Companion tools
|
|
206
206
|
|
|
207
|
-
`xcresulttool`, `xccov` and `simctl` are not xcodebuild, so they are not in the number above — but this tool wraps all three, and an agent that has to shell out to one directly has dropped back down. **
|
|
207
|
+
`xcresulttool`, `xccov` and `simctl` are not xcodebuild, so they are not in the number above — but this tool wraps all three, and an agent that has to shell out to one directly has dropped back down. **43.7% of 71 leaves**, counted the same way:
|
|
208
208
|
|
|
209
|
-
| Tool | Leaves | Covered
|
|
210
|
-
| -------------- | ------ |
|
|
211
|
-
| `xcresulttool` | 21 |
|
|
212
|
-
| `xccov` | 9 |
|
|
213
|
-
| `simctl` | 41 | 5 (12.2%)
|
|
209
|
+
| Tool | Leaves | Covered |
|
|
210
|
+
| -------------- | ------ | --------- |
|
|
211
|
+
| `xcresulttool` | 21 | 17 (81%) |
|
|
212
|
+
| `xccov` | 9 | 9 (100%) |
|
|
213
|
+
| `simctl` | 41 | 5 (12.2%) |
|
|
214
214
|
|
|
215
215
|
### Still open
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
| Leaf
|
|
220
|
-
|
|
|
221
|
-
| `
|
|
222
|
-
| `
|
|
223
|
-
| `
|
|
224
|
-
| `
|
|
225
|
-
| `
|
|
226
|
-
| `
|
|
227
|
-
| `
|
|
228
|
-
| `
|
|
229
|
-
| `
|
|
230
|
-
| `
|
|
231
|
-
| `
|
|
232
|
-
| `simctl
|
|
233
|
-
| `simctl
|
|
234
|
-
| `simctl terminate` | `?` | a running app cannot be stopped |
|
|
235
|
-
| `simctl uninstall` | `?` | an installed app cannot be removed |
|
|
236
|
-
| `simctl listapps` | `sim` | what is installed on a simulator cannot be listed |
|
|
237
|
-
| `simctl create` | `?` | a missing device cannot be created |
|
|
238
|
-
| `simctl delete` | `sim` | stale devices cannot be reclaimed, and they cost gigabytes |
|
|
239
|
-
| `simctl io` | `sim` | a screenshot of a failing UI cannot be taken |
|
|
240
|
-
| `simctl openurl` | `sim` | a deep link cannot be opened, which is how deep links are tested |
|
|
241
|
-
| `simctl privacy` | `sim` | a permission prompt cannot be granted ahead of a UI test |
|
|
242
|
-
| `simctl push` | `sim` | a push notification cannot be simulated |
|
|
243
|
-
| `simctl status_bar` | `sim` | the status bar cannot be pinned, which screenshot tests need |
|
|
244
|
-
| `simctl ui` | `sim` | dark mode and content size cannot be set for a test run |
|
|
217
|
+
13 leaves are known gaps rather than decisions — each one a reason someone would still reach for the raw tool:
|
|
218
|
+
|
|
219
|
+
| Leaf | Unreachable from | What that costs |
|
|
220
|
+
| ------------------- | ---------------- | ---------------------------------------------------------------- |
|
|
221
|
+
| `simctl install` | `sim` | a built .app cannot be put on the simulator it was built for |
|
|
222
|
+
| `simctl launch` | `sim` | the app a build just produced cannot be run |
|
|
223
|
+
| `simctl terminate` | `?` | a running app cannot be stopped |
|
|
224
|
+
| `simctl uninstall` | `?` | an installed app cannot be removed |
|
|
225
|
+
| `simctl listapps` | `sim` | what is installed on a simulator cannot be listed |
|
|
226
|
+
| `simctl create` | `?` | a missing device cannot be created |
|
|
227
|
+
| `simctl delete` | `sim` | stale devices cannot be reclaimed, and they cost gigabytes |
|
|
228
|
+
| `simctl io` | `sim` | a screenshot of a failing UI cannot be taken |
|
|
229
|
+
| `simctl openurl` | `sim` | a deep link cannot be opened, which is how deep links are tested |
|
|
230
|
+
| `simctl privacy` | `sim` | a permission prompt cannot be granted ahead of a UI test |
|
|
231
|
+
| `simctl push` | `sim` | a push notification cannot be simulated |
|
|
232
|
+
| `simctl status_bar` | `sim` | the status bar cannot be pinned, which screenshot tests need |
|
|
233
|
+
| `simctl ui` | `sim` | dark mode and content size cannot be set for a test run |
|
|
245
234
|
|
|
246
235
|
The denominator is read from `xcodebuild -help` rather than hand-maintained, and this table is written against **Xcode 27.0** — the option list moves between releases. `npm run coverage:check` fails on that Xcode if an option here is unclassified or has been dropped, and reports the difference without failing on any other.
|
|
247
236
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const
|
|
1
|
+
import { type CoverageLine } from "../xccov.js";
|
|
2
|
+
export declare const COVERAGE_HELP = "usage: xcodebuild-axi coverage <path> [flags]\nReads code coverage out of a result bundle \u2014 one percentage per target, not the\nthousands of per-file lines xccov prints by default. The path can also be an\n.xccovreport or .xccovarchive.\nflags[9]:\n --files list per-file coverage as well as per-target\n --target <name> only this target\n --below <percent> only files under this coverage, e.g. --below 50\n --functions <file> per-function coverage for one file, so an uncovered\n branch has a name\n --lines <file> how many times each line of one file ran\n --against <path> compare coverage with an earlier run: what moved, and\n which files went with it\n --merge combine the coverage of two or more runs into one report\n --to <path> where --merge writes (default: under ~/Library/Caches)\n --max <n> rows to list before summarizing the rest (default: 25)\nnote:\n Coverage has to have been collected. Run the tests with\n `xcodebuild-axi test --coverage` if the bundle has none.\n\n --lines reads the archive rather than the report: the report knows what\n percentage of a file ran, the archive knows how many times each line did.\nexamples:\n xcodebuild-axi coverage ~/Library/Caches/xcodebuild-axi/MyApps-1a2b3c4d/MyApp-test.xcresult\n xcodebuild-axi coverage build/MyApp.xcresult --files --below 50\n xcodebuild-axi coverage build/MyApp.xcresult --functions Checkout.swift\n xcodebuild-axi coverage build/MyApp.xcresult --against build/baseline.xcresult\n";
|
|
3
|
+
export declare const COVERAGE_FLAGS: readonly ["--files", "--target", "--below", "--functions", "--lines", "--against", "--merge", "--to", "--max"];
|
|
3
4
|
export declare function coverageCommand(args: string[]): Promise<string>;
|
|
5
|
+
/** Consecutive lines that never ran, as ranges rather than one row each. */
|
|
6
|
+
export declare function uncoveredRanges(lines: CoverageLine[]): Array<Record<string, unknown>>;
|
|
7
|
+
/**
|
|
8
|
+
* Which way coverage moved, in words.
|
|
9
|
+
*
|
|
10
|
+
* Words rather than a signed percentage because TOON quotes any scalar that
|
|
11
|
+
* starts with `-`, and `"-2.1%"` costs more in quotes than `down 2.1%` costs
|
|
12
|
+
* in letters.
|
|
13
|
+
*/
|
|
14
|
+
export declare function movement(delta: number): string;
|
|
@@ -1,31 +1,59 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
2
3
|
import { AxiError } from "../errors.js";
|
|
3
|
-
import { percent, readCoverage } from "../xccov.js";
|
|
4
|
+
import { coverageSource, mergeCoverage, percent, readArchiveFiles, readCoverage, readCoverageDiff, readFileLines, readFunctions, } from "../xccov.js";
|
|
4
5
|
import { relativize } from "../xcresult.js";
|
|
6
|
+
import { mergedCoveragePath } from "../xcodebuild.js";
|
|
5
7
|
import { renderFields, renderHelp, renderList, renderOutput, tildePath, } from "../toon.js";
|
|
6
8
|
import { getFlag, getIntFlag, hasFlag, positionals, rejectUnknownFlags, } from "../args.js";
|
|
7
|
-
export const COVERAGE_HELP = `usage: xcodebuild-axi coverage <path
|
|
9
|
+
export const COVERAGE_HELP = `usage: xcodebuild-axi coverage <path> [flags]
|
|
8
10
|
Reads code coverage out of a result bundle — one percentage per target, not the
|
|
9
|
-
thousands of per-file lines xccov prints by default.
|
|
10
|
-
|
|
11
|
+
thousands of per-file lines xccov prints by default. The path can also be an
|
|
12
|
+
.xccovreport or .xccovarchive.
|
|
13
|
+
flags[9]:
|
|
11
14
|
--files list per-file coverage as well as per-target
|
|
12
15
|
--target <name> only this target
|
|
13
16
|
--below <percent> only files under this coverage, e.g. --below 50
|
|
17
|
+
--functions <file> per-function coverage for one file, so an uncovered
|
|
18
|
+
branch has a name
|
|
19
|
+
--lines <file> how many times each line of one file ran
|
|
20
|
+
--against <path> compare coverage with an earlier run: what moved, and
|
|
21
|
+
which files went with it
|
|
22
|
+
--merge combine the coverage of two or more runs into one report
|
|
23
|
+
--to <path> where --merge writes (default: under ~/Library/Caches)
|
|
14
24
|
--max <n> rows to list before summarizing the rest (default: 25)
|
|
15
25
|
note:
|
|
16
26
|
Coverage has to have been collected. Run the tests with
|
|
17
27
|
\`xcodebuild-axi test --coverage\` if the bundle has none.
|
|
28
|
+
|
|
29
|
+
--lines reads the archive rather than the report: the report knows what
|
|
30
|
+
percentage of a file ran, the archive knows how many times each line did.
|
|
18
31
|
examples:
|
|
19
32
|
xcodebuild-axi coverage ~/Library/Caches/xcodebuild-axi/MyApps-1a2b3c4d/MyApp-test.xcresult
|
|
20
33
|
xcodebuild-axi coverage build/MyApp.xcresult --files --below 50
|
|
34
|
+
xcodebuild-axi coverage build/MyApp.xcresult --functions Checkout.swift
|
|
35
|
+
xcodebuild-axi coverage build/MyApp.xcresult --against build/baseline.xcresult
|
|
21
36
|
`;
|
|
22
37
|
export const COVERAGE_FLAGS = [
|
|
23
38
|
"--files",
|
|
24
39
|
"--target",
|
|
25
40
|
"--below",
|
|
41
|
+
"--functions",
|
|
42
|
+
"--lines",
|
|
43
|
+
"--against",
|
|
44
|
+
"--merge",
|
|
45
|
+
"--to",
|
|
46
|
+
"--max",
|
|
47
|
+
];
|
|
48
|
+
const VALUE_FLAGS = [
|
|
49
|
+
"--target",
|
|
50
|
+
"--below",
|
|
51
|
+
"--functions",
|
|
52
|
+
"--lines",
|
|
53
|
+
"--against",
|
|
54
|
+
"--to",
|
|
26
55
|
"--max",
|
|
27
56
|
];
|
|
28
|
-
const VALUE_FLAGS = ["--target", "--below", "--max"];
|
|
29
57
|
export async function coverageCommand(args) {
|
|
30
58
|
rejectUnknownFlags(args, "coverage", COVERAGE_FLAGS, VALUE_FLAGS);
|
|
31
59
|
const [rawPath] = positionals(args, VALUE_FLAGS);
|
|
@@ -38,6 +66,14 @@ export async function coverageCommand(args) {
|
|
|
38
66
|
const path = resolve(expandTilde(rawPath));
|
|
39
67
|
const below = getIntFlag(args, "--below");
|
|
40
68
|
const max = getIntFlag(args, "--max") ?? 25;
|
|
69
|
+
const mode = soleMode(args);
|
|
70
|
+
if (mode)
|
|
71
|
+
return readMode(mode, path, args, max);
|
|
72
|
+
// An archive holds raw execution counts and no report at all, so the
|
|
73
|
+
// percentages the default view is made of do not exist for one. What it can
|
|
74
|
+
// answer is which files it covers, which is also what --lines takes.
|
|
75
|
+
if (coverageSource(path) === "archive")
|
|
76
|
+
return reportArchive(path, max);
|
|
41
77
|
const targetFilter = getFlag(args, "--target")?.toLowerCase();
|
|
42
78
|
// A --below filter is meaningless without the files it filters, so imply it
|
|
43
79
|
// rather than returning an empty list the agent has to debug.
|
|
@@ -100,7 +136,7 @@ export async function coverageCommand(args) {
|
|
|
100
136
|
: "files", shown));
|
|
101
137
|
}
|
|
102
138
|
}
|
|
103
|
-
blocks.push(renderFields(
|
|
139
|
+
blocks.push(renderFields(sourceField(path)));
|
|
104
140
|
const hints = [];
|
|
105
141
|
if (!wantFiles) {
|
|
106
142
|
hints.push(`Run \`xcodebuild-axi coverage ${rawPath} --files\` for per-file coverage`);
|
|
@@ -109,6 +145,277 @@ export async function coverageCommand(args) {
|
|
|
109
145
|
blocks.push(renderHelp(hints));
|
|
110
146
|
return renderOutput(blocks);
|
|
111
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Name the path by what it is. A `.xccovreport` reported as `bundle:` is a
|
|
150
|
+
* path the next call cannot reuse the same way.
|
|
151
|
+
*/
|
|
152
|
+
function sourceField(path) {
|
|
153
|
+
const kind = coverageSource(path);
|
|
154
|
+
return { [kind]: tildePath(path) };
|
|
155
|
+
}
|
|
156
|
+
/** What an .xccovarchive can answer on its own: which files it holds. */
|
|
157
|
+
async function reportArchive(path, max) {
|
|
158
|
+
const files = await readArchiveFiles(path);
|
|
159
|
+
const shown = files.slice(0, max).map((file) => ({ file: relativize(file) }));
|
|
160
|
+
return renderOutput([
|
|
161
|
+
renderFields({ archive: tildePath(path), files: files.length }),
|
|
162
|
+
files.length > 0
|
|
163
|
+
? renderList(files.length > shown.length
|
|
164
|
+
? `files (${shown.length} of ${files.length})`
|
|
165
|
+
: "files", shown)
|
|
166
|
+
: renderFields({ files: "none — this archive holds no coverage" }),
|
|
167
|
+
renderHelp([
|
|
168
|
+
`Run \`xcodebuild-axi coverage ${tildePath(path)} --lines <file>\` for the lines that never ran`,
|
|
169
|
+
]),
|
|
170
|
+
]);
|
|
171
|
+
}
|
|
172
|
+
/** The one coverage question this invocation is for, if not the default. */
|
|
173
|
+
const MODES = ["--functions", "--lines", "--against", "--merge"];
|
|
174
|
+
function soleMode(args) {
|
|
175
|
+
const asked = MODES.filter((mode) => args.includes(mode));
|
|
176
|
+
if (asked.length > 1) {
|
|
177
|
+
throw new AxiError(`${asked.join(" and ")} ask different questions — pass one`, "VALIDATION_ERROR", [`each is its own read of the coverage data: ${MODES.join(", ")}`]);
|
|
178
|
+
}
|
|
179
|
+
return asked[0];
|
|
180
|
+
}
|
|
181
|
+
async function readMode(mode, path, args, max) {
|
|
182
|
+
switch (mode) {
|
|
183
|
+
case "--functions":
|
|
184
|
+
return reportFunctions(path, requireValue(args, "--functions"), max);
|
|
185
|
+
case "--lines":
|
|
186
|
+
return reportLines(path, requireValue(args, "--lines"), max);
|
|
187
|
+
case "--against":
|
|
188
|
+
return reportDiff(path, resolve(expandTilde(requireValue(args, "--against"))), max);
|
|
189
|
+
case "--merge":
|
|
190
|
+
return runMerge(path, args, max);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function requireValue(args, flag) {
|
|
194
|
+
const value = getFlag(args, flag);
|
|
195
|
+
if (value === undefined) {
|
|
196
|
+
throw new AxiError(`${flag} needs a value`, "VALIDATION_ERROR", [
|
|
197
|
+
`xcodebuild-axi coverage <path> ${flag} <value>`,
|
|
198
|
+
]);
|
|
199
|
+
}
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Per-function coverage, which is where an uncovered branch gets a name.
|
|
204
|
+
*
|
|
205
|
+
* A file at 60% says a test is missing; it does not say which one. The
|
|
206
|
+
* function list does, and it is sorted with the least covered first because
|
|
207
|
+
* that is the row someone is looking for.
|
|
208
|
+
*/
|
|
209
|
+
async function reportFunctions(path, file, max) {
|
|
210
|
+
const found = await readFunctions(path, file);
|
|
211
|
+
const functions = found.flatMap((entry) => entry.functions);
|
|
212
|
+
if (functions.length === 0) {
|
|
213
|
+
return renderOutput([
|
|
214
|
+
renderFields({
|
|
215
|
+
functions: `no coverage recorded for a file named '${file}'`,
|
|
216
|
+
}),
|
|
217
|
+
renderFields(sourceField(path)),
|
|
218
|
+
renderHelp([
|
|
219
|
+
`Run \`xcodebuild-axi coverage ${tildePath(path)} --files\` to see which files the report covers`,
|
|
220
|
+
"The name is matched against the path the file had when the report was written",
|
|
221
|
+
]),
|
|
222
|
+
]);
|
|
223
|
+
}
|
|
224
|
+
const sorted = functions
|
|
225
|
+
.slice()
|
|
226
|
+
.sort((a, b) => a.lineCoverage - b.lineCoverage);
|
|
227
|
+
const shown = sorted.slice(0, max).map(functionRow);
|
|
228
|
+
return renderOutput([
|
|
229
|
+
renderFields({
|
|
230
|
+
file: relativize(found[0]?.file ?? file),
|
|
231
|
+
functions: functions.length,
|
|
232
|
+
uncovered: functions.filter((fn) => fn.executionCount === 0).length,
|
|
233
|
+
}),
|
|
234
|
+
renderList(sorted.length > shown.length
|
|
235
|
+
? `functions (${shown.length} of ${sorted.length})`
|
|
236
|
+
: "functions", shown),
|
|
237
|
+
renderFields(sourceField(path)),
|
|
238
|
+
]);
|
|
239
|
+
}
|
|
240
|
+
function functionRow(fn) {
|
|
241
|
+
return {
|
|
242
|
+
function: fn.name,
|
|
243
|
+
line: fn.lineNumber,
|
|
244
|
+
coverage: percent(fn.lineCoverage),
|
|
245
|
+
lines: `${fn.coveredLines}/${fn.executableLines}`,
|
|
246
|
+
runs: fn.executionCount,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Per-line execution counts, reported as the ranges that did not run.
|
|
251
|
+
*
|
|
252
|
+
* Printing one row per line is the thing `xccov` already does and the thing
|
|
253
|
+
* nobody can read: a 400-line file is 400 rows to find the eight that matter.
|
|
254
|
+
* Consecutive uncovered lines collapse into a range instead.
|
|
255
|
+
*/
|
|
256
|
+
async function reportLines(path, file, max) {
|
|
257
|
+
const lines = await readFileLines(path, file).catch(async (error) => {
|
|
258
|
+
// xccov answers an unknown file with a load failure rather than a list, so
|
|
259
|
+
// the list is what the refusal carries.
|
|
260
|
+
const candidates = await readArchiveFiles(path).catch(() => []);
|
|
261
|
+
if (candidates.length === 0)
|
|
262
|
+
throw error;
|
|
263
|
+
const near = candidates.filter((candidate) => candidate.includes(file));
|
|
264
|
+
throw new AxiError(`No coverage recorded for '${file}'`, "VALIDATION_ERROR", near.length > 0
|
|
265
|
+
? [`did you mean: ${near.slice(0, 5).join(", ")}`]
|
|
266
|
+
: [
|
|
267
|
+
`Run \`xcodebuild-axi coverage ${tildePath(path)} --files\` to see the files this archive holds`,
|
|
268
|
+
]);
|
|
269
|
+
});
|
|
270
|
+
const executable = lines.filter((line) => line.isExecutable);
|
|
271
|
+
const covered = executable.filter((line) => line.executionCount > 0).length;
|
|
272
|
+
const gaps = uncoveredRanges(executable);
|
|
273
|
+
const shown = gaps.slice(0, max);
|
|
274
|
+
return renderOutput([
|
|
275
|
+
renderFields({
|
|
276
|
+
file: relativize(file),
|
|
277
|
+
coverage: percent(executable.length > 0 ? covered / executable.length : 0),
|
|
278
|
+
lines: `${covered} of ${executable.length} covered`,
|
|
279
|
+
}),
|
|
280
|
+
gaps.length === 0
|
|
281
|
+
? renderFields({ uncovered: "none — every executable line ran" })
|
|
282
|
+
: renderList(gaps.length > shown.length
|
|
283
|
+
? `uncovered (${shown.length} of ${gaps.length})`
|
|
284
|
+
: "uncovered", shown),
|
|
285
|
+
renderFields(sourceField(path)),
|
|
286
|
+
]);
|
|
287
|
+
}
|
|
288
|
+
/** Consecutive lines that never ran, as ranges rather than one row each. */
|
|
289
|
+
export function uncoveredRanges(lines) {
|
|
290
|
+
const ranges = [];
|
|
291
|
+
for (const line of lines) {
|
|
292
|
+
if (line.executionCount > 0)
|
|
293
|
+
continue;
|
|
294
|
+
const last = ranges[ranges.length - 1];
|
|
295
|
+
if (last && line.line === last.to + 1)
|
|
296
|
+
last.to = line.line;
|
|
297
|
+
else
|
|
298
|
+
ranges.push({ from: line.line, to: line.line });
|
|
299
|
+
}
|
|
300
|
+
return ranges.map((range) => ({
|
|
301
|
+
lines: range.from === range.to ? `${range.from}` : `${range.from}-${range.to}`,
|
|
302
|
+
count: range.to - range.from + 1,
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* `--against`, which answers "did coverage drop" without a spreadsheet.
|
|
307
|
+
*
|
|
308
|
+
* The headline is the delta, because a coverage check in CI is a comparison
|
|
309
|
+
* rather than a threshold most of the time.
|
|
310
|
+
*/
|
|
311
|
+
async function reportDiff(path, baseline, max) {
|
|
312
|
+
// xccov's argument order is before, after; the bundle being asked about is
|
|
313
|
+
// the after, so the baseline goes first.
|
|
314
|
+
const diff = await readCoverageDiff(baseline, path);
|
|
315
|
+
const overall = diff.lineCoverageDelta ?? {};
|
|
316
|
+
const blocks = [
|
|
317
|
+
renderFields({
|
|
318
|
+
coverage: movement(overall.lineCoverageDelta ?? 0),
|
|
319
|
+
covered_lines: overall.coveredLinesDelta ?? 0,
|
|
320
|
+
executable_lines: overall.executableLinesDelta ?? 0,
|
|
321
|
+
}),
|
|
322
|
+
];
|
|
323
|
+
// Sorted on the number and rendered afterwards: "down 45.5%" does not
|
|
324
|
+
// compare as a number, and the biggest drop is the row being looked for.
|
|
325
|
+
const moved = (diff.targetDeltas ?? [])
|
|
326
|
+
.flatMap((target) => (target.fileDeltas ?? []).map((file) => ({
|
|
327
|
+
target: target.name ?? "",
|
|
328
|
+
file: relativize(file.documentLocation ?? ""),
|
|
329
|
+
delta: file.lineCoverageDelta?.lineCoverageDelta ?? 0,
|
|
330
|
+
lines: file.lineCoverageDelta?.coveredLinesDelta ?? 0,
|
|
331
|
+
})))
|
|
332
|
+
.sort((a, b) => a.delta - b.delta);
|
|
333
|
+
if (moved.length > 0) {
|
|
334
|
+
const shown = moved.slice(0, max).map(({ target, file, delta, lines }) => ({
|
|
335
|
+
target,
|
|
336
|
+
file,
|
|
337
|
+
coverage: movement(delta),
|
|
338
|
+
lines,
|
|
339
|
+
}));
|
|
340
|
+
blocks.push(renderList(moved.length > shown.length
|
|
341
|
+
? `files (${shown.length} of ${moved.length})`
|
|
342
|
+
: "files", shown));
|
|
343
|
+
}
|
|
344
|
+
const added = namesOf(diff, "addedFiles");
|
|
345
|
+
const removed = namesOf(diff, "removedFiles");
|
|
346
|
+
if (added.length > 0)
|
|
347
|
+
blocks.push(renderFields({ added_files: added }));
|
|
348
|
+
if (removed.length > 0)
|
|
349
|
+
blocks.push(renderFields({ removed_files: removed }));
|
|
350
|
+
if (blocks.length === 1 && moved.length === 0) {
|
|
351
|
+
blocks.push(renderFields({ difference: "none — coverage matches the baseline" }));
|
|
352
|
+
}
|
|
353
|
+
return renderOutput([
|
|
354
|
+
...blocks,
|
|
355
|
+
renderFields({ baseline: tildePath(baseline), ...sourceField(path) }),
|
|
356
|
+
]);
|
|
357
|
+
}
|
|
358
|
+
function namesOf(diff, key) {
|
|
359
|
+
return (diff.targetDeltas ?? []).flatMap((target) => (target[key] ?? []).map((file) => relativize(file.documentLocation ?? "")));
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Which way coverage moved, in words.
|
|
363
|
+
*
|
|
364
|
+
* Words rather than a signed percentage because TOON quotes any scalar that
|
|
365
|
+
* starts with `-`, and `"-2.1%"` costs more in quotes than `down 2.1%` costs
|
|
366
|
+
* in letters.
|
|
367
|
+
*/
|
|
368
|
+
export function movement(delta) {
|
|
369
|
+
if (delta === 0)
|
|
370
|
+
return "unchanged";
|
|
371
|
+
return `${delta > 0 ? "up" : "down"} ${percent(Math.abs(delta))}`;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* `--merge`, which combines the coverage of a sharded run.
|
|
375
|
+
*
|
|
376
|
+
* `xccov merge` wants report/archive pairs rather than result bundles, so the
|
|
377
|
+
* bundles are unpacked first — the two-step that makes this something people
|
|
378
|
+
* give up on doing in CI.
|
|
379
|
+
*/
|
|
380
|
+
async function runMerge(first, args, max) {
|
|
381
|
+
const paths = positionals(args, VALUE_FLAGS).map((path) => resolve(expandTilde(path)));
|
|
382
|
+
if (paths.length < 2) {
|
|
383
|
+
throw new AxiError(`--merge combines the coverage of two or more runs, and ${paths.length} was given`, "VALIDATION_ERROR", [
|
|
384
|
+
"xcodebuild-axi coverage shard1.xcresult shard2.xcresult --merge",
|
|
385
|
+
"`xcodebuild-axi test --coverage` prints the bundle path it wrote",
|
|
386
|
+
]);
|
|
387
|
+
}
|
|
388
|
+
const requested = getFlag(args, "--to");
|
|
389
|
+
const outReport = requested
|
|
390
|
+
? resolve(expandTilde(requested))
|
|
391
|
+
: mergedCoveragePath(paths);
|
|
392
|
+
const outArchive = outReport.replace(/\.xccovreport$/, "") + ".xccovarchive";
|
|
393
|
+
if (requested && (existsSync(outReport) || existsSync(outArchive))) {
|
|
394
|
+
throw new AxiError(`Something is already at ${tildePath(outReport)}`, "VALIDATION_ERROR", [
|
|
395
|
+
"Pass a path that does not exist yet, or drop --to to write under ~/Library/Caches",
|
|
396
|
+
]);
|
|
397
|
+
}
|
|
398
|
+
if (!requested) {
|
|
399
|
+
rmSync(outReport, { recursive: true, force: true });
|
|
400
|
+
rmSync(outArchive, { recursive: true, force: true });
|
|
401
|
+
}
|
|
402
|
+
mkdirSync(dirname(outReport), { recursive: true });
|
|
403
|
+
await mergeCoverage(paths, outReport, outArchive);
|
|
404
|
+
const merged = await readCoverage(outReport);
|
|
405
|
+
return renderOutput([
|
|
406
|
+
renderFields({
|
|
407
|
+
merged: paths.length,
|
|
408
|
+
coverage: percent(merged.lineCoverage),
|
|
409
|
+
lines: `${merged.coveredLines} of ${merged.executableLines} covered`,
|
|
410
|
+
report: tildePath(outReport),
|
|
411
|
+
archive: tildePath(outArchive),
|
|
412
|
+
}),
|
|
413
|
+
renderList("from", paths.slice(0, max).map((path) => ({ bundle: tildePath(path) }))),
|
|
414
|
+
renderHelp([
|
|
415
|
+
`Run \`xcodebuild-axi coverage ${tildePath(outReport)} --files\` to report on the merged coverage`,
|
|
416
|
+
]),
|
|
417
|
+
]);
|
|
418
|
+
}
|
|
112
419
|
function expandTilde(path) {
|
|
113
420
|
const home = process.env["HOME"];
|
|
114
421
|
return home && path.startsWith("~/") ? `${home}${path.slice(1)}` : path;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../../src/commands/coverage.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../../src/commands/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import { type BuildResults, type TestNode } from "../xcresult.js";
|
|
2
|
-
export declare const RESULT_HELP = "usage: xcodebuild-axi result <path.xcresult> [flags]\nRe-reads a result bundle that a previous run wrote, without rebuilding.\nflags[
|
|
3
|
-
export declare const RESULT_FLAGS: readonly ["--failures", "--warnings", "--tests", "--insights", "--activities", "--metrics", "--log", "--available", "--metadata", "--test", "--max", "--full"];
|
|
1
|
+
import { type BuildResults, type CountDelta, type ExportKind, type TestFailureDelta, type TestNode } from "../xcresult.js";
|
|
2
|
+
export declare const RESULT_HELP = "usage: xcodebuild-axi result <path.xcresult> [flags]\nRe-reads a result bundle that a previous run wrote, without rebuilding.\nflags[17]:\n --failures failures and errors only\n --warnings include the full warning list\n --tests every test the run recorded, as the tree Xcode groups them into\n --insights Xcode's own diagnosis: what failed together, and what was slow\n --activities what one test did, step by step; needs --test\n --metrics what the performance tests measured; --test narrows it\n --log <type> the stored build, action, or console log, as timed sections\n --available what this bundle holds at all: coverage, logs, test results\n --metadata when the bundle was written, and in what format\n --export <what> write part of the bundle out: attachments, diagnostics,\n metrics, or evaluations\n --against <path> compare this run to a baseline bundle: what broke, what\n got fixed, which tests came and went\n --merge combine two or more bundles into one, for a sharded run\n --to <path> where --export or --merge writes (default: under\n ~/Library/Caches)\n --test <id> the test --activities, --metrics or --export is about\n --filter <glob> with --export attachments: filenames to keep, e.g. '*.png'\n --max <n> rows to list before summarizing the rest (default: 20)\n --full untruncated messages\nnote:\n Everything here reads the bundle a run already wrote, so none of it rebuilds\n anything. --available is the cheapest first question about a bundle from\n somewhere else: it says whether there is coverage or a log to ask for,\n instead of letting you find out by failing to read one.\n\n --export writes files rather than printing them, so it reports what landed\n and where. --failures narrows attachments and evaluations to what a failing\n test produced, which is usually all anyone wants out of a green run's\n hundreds of screenshots.\n\n --against answers 'is this worse than before' in one call: a failure the\n baseline did not have is what a CI check is looking for, and it is reported\n ahead of everything else.\nexamples:\n xcodebuild-axi result ~/Library/Caches/xcodebuild-axi/MyApps-1a2b3c4d/MyApp-iPhone-17-Pro-test.xcresult\n xcodebuild-axi result build/MyApp.xcresult --failures --full\n xcodebuild-axi result build/MyApp.xcresult --log build --max 10\n xcodebuild-axi result build/MyApp.xcresult --activities --test MyAppTests/CheckoutTests/testTotal\n xcodebuild-axi result build/MyApp.xcresult --export attachments --failures\n xcodebuild-axi result build/MyApp.xcresult --against build/baseline.xcresult\n xcodebuild-axi result shard1.xcresult shard2.xcresult --merge\n";
|
|
3
|
+
export declare const RESULT_FLAGS: readonly ["--failures", "--warnings", "--tests", "--insights", "--activities", "--metrics", "--log", "--available", "--metadata", "--export", "--against", "--merge", "--to", "--test", "--filter", "--max", "--full"];
|
|
4
4
|
export declare function resultCommand(args: string[]): Promise<string>;
|
|
5
|
+
/** "0 → 2 (+2 -0)", which says both the level and the direction. */
|
|
6
|
+
export declare function deltaField(delta: CountDelta | undefined): string;
|
|
7
|
+
export declare function failureDeltaRows(deltas: TestFailureDelta[]): Array<Record<string, unknown>>;
|
|
8
|
+
/**
|
|
9
|
+
* The manifest `xcresulttool` writes beside the files it exported, which is
|
|
10
|
+
* the only thing that ties an exported filename back to the test that made it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function manifestRows(outputPath: string, kind: ExportKind): Array<Record<string, unknown>>;
|
|
5
13
|
/**
|
|
6
14
|
* The test tree, flattened to one row per test case.
|
|
7
15
|
*
|