@hominis/fireforge 0.49.2 → 0.51.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 +87 -1
- package/README.md +1 -1
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/commands/build-prelock.d.ts +20 -0
- package/dist/src/commands/build-prelock.js +50 -0
- package/dist/src/commands/build.d.ts +3 -1
- package/dist/src/commands/build.js +13 -6
- package/dist/src/commands/check-report.d.ts +41 -0
- package/dist/src/commands/check-report.js +91 -0
- package/dist/src/commands/check-run.d.ts +33 -0
- package/dist/src/commands/check-run.js +112 -0
- package/dist/src/commands/check-steps.d.ts +75 -0
- package/dist/src/commands/check-steps.js +200 -0
- package/dist/src/commands/check.d.ts +32 -0
- package/dist/src/commands/check.js +160 -0
- package/dist/src/commands/config.js +5 -6
- package/dist/src/commands/declarations-report.d.ts +43 -0
- package/dist/src/commands/declarations-report.js +76 -0
- package/dist/src/commands/doctor-engine-eslint.js +6 -1
- package/dist/src/commands/doctor-source-pin.js +4 -1
- package/dist/src/commands/export-adopt-check.d.ts +38 -0
- package/dist/src/commands/export-adopt-check.js +98 -0
- package/dist/src/commands/export-flow.js +29 -14
- package/dist/src/commands/export-placement-gate.d.ts +6 -2
- package/dist/src/commands/export-placement-gate.js +8 -0
- package/dist/src/commands/export-shared.d.ts +2 -1
- package/dist/src/commands/export-staged-registration.d.ts +46 -0
- package/dist/src/commands/export-staged-registration.js +91 -0
- package/dist/src/commands/forward-import-remedy.d.ts +32 -0
- package/dist/src/commands/forward-import-remedy.js +63 -0
- package/dist/src/commands/furnace/apply.js +3 -3
- package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
- package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
- package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
- package/dist/src/commands/furnace/chrome-doc.js +2 -2
- package/dist/src/commands/furnace/create.js +2 -2
- package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
- package/dist/src/commands/furnace/deploy-named.js +107 -0
- package/dist/src/commands/furnace/deploy.d.ts +3 -2
- package/dist/src/commands/furnace/deploy.js +50 -86
- package/dist/src/commands/furnace/diff.js +26 -3
- package/dist/src/commands/furnace/index.js +66 -41
- package/dist/src/commands/furnace/init.js +13 -6
- package/dist/src/commands/furnace/override.js +4 -2
- package/dist/src/commands/furnace/preview.js +4 -3
- package/dist/src/commands/furnace/refresh.js +2 -2
- package/dist/src/commands/furnace/remove.js +4 -3
- package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
- package/dist/src/commands/furnace/rename-dry-run.js +127 -0
- package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
- package/dist/src/commands/furnace/rename-helpers.js +15 -1
- package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
- package/dist/src/commands/furnace/rename-registrations.js +98 -0
- package/dist/src/commands/furnace/rename.d.ts +2 -1
- package/dist/src/commands/furnace/rename.js +28 -66
- package/dist/src/commands/furnace/scan.d.ts +9 -4
- package/dist/src/commands/furnace/scan.js +11 -9
- package/dist/src/commands/furnace/sync.js +3 -2
- package/dist/src/commands/furnace/validate-report.d.ts +45 -0
- package/dist/src/commands/furnace/validate-report.js +91 -0
- package/dist/src/commands/furnace/validate.d.ts +1 -1
- package/dist/src/commands/furnace/validate.js +151 -113
- package/dist/src/commands/furnace/validation-output.js +14 -3
- package/dist/src/commands/lint-per-patch.js +36 -61
- package/dist/src/commands/lint-per-run-checkjs.js +2 -2
- package/dist/src/commands/lint-report.d.ts +8 -4
- package/dist/src/commands/lint-report.js +20 -5
- package/dist/src/commands/lint.js +15 -34
- package/dist/src/commands/manifest.js +4 -0
- package/dist/src/commands/park.d.ts +22 -0
- package/dist/src/commands/park.js +232 -0
- package/dist/src/commands/patch/delete-gap-notice.js +3 -1
- package/dist/src/commands/patch/delete.d.ts +1 -1
- package/dist/src/commands/patch/delete.js +24 -104
- package/dist/src/commands/patch/index.d.ts +3 -3
- package/dist/src/commands/patch/index.js +10 -4
- package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
- package/dist/src/commands/patch/lint-ignore-from.js +142 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
- package/dist/src/commands/patch/lint-ignore.js +78 -31
- package/dist/src/commands/patch/move-files-create.js +34 -18
- package/dist/src/commands/patch/move-files-into.js +15 -7
- package/dist/src/commands/patch/move-files.js +6 -2
- package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
- package/dist/src/commands/patch/removal-created-files.js +83 -0
- package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
- package/dist/src/commands/patch/removal-dependents.js +133 -0
- package/dist/src/commands/patch/rename.js +20 -1
- package/dist/src/commands/patch/reserve.d.ts +33 -0
- package/dist/src/commands/patch/reserve.js +152 -0
- package/dist/src/commands/patch/retire.d.ts +34 -0
- package/dist/src/commands/patch/retire.js +133 -0
- package/dist/src/commands/patch/split-plan.d.ts +17 -8
- package/dist/src/commands/patch/split-plan.js +60 -28
- package/dist/src/commands/patch/split-staged.d.ts +108 -0
- package/dist/src/commands/patch/split-staged.js +202 -0
- package/dist/src/commands/patch/split.d.ts +5 -0
- package/dist/src/commands/patch/split.js +62 -17
- package/dist/src/commands/patch/stage.d.ts +34 -0
- package/dist/src/commands/patch/stage.js +153 -0
- package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
- package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
- package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
- package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
- package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
- package/dist/src/commands/patch/staged-dependency-from.js +108 -0
- package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
- package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
- package/dist/src/commands/patch/staged-dependency.js +54 -139
- package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
- package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
- package/dist/src/commands/re-export-adjacent.d.ts +50 -2
- package/dist/src/commands/re-export-adjacent.js +160 -40
- package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
- package/dist/src/commands/re-export-bulk-scan.js +22 -7
- package/dist/src/commands/re-export-drift.d.ts +36 -8
- package/dist/src/commands/re-export-drift.js +73 -49
- package/dist/src/commands/re-export-files.js +11 -8
- package/dist/src/commands/re-export-hunks.d.ts +35 -0
- package/dist/src/commands/re-export-hunks.js +220 -0
- package/dist/src/commands/re-export-lint.d.ts +2 -1
- package/dist/src/commands/re-export-lint.js +23 -10
- package/dist/src/commands/re-export-options.js +74 -6
- package/dist/src/commands/re-export-preflight.d.ts +23 -0
- package/dist/src/commands/re-export-preflight.js +160 -0
- package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
- package/dist/src/commands/re-export-purity-scope.js +131 -0
- package/dist/src/commands/re-export-register.js +56 -17
- package/dist/src/commands/re-export-removed.d.ts +13 -2
- package/dist/src/commands/re-export-removed.js +57 -12
- package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
- package/dist/src/commands/re-export-scan-owner.js +116 -0
- package/dist/src/commands/re-export-scan.d.ts +19 -9
- package/dist/src/commands/re-export-scan.js +60 -24
- package/dist/src/commands/re-export-single.js +122 -46
- package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
- package/dist/src/commands/re-export-stale-registrations.js +62 -0
- package/dist/src/commands/re-export-summary.d.ts +28 -0
- package/dist/src/commands/re-export-summary.js +36 -0
- package/dist/src/commands/re-export.js +71 -57
- package/dist/src/commands/rebase/index.js +17 -17
- package/dist/src/commands/run.js +16 -2
- package/dist/src/commands/status-check.d.ts +55 -16
- package/dist/src/commands/status-check.js +92 -37
- package/dist/src/commands/status-json.d.ts +22 -9
- package/dist/src/commands/status-json.js +47 -32
- package/dist/src/commands/status-output.js +3 -1
- package/dist/src/commands/status-scope.d.ts +37 -0
- package/dist/src/commands/status-scope.js +54 -0
- package/dist/src/commands/status.js +66 -23
- package/dist/src/commands/test-browser-preflight.js +19 -3
- package/dist/src/commands/test-build-furnace.d.ts +22 -0
- package/dist/src/commands/test-build-furnace.js +54 -0
- package/dist/src/commands/test-build-phase.js +64 -41
- package/dist/src/commands/test-checkjs.js +10 -2
- package/dist/src/commands/test-diagnose.js +7 -0
- package/dist/src/commands/test-dispatch.d.ts +39 -0
- package/dist/src/commands/test-dispatch.js +211 -0
- package/dist/src/commands/test-furnace-reach.d.ts +37 -0
- package/dist/src/commands/test-furnace-reach.js +132 -0
- package/dist/src/commands/test-modes.d.ts +16 -1
- package/dist/src/commands/test-modes.js +24 -1
- package/dist/src/commands/test-multi-verdict.d.ts +61 -0
- package/dist/src/commands/test-multi-verdict.js +111 -0
- package/dist/src/commands/test-orchestrate.d.ts +52 -0
- package/dist/src/commands/test-orchestrate.js +240 -0
- package/dist/src/commands/test-perf-scope.d.ts +50 -0
- package/dist/src/commands/test-perf-scope.js +138 -0
- package/dist/src/commands/test-prelock.d.ts +51 -0
- package/dist/src/commands/test-prelock.js +273 -0
- package/dist/src/commands/test-register.js +69 -10
- package/dist/src/commands/test-results.d.ts +62 -0
- package/dist/src/commands/test-results.js +62 -0
- package/dist/src/commands/test-run.d.ts +13 -55
- package/dist/src/commands/test-run.js +74 -99
- package/dist/src/commands/test-shards.d.ts +110 -0
- package/dist/src/commands/test-shards.js +255 -0
- package/dist/src/commands/test-stale-gate.d.ts +5 -1
- package/dist/src/commands/test-stale-gate.js +60 -28
- package/dist/src/commands/test-verdict.d.ts +11 -1
- package/dist/src/commands/test-verdict.js +28 -1
- package/dist/src/commands/test.d.ts +6 -1
- package/dist/src/commands/test.js +120 -124
- package/dist/src/commands/token-lint.d.ts +14 -0
- package/dist/src/commands/token-lint.js +151 -0
- package/dist/src/commands/token.js +10 -0
- package/dist/src/commands/verify-scope.d.ts +28 -0
- package/dist/src/commands/verify-scope.js +67 -0
- package/dist/src/commands/verify.d.ts +10 -2
- package/dist/src/commands/verify.js +67 -36
- package/dist/src/core/build-baseline-types.d.ts +46 -0
- package/dist/src/core/build-baseline-validate.js +19 -0
- package/dist/src/core/build-baseline.d.ts +5 -1
- package/dist/src/core/build-baseline.js +3 -1
- package/dist/src/core/build-overwrite-guard.d.ts +50 -0
- package/dist/src/core/build-overwrite-guard.js +84 -4
- package/dist/src/core/build-prepare.d.ts +13 -0
- package/dist/src/core/build-prepare.js +42 -10
- package/dist/src/core/build-run-record.d.ts +74 -0
- package/dist/src/core/build-run-record.js +136 -0
- package/dist/src/core/checkjs-support-heads.d.ts +41 -0
- package/dist/src/core/checkjs-support-heads.js +104 -0
- package/dist/src/core/config-paths.d.ts +2 -2
- package/dist/src/core/config-paths.js +10 -0
- package/dist/src/core/config-validate-check.d.ts +8 -0
- package/dist/src/core/config-validate-check.js +219 -0
- package/dist/src/core/config-validate-file-size.d.ts +9 -6
- package/dist/src/core/config-validate-file-size.js +91 -2
- package/dist/src/core/config-validate-history.d.ts +11 -0
- package/dist/src/core/config-validate-history.js +38 -0
- package/dist/src/core/config-validate-patch-policy.js +100 -0
- package/dist/src/core/config-validate-test-toolchains.js +21 -0
- package/dist/src/core/config-validate-token-scales.d.ts +9 -0
- package/dist/src/core/config-validate-token-scales.js +92 -0
- package/dist/src/core/config-validate.js +20 -5
- package/dist/src/core/config.d.ts +5 -0
- package/dist/src/core/config.js +16 -0
- package/dist/src/core/coverage-dispatch.d.ts +24 -0
- package/dist/src/core/coverage-dispatch.js +44 -0
- package/dist/src/core/coverage-extend.d.ts +70 -45
- package/dist/src/core/coverage-extend.js +199 -144
- package/dist/src/core/coverage-records.d.ts +108 -0
- package/dist/src/core/coverage-records.js +384 -0
- package/dist/src/core/destructive.d.ts +7 -4
- package/dist/src/core/destructive.js +10 -10
- package/dist/src/core/engine-session-lock.d.ts +16 -1
- package/dist/src/core/engine-session-lock.js +38 -10
- package/dist/src/core/export-moved-code-shape.d.ts +49 -11
- package/dist/src/core/export-moved-code-shape.js +135 -44
- package/dist/src/core/file-lock-queue.d.ts +67 -0
- package/dist/src/core/file-lock-queue.js +221 -0
- package/dist/src/core/file-lock-shared.d.ts +57 -0
- package/dist/src/core/file-lock-shared.js +117 -0
- package/dist/src/core/file-lock.d.ts +13 -25
- package/dist/src/core/file-lock.js +163 -140
- package/dist/src/core/furnace-apply-output.d.ts +10 -0
- package/dist/src/core/furnace-apply-output.js +31 -1
- package/dist/src/core/furnace-apply.js +22 -12
- package/dist/src/core/furnace-composed-source.d.ts +76 -0
- package/dist/src/core/furnace-composed-source.js +167 -0
- package/dist/src/core/furnace-config-validate-exceptions.d.ts +16 -0
- package/dist/src/core/furnace-config-validate-exceptions.js +102 -0
- package/dist/src/core/furnace-config-validate.js +14 -0
- package/dist/src/core/furnace-css-fragments.d.ts +10 -0
- package/dist/src/core/furnace-css-fragments.js +26 -0
- package/dist/src/core/furnace-operation.d.ts +3 -3
- package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
- package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
- package/dist/src/core/furnace-registration-remove.d.ts +22 -1
- package/dist/src/core/furnace-registration-remove.js +53 -17
- package/dist/src/core/furnace-registration-rename.d.ts +26 -0
- package/dist/src/core/furnace-registration-rename.js +77 -0
- package/dist/src/core/furnace-registration.d.ts +14 -4
- package/dist/src/core/furnace-registration.js +44 -10
- package/dist/src/core/furnace-staleness.d.ts +7 -0
- package/dist/src/core/furnace-staleness.js +34 -24
- package/dist/src/core/furnace-validate-accessibility.d.ts +8 -4
- package/dist/src/core/furnace-validate-accessibility.js +71 -28
- package/dist/src/core/furnace-validate-exceptions.d.ts +48 -0
- package/dist/src/core/furnace-validate-exceptions.js +80 -0
- package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
- package/dist/src/core/furnace-validate-icon-button.js +78 -0
- package/dist/src/core/furnace-validate.js +1 -1
- package/dist/src/core/harness-port-fallback.d.ts +60 -0
- package/dist/src/core/harness-port-fallback.js +96 -0
- package/dist/src/core/history-log-file.d.ts +61 -0
- package/dist/src/core/history-log-file.js +164 -0
- package/dist/src/core/history-log.d.ts +2 -1
- package/dist/src/core/history-log.js +2 -1
- package/dist/src/core/json-preserving-edit.d.ts +22 -0
- package/dist/src/core/json-preserving-edit.js +199 -0
- package/dist/src/core/line-prefixer.d.ts +18 -0
- package/dist/src/core/line-prefixer.js +34 -0
- package/dist/src/core/mach.d.ts +7 -0
- package/dist/src/core/mach.js +32 -10
- package/dist/src/core/module-resolution-preflight.d.ts +19 -3
- package/dist/src/core/module-resolution-preflight.js +24 -6
- package/dist/src/core/negative-control-compiled.d.ts +27 -0
- package/dist/src/core/negative-control-compiled.js +73 -0
- package/dist/src/core/negative-control-diff.d.ts +51 -0
- package/dist/src/core/negative-control-diff.js +179 -0
- package/dist/src/core/negative-control.d.ts +150 -0
- package/dist/src/core/negative-control.js +399 -0
- package/dist/src/core/objdir-install-manifests.d.ts +73 -0
- package/dist/src/core/objdir-install-manifests.js +226 -0
- package/dist/src/core/park-store.d.ts +63 -0
- package/dist/src/core/park-store.js +216 -0
- package/dist/src/core/patch-export-update.d.ts +6 -0
- package/dist/src/core/patch-export-update.js +13 -3
- package/dist/src/core/patch-export.d.ts +3 -2
- package/dist/src/core/patch-export.js +22 -16
- package/dist/src/core/patch-files.js +26 -8
- package/dist/src/core/patch-lint-checkjs-any-import.d.ts +39 -0
- package/dist/src/core/patch-lint-checkjs-any-import.js +63 -0
- package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
- package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
- package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
- package/dist/src/core/patch-lint-checkjs.js +20 -13
- package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
- package/dist/src/core/patch-lint-code-lines.js +105 -0
- package/dist/src/core/patch-lint-cross.d.ts +3 -1
- package/dist/src/core/patch-lint-cross.js +17 -4
- package/dist/src/core/patch-lint-css.d.ts +8 -2
- package/dist/src/core/patch-lint-css.js +24 -14
- package/dist/src/core/patch-lint-file-size.d.ts +12 -5
- package/dist/src/core/patch-lint-file-size.js +22 -11
- package/dist/src/core/patch-lint-forward-registration-extended.d.ts +23 -0
- package/dist/src/core/patch-lint-forward-registration-extended.js +36 -11
- package/dist/src/core/patch-lint-forward-registration.js +10 -0
- package/dist/src/core/patch-lint-ignore.d.ts +196 -0
- package/dist/src/core/patch-lint-ignore.js +429 -0
- package/dist/src/core/patch-lint-ownership.d.ts +10 -0
- package/dist/src/core/patch-lint-ownership.js +26 -0
- package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
- package/dist/src/core/patch-lint-size-thresholds.js +110 -0
- package/dist/src/core/patch-lint-size.d.ts +117 -0
- package/dist/src/core/patch-lint-size.js +331 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
- package/dist/src/core/patch-lint-staged-registration.js +20 -0
- package/dist/src/core/patch-lint-token-scale.d.ts +57 -0
- package/dist/src/core/patch-lint-token-scale.js +286 -0
- package/dist/src/core/patch-lint.d.ts +11 -83
- package/dist/src/core/patch-lint.js +66 -288
- package/dist/src/core/patch-lock.js +7 -6
- package/dist/src/core/patch-manifest-consistency.js +7 -6
- package/dist/src/core/patch-manifest-io.d.ts +6 -3
- package/dist/src/core/patch-manifest-io.js +27 -9
- package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
- package/dist/src/core/patch-manifest-key-order.js +61 -0
- package/dist/src/core/patch-manifest-stage.d.ts +46 -0
- package/dist/src/core/patch-manifest-stage.js +96 -0
- package/dist/src/core/patch-manifest-validate.js +61 -3
- package/dist/src/core/patch-order-legal.d.ts +26 -0
- package/dist/src/core/patch-order-legal.js +88 -0
- package/dist/src/core/patch-policy-content.d.ts +40 -0
- package/dist/src/core/patch-policy-content.js +216 -0
- package/dist/src/core/patch-policy.d.ts +22 -5
- package/dist/src/core/patch-policy.js +26 -12
- package/dist/src/core/patch-retired.d.ts +57 -0
- package/dist/src/core/patch-retired.js +92 -0
- package/dist/src/core/patch-subset.d.ts +16 -0
- package/dist/src/core/patch-subset.js +66 -0
- package/dist/src/core/preflight-wait.d.ts +20 -0
- package/dist/src/core/preflight-wait.js +38 -0
- package/dist/src/core/rebase-from-version.d.ts +46 -0
- package/dist/src/core/rebase-from-version.js +71 -0
- package/dist/src/core/run-log.d.ts +26 -0
- package/dist/src/core/run-log.js +106 -4
- package/dist/src/core/run-profile.d.ts +7 -0
- package/dist/src/core/run-profile.js +7 -1
- package/dist/src/core/smoke-patterns.d.ts +5 -0
- package/dist/src/core/smoke-patterns.js +13 -0
- package/dist/src/core/test-harness-crash.d.ts +19 -1
- package/dist/src/core/test-harness-crash.js +8 -9
- package/dist/src/core/test-harness-signature.d.ts +33 -0
- package/dist/src/core/test-harness-signature.js +23 -1
- package/dist/src/core/test-raw-log.d.ts +66 -0
- package/dist/src/core/test-raw-log.js +122 -0
- package/dist/src/core/test-run-completeness.d.ts +90 -0
- package/dist/src/core/test-run-completeness.js +184 -0
- package/dist/src/core/test-stale-check.d.ts +27 -1
- package/dist/src/core/test-stale-check.js +39 -49
- package/dist/src/core/test-stale-exempt.d.ts +40 -0
- package/dist/src/core/test-stale-exempt.js +70 -0
- package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
- package/dist/src/core/test-xpcshell-retry.js +2 -1
- package/dist/src/core/token-lint.d.ts +53 -0
- package/dist/src/core/token-lint.js +131 -0
- package/dist/src/core/token-sibling-sheets.d.ts +46 -0
- package/dist/src/core/token-sibling-sheets.js +119 -0
- package/dist/src/core/tree-guard.js +5 -0
- package/dist/src/core/typecheck-shim.d.ts +6 -2
- package/dist/src/core/typecheck-shim.js +205 -4
- package/dist/src/core/typecheck.js +3 -1
- package/dist/src/index.d.ts +14 -3
- package/dist/src/index.js +6 -1
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +212 -24
- package/dist/src/types/commands/patches.d.ts +118 -1
- package/dist/src/types/config.d.ts +264 -0
- package/dist/src/types/config.js +9 -0
- package/dist/src/types/furnace.d.ts +63 -1
- package/dist/src/types/furnace.js +7 -0
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/utils/options.d.ts +36 -7
- package/dist/src/utils/options.js +94 -8
- package/dist/src/utils/path-glob.d.ts +15 -0
- package/dist/src/utils/path-glob.js +47 -0
- package/dist/src/utils/regex.d.ts +15 -3
- package/dist/src/utils/regex.js +37 -16
- package/docs/configuration.md +369 -11
- package/docs/exit-codes.md +18 -1
- package/docs/furnace.md +139 -3
- package/docs/lifecycle-invariants.md +65 -30
- package/docs/machine-output.md +120 -12
- package/docs/patch-workflow.md +458 -22
- package/docs/run-logs.md +20 -1
- package/docs/testing.md +346 -21
- package/package.json +3 -3
package/dist/src/core/run-log.js
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
* exactly the behaviour that existed before this module.
|
|
21
21
|
*/
|
|
22
22
|
import { createWriteStream } from 'node:fs';
|
|
23
|
-
import { mkdir, readdir, unlink } from 'node:fs/promises';
|
|
24
|
-
import { join } from 'node:path';
|
|
23
|
+
import { mkdir, readdir, stat, unlink } from 'node:fs/promises';
|
|
24
|
+
import { basename as basenameOf, dirname, join, resolve } from 'node:path';
|
|
25
25
|
import { Writable } from 'node:stream';
|
|
26
26
|
import { toError } from '../utils/errors.js';
|
|
27
27
|
import { verbose } from '../utils/logger.js';
|
|
@@ -107,11 +107,27 @@ async function pruneRunLogs(dir, command) {
|
|
|
107
107
|
*/
|
|
108
108
|
export async function openRunLog(projectRoot, command, now = new Date()) {
|
|
109
109
|
const dir = getRunLogDir(projectRoot);
|
|
110
|
-
let stream;
|
|
111
110
|
const path = join(dir, `${command}-${fileSafeTimestamp(now)}.log`);
|
|
112
111
|
try {
|
|
113
112
|
await mkdir(dir, { recursive: true });
|
|
114
113
|
await pruneRunLogs(dir, command);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
verbose(`Run log unavailable (${path}): ${toError(error).message}`);
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
return openRunLogSink(path);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Opens one redacting log file at `path`, creating its directory.
|
|
123
|
+
*
|
|
124
|
+
* @param path - Absolute file path
|
|
125
|
+
* @returns The sink, or undefined when the file could not be opened
|
|
126
|
+
*/
|
|
127
|
+
async function openRunLogSink(path) {
|
|
128
|
+
let stream;
|
|
129
|
+
try {
|
|
130
|
+
await mkdir(dirname(path), { recursive: true });
|
|
115
131
|
stream = createWriteStream(path, { flags: 'a' });
|
|
116
132
|
}
|
|
117
133
|
catch (error) {
|
|
@@ -172,6 +188,76 @@ export async function openRunLog(projectRoot, command, now = new Date()) {
|
|
|
172
188
|
},
|
|
173
189
|
};
|
|
174
190
|
}
|
|
191
|
+
/** Environment variable naming where every run's log is also kept. */
|
|
192
|
+
const LOG_KEEP_ENV_VAR = 'FIREFORGE_LOG_KEEP';
|
|
193
|
+
/**
|
|
194
|
+
* Where a run's kept copy goes: `--keep-log <path>` when given, else
|
|
195
|
+
* {@link LOG_KEEP_ENV_VAR}, else nowhere. A value that ends in a path
|
|
196
|
+
* separator or names an existing directory receives the log under its own
|
|
197
|
+
* `.fireforge/logs/` basename, so a session-wide directory collects one
|
|
198
|
+
* file per run. Any other value is the file itself. Relative values resolve
|
|
199
|
+
* against the caller's working directory.
|
|
200
|
+
*
|
|
201
|
+
* @param flag - The `--keep-log` value, if any
|
|
202
|
+
* @param basename - The run log's own file name
|
|
203
|
+
* @returns The absolute destination, or undefined when none was asked for
|
|
204
|
+
*/
|
|
205
|
+
async function resolveRunLogKeepPath(flag, basename) {
|
|
206
|
+
const raw = flag ?? process.env[LOG_KEEP_ENV_VAR]?.trim();
|
|
207
|
+
if (raw === undefined || raw.length === 0)
|
|
208
|
+
return undefined;
|
|
209
|
+
const target = resolve(raw);
|
|
210
|
+
let directory = /[\\/]$/.test(raw);
|
|
211
|
+
if (!directory) {
|
|
212
|
+
try {
|
|
213
|
+
directory = (await stat(target)).isDirectory();
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
directory = false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return directory ? join(target, basename) : target;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Tees a run log into a caller-chosen copy (`--keep-log`,
|
|
223
|
+
* {@link LOG_KEEP_ENV_VAR}) that retention never prunes.
|
|
224
|
+
*
|
|
225
|
+
* `.fireforge/logs/` keeps twenty logs per command kind for EVERY session
|
|
226
|
+
* on the checkout, so on a shared checkout a log named by a verdict line
|
|
227
|
+
* can be gone within the hour, and a failure recorded only by its log path
|
|
228
|
+
* cannot be read later. The copy is written live, line for line with the
|
|
229
|
+
* same redaction, rather than copied at the end: a killed run keeps what it
|
|
230
|
+
* had written, like the primary log does.
|
|
231
|
+
*
|
|
232
|
+
* The primary path stays the one `log=` names. When the primary could not
|
|
233
|
+
* be opened the copy stands in for it.
|
|
234
|
+
*
|
|
235
|
+
* @param log - The primary run log, if one opened
|
|
236
|
+
* @param flag - The `--keep-log` value, if any
|
|
237
|
+
* @param command - Command kind, naming a copy that has no primary
|
|
238
|
+
* @returns A sink writing to both, or whichever one opened
|
|
239
|
+
*/
|
|
240
|
+
export async function keepRunLogCopy(log, flag, command) {
|
|
241
|
+
const basename = log === undefined ? `${command}-${fileSafeTimestamp(new Date())}.log` : basenameOf(log.path);
|
|
242
|
+
const keepPath = await resolveRunLogKeepPath(flag, basename);
|
|
243
|
+
if (keepPath === undefined || keepPath === log?.path)
|
|
244
|
+
return log;
|
|
245
|
+
const copy = await openRunLogSink(keepPath);
|
|
246
|
+
if (copy === undefined)
|
|
247
|
+
return log;
|
|
248
|
+
if (log === undefined)
|
|
249
|
+
return copy;
|
|
250
|
+
return {
|
|
251
|
+
path: log.path,
|
|
252
|
+
write: (chunk) => {
|
|
253
|
+
log.write(chunk);
|
|
254
|
+
copy.write(chunk);
|
|
255
|
+
},
|
|
256
|
+
close: async () => {
|
|
257
|
+
await Promise.all([log.close(), copy.close()]);
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
}
|
|
175
261
|
/**
|
|
176
262
|
* The run log for the command currently executing, if any.
|
|
177
263
|
*
|
|
@@ -185,9 +271,20 @@ export async function openRunLog(projectRoot, command, now = new Date()) {
|
|
|
185
271
|
* One command runs per process, so a single slot is the whole lifetime.
|
|
186
272
|
*/
|
|
187
273
|
let activeRunLog;
|
|
274
|
+
/** Newlines written to the active log so far, for line references into it. */
|
|
275
|
+
let activeRunLogNewlines = 0;
|
|
188
276
|
/** Installs (or clears, with `undefined`) the run log for this process. */
|
|
189
277
|
export function setActiveRunLog(log) {
|
|
190
278
|
activeRunLog = log;
|
|
279
|
+
activeRunLogNewlines = 0;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* The 1-based line of the active run log the next write starts on.
|
|
283
|
+
* Redaction rewrites within a line and never adds or drops one, so the
|
|
284
|
+
* number holds for the file on disk.
|
|
285
|
+
*/
|
|
286
|
+
export function activeRunLogLine() {
|
|
287
|
+
return activeRunLogNewlines + 1;
|
|
191
288
|
}
|
|
192
289
|
/** Absolute path of the active run log, or undefined when none is open. */
|
|
193
290
|
export function getActiveRunLogPath() {
|
|
@@ -195,7 +292,12 @@ export function getActiveRunLogPath() {
|
|
|
195
292
|
}
|
|
196
293
|
/** Appends to the active run log. A no-op when none is open. */
|
|
197
294
|
export function writeToActiveRunLog(chunk) {
|
|
198
|
-
activeRunLog
|
|
295
|
+
if (activeRunLog === undefined)
|
|
296
|
+
return;
|
|
297
|
+
for (let index = chunk.indexOf('\n'); index !== -1; index = chunk.indexOf('\n', index + 1)) {
|
|
298
|
+
activeRunLogNewlines += 1;
|
|
299
|
+
}
|
|
300
|
+
activeRunLog.write(chunk);
|
|
199
301
|
}
|
|
200
302
|
/**
|
|
201
303
|
* Closes and clears the active run log. Resolves even when none is open.
|
|
@@ -17,6 +17,13 @@ export interface RunProfileRequest {
|
|
|
17
17
|
profile?: string | undefined;
|
|
18
18
|
/** `--temp-profile`: launch with a fresh directory removed afterwards. */
|
|
19
19
|
tempProfile?: boolean | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Whether a named `profile` launches with `-purgecaches` (default `true`).
|
|
22
|
+
* A UI build does not change the build id the profile's startup cache is
|
|
23
|
+
* keyed on, so without it a kept profile runs the chrome scripts an
|
|
24
|
+
* earlier build cached. Temporary profiles start without a cache.
|
|
25
|
+
*/
|
|
26
|
+
purgeCaches?: boolean | undefined;
|
|
20
27
|
/**
|
|
21
28
|
* Whether this is a `--smoke-exit` run. A smoke run with neither flag gets
|
|
22
29
|
* a temporary profile: the step exists to prove what the build does on a
|
|
@@ -68,7 +68,13 @@ export async function resolveRunProfile(request) {
|
|
|
68
68
|
}
|
|
69
69
|
if (request.profile !== undefined) {
|
|
70
70
|
const dir = resolve(request.profile);
|
|
71
|
-
|
|
71
|
+
const purge = request.purgeCaches === false ? [] : ['-purgecaches'];
|
|
72
|
+
return {
|
|
73
|
+
args: ['-profile', dir, ...purge],
|
|
74
|
+
dir,
|
|
75
|
+
temporary: false,
|
|
76
|
+
dispose: NO_PROFILE.dispose,
|
|
77
|
+
};
|
|
72
78
|
}
|
|
73
79
|
if (request.tempProfile !== true && !request.smoke) {
|
|
74
80
|
return NO_PROFILE;
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
* allowlisted hits separately from raw error matches for its summary.
|
|
18
18
|
*/
|
|
19
19
|
export declare function matchesSmokeError(line: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Returns `true` when `line` is console output from the browser rather than
|
|
22
|
+
* mach's own timestamped log. A blank line is neither.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isBrowserConsoleLine(line: string): boolean;
|
|
20
25
|
/**
|
|
21
26
|
* One compiled allowlist entry with its provenance retained so the smoke
|
|
22
27
|
* summary can attribute hits per entry. An entry that silently
|
|
@@ -56,6 +56,19 @@ export function matchesSmokeError(line) {
|
|
|
56
56
|
}
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Mach's own log lines carry an elapsed-time prefix (` 0:00.42 <message>`),
|
|
61
|
+
* the first of which echoes the browser command line. They prove mach ran,
|
|
62
|
+
* not that the browser printed anything.
|
|
63
|
+
*/
|
|
64
|
+
const MACH_LOG_LINE = /^\s*\d+:\d{2}\.\d{2} /;
|
|
65
|
+
/**
|
|
66
|
+
* Returns `true` when `line` is console output from the browser rather than
|
|
67
|
+
* mach's own timestamped log. A blank line is neither.
|
|
68
|
+
*/
|
|
69
|
+
export function isBrowserConsoleLine(line) {
|
|
70
|
+
return line.trim() !== '' && !MACH_LOG_LINE.test(line);
|
|
71
|
+
}
|
|
59
72
|
/** `# max-hits: N` on its own comment line, case-insensitive. */
|
|
60
73
|
const MAX_HITS_DIRECTIVE = /^#\s*max-hits:\s*(\S+)\s*$/i;
|
|
61
74
|
function parseMaxHitsDirective(raw, at) {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* reporting phantom test failures (or phantom passes).
|
|
23
23
|
*/
|
|
24
24
|
export type { HarnessCrashSignature } from './test-harness-signature.js';
|
|
25
|
-
import type
|
|
25
|
+
import { type HarnessCrashSignature, type IncompleteRunEvidence } from './test-harness-signature.js';
|
|
26
26
|
export { headedDisplayAsleepVerdictNote, headedNoOutputTimeoutHint } from './test-stall-triage.js';
|
|
27
27
|
/** How a completed harness run should be interpreted. */
|
|
28
28
|
export type HarnessRunClassification = 'tests-ran-ok' | 'test-failures' | 'harness-crash' | 'harness-arguments' | 'no-tests';
|
|
@@ -71,6 +71,12 @@ export interface HarnessRunVerdict extends HarnessSummaryCounts {
|
|
|
71
71
|
* only. The status and reason keys are unaffected.
|
|
72
72
|
*/
|
|
73
73
|
note?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Set when a mach-exit-0 run was refused its pass because it is
|
|
76
|
+
* incomplete or reported unexpected results. See
|
|
77
|
+
* `test-run-completeness.ts`.
|
|
78
|
+
*/
|
|
79
|
+
incomplete?: IncompleteRunEvidence;
|
|
74
80
|
}
|
|
75
81
|
/** Why a green-looking embedded summary was not trusted. */
|
|
76
82
|
export interface GreenSummaryRejection {
|
|
@@ -81,6 +87,7 @@ export interface GreenSummaryRejection {
|
|
|
81
87
|
/** Files whose `TEST_START` has no matching end marker. */
|
|
82
88
|
neverEnded: string[];
|
|
83
89
|
}
|
|
90
|
+
export declare const SHUTDOWN_REENTRY_PATTERN: RegExp;
|
|
84
91
|
/**
|
|
85
92
|
* Strips non-signal noise from captured output before crash-signature
|
|
86
93
|
* matching: resource-monitor degradation warnings, and traceback blocks
|
|
@@ -108,6 +115,16 @@ export declare function findCrashMarkerLine(output: string): string | undefined;
|
|
|
108
115
|
* Exported for direct unit testing.
|
|
109
116
|
*/
|
|
110
117
|
export declare function hasCompletedGreenSummary(output: string): boolean;
|
|
118
|
+
/** Basename shape of a mozbuild-manifest test implementation file. */
|
|
119
|
+
export declare const TEST_FILE_BASENAME_PATTERN: RegExp;
|
|
120
|
+
/**
|
|
121
|
+
* Start/end execution markers, both log dialects: the structured mozlog
|
|
122
|
+
* `TEST_START`/`TEST_END` pair and the human browser-chrome
|
|
123
|
+
* `TEST-START`/`TEST-OK` pair. `TEST-UNEXPECTED-*` end shapes are
|
|
124
|
+
* irrelevant here, since any such line already fails the green-summary check
|
|
125
|
+
* before completeness is consulted.
|
|
126
|
+
*/
|
|
127
|
+
export declare const START_MARKER_PATTERN: RegExp;
|
|
111
128
|
/**
|
|
112
129
|
* Cross-checks run completeness against the requested test files: every
|
|
113
130
|
* requested file must produce a start marker, and every started test must
|
|
@@ -181,6 +198,7 @@ export declare function extractSummaryCounts(output: string): HarnessSummaryCoun
|
|
|
181
198
|
export declare function formatFireforgeVerdictLine(verdict: HarnessRunVerdict, shards?: {
|
|
182
199
|
passed: number;
|
|
183
200
|
total: number;
|
|
201
|
+
failed?: readonly string[];
|
|
184
202
|
}): string;
|
|
185
203
|
/**
|
|
186
204
|
* Builds the operator-facing failure message for a green-looking summary
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
import { hasKnownTeardownNoise } from './mach-known-noise-filter.js';
|
|
26
26
|
import { truncateEvidence, unmarkedFailureEvidenceNote, } from './test-harness-verdict-notes.js';
|
|
27
27
|
import { classifyProfileArgumentFailure } from './test-profile-files.js';
|
|
28
|
+
import { formatIncompleteSuffix, formatShardsSuffix, } from './test-harness-signature.js';
|
|
28
29
|
// The no-output-stall triage text lives in `test-stall-triage.ts` (it is
|
|
29
30
|
// operator advice, not classification) and is re-exported here so the
|
|
30
31
|
// command layer keeps importing its harness diagnostics from one module.
|
|
@@ -76,7 +77,7 @@ const FAIL_LINE_PATTERN = /^.*\bTEST-(?!KNOWN-FAIL\b)[A-Z-]*FAIL\b.*$/gm;
|
|
|
76
77
|
* test failure, pointing the reader at the wrong line.
|
|
77
78
|
*/
|
|
78
79
|
const ASSERTION_LINE_PATTERN = /^.*(?:Assertion failure:|MOZ_ASSERT\(|###!!! ASSERTION).*$/gm;
|
|
79
|
-
const SHUTDOWN_REENTRY_PATTERN = /Application shut down \(without crashing\) in the middle of a test/i;
|
|
80
|
+
export const SHUTDOWN_REENTRY_PATTERN = /Application shut down \(without crashing\) in the middle of a test/i;
|
|
80
81
|
const FOCUS_STALL_PATTERN = /must wait for focus/i;
|
|
81
82
|
const TRACEBACK_PATTERN = /Traceback \(most recent call last\)/;
|
|
82
83
|
const NO_OUTPUT_TIMEOUT_PATTERN = /timed out after \d+ seconds with no output/i;
|
|
@@ -248,7 +249,7 @@ export function hasCompletedGreenSummary(output) {
|
|
|
248
249
|
return hasGreenShapedSummary(output) && findCrashMarkerLine(output) === undefined;
|
|
249
250
|
}
|
|
250
251
|
/** Basename shape of a mozbuild-manifest test implementation file. */
|
|
251
|
-
const TEST_FILE_BASENAME_PATTERN = /^(?:browser|test)_.*\.m?js$/;
|
|
252
|
+
export const TEST_FILE_BASENAME_PATTERN = /^(?:browser|test)_.*\.m?js$/;
|
|
252
253
|
/**
|
|
253
254
|
* Start/end execution markers, both log dialects: the structured mozlog
|
|
254
255
|
* `TEST_START`/`TEST_END` pair and the human browser-chrome
|
|
@@ -256,7 +257,7 @@ const TEST_FILE_BASENAME_PATTERN = /^(?:browser|test)_.*\.m?js$/;
|
|
|
256
257
|
* irrelevant here, since any such line already fails the green-summary check
|
|
257
258
|
* before completeness is consulted.
|
|
258
259
|
*/
|
|
259
|
-
const START_MARKER_PATTERN = /\bTEST[-_]START\b[:| ]*\s*(\S+)?/;
|
|
260
|
+
export const START_MARKER_PATTERN = /\bTEST[-_]START\b[:| ]*\s*(\S+)?/;
|
|
260
261
|
const END_MARKER_PATTERN = /\bTEST[-_]END\b|\bTEST-OK\b/;
|
|
261
262
|
/**
|
|
262
263
|
* Cross-checks run completeness against the requested test files: every
|
|
@@ -659,13 +660,11 @@ function lastCapturedCount(output, pattern) {
|
|
|
659
660
|
export function formatFireforgeVerdictLine(verdict, shards) {
|
|
660
661
|
const counts = (verdict.checks !== undefined ? ` checks=${verdict.checks}` : '') +
|
|
661
662
|
(verdict.unexpected !== undefined ? ` unexpected=${verdict.unexpected}` : '');
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
return `FIREFORGE-VERDICT: PASS${counts}${shardSuffix}${note}`;
|
|
666
|
-
}
|
|
663
|
+
const tail = `${formatShardsSuffix(shards)}${verdict.note !== undefined ? ` (${verdict.note})` : ''}`;
|
|
664
|
+
if (verdict.kind === 'tests-ran-ok')
|
|
665
|
+
return `FIREFORGE-VERDICT: PASS${counts}${tail}`;
|
|
667
666
|
const reason = verdict.kind === 'harness-crash' ? 'crash' : verdict.kind;
|
|
668
|
-
return `FIREFORGE-VERDICT: FAIL reason=${reason}${counts}${
|
|
667
|
+
return `FIREFORGE-VERDICT: FAIL reason=${reason}${counts}${formatIncompleteSuffix(verdict.incomplete)}${tail}`;
|
|
669
668
|
}
|
|
670
669
|
/**
|
|
671
670
|
* Builds the operator-facing failure message for a green-looking summary
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* graph rather than the emitted code, and a shared leaf is a truer
|
|
9
9
|
* description of the relationship than either direction of the cycle was:
|
|
10
10
|
* neither module owns this type more than the other.
|
|
11
|
+
*
|
|
12
|
+
* {@link IncompleteRunEvidence} lives here for the same reason:
|
|
13
|
+
* `test-run-completeness.ts` produces it from helpers in
|
|
14
|
+
* `test-harness-crash.ts`, whose verdict type carries it.
|
|
11
15
|
*/
|
|
12
16
|
/** A recognized harness-crash shape with its evidence line. */
|
|
13
17
|
export interface HarnessCrashSignature {
|
|
@@ -16,3 +20,32 @@ export interface HarnessCrashSignature {
|
|
|
16
20
|
/** The concrete output line the recognition was based on. */
|
|
17
21
|
line: string;
|
|
18
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* The verdict line's `started=<n>/<m> first-unstarted=<path>
|
|
25
|
+
* [started-source=<src>]` keys, or nothing when every file started.
|
|
26
|
+
*/
|
|
27
|
+
export declare function formatIncompleteSuffix(evidence: IncompleteRunEvidence | undefined): string;
|
|
28
|
+
/** The verdict line's `shards=<p>/<t> [failed-shards=<labels>]` keys of a sharded run. */
|
|
29
|
+
export declare function formatShardsSuffix(shards: {
|
|
30
|
+
passed: number;
|
|
31
|
+
total: number;
|
|
32
|
+
failed?: readonly string[];
|
|
33
|
+
} | undefined): string;
|
|
34
|
+
/** Why an exit-0 run that would have read as a pass was failed instead. */
|
|
35
|
+
export interface IncompleteRunEvidence {
|
|
36
|
+
/** Requested test files that produced a start (or skip) marker. */
|
|
37
|
+
started: number;
|
|
38
|
+
/** Requested test files the run could account for (test-file-shaped paths). */
|
|
39
|
+
requested: number;
|
|
40
|
+
/** First requested file, in dispatch order, that never started. */
|
|
41
|
+
firstUnstarted?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Which evidence the start count came from, stamped with a short count:
|
|
44
|
+
* the structured raw log, the streamed output, or the capped capture.
|
|
45
|
+
*/
|
|
46
|
+
startedSource?: 'raw' | 'stream' | 'capture';
|
|
47
|
+
/** The harness's "shut down in the middle of a test" line, when present. */
|
|
48
|
+
shutdownLine?: string;
|
|
49
|
+
/** The summary's non-zero `Unexpected results:` count, when it printed one. */
|
|
50
|
+
unexpected?: number;
|
|
51
|
+
}
|
|
@@ -9,5 +9,27 @@
|
|
|
9
9
|
* graph rather than the emitted code, and a shared leaf is a truer
|
|
10
10
|
* description of the relationship than either direction of the cycle was:
|
|
11
11
|
* neither module owns this type more than the other.
|
|
12
|
+
*
|
|
13
|
+
* {@link IncompleteRunEvidence} lives here for the same reason:
|
|
14
|
+
* `test-run-completeness.ts` produces it from helpers in
|
|
15
|
+
* `test-harness-crash.ts`, whose verdict type carries it.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The verdict line's `started=<n>/<m> first-unstarted=<path>
|
|
19
|
+
* [started-source=<src>]` keys, or nothing when every file started.
|
|
12
20
|
*/
|
|
13
|
-
export {
|
|
21
|
+
export function formatIncompleteSuffix(evidence) {
|
|
22
|
+
if (evidence?.firstUnstarted === undefined)
|
|
23
|
+
return '';
|
|
24
|
+
const source = evidence.startedSource === undefined ? '' : ` started-source=${evidence.startedSource}`;
|
|
25
|
+
return ` started=${evidence.started}/${evidence.requested} first-unstarted=${evidence.firstUnstarted}${source}`;
|
|
26
|
+
}
|
|
27
|
+
/** The verdict line's `shards=<p>/<t> [failed-shards=<labels>]` keys of a sharded run. */
|
|
28
|
+
export function formatShardsSuffix(shards) {
|
|
29
|
+
if (shards === undefined)
|
|
30
|
+
return '';
|
|
31
|
+
const failed = shards.failed !== undefined && shards.failed.length > 0
|
|
32
|
+
? ` failed-shards=${shards.failed.join(',')}`
|
|
33
|
+
: '';
|
|
34
|
+
return ` shards=${shards.passed}/${shards.total}${failed}`;
|
|
35
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The mozlog structured ("raw") log of one mach test dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Everything else FireForge reads from a run is human text: the
|
|
5
|
+
* `TEST_START`/`TEST_END` lines and the `Unexpected results:` summary, in two
|
|
6
|
+
* dialects, out of a capture that keeps only its last 2 MB. A gate that
|
|
7
|
+
* wants to name the files a run failed had to regex that text, and agent-
|
|
8
|
+
* quiet mozbuild drops `TEST_START` from it altogether. The raw log is the
|
|
9
|
+
* record the summary itself is computed from: one JSON object per line,
|
|
10
|
+
* with `test_start`, `test_status` and `test_end` actions naming each test
|
|
11
|
+
* by its manifest id.
|
|
12
|
+
*
|
|
13
|
+
* It is requested per dispatch with mozlog's `--log-raw=<path>`, which
|
|
14
|
+
* `mach test`, `mach mochitest` and `mach xpcshell-test` all accept, only
|
|
15
|
+
* when a run asks for per-file results (`--results`, `--shard-size`).
|
|
16
|
+
*/
|
|
17
|
+
import type { StartMarkers } from './test-run-completeness.js';
|
|
18
|
+
/** One test file's outcome, from its `test_end` and failing `test_status` records. */
|
|
19
|
+
export interface RawTestResult {
|
|
20
|
+
/** The test id mozlog reports (a manifest-relative path). */
|
|
21
|
+
test: string;
|
|
22
|
+
/** `test_end` status (`OK`, `PASS`, `FAIL`, `ERROR`, `TIMEOUT`, `CRASH`, `SKIP`). */
|
|
23
|
+
status: string;
|
|
24
|
+
/** Expected status; equal to `status` when mozlog omitted it. */
|
|
25
|
+
expected: string;
|
|
26
|
+
/** True when the file ended unexpectedly or any subtest did. */
|
|
27
|
+
unexpected: boolean;
|
|
28
|
+
/** Subtests that reported an unexpected status. */
|
|
29
|
+
unexpectedSubtests: number;
|
|
30
|
+
/** Wall time between `test_start` and `test_end`, when both carried a time. */
|
|
31
|
+
durationMs?: number;
|
|
32
|
+
}
|
|
33
|
+
/** Everything one raw log says about the run. */
|
|
34
|
+
export interface RawTestLog {
|
|
35
|
+
/** Files in `test_end` order. A started file with no end is not listed. */
|
|
36
|
+
results: RawTestResult[];
|
|
37
|
+
/** Start markers for the completeness veto: every `test_start` id. */
|
|
38
|
+
markers: StartMarkers;
|
|
39
|
+
/** Started tests that never ended (a crash or a cut-off run). */
|
|
40
|
+
unfinished: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parses a mozlog raw log. Unknown actions and malformed lines are skipped,
|
|
44
|
+
* so a log truncated by a crash still yields the files that finished.
|
|
45
|
+
*
|
|
46
|
+
* @param text - The raw log's contents
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseRawTestLog(text: string): RawTestLog;
|
|
49
|
+
/**
|
|
50
|
+
* Reads and parses a raw log. Returns undefined when the file is missing or
|
|
51
|
+
* unreadable (the harness never started, or the engine's mach ignored the
|
|
52
|
+
* flag), so callers fall back to the streamed text.
|
|
53
|
+
*
|
|
54
|
+
* @param path - The `--log-raw` destination
|
|
55
|
+
*/
|
|
56
|
+
export declare function readRawTestLog(path: string): Promise<RawTestLog | undefined>;
|
|
57
|
+
/**
|
|
58
|
+
* The `--log-raw` destination the operator already forwarded with
|
|
59
|
+
* `--mach-arg`, when it names a file. FireForge then reads that file instead
|
|
60
|
+
* of adding its own flag, so the operator's log is not replaced.
|
|
61
|
+
*
|
|
62
|
+
* @param args - The dispatch's extra mach arguments
|
|
63
|
+
*/
|
|
64
|
+
export declare function forwardedRawLogPath(args: readonly string[]): string | undefined;
|
|
65
|
+
/** True when the dispatch arguments already carry any `--log-raw`. */
|
|
66
|
+
export declare function hasForwardedRawLog(args: readonly string[]): boolean;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* The mozlog structured ("raw") log of one mach test dispatch.
|
|
4
|
+
*
|
|
5
|
+
* Everything else FireForge reads from a run is human text: the
|
|
6
|
+
* `TEST_START`/`TEST_END` lines and the `Unexpected results:` summary, in two
|
|
7
|
+
* dialects, out of a capture that keeps only its last 2 MB. A gate that
|
|
8
|
+
* wants to name the files a run failed had to regex that text, and agent-
|
|
9
|
+
* quiet mozbuild drops `TEST_START` from it altogether. The raw log is the
|
|
10
|
+
* record the summary itself is computed from: one JSON object per line,
|
|
11
|
+
* with `test_start`, `test_status` and `test_end` actions naming each test
|
|
12
|
+
* by its manifest id.
|
|
13
|
+
*
|
|
14
|
+
* It is requested per dispatch with mozlog's `--log-raw=<path>`, which
|
|
15
|
+
* `mach test`, `mach mochitest` and `mach xpcshell-test` all accept, only
|
|
16
|
+
* when a run asks for per-file results (`--results`, `--shard-size`).
|
|
17
|
+
*/
|
|
18
|
+
import { readFile } from 'node:fs/promises';
|
|
19
|
+
function parseRecord(line) {
|
|
20
|
+
if (!line.startsWith('{'))
|
|
21
|
+
return undefined;
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(line);
|
|
24
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : undefined;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// A line cut off by a killed harness is not a record.
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parses a mozlog raw log. Unknown actions and malformed lines are skipped,
|
|
33
|
+
* so a log truncated by a crash still yields the files that finished.
|
|
34
|
+
*
|
|
35
|
+
* @param text - The raw log's contents
|
|
36
|
+
*/
|
|
37
|
+
export function parseRawTestLog(text) {
|
|
38
|
+
const results = [];
|
|
39
|
+
const started = [];
|
|
40
|
+
const startTimes = new Map();
|
|
41
|
+
const subtestFailures = new Map();
|
|
42
|
+
for (const line of text.split(/\r?\n/)) {
|
|
43
|
+
const record = parseRecord(line.trim());
|
|
44
|
+
if (record === undefined || typeof record.test !== 'string')
|
|
45
|
+
continue;
|
|
46
|
+
const test = record.test;
|
|
47
|
+
if (record.action === 'test_start') {
|
|
48
|
+
started.push(test);
|
|
49
|
+
if (typeof record.time === 'number')
|
|
50
|
+
startTimes.set(test, record.time);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (record.action === 'test_status' && typeof record.expected === 'string') {
|
|
54
|
+
// mozlog sets `expected` on a status record only when it differs.
|
|
55
|
+
subtestFailures.set(test, (subtestFailures.get(test) ?? 0) + 1);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (record.action !== 'test_end' || typeof record.status !== 'string')
|
|
59
|
+
continue;
|
|
60
|
+
const expected = typeof record.expected === 'string' ? record.expected : record.status;
|
|
61
|
+
const unexpectedSubtests = subtestFailures.get(test) ?? 0;
|
|
62
|
+
const start = startTimes.get(test);
|
|
63
|
+
results.push({
|
|
64
|
+
test,
|
|
65
|
+
status: record.status,
|
|
66
|
+
expected,
|
|
67
|
+
unexpected: expected !== record.status || unexpectedSubtests > 0,
|
|
68
|
+
unexpectedSubtests,
|
|
69
|
+
...(start !== undefined && typeof record.time === 'number'
|
|
70
|
+
? { durationMs: record.time - start }
|
|
71
|
+
: {}),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const ended = new Set(results.map((result) => result.test));
|
|
75
|
+
return {
|
|
76
|
+
results,
|
|
77
|
+
markers: {
|
|
78
|
+
started,
|
|
79
|
+
skipped: results.filter((r) => r.status === 'SKIP').map((r) => r.test),
|
|
80
|
+
},
|
|
81
|
+
unfinished: started.filter((test) => !ended.has(test)),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Reads and parses a raw log. Returns undefined when the file is missing or
|
|
86
|
+
* unreadable (the harness never started, or the engine's mach ignored the
|
|
87
|
+
* flag), so callers fall back to the streamed text.
|
|
88
|
+
*
|
|
89
|
+
* @param path - The `--log-raw` destination
|
|
90
|
+
*/
|
|
91
|
+
export async function readRawTestLog(path) {
|
|
92
|
+
try {
|
|
93
|
+
return parseRawTestLog(await readFile(path, 'utf8'));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The `--log-raw` destination the operator already forwarded with
|
|
101
|
+
* `--mach-arg`, when it names a file. FireForge then reads that file instead
|
|
102
|
+
* of adding its own flag, so the operator's log is not replaced.
|
|
103
|
+
*
|
|
104
|
+
* @param args - The dispatch's extra mach arguments
|
|
105
|
+
*/
|
|
106
|
+
export function forwardedRawLogPath(args) {
|
|
107
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
108
|
+
const arg = args[index] ?? '';
|
|
109
|
+
const value = arg.startsWith('--log-raw=')
|
|
110
|
+
? arg.slice('--log-raw='.length)
|
|
111
|
+
: arg === '--log-raw'
|
|
112
|
+
? args[index + 1]
|
|
113
|
+
: undefined;
|
|
114
|
+
if (value !== undefined)
|
|
115
|
+
return value === '-' ? undefined : value;
|
|
116
|
+
}
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
/** True when the dispatch arguments already carry any `--log-raw`. */
|
|
120
|
+
export function hasForwardedRawLog(args) {
|
|
121
|
+
return args.some((arg) => arg === '--log-raw' || arg.startsWith('--log-raw='));
|
|
122
|
+
}
|