@hominis/fireforge 0.49.1 → 0.50.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 +41 -0
- 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 +28 -0
- package/dist/src/commands/check-report.js +78 -0
- package/dist/src/commands/check-run.d.ts +28 -0
- package/dist/src/commands/check-run.js +104 -0
- package/dist/src/commands/check-steps.d.ts +67 -0
- package/dist/src/commands/check-steps.js +175 -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/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-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-templates.d.ts +8 -3
- package/dist/src/commands/furnace/create-templates.js +8 -23
- 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 +93 -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 +127 -114
- package/dist/src/commands/furnace/validation-output.js +14 -3
- package/dist/src/commands/lint-per-patch.js +31 -60
- package/dist/src/commands/lint-report.d.ts +8 -4
- package/dist/src/commands/lint-report.js +15 -5
- package/dist/src/commands/lint.js +15 -34
- package/dist/src/commands/manifest.js +2 -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 +13 -98
- package/dist/src/commands/patch/index.d.ts +1 -1
- package/dist/src/commands/patch/index.js +4 -2
- package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
- package/dist/src/commands/patch/lint-ignore.js +65 -28
- package/dist/src/commands/patch/move-files-create.js +26 -17
- package/dist/src/commands/patch/move-files-into.js +5 -3
- package/dist/src/commands/patch/move-files.js +3 -1
- 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 +7 -0
- package/dist/src/commands/patch/retire.d.ts +34 -0
- package/dist/src/commands/patch/retire.js +128 -0
- package/dist/src/commands/patch/split-plan.d.ts +7 -7
- package/dist/src/commands/patch/split-plan.js +45 -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 +51 -15
- 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.js +14 -41
- 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 +45 -2
- package/dist/src/commands/re-export-adjacent.js +156 -37
- 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-lint.d.ts +2 -1
- package/dist/src/commands/re-export-lint.js +23 -10
- package/dist/src/commands/re-export-options.js +45 -4
- 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-register.js +42 -17
- package/dist/src/commands/re-export-removed.d.ts +12 -1
- package/dist/src/commands/re-export-removed.js +41 -11
- 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 +17 -9
- package/dist/src/commands/re-export-scan.js +56 -23
- package/dist/src/commands/re-export-single.js +22 -6
- 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 +37 -24
- 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 +21 -0
- package/dist/src/commands/test-build-furnace.js +48 -0
- package/dist/src/commands/test-build-phase.js +47 -41
- package/dist/src/commands/test-checkjs.js +7 -0
- package/dist/src/commands/test-diagnose.js +7 -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 +43 -0
- package/dist/src/commands/test-orchestrate.js +222 -0
- package/dist/src/commands/test-perf-scope.d.ts +29 -0
- package/dist/src/commands/test-perf-scope.js +83 -0
- package/dist/src/commands/test-prelock.d.ts +51 -0
- package/dist/src/commands/test-prelock.js +177 -0
- package/dist/src/commands/test-register.js +54 -10
- package/dist/src/commands/test-run.js +4 -1
- package/dist/src/commands/test-stale-gate.js +57 -27
- package/dist/src/commands/test-verdict.d.ts +10 -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 +66 -60
- package/dist/src/commands/token-lint.d.ts +14 -0
- package/dist/src/commands/token-lint.js +111 -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 +59 -35
- 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 +7 -0
- package/dist/src/core/build-prepare.js +14 -8
- 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 +8 -0
- package/dist/src/core/config-validate-check.d.ts +8 -0
- package/dist/src/core/config-validate-check.js +143 -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 +7 -0
- package/dist/src/core/config-validate-token-scales.d.ts +6 -0
- package/dist/src/core/config-validate-token-scales.js +50 -0
- package/dist/src/core/config-validate.js +14 -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 +97 -0
- package/dist/src/core/coverage-records.js +350 -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 +10 -1
- package/dist/src/core/engine-session-lock.js +28 -8
- 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.d.ts +4 -25
- package/dist/src/core/file-lock.js +105 -138
- 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 +12 -2
- 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 +9 -0
- package/dist/src/core/furnace-config-validate-exceptions.js +71 -0
- package/dist/src/core/furnace-config-validate.js +8 -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-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 +4 -2
- package/dist/src/core/furnace-validate-accessibility.js +10 -1
- package/dist/src/core/furnace-validate-exceptions.d.ts +40 -0
- package/dist/src/core/furnace-validate-exceptions.js +43 -0
- package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
- package/dist/src/core/furnace-validate-icon-button.js +49 -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 +157 -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/mach.js +8 -1
- package/dist/src/core/negative-control-diff.d.ts +39 -0
- package/dist/src/core/negative-control-diff.js +136 -0
- package/dist/src/core/negative-control.d.ts +138 -0
- package/dist/src/core/negative-control.js +356 -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/patch-export-update.d.ts +2 -0
- package/dist/src/core/patch-export-update.js +1 -0
- package/dist/src/core/patch-export.js +3 -4
- package/dist/src/core/patch-lint-checkjs-any-import.d.ts +37 -0
- package/dist/src/core/patch-lint-checkjs-any-import.js +61 -0
- package/dist/src/core/patch-lint-checkjs.js +8 -11
- 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.js +12 -4
- package/dist/src/core/patch-lint-css.d.ts +8 -2
- package/dist/src/core/patch-lint-css.js +10 -4
- 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 +18 -0
- package/dist/src/core/patch-lint-forward-registration-extended.js +35 -10
- package/dist/src/core/patch-lint-forward-registration.js +10 -0
- package/dist/src/core/patch-lint-ignore.d.ts +152 -0
- package/dist/src/core/patch-lint-ignore.js +299 -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 +323 -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 +39 -0
- package/dist/src/core/patch-lint-token-scale.js +109 -0
- package/dist/src/core/patch-lint.d.ts +11 -83
- package/dist/src/core/patch-lint.js +64 -286
- 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 +19 -8
- package/dist/src/core/patch-manifest-validate.js +34 -2
- package/dist/src/core/patch-order-legal.d.ts +25 -0
- package/dist/src/core/patch-order-legal.js +83 -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 +16 -3
- package/dist/src/core/patch-policy.js +16 -9
- package/dist/src/core/patch-retired.d.ts +35 -0
- package/dist/src/core/patch-retired.js +54 -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 +20 -0
- package/dist/src/core/run-log.js +89 -3
- 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 +18 -1
- package/dist/src/core/test-harness-crash.js +6 -4
- package/dist/src/core/test-harness-signature.d.ts +17 -0
- package/dist/src/core/test-harness-signature.js +4 -0
- package/dist/src/core/test-run-completeness.d.ts +57 -0
- package/dist/src/core/test-run-completeness.js +144 -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/token-lint.d.ts +50 -0
- package/dist/src/core/token-lint.js +126 -0
- package/dist/src/core/tree-guard.js +3 -0
- package/dist/src/core/typecheck-shim.d.ts +1 -1
- package/dist/src/core/typecheck-shim.js +90 -2
- package/dist/src/index.d.ts +8 -3
- package/dist/src/index.js +3 -1
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +148 -21
- package/dist/src/types/commands/patches.d.ts +75 -1
- package/dist/src/types/config.d.ts +192 -0
- package/dist/src/types/config.js +9 -0
- package/dist/src/types/furnace.d.ts +43 -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 +34 -6
- package/dist/src/utils/options.js +86 -5
- 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 +282 -9
- package/docs/exit-codes.md +18 -1
- package/docs/furnace.md +97 -3
- package/docs/lifecycle-invariants.md +52 -19
- package/docs/machine-output.md +74 -12
- package/docs/patch-workflow.md +297 -22
- package/docs/run-logs.md +20 -1
- package/docs/testing.md +276 -20
- package/package.json +2 -2
|
@@ -1,62 +1,87 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Decides which earlier packaging claims a scoped `fireforge test --build`
|
|
3
|
+
* keeps. Retention is per staged path (see `coverage-records.ts`): an
|
|
4
|
+
* earlier path stays covered while its own staging inputs are unchanged,
|
|
5
|
+
* whatever moved elsewhere in the engine, and a full claim narrows to
|
|
6
|
+
* per-path checks once something outside the new scope changed instead of
|
|
7
|
+
* collapsing to this build's paths. `--extend-coverage` turns any drop into
|
|
8
|
+
* a refusal before the build.
|
|
9
|
+
*
|
|
10
|
+
* Fingerprints must be complete: a legacy packageable-only record cannot
|
|
5
11
|
* prove that a test fixture or manifest still matches its staged copy.
|
|
6
12
|
*/
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
import type { BuildBaseline, CoverageAnchor, CoverageRecord, TestPackagingCoverage } from './build-baseline-types.js';
|
|
14
|
+
export { hashEngineFile } from './coverage-records.js';
|
|
15
|
+
/** What a dropped full claim is called in notices and refusals. */
|
|
16
|
+
export declare const FULL_CLAIM_LABEL = "full coverage";
|
|
17
|
+
/** An earlier claim this build cannot keep, and why. */
|
|
18
|
+
export interface DroppedClaim {
|
|
19
|
+
/** Request path, or {@link FULL_CLAIM_LABEL}. */
|
|
20
|
+
path: string;
|
|
21
|
+
/** Staging inputs whose content changed since the claim was staged. */
|
|
22
|
+
changed: string[];
|
|
23
|
+
/** Why the claim cannot be verified at all, when no input list explains it. */
|
|
24
|
+
reason?: string;
|
|
25
|
+
}
|
|
26
|
+
/** What a scoped build keeps of the recorded coverage. */
|
|
27
|
+
export interface CoverageRetentionPlan {
|
|
28
|
+
/** The previous claim was full and nothing outside this build's scope moved. */
|
|
29
|
+
keepFull: boolean;
|
|
30
|
+
/** Earlier per-path records kept, refreshed for this build's paths. */
|
|
31
|
+
retained: Record<string, CoverageRecord>;
|
|
32
|
+
/** Full-build anchor carried for dispatch-time per-path checks. */
|
|
33
|
+
fullAnchor: CoverageAnchor | undefined;
|
|
34
|
+
/** Changed inputs that narrowed a full claim to per-path checks. */
|
|
35
|
+
narrowedBy: string[];
|
|
36
|
+
/** Earlier claims this build cannot keep. */
|
|
37
|
+
dropped: DroppedClaim[];
|
|
38
|
+
}
|
|
39
|
+
/** The baseline-wide anchor a baseline's own fields describe, when complete. */
|
|
40
|
+
export declare function baselineAnchor(baseline: BuildBaseline): CoverageAnchor | undefined;
|
|
18
41
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
42
|
+
* Plans which earlier claims a scoped build over `requested` keeps. Runs
|
|
43
|
+
* before the build lock, so a refusal costs neither build time nor the
|
|
44
|
+
* lock. The mozconfig half runs later, via {@link applyMozconfigAnchor}.
|
|
45
|
+
*
|
|
22
46
|
* @param engineDir - Path to the engine directory
|
|
23
|
-
* @param
|
|
47
|
+
* @param previous - Baseline recorded by the previous build
|
|
48
|
+
* @param requested - Normalized request paths this build packages
|
|
24
49
|
*/
|
|
25
|
-
export declare function
|
|
50
|
+
export declare function planCoverageRetention(engineDir: string, previous: BuildBaseline | undefined, requested: string[]): Promise<CoverageRetentionPlan>;
|
|
26
51
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* costs no build time.
|
|
52
|
+
* Applies the mozconfig half of the anchor: a claim staged under a different
|
|
53
|
+
* `engine/mozconfig` is dropped. Runs after `prepareBuildEnvironment`
|
|
54
|
+
* regenerated the file this build configures with, and before mach.
|
|
55
|
+
*
|
|
32
56
|
* @param engineDir - Path to the engine directory
|
|
33
|
-
* @param
|
|
57
|
+
* @param plan - Plan from {@link planCoverageRetention}
|
|
34
58
|
*/
|
|
35
|
-
export declare function
|
|
59
|
+
export declare function applyMozconfigAnchor(engineDir: string, plan: CoverageRetentionPlan): Promise<CoverageRetentionPlan>;
|
|
60
|
+
/** Fields a scoped build writes onto its baseline. */
|
|
61
|
+
export interface RecordedCoverage {
|
|
62
|
+
testPackagingCoverage: TestPackagingCoverage;
|
|
63
|
+
testCoverageRecords?: Record<string, CoverageRecord>;
|
|
64
|
+
fullCoverageAnchor?: CoverageAnchor;
|
|
65
|
+
}
|
|
36
66
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
67
|
+
* The coverage a green scoped build records: `'full'` when the plan kept a
|
|
68
|
+
* full claim, otherwise this build's paths with fresh records plus every
|
|
69
|
+
* retained earlier path, and the carried full anchor.
|
|
40
70
|
*
|
|
41
|
-
* @param
|
|
71
|
+
* @param engineDir - Path to the engine directory
|
|
72
|
+
* @param plan - Plan after {@link applyMozconfigAnchor}
|
|
42
73
|
* @param requested - Normalized request paths this build packaged
|
|
43
74
|
*/
|
|
44
|
-
export declare function
|
|
75
|
+
export declare function recordScopedCoverage(engineDir: string, plan: CoverageRetentionPlan, requested: string[]): Promise<RecordedCoverage>;
|
|
76
|
+
/** Renders one dropped claim with its cause. */
|
|
77
|
+
export declare function describeDroppedClaim(claim: DroppedClaim): string;
|
|
45
78
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* without matching copy.
|
|
49
|
-
* @param result - Failing result from an anchor check
|
|
79
|
+
* The notice a scoped build prints about earlier coverage, or undefined
|
|
80
|
+
* when nothing was dropped or narrowed.
|
|
50
81
|
*/
|
|
51
|
-
export declare function
|
|
52
|
-
reason: ExtendAnchorReason;
|
|
53
|
-
detail: string[];
|
|
54
|
-
}): string;
|
|
82
|
+
export declare function formatCoverageRetentionNotice(plan: CoverageRetentionPlan): string | undefined;
|
|
55
83
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* treats as "cannot prove unchanged", i.e. a refusal.
|
|
59
|
-
* @param engineDir - Path to the engine directory
|
|
60
|
-
* @param relPath - Engine-relative POSIX path
|
|
84
|
+
* The `--extend-coverage` refusal: the flag asks that no earlier claim be
|
|
85
|
+
* dropped, and the plan would drop some.
|
|
61
86
|
*/
|
|
62
|
-
export declare function
|
|
87
|
+
export declare function formatExtendCoverageRefusal(dropped: readonly DroppedClaim[]): string;
|
|
@@ -1,179 +1,234 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Decides which earlier packaging claims a scoped `fireforge test --build`
|
|
4
|
+
* keeps. Retention is per staged path (see `coverage-records.ts`): an
|
|
5
|
+
* earlier path stays covered while its own staging inputs are unchanged,
|
|
6
|
+
* whatever moved elsewhere in the engine, and a full claim narrows to
|
|
7
|
+
* per-path checks once something outside the new scope changed instead of
|
|
8
|
+
* collapsing to this build's paths. `--extend-coverage` turns any drop into
|
|
9
|
+
* a refusal before the build.
|
|
10
|
+
*
|
|
11
|
+
* Fingerprints must be complete: a legacy packageable-only record cannot
|
|
6
12
|
* prove that a test fixture or manifest still matches its staged copy.
|
|
7
13
|
*/
|
|
8
|
-
import {
|
|
9
|
-
import { join } from 'node:path';
|
|
10
|
-
import { getNodeErrorCode, toError } from '../utils/errors.js';
|
|
11
|
-
import { sha256Hex } from '../utils/hash.js';
|
|
14
|
+
import { toError } from '../utils/errors.js';
|
|
12
15
|
import { verbose } from '../utils/logger.js';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
import { git } from './git-base.js';
|
|
16
|
-
import { getUntrackedFiles } from './git-status.js';
|
|
16
|
+
import { collectStagingInputs, createCoverageRecord, findChangedInputs, hashEngineFile, isUnderPath, narrowAnchor, normalizeRequestPath, readEngineContentState, refreshAnchor, } from './coverage-records.js';
|
|
17
|
+
export { hashEngineFile } from './coverage-records.js';
|
|
17
18
|
/** Filename of the generated mozconfig, relative to the engine directory. */
|
|
18
19
|
const MOZCONFIG_FILENAME = 'mozconfig';
|
|
19
|
-
/** How many
|
|
20
|
-
const
|
|
20
|
+
/** How many paths a notice or refusal names before truncating. */
|
|
21
|
+
const MAX_PATHS_REPORTED = 5;
|
|
22
|
+
/** What a dropped full claim is called in notices and refusals. */
|
|
23
|
+
export const FULL_CLAIM_LABEL = 'full coverage';
|
|
24
|
+
const UNVERIFIABLE = 'engine HEAD or the recorded anchor cannot be compared';
|
|
25
|
+
const NO_FINGERPRINTS = 'the record has no complete staging-input fingerprints';
|
|
26
|
+
/** The baseline-wide anchor a baseline's own fields describe, when complete. */
|
|
27
|
+
export function baselineAnchor(baseline) {
|
|
28
|
+
if (baseline.testInputFingerprints === undefined || baseline.mozconfigHash === undefined) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
engineHeadSha: baseline.engineHeadSha,
|
|
33
|
+
mozconfigHash: baseline.mozconfigHash,
|
|
34
|
+
fingerprints: baseline.testInputFingerprints,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function emptyPlan() {
|
|
38
|
+
return { keepFull: false, retained: {}, fullAnchor: undefined, narrowedBy: [], dropped: [] };
|
|
39
|
+
}
|
|
40
|
+
/** True when a request path in `requested` stages `path` afresh. */
|
|
41
|
+
function rebuiltBy(path, rebuilt) {
|
|
42
|
+
const normalized = normalizeRequestPath(path);
|
|
43
|
+
return rebuilt.some((request) => isUnderPath(normalized, request));
|
|
44
|
+
}
|
|
45
|
+
async function planFullClaim(state, previous, requested) {
|
|
46
|
+
const plan = emptyPlan();
|
|
47
|
+
const anchor = previous.fullCoverageAnchor ?? baselineAnchor(previous);
|
|
48
|
+
if (anchor === undefined) {
|
|
49
|
+
plan.dropped.push({ path: FULL_CLAIM_LABEL, changed: [], reason: NO_FINGERPRINTS });
|
|
50
|
+
return plan;
|
|
51
|
+
}
|
|
52
|
+
const changed = await findChangedInputs(state, anchor, undefined, requested);
|
|
53
|
+
const refreshed = changed === undefined ? undefined : await refreshAnchor(state, anchor, requested);
|
|
54
|
+
if (changed === undefined || refreshed === undefined) {
|
|
55
|
+
plan.dropped.push({ path: FULL_CLAIM_LABEL, changed: [], reason: UNVERIFIABLE });
|
|
56
|
+
return plan;
|
|
57
|
+
}
|
|
58
|
+
plan.keepFull = changed.length === 0;
|
|
59
|
+
plan.fullAnchor = refreshed;
|
|
60
|
+
plan.narrowedBy = changed;
|
|
61
|
+
return plan;
|
|
62
|
+
}
|
|
63
|
+
async function retainRecord(state, previous, path, requested) {
|
|
64
|
+
let record = previous.testCoverageRecords?.[path];
|
|
65
|
+
if (record === undefined) {
|
|
66
|
+
// A path recorded before per-path anchors existed: the baseline-wide
|
|
67
|
+
// anchor, restricted to the path's own inputs, says the same thing.
|
|
68
|
+
const anchor = baselineAnchor(previous);
|
|
69
|
+
if (anchor === undefined)
|
|
70
|
+
return { path, changed: [], reason: NO_FINGERPRINTS };
|
|
71
|
+
const inputs = await collectStagingInputs(state.engineDir, path);
|
|
72
|
+
record = await narrowAnchor(state, anchor, inputs);
|
|
73
|
+
if (record === undefined)
|
|
74
|
+
return { path, changed: [], reason: UNVERIFIABLE };
|
|
75
|
+
}
|
|
76
|
+
const changed = await findChangedInputs(state, record, record.inputs, requested);
|
|
77
|
+
if (changed === undefined)
|
|
78
|
+
return { path, changed: [], reason: UNVERIFIABLE };
|
|
79
|
+
if (changed.length > 0)
|
|
80
|
+
return { path, changed };
|
|
81
|
+
const refreshed = await refreshAnchor(state, record, requested);
|
|
82
|
+
return refreshed === undefined
|
|
83
|
+
? { path, changed: [], reason: UNVERIFIABLE }
|
|
84
|
+
: { record: refreshed };
|
|
85
|
+
}
|
|
21
86
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
87
|
+
* Plans which earlier claims a scoped build over `requested` keeps. Runs
|
|
88
|
+
* before the build lock, so a refusal costs neither build time nor the
|
|
89
|
+
* lock. The mozconfig half runs later, via {@link applyMozconfigAnchor}.
|
|
90
|
+
*
|
|
25
91
|
* @param engineDir - Path to the engine directory
|
|
26
|
-
* @param
|
|
92
|
+
* @param previous - Baseline recorded by the previous build
|
|
93
|
+
* @param requested - Normalized request paths this build packages
|
|
27
94
|
*/
|
|
28
|
-
export async function
|
|
29
|
-
if (
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const rebuilt = (file) => rebuiltPaths.some((path) => file === path || file.startsWith(path.replace(/\/$/, '') + '/'));
|
|
37
|
-
if (recordedFingerprints === undefined) {
|
|
38
|
-
return { ok: false, reason: 'no-fingerprints', detail: [] };
|
|
39
|
-
}
|
|
40
|
-
const currentHead = await readEngineHead(engineDir);
|
|
41
|
-
if (currentHead === undefined || previousBaseline.engineHeadSha === '') {
|
|
42
|
-
// An unborn or unreadable HEAD gives nothing to anchor to.
|
|
43
|
-
return { ok: false, reason: 'head-moved', detail: [] };
|
|
95
|
+
export async function planCoverageRetention(engineDir, previous, requested) {
|
|
96
|
+
if (previous === undefined)
|
|
97
|
+
return emptyPlan();
|
|
98
|
+
const coverage = previous.testPackagingCoverage ?? 'full';
|
|
99
|
+
const rebuilt = requested.map(normalizeRequestPath).filter((path) => path !== '');
|
|
100
|
+
let state;
|
|
101
|
+
try {
|
|
102
|
+
state = await readEngineContentState(engineDir);
|
|
44
103
|
}
|
|
45
|
-
|
|
104
|
+
catch (error) {
|
|
105
|
+
verbose(`Coverage retention: engine state unreadable — ${toError(error).message}`);
|
|
106
|
+
const paths = coverage === 'full' ? [FULL_CLAIM_LABEL] : coverage;
|
|
46
107
|
return {
|
|
47
|
-
|
|
48
|
-
reason:
|
|
49
|
-
detail: [`recorded ${previousBaseline.engineHeadSha}`, `current ${currentHead}`],
|
|
108
|
+
...emptyPlan(),
|
|
109
|
+
dropped: paths.map((path) => ({ path, changed: [], reason: UNVERIFIABLE })),
|
|
50
110
|
};
|
|
51
111
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
// New dirty test inputs are absent from the previous fingerprint map.
|
|
61
|
-
// They invalidate retained staging too; explicitly rebuilt inputs are safe.
|
|
62
|
-
if (previousBaseline.testInputFingerprints !== undefined) {
|
|
63
|
-
const changed = (await git(['diff', '--name-only', 'HEAD'], engineDir)).split('\n');
|
|
64
|
-
changed.push(...(await getUntrackedFiles(engineDir)));
|
|
65
|
-
for (const file of changed.filter(Boolean)) {
|
|
66
|
-
if (file === MOZCONFIG_FILENAME || rebuilt(file) || Object.hasOwn(recordedFingerprints, file))
|
|
67
|
-
continue;
|
|
68
|
-
// A retained manifest may stage a shared fixture outside test-named
|
|
69
|
-
// directories. Without its full dependency graph, refuse conservatively.
|
|
70
|
-
diverged.push(file);
|
|
112
|
+
if (coverage === 'full')
|
|
113
|
+
return planFullClaim(state, previous, rebuilt);
|
|
114
|
+
const plan = emptyPlan();
|
|
115
|
+
if (previous.fullCoverageAnchor !== undefined) {
|
|
116
|
+
plan.fullAnchor = await refreshAnchor(state, previous.fullCoverageAnchor, rebuilt);
|
|
117
|
+
if (plan.fullAnchor === undefined) {
|
|
118
|
+
plan.dropped.push({ path: FULL_CLAIM_LABEL, changed: [], reason: UNVERIFIABLE });
|
|
71
119
|
}
|
|
72
120
|
}
|
|
73
|
-
|
|
74
|
-
|
|
121
|
+
for (const path of coverage) {
|
|
122
|
+
if (rebuiltBy(path, rebuilt))
|
|
123
|
+
continue;
|
|
124
|
+
const outcome = await retainRecord(state, previous, path, rebuilt);
|
|
125
|
+
if ('record' in outcome)
|
|
126
|
+
plan.retained[path] = outcome.record;
|
|
127
|
+
else
|
|
128
|
+
plan.dropped.push(outcome);
|
|
75
129
|
}
|
|
76
|
-
return
|
|
130
|
+
return plan;
|
|
77
131
|
}
|
|
78
132
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* costs no build time.
|
|
133
|
+
* Applies the mozconfig half of the anchor: a claim staged under a different
|
|
134
|
+
* `engine/mozconfig` is dropped. Runs after `prepareBuildEnvironment`
|
|
135
|
+
* regenerated the file this build configures with, and before mach.
|
|
136
|
+
*
|
|
84
137
|
* @param engineDir - Path to the engine directory
|
|
85
|
-
* @param
|
|
138
|
+
* @param plan - Plan from {@link planCoverageRetention}
|
|
86
139
|
*/
|
|
87
|
-
export async function
|
|
88
|
-
const recorded = previousBaseline?.mozconfigHash;
|
|
89
|
-
if (recorded === undefined) {
|
|
90
|
-
return { ok: false, reason: 'no-mozconfig-hash', detail: [] };
|
|
91
|
-
}
|
|
140
|
+
export async function applyMozconfigAnchor(engineDir, plan) {
|
|
92
141
|
const live = await hashEngineFile(engineDir, MOZCONFIG_FILENAME);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
142
|
+
const reason = 'engine/mozconfig differs from the build that staged it';
|
|
143
|
+
const next = { ...plan, retained: {}, dropped: [...plan.dropped] };
|
|
144
|
+
for (const [path, record] of Object.entries(plan.retained)) {
|
|
145
|
+
if (live !== undefined && record.mozconfigHash === live)
|
|
146
|
+
next.retained[path] = record;
|
|
147
|
+
else
|
|
148
|
+
next.dropped.push({ path, changed: [], reason });
|
|
149
|
+
}
|
|
150
|
+
if (plan.fullAnchor !== undefined &&
|
|
151
|
+
(live === undefined || plan.fullAnchor.mozconfigHash !== live)) {
|
|
152
|
+
next.fullAnchor = undefined;
|
|
153
|
+
next.keepFull = false;
|
|
154
|
+
next.narrowedBy = [];
|
|
155
|
+
next.dropped.push({ path: FULL_CLAIM_LABEL, changed: [], reason });
|
|
156
|
+
}
|
|
157
|
+
return next;
|
|
97
158
|
}
|
|
98
159
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
160
|
+
* The coverage a green scoped build records: `'full'` when the plan kept a
|
|
161
|
+
* full claim, otherwise this build's paths with fresh records plus every
|
|
162
|
+
* retained earlier path, and the carried full anchor.
|
|
102
163
|
*
|
|
103
|
-
* @param
|
|
164
|
+
* @param engineDir - Path to the engine directory
|
|
165
|
+
* @param plan - Plan after {@link applyMozconfigAnchor}
|
|
104
166
|
* @param requested - Normalized request paths this build packaged
|
|
105
167
|
*/
|
|
106
|
-
export function
|
|
107
|
-
if (
|
|
108
|
-
return 'full';
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
'with the paths it actually vouches for.';
|
|
121
|
-
switch (result.reason) {
|
|
122
|
-
case 'no-baseline':
|
|
123
|
-
return `--extend-coverage has nothing to extend: no previous build baseline is recorded. ${remedy}`;
|
|
124
|
-
case 'no-mozconfig-hash':
|
|
125
|
-
return ('--extend-coverage refused: the recorded baseline predates the mozconfig anchor, so it ' +
|
|
126
|
-
`cannot be proven that this build configures identically. ${remedy}`);
|
|
127
|
-
case 'no-fingerprints':
|
|
128
|
-
return ('--extend-coverage refused: the recorded baseline carries no complete test-input fingerprints, so ' +
|
|
129
|
-
`the earlier scope's staging inputs cannot be verified unchanged. ${remedy}`);
|
|
130
|
-
case 'head-moved':
|
|
131
|
-
return ('--extend-coverage refused: engine HEAD moved since the recorded build ' +
|
|
132
|
-
`(${result.detail.join(', ') || 'no usable HEAD'}), so the earlier scope's packaging is no ` +
|
|
133
|
-
`longer anchored. ${remedy}`);
|
|
134
|
-
case 'fingerprint-diverged':
|
|
135
|
-
return ('--extend-coverage refused: ' +
|
|
136
|
-
`${result.detail.length} staging input(s) the recorded build staged have changed ` +
|
|
137
|
-
`since (${formatDivergedPaths(result.detail)}). Extending would vouch for the earlier scope ` +
|
|
138
|
-
`while obj-*/_tests/ still holds its stale staging. ${remedy}`);
|
|
139
|
-
case 'mozconfig-changed':
|
|
140
|
-
return ('--extend-coverage refused: engine/mozconfig differs from the recorded build (it is ' +
|
|
141
|
-
'regenerated from configs/*.mozconfig and fireforge.json on every build, so engine HEAD ' +
|
|
142
|
-
`does not cover it). ${remedy}`);
|
|
168
|
+
export async function recordScopedCoverage(engineDir, plan, requested) {
|
|
169
|
+
if (plan.keepFull)
|
|
170
|
+
return { testPackagingCoverage: 'full' };
|
|
171
|
+
const records = { ...plan.retained };
|
|
172
|
+
try {
|
|
173
|
+
const state = await readEngineContentState(engineDir);
|
|
174
|
+
const mozconfigHash = await hashEngineFile(engineDir, MOZCONFIG_FILENAME);
|
|
175
|
+
for (const path of requested) {
|
|
176
|
+
const record = mozconfigHash === undefined
|
|
177
|
+
? undefined
|
|
178
|
+
: await createCoverageRecord(state, path, mozconfigHash);
|
|
179
|
+
if (record !== undefined)
|
|
180
|
+
records[path] = record;
|
|
181
|
+
}
|
|
143
182
|
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
verbose(`Coverage records: could not anchor this build's paths — ${toError(error).message}`);
|
|
185
|
+
}
|
|
186
|
+
const kept = Object.keys(plan.retained);
|
|
187
|
+
const coverage = kept.length === 0 ? [...requested] : [...new Set([...kept, ...requested])].sort();
|
|
188
|
+
return {
|
|
189
|
+
testPackagingCoverage: coverage,
|
|
190
|
+
...(Object.keys(records).length > 0 ? { testCoverageRecords: records } : {}),
|
|
191
|
+
...(plan.fullAnchor !== undefined ? { fullCoverageAnchor: plan.fullAnchor } : {}),
|
|
192
|
+
};
|
|
144
193
|
}
|
|
145
|
-
function
|
|
146
|
-
const head = paths.slice(0,
|
|
147
|
-
const extra = paths.length - Math.min(paths.length,
|
|
194
|
+
function capList(paths) {
|
|
195
|
+
const head = paths.slice(0, MAX_PATHS_REPORTED).join(', ');
|
|
196
|
+
const extra = paths.length - Math.min(paths.length, MAX_PATHS_REPORTED);
|
|
148
197
|
return extra > 0 ? `${head}, … (+${extra} more)` : head;
|
|
149
198
|
}
|
|
199
|
+
/** Renders one dropped claim with its cause. */
|
|
200
|
+
export function describeDroppedClaim(claim) {
|
|
201
|
+
const cause = claim.changed.length > 0
|
|
202
|
+
? `staging inputs changed: ${capList(claim.changed)}`
|
|
203
|
+
: (claim.reason ?? UNVERIFIABLE);
|
|
204
|
+
return `${claim.path} (${cause})`;
|
|
205
|
+
}
|
|
150
206
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* treats as "cannot prove unchanged", i.e. a refusal.
|
|
154
|
-
* @param engineDir - Path to the engine directory
|
|
155
|
-
* @param relPath - Engine-relative POSIX path
|
|
207
|
+
* The notice a scoped build prints about earlier coverage, or undefined
|
|
208
|
+
* when nothing was dropped or narrowed.
|
|
156
209
|
*/
|
|
157
|
-
export
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
210
|
+
export function formatCoverageRetentionNotice(plan) {
|
|
211
|
+
const lines = [];
|
|
212
|
+
if (plan.dropped.length > 0) {
|
|
213
|
+
const kept = Object.keys(plan.retained);
|
|
214
|
+
lines.push(`Scoped build drops previous packaging coverage for ${plan.dropped.map(describeDroppedClaim).join('; ')}.` +
|
|
215
|
+
(kept.length > 0 ? ` Kept: ${capList(kept)}.` : '') +
|
|
216
|
+
' Rebuild a dropped path (alone or with this one) before running it without --build.');
|
|
217
|
+
}
|
|
218
|
+
if (!plan.keepFull && plan.fullAnchor !== undefined && plan.narrowedBy.length > 0) {
|
|
219
|
+
lines.push(`Full packaging coverage is now checked per path: ${capList(plan.narrowedBy)} changed outside ` +
|
|
220
|
+
"this build's scope, so a later run is refused only for paths whose own staging inputs include a changed file.");
|
|
221
|
+
}
|
|
222
|
+
return lines.length > 0 ? lines.join('\n') : undefined;
|
|
169
223
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
224
|
+
/**
|
|
225
|
+
* The `--extend-coverage` refusal: the flag asks that no earlier claim be
|
|
226
|
+
* dropped, and the plan would drop some.
|
|
227
|
+
*/
|
|
228
|
+
export function formatExtendCoverageRefusal(dropped) {
|
|
229
|
+
return (`--extend-coverage refused: this build would drop earlier packaging coverage for ` +
|
|
230
|
+
`${dropped.length} claim(s): ${dropped.map(describeDroppedClaim).join('; ')}. ` +
|
|
231
|
+
'Extending would vouch for staging that obj-*/_tests/ no longer matches. Rebuild those paths ' +
|
|
232
|
+
'together with this one, or drop the flag: without it the dropped claims are named and the ' +
|
|
233
|
+
'rest of the coverage is kept.');
|
|
179
234
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-path packaging-coverage anchors for scoped `fireforge test --build`.
|
|
3
|
+
*
|
|
4
|
+
* A scoped build used to carry one claim anchored to the whole engine, so
|
|
5
|
+
* any edit outside the new scope (a peer's, on a shared engine, nearly
|
|
6
|
+
* always) replaced it. Each staged request path now carries its own anchor
|
|
7
|
+
* restricted to its own staging inputs, and a claim is dropped only when
|
|
8
|
+
* one of those inputs changed.
|
|
9
|
+
*
|
|
10
|
+
* The staging inputs of a request path are its manifest directory (the
|
|
11
|
+
* nearest directory at or above it that holds a test manifest) plus every
|
|
12
|
+
* path a manifest there names outside that directory (`support-files`,
|
|
13
|
+
* `head`, `!/`-rooted shared fixtures). Without the full mozbuild graph
|
|
14
|
+
* that is the closest sound boundary: an edit outside it cannot change
|
|
15
|
+
* what the harness stages for that path.
|
|
16
|
+
*/
|
|
17
|
+
import { type CoverageAnchor, type CoverageRecord } from './build-baseline-types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Hex-encoded SHA-256 of an engine-relative file, matching the digest the
|
|
20
|
+
* baseline writer produces. A missing file hashes to
|
|
21
|
+
* {@link DELETED_FILE_FINGERPRINT}. `undefined` on any other IO error,
|
|
22
|
+
* which every caller treats as "cannot prove unchanged".
|
|
23
|
+
* @param engineDir - Path to the engine directory
|
|
24
|
+
* @param relPath - Engine-relative POSIX path
|
|
25
|
+
*/
|
|
26
|
+
export declare function hashEngineFile(engineDir: string, relPath: string): Promise<string | undefined>;
|
|
27
|
+
/** True for a test manifest path (by basename). */
|
|
28
|
+
export declare function isTestManifestPath(path: string): boolean;
|
|
29
|
+
/** Normalizes a request path: forward slashes, no `./`, no trailing slash. */
|
|
30
|
+
export declare function normalizeRequestPath(path: string): string;
|
|
31
|
+
/** True when `file` is `prefix` or sits beneath it. The empty prefix is the whole tree. */
|
|
32
|
+
export declare function isUnderPath(file: string, prefix: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Engine state one coverage decision reads. Shared across every anchor a
|
|
35
|
+
* decision verifies, so the git probes run once and each file is hashed
|
|
36
|
+
* once.
|
|
37
|
+
*/
|
|
38
|
+
export interface EngineContentState {
|
|
39
|
+
engineDir: string;
|
|
40
|
+
/** Current engine HEAD, or undefined for an unborn branch. */
|
|
41
|
+
head: string | undefined;
|
|
42
|
+
/** Engine-relative paths dirty against HEAD (tracked and untracked). */
|
|
43
|
+
dirty: ReadonlySet<string>;
|
|
44
|
+
hashes: Map<string, Promise<string | undefined>>;
|
|
45
|
+
diffs: Map<string, Promise<ReadonlySet<string> | undefined>>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Reads HEAD and the dirty set. Throws on a git failure other than an
|
|
49
|
+
* unborn HEAD: callers treat that as "nothing can be proven unchanged".
|
|
50
|
+
* @param engineDir - Path to the engine directory
|
|
51
|
+
*/
|
|
52
|
+
export declare function readEngineContentState(engineDir: string): Promise<EngineContentState>;
|
|
53
|
+
/**
|
|
54
|
+
* Inputs whose live content differs from what the anchor staged, sorted.
|
|
55
|
+
* Undefined when the anchor cannot be compared, which every caller treats as
|
|
56
|
+
* "changed".
|
|
57
|
+
*
|
|
58
|
+
* @param state - Engine state from {@link readEngineContentState}
|
|
59
|
+
* @param anchor - The claim's anchor
|
|
60
|
+
* @param inputs - Staging inputs to compare, or undefined for the whole tree
|
|
61
|
+
* @param rebuilt - Request paths the current build stages afresh
|
|
62
|
+
*/
|
|
63
|
+
export declare function findChangedInputs(state: EngineContentState, anchor: CoverageAnchor, inputs: readonly string[] | undefined, rebuilt?: readonly string[]): Promise<string[] | undefined>;
|
|
64
|
+
/**
|
|
65
|
+
* The anchor after the current build restaged `rebuilt`: recorded content
|
|
66
|
+
* for those paths becomes their live content. Undefined when that content
|
|
67
|
+
* cannot be read or the anchor cannot be compared.
|
|
68
|
+
*/
|
|
69
|
+
export declare function refreshAnchor<T extends CoverageAnchor>(state: EngineContentState, anchor: T, rebuilt: readonly string[]): Promise<T | undefined>;
|
|
70
|
+
/**
|
|
71
|
+
* Engine-relative paths a manifest names outside its own directory. Bare
|
|
72
|
+
* names stay inside it. `!/` and `/` prefixes are engine-root relative, as
|
|
73
|
+
* in mozbuild manifests. A glob keeps the directory part before its first
|
|
74
|
+
* wildcard segment.
|
|
75
|
+
*/
|
|
76
|
+
export declare function manifestExternalReferences(manifestPath: string, text: string): string[];
|
|
77
|
+
/**
|
|
78
|
+
* Staging inputs of one request path. See the module comment.
|
|
79
|
+
* @param engineDir - Path to the engine directory
|
|
80
|
+
* @param requestPath - Engine-relative request path (file or directory)
|
|
81
|
+
*/
|
|
82
|
+
export declare function collectStagingInputs(engineDir: string, requestPath: string): Promise<string[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Records the anchor of a request path this build staged. Undefined when
|
|
85
|
+
* HEAD is unborn or an input's content cannot be read: the path is still
|
|
86
|
+
* claimed, and later retention falls back to the baseline-wide anchor.
|
|
87
|
+
*
|
|
88
|
+
* @param state - Engine state after the build
|
|
89
|
+
* @param requestPath - Engine-relative request path
|
|
90
|
+
* @param mozconfigHash - Hash of the mozconfig the build configured with
|
|
91
|
+
*/
|
|
92
|
+
export declare function createCoverageRecord(state: EngineContentState, requestPath: string, mozconfigHash: string): Promise<CoverageRecord | undefined>;
|
|
93
|
+
/**
|
|
94
|
+
* Restricts an anchor to `inputs`. `extraDirty` adds paths whose live content
|
|
95
|
+
* becomes the recorded one (the dirty set of a record being created).
|
|
96
|
+
*/
|
|
97
|
+
export declare function narrowAnchor(state: EngineContentState, anchor: CoverageAnchor, inputs: string[], extraDirty?: readonly string[]): Promise<CoverageRecord | undefined>;
|