@hominis/fireforge 0.44.4 → 0.46.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 +120 -0
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +46 -0
- package/dist/src/cli-usage-error.js +81 -0
- package/dist/src/cli.d.ts +5 -1
- package/dist/src/cli.js +20 -21
- package/dist/src/commands/bootstrap.js +1 -2
- package/dist/src/commands/build.js +15 -6
- package/dist/src/commands/destructive-decision.d.ts +19 -0
- package/dist/src/commands/destructive-decision.js +31 -0
- package/dist/src/commands/doctor-check-core.d.ts +0 -6
- package/dist/src/commands/doctor-check-core.js +0 -8
- package/dist/src/commands/doctor-orphaned-harness.d.ts +0 -6
- package/dist/src/commands/doctor-orphaned-harness.js +4 -12
- package/dist/src/commands/doctor-post-rebase-audit.js +1 -1
- package/dist/src/commands/doctor-source-pin.d.ts +29 -0
- package/dist/src/commands/doctor-source-pin.js +81 -0
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +9 -8
- package/dist/src/commands/download.js +35 -24
- package/dist/src/commands/export-all.js +21 -4
- package/dist/src/commands/export-flow.js +15 -60
- package/dist/src/commands/export-placement-conflicts.js +3 -3
- package/dist/src/commands/export-placement-gate.js +2 -8
- package/dist/src/commands/export-placement-policy.js +3 -5
- package/dist/src/commands/export-shared.d.ts +42 -23
- package/dist/src/commands/export-shared.js +4 -19
- package/dist/src/commands/export.js +10 -1
- package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
- package/dist/src/commands/furnace/authoring-config.js +19 -0
- package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
- package/dist/src/commands/furnace/create-browser-test.js +3 -8
- package/dist/src/commands/furnace/create-dry-run.js +2 -5
- package/dist/src/commands/furnace/create-templates.d.ts +17 -1
- package/dist/src/commands/furnace/create-templates.js +2 -1
- package/dist/src/commands/furnace/create.js +25 -19
- package/dist/src/commands/furnace/deploy.js +11 -2
- package/dist/src/commands/furnace/init.js +2 -1
- package/dist/src/commands/furnace/override.js +28 -19
- package/dist/src/commands/furnace/refresh.js +9 -1
- package/dist/src/commands/furnace/remove-mutations.d.ts +6 -7
- package/dist/src/commands/furnace/remove-mutations.js +0 -1
- package/dist/src/commands/furnace/remove.js +2 -6
- package/dist/src/commands/furnace/rename-browser-test.js +1 -7
- package/dist/src/commands/furnace/rename.js +29 -29
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
- package/dist/src/commands/furnace/test-file-name.js +39 -0
- package/dist/src/commands/furnace/validation-output.d.ts +21 -9
- package/dist/src/commands/furnace/validation-output.js +3 -8
- package/dist/src/commands/import.js +2 -9
- package/dist/src/commands/lint-per-patch.d.ts +2 -2
- package/dist/src/commands/lint-per-patch.js +19 -4
- package/dist/src/commands/lint-per-run-checkjs.d.ts +2 -2
- package/dist/src/commands/lint.d.ts +2 -1
- package/dist/src/commands/lint.js +1 -1
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +2 -4
- package/dist/src/commands/patch/compact.js +14 -15
- package/dist/src/commands/patch/delete.js +15 -25
- package/dist/src/commands/patch/entry-projection.d.ts +13 -0
- package/dist/src/commands/patch/entry-projection.js +24 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +0 -8
- package/dist/src/commands/patch/lint-ignore.js +19 -29
- package/dist/src/commands/patch/move-files-create.js +24 -10
- package/dist/src/commands/patch/move-files-into.js +38 -37
- package/dist/src/commands/patch/move-files.js +4 -13
- package/dist/src/commands/patch/rename.js +27 -41
- package/dist/src/commands/patch/reorder.js +25 -38
- package/dist/src/commands/patch/split-plan.d.ts +4 -5
- package/dist/src/commands/patch/split-plan.js +4 -11
- package/dist/src/commands/patch/split.js +45 -43
- package/dist/src/commands/patch/staged-dependency.js +16 -22
- package/dist/src/commands/patch/tier.js +15 -25
- package/dist/src/commands/patch-rename-map.d.ts +19 -0
- package/dist/src/commands/patch-rename-map.js +36 -0
- package/dist/src/commands/pending-resolution.d.ts +15 -0
- package/dist/src/commands/pending-resolution.js +25 -0
- package/dist/src/commands/re-export-adjacent.d.ts +32 -2
- package/dist/src/commands/re-export-adjacent.js +51 -10
- package/dist/src/commands/re-export-bulk-scan.js +6 -10
- package/dist/src/commands/re-export-drift.d.ts +8 -0
- package/dist/src/commands/re-export-drift.js +65 -4
- package/dist/src/commands/re-export-files.d.ts +2 -3
- package/dist/src/commands/re-export-files.js +38 -32
- package/dist/src/commands/re-export-lint.d.ts +3 -4
- package/dist/src/commands/re-export-lint.js +9 -2
- package/dist/src/commands/re-export-options.js +19 -5
- package/dist/src/commands/re-export-register.js +5 -1
- package/dist/src/commands/re-export-scan.js +8 -8
- package/dist/src/commands/re-export-single.d.ts +22 -3
- package/dist/src/commands/re-export-single.js +19 -11
- package/dist/src/commands/re-export.js +44 -27
- package/dist/src/commands/rebase/abort.js +3 -8
- package/dist/src/commands/rebase/continue.js +12 -12
- package/dist/src/commands/rebase/index.js +2 -2
- package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
- package/dist/src/commands/rebase/patch-loop.js +2 -7
- package/dist/src/commands/resolve.js +18 -10
- package/dist/src/commands/run.d.ts +0 -13
- package/dist/src/commands/run.js +12 -25
- package/dist/src/commands/setup-support.d.ts +16 -4
- package/dist/src/commands/setup-support.js +16 -16
- package/dist/src/commands/setup.js +3 -9
- package/dist/src/commands/source.js +8 -1
- package/dist/src/commands/status-check.js +2 -2
- package/dist/src/commands/status-output.js +2 -2
- package/dist/src/commands/status.js +3 -4
- package/dist/src/commands/test-build-phase.d.ts +2 -2
- package/dist/src/commands/test-build-phase.js +33 -8
- package/dist/src/commands/test-diagnose.js +14 -5
- package/dist/src/commands/test-modes.d.ts +2 -2
- package/dist/src/commands/test-modes.js +0 -1
- package/dist/src/commands/test-register.js +6 -3
- package/dist/src/commands/test-run.js +29 -21
- package/dist/src/commands/test-stale-gate.js +8 -5
- package/dist/src/commands/test-verdict.d.ts +16 -2
- package/dist/src/commands/test-verdict.js +18 -3
- package/dist/src/commands/test.js +51 -7
- package/dist/src/commands/token-list.d.ts +26 -0
- package/dist/src/commands/token-list.js +153 -0
- package/dist/src/commands/token.js +17 -1
- package/dist/src/commands/tree.js +7 -2
- package/dist/src/commands/typecheck.js +9 -9
- package/dist/src/commands/wire.js +4 -3
- package/dist/src/core/branding.d.ts +0 -7
- package/dist/src/core/branding.js +3 -2
- package/dist/src/core/browser-wire.js +6 -3
- package/dist/src/core/build-audit-platform.d.ts +29 -0
- package/dist/src/core/build-audit-platform.js +140 -0
- package/dist/src/core/build-audit-registration.js +3 -2
- package/dist/src/core/build-audit-skip.d.ts +57 -0
- package/dist/src/core/build-audit-skip.js +112 -0
- package/dist/src/core/build-audit.d.ts +15 -2
- package/dist/src/core/build-audit.js +154 -12
- package/dist/src/core/build-baseline.d.ts +45 -28
- package/dist/src/core/build-baseline.js +6 -29
- package/dist/src/core/build-jar-escalation.d.ts +64 -0
- package/dist/src/core/build-jar-escalation.js +128 -0
- package/dist/src/core/build-overwrite-guard.js +1 -1
- package/dist/src/core/build-prepare.d.ts +5 -2
- package/dist/src/core/build-prepare.js +34 -6
- package/dist/src/core/config-paths.d.ts +2 -6
- package/dist/src/core/config-paths.js +4 -2
- package/dist/src/core/config-state.d.ts +0 -6
- package/dist/src/core/config-state.js +1 -19
- package/dist/src/core/config-validate-build-audit.d.ts +8 -0
- package/dist/src/core/config-validate-build-audit.js +80 -0
- package/dist/src/core/config-validate-file-size.d.ts +12 -0
- package/dist/src/core/config-validate-file-size.js +65 -0
- package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
- package/dist/src/core/config-validate-patch-policy.js +3 -3
- package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
- package/dist/src/core/config-validate-test-toolchains.js +4 -5
- package/dist/src/core/config-validate.js +20 -3
- package/dist/src/core/config.d.ts +2 -2
- package/dist/src/core/config.js +11 -15
- package/dist/src/core/coverage-extend.js +4 -4
- package/dist/src/core/discard-baseline.js +7 -7
- package/dist/src/core/engine-precondition.d.ts +1 -9
- package/dist/src/core/engine-precondition.js +3 -8
- package/dist/src/core/engine-session-lock.js +13 -17
- package/dist/src/core/export-moved-code-shape.js +2 -2
- package/dist/src/core/file-lock-owner.d.ts +103 -0
- package/dist/src/core/file-lock-owner.js +259 -0
- package/dist/src/core/file-lock.d.ts +2 -7
- package/dist/src/core/file-lock.js +40 -91
- package/dist/src/core/firefox-cache.d.ts +13 -1
- package/dist/src/core/firefox-cache.js +59 -34
- package/dist/src/core/firefox-download.d.ts +15 -0
- package/dist/src/core/firefox-download.js +37 -21
- package/dist/src/core/firefox-extract.d.ts +6 -5
- package/dist/src/core/firefox-extract.js +36 -18
- package/dist/src/core/firefox.d.ts +30 -32
- package/dist/src/core/firefox.js +5 -36
- package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
- package/dist/src/core/furnace-apply-dry-run.js +1 -7
- package/dist/src/core/furnace-apply-helpers.d.ts +0 -11
- package/dist/src/core/furnace-apply-helpers.js +8 -19
- package/dist/src/core/furnace-apply-overwrite-warn.js +4 -2
- package/dist/src/core/furnace-apply.d.ts +1 -1
- package/dist/src/core/furnace-apply.js +30 -10
- package/dist/src/core/furnace-config.d.ts +1 -1
- package/dist/src/core/furnace-config.js +23 -36
- package/dist/src/core/furnace-constants.js +3 -2
- package/dist/src/core/furnace-dir-entry.d.ts +20 -0
- package/dist/src/core/furnace-dir-entry.js +21 -0
- package/dist/src/core/furnace-operation.d.ts +2 -0
- package/dist/src/core/furnace-operation.js +3 -1
- package/dist/src/core/furnace-refresh.d.ts +18 -6
- package/dist/src/core/furnace-refresh.js +3 -6
- package/dist/src/core/furnace-registration-ast.d.ts +0 -1
- package/dist/src/core/furnace-registration-ast.js +0 -3
- package/dist/src/core/furnace-registration.d.ts +2 -1
- package/dist/src/core/furnace-registration.js +22 -29
- package/dist/src/core/furnace-scanner.js +3 -6
- package/dist/src/core/furnace-state-persist.d.ts +2 -2
- package/dist/src/core/furnace-validate-registration.js +5 -7
- package/dist/src/core/git-base.d.ts +3 -1
- package/dist/src/core/git-base.js +25 -3
- package/dist/src/core/git-diff-new-file.d.ts +40 -0
- package/dist/src/core/git-diff-new-file.js +119 -0
- package/dist/src/core/git-diff.d.ts +9 -9
- package/dist/src/core/git-diff.js +88 -157
- package/dist/src/core/git-file-ops.d.ts +0 -7
- package/dist/src/core/git-file-ops.js +4 -28
- package/dist/src/core/git-readonly-index.d.ts +0 -2
- package/dist/src/core/git-readonly-index.js +0 -4
- package/dist/src/core/git-status.d.ts +7 -0
- package/dist/src/core/git-status.js +21 -9
- package/dist/src/core/git.d.ts +0 -6
- package/dist/src/core/git.js +14 -43
- package/dist/src/core/harness-orphans.d.ts +73 -0
- package/dist/src/core/harness-orphans.js +187 -0
- package/dist/src/core/history-log.d.ts +19 -0
- package/dist/src/core/history-log.js +29 -0
- package/dist/src/core/mach-error-hints.d.ts +0 -5
- package/dist/src/core/mach-error-hints.js +1 -1
- package/dist/src/core/mach-known-noise-filter.d.ts +25 -3
- package/dist/src/core/mach-known-noise-filter.js +31 -10
- package/dist/src/core/mach-mozconfig.js +2 -1
- package/dist/src/core/mach-python.d.ts +2 -0
- package/dist/src/core/mach-python.js +12 -7
- package/dist/src/core/mach-resource-shim.d.ts +13 -1
- package/dist/src/core/mach-resource-shim.js +112 -9
- package/dist/src/core/mach.d.ts +46 -53
- package/dist/src/core/mach.js +31 -83
- package/dist/src/core/marionette-port.d.ts +0 -17
- package/dist/src/core/marionette-port.js +12 -58
- package/dist/src/core/marionette-preflight.js +9 -27
- package/dist/src/core/mochitest-server-port.js +3 -3
- package/dist/src/core/moz-manifest-rules.js +37 -33
- package/dist/src/core/patch-apply-fuzz.js +4 -4
- package/dist/src/core/patch-apply.d.ts +4 -5
- package/dist/src/core/patch-apply.js +55 -32
- package/dist/src/core/patch-export-coverage.d.ts +0 -9
- package/dist/src/core/patch-export-coverage.js +1 -30
- package/dist/src/core/patch-export-update.d.ts +18 -1
- package/dist/src/core/patch-export-update.js +4 -3
- package/dist/src/core/patch-export.d.ts +11 -21
- package/dist/src/core/patch-export.js +44 -66
- package/dist/src/core/patch-files.d.ts +0 -4
- package/dist/src/core/patch-files.js +0 -11
- package/dist/src/core/patch-lint-binary.d.ts +6 -12
- package/dist/src/core/patch-lint-cache.d.ts +17 -1
- package/dist/src/core/patch-lint-cache.js +3 -6
- package/dist/src/core/patch-lint-checkjs.d.ts +33 -16
- package/dist/src/core/patch-lint-checkjs.js +43 -25
- package/dist/src/core/patch-lint-creators.d.ts +2 -6
- package/dist/src/core/patch-lint-cross.d.ts +16 -8
- package/dist/src/core/patch-lint-cross.js +49 -92
- package/dist/src/core/patch-lint-css.js +10 -6
- package/dist/src/core/patch-lint-file-size.d.ts +52 -0
- package/dist/src/core/patch-lint-file-size.js +53 -0
- package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
- package/dist/src/core/patch-lint-forward-registration.js +210 -0
- package/dist/src/core/patch-lint-jsdoc.js +36 -36
- package/dist/src/core/patch-lint-module-registration.d.ts +2 -8
- package/dist/src/core/patch-lint-prettier.d.ts +36 -0
- package/dist/src/core/patch-lint-prettier.js +126 -0
- package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
- package/dist/src/core/patch-lint-queue-types.js +12 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
- package/dist/src/core/patch-lint-staged-registration.js +90 -0
- package/dist/src/core/patch-lint-unmanaged-companion.d.ts +106 -0
- package/dist/src/core/patch-lint-unmanaged-companion.js +214 -0
- package/dist/src/core/patch-lint.d.ts +14 -9
- package/dist/src/core/patch-lint.js +27 -27
- package/dist/src/core/patch-lock.js +3 -3
- package/dist/src/core/patch-manifest-io.js +8 -7
- package/dist/src/core/patch-parse.d.ts +19 -8
- package/dist/src/core/patch-parse.js +25 -0
- package/dist/src/core/patch-policy.js +15 -27
- package/dist/src/core/patch-source-metadata.d.ts +1 -3
- package/dist/src/core/patch-source-metadata.js +0 -4
- package/dist/src/core/patch-transform.d.ts +21 -8
- package/dist/src/core/patch-transform.js +38 -10
- package/dist/src/core/process-cpu-time.js +1 -1
- package/dist/src/core/rebase-session.d.ts +2 -8
- package/dist/src/core/rebase-session.js +5 -17
- package/dist/src/core/register-browser-content.js +3 -2
- package/dist/src/core/register-browser-test.js +2 -1
- package/dist/src/core/register-module.js +2 -1
- package/dist/src/core/register-scaffold.js +5 -4
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/run-log-redact.d.ts +38 -0
- package/dist/src/core/run-log-redact.js +69 -0
- package/dist/src/core/run-log.d.ts +13 -2
- package/dist/src/core/run-log.js +67 -18
- package/dist/src/core/signal-critical.js +2 -4
- package/dist/src/core/smoke-patterns.d.ts +0 -1
- package/dist/src/core/smoke-patterns.js +18 -11
- package/dist/src/core/state-file.d.ts +12 -1
- package/dist/src/core/state-file.js +14 -1
- package/dist/src/core/status-classify.js +2 -1
- package/dist/src/core/test-changed-prefs.js +26 -11
- package/dist/src/core/test-harness-crash.js +61 -48
- package/dist/src/core/test-harness-verdict-notes.d.ts +55 -0
- package/dist/src/core/test-harness-verdict-notes.js +48 -0
- package/dist/src/core/test-stale-check.d.ts +23 -8
- package/dist/src/core/test-stale-check.js +77 -4
- package/dist/src/core/test-stall-triage.js +37 -19
- package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
- package/dist/src/core/test-xpcshell-retry.js +14 -11
- package/dist/src/core/token-category.d.ts +33 -0
- package/dist/src/core/token-category.js +56 -48
- package/dist/src/core/token-dark-mode.js +2 -14
- package/dist/src/core/token-inventory.d.ts +56 -0
- package/dist/src/core/token-inventory.js +109 -0
- package/dist/src/core/token-manager.d.ts +1 -1
- package/dist/src/core/token-manager.js +1 -1
- package/dist/src/core/token-variant.js +21 -22
- package/dist/src/core/toolchain-preflight.js +1 -1
- package/dist/src/core/tree-cow.d.ts +0 -2
- package/dist/src/core/tree-cow.js +2 -2
- package/dist/src/core/tree-store.js +4 -5
- package/dist/src/core/typecheck.js +2 -2
- package/dist/src/core/wire-dom-fragment.js +6 -17
- package/dist/src/core/wire-utils.js +5 -17
- package/dist/src/core/xpcshell-appdir.js +2 -4
- package/dist/src/errors/base.d.ts +53 -1
- package/dist/src/errors/base.js +79 -11
- package/dist/src/errors/build.d.ts +28 -0
- package/dist/src/errors/build.js +51 -10
- package/dist/src/errors/config.d.ts +0 -14
- package/dist/src/errors/config.js +13 -34
- package/dist/src/errors/download.d.ts +13 -0
- package/dist/src/errors/download.js +53 -24
- package/dist/src/errors/furnace.js +8 -9
- package/dist/src/errors/git.d.ts +8 -8
- package/dist/src/errors/git.js +20 -30
- package/dist/src/errors/patch.js +8 -10
- package/dist/src/errors/rebase.js +7 -7
- package/dist/src/types/commands/options.d.ts +96 -123
- package/dist/src/types/commands/patches.d.ts +17 -6
- package/dist/src/types/config.d.ts +75 -2
- package/dist/src/types/index.d.ts +0 -1
- package/dist/src/utils/assert.d.ts +3 -15
- package/dist/src/utils/assert.js +1 -18
- package/dist/src/utils/build-info.d.ts +1 -1
- package/dist/src/utils/child-env.d.ts +2 -1
- package/dist/src/utils/elapsed.js +10 -1
- package/dist/src/utils/fs.d.ts +4 -2
- package/dist/src/utils/fs.js +11 -14
- package/dist/src/utils/hash.d.ts +12 -0
- package/dist/src/utils/hash.js +16 -0
- package/dist/src/utils/line-dispatch.d.ts +15 -0
- package/dist/src/utils/line-dispatch.js +48 -0
- package/dist/src/utils/options.d.ts +1 -7
- package/dist/src/utils/options.js +6 -7
- package/dist/src/utils/package-root.js +3 -12
- package/dist/src/utils/platform.d.ts +0 -4
- package/dist/src/utils/process-group.d.ts +2 -1
- package/dist/src/utils/process-group.js +20 -19
- package/dist/src/utils/process.d.ts +40 -26
- package/dist/src/utils/process.js +115 -166
- package/dist/src/utils/ps-duration.js +3 -3
- package/dist/src/utils/sleep.d.ts +26 -0
- package/dist/src/utils/sleep.js +31 -0
- package/dist/src/utils/validation.d.ts +2 -38
- package/dist/src/utils/validation.js +7 -16
- package/docs/configuration.md +136 -1
- package/docs/exit-codes.md +34 -20
- package/docs/lifecycle-invariants.md +18 -12
- package/docs/machine-output.md +31 -8
- package/docs/patch-workflow.md +2 -1
- package/docs/run-logs.md +44 -4
- package/docs/testing.md +70 -11
- package/package.json +8 -7
- package/dist/src/commands/rebase.d.ts +0 -4
- package/dist/src/commands/rebase.js +0 -5
- package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
- package/dist/src/core/patch-artifact-normalize.js +0 -24
- package/dist/src/core/patch-lint-reexports.d.ts +0 -7
- package/dist/src/core/patch-lint-reexports.js +0 -8
- package/dist/src/core/wire-targets.d.ts +0 -7
- package/dist/src/core/wire-targets.js +0 -8
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* the per-file line budget): the incremental protected mach build with
|
|
4
4
|
* its baseline write, and the `--build-only` union-build shape.
|
|
5
5
|
*/
|
|
6
|
-
import type { getProjectPaths, loadConfig } from '../core/config.js';
|
|
7
6
|
import type { TestOptions } from '../types/commands/index.js';
|
|
7
|
+
import type { FireForgeConfig, ProjectPaths } from '../types/config.js';
|
|
8
8
|
import type { HarnessClassification } from './test-modes.js';
|
|
9
9
|
/**
|
|
10
10
|
* Runs the pre-test build (or the stale-build gate when no build was
|
|
@@ -13,7 +13,7 @@ import type { HarnessClassification } from './test-modes.js';
|
|
|
13
13
|
* (mixed harnesses legal, nothing dispatches), prints the per-harness
|
|
14
14
|
* next steps, and emits the run's single `PASS` verdict.
|
|
15
15
|
*/
|
|
16
|
-
export declare function runTestBuildPhase(projectRoot: string, paths:
|
|
16
|
+
export declare function runTestBuildPhase(projectRoot: string, paths: ProjectPaths, projectConfig: FireForgeConfig, harnessRetries: number, options: TestOptions, request: {
|
|
17
17
|
classification: HarnessClassification;
|
|
18
18
|
normalizedPaths: string[];
|
|
19
19
|
}): Promise<boolean>;
|
|
@@ -16,7 +16,14 @@ import { info, notice, spinner, verbose } from '../utils/logger.js';
|
|
|
16
16
|
import { reportBuildOnlyCompletion } from './test-modes.js';
|
|
17
17
|
import { enforceStaleBuildGate, enforceStaticComponentsGate } from './test-stale-gate.js';
|
|
18
18
|
import { emitPassVerdict } from './test-verdict.js';
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Runs the incremental pre-test build under the build lock and records the
|
|
21
|
+
* baseline it produced.
|
|
22
|
+
*
|
|
23
|
+
* @param options - See {@link RunPreTestBuildOptions}
|
|
24
|
+
*/
|
|
25
|
+
async function runPreTestBuild(options) {
|
|
26
|
+
const { projectRoot, paths, projectConfig, harnessRetries, testPackagingCoverage, refuseUnexportedDrift, extend, } = options;
|
|
20
27
|
await withBuildLock(projectRoot, async () => {
|
|
21
28
|
// Pass the previous baseline exactly like `fireforge build` does, so
|
|
22
29
|
// auto-configure runs under the same conditions on both paths. The
|
|
@@ -43,7 +50,8 @@ async function runPreTestBuild(projectRoot, paths, projectConfig, harnessRetries
|
|
|
43
50
|
// Warning severity, not info: agent-facing output filters
|
|
44
51
|
// keep warnings and errors only, and this is the line that explains an
|
|
45
52
|
// otherwise unexplained multi-minute build.
|
|
46
|
-
notice(
|
|
53
|
+
notice(preparation.fullBuildReason ??
|
|
54
|
+
'A jar.mn registration changed since the last successful build; escalating this pre-test build to a full mach build so new install-manifest destinations are created.');
|
|
47
55
|
}
|
|
48
56
|
const s = spinner(preparation.fullBuildRequired
|
|
49
57
|
? 'Running required full build...'
|
|
@@ -80,11 +88,20 @@ async function runPreTestBuild(projectRoot, paths, projectConfig, harnessRetries
|
|
|
80
88
|
const recordedCoverage = extend !== undefined
|
|
81
89
|
? unionTestPackagingCoverage(previousBaseline?.testPackagingCoverage, extend.requestedPaths)
|
|
82
90
|
: testPackagingCoverage;
|
|
83
|
-
await writeBuildBaseline(
|
|
84
|
-
|
|
85
|
-
:
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
await writeBuildBaseline({
|
|
92
|
+
projectRoot,
|
|
93
|
+
engineDir: paths.engine,
|
|
94
|
+
binaryName: projectConfig.binaryName,
|
|
95
|
+
testPackagingCoverage: recordedCoverage,
|
|
96
|
+
previousBaseline,
|
|
97
|
+
recordedBy: describeBuildInvocation(extend !== undefined, testPackagingCoverage),
|
|
98
|
+
staticComponentsHandling: preparation.fullBuildRequired
|
|
99
|
+
? 'refresh'
|
|
100
|
+
: extend !== undefined
|
|
101
|
+
? 'carry-forward'
|
|
102
|
+
: 'auto',
|
|
103
|
+
buildKind,
|
|
104
|
+
});
|
|
88
105
|
}
|
|
89
106
|
catch (baselineError) {
|
|
90
107
|
verbose(`Could not persist build baseline: ${toError(baselineError).message}`);
|
|
@@ -165,7 +182,15 @@ export async function runTestBuildPhase(projectRoot, paths, projectConfig, harne
|
|
|
165
182
|
}
|
|
166
183
|
}
|
|
167
184
|
}
|
|
168
|
-
await runPreTestBuild(
|
|
185
|
+
await runPreTestBuild({
|
|
186
|
+
projectRoot,
|
|
187
|
+
paths,
|
|
188
|
+
projectConfig,
|
|
189
|
+
harnessRetries,
|
|
190
|
+
testPackagingCoverage: coverage,
|
|
191
|
+
refuseUnexportedDrift: options.refuseUnexportedDrift === true,
|
|
192
|
+
extend: extending ? { requestedPaths: normalizedPaths } : undefined,
|
|
193
|
+
});
|
|
169
194
|
info('');
|
|
170
195
|
if (options.buildOnly) {
|
|
171
196
|
// Union build for mixed harnesses: the coverage claim
|
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
* `test-harness-crash.ts` for single and sharded invocations. Split out of
|
|
8
8
|
* `test.ts` to keep both files within the per-file line budget.
|
|
9
9
|
*/
|
|
10
|
+
import { getActiveRunLogPath } from '../core/run-log.js';
|
|
10
11
|
import { describeChangedPrefNoise } from '../core/test-changed-prefs.js';
|
|
11
12
|
import { buildGreenSummaryRejectedMessage, buildHarnessCrashMessage, buildNoTestsRanMessage, buildSilentSegfaultMessage, headedNoOutputTimeoutHint, isSilentSegfault, } from '../core/test-harness-crash.js';
|
|
12
13
|
import { buildHarnessEarlyExitMessage, classifyHarnessEarlyExit, completePostRebuildFailureContext, prependPostRebuildFailureContext, } from '../core/test-harness-output.js';
|
|
13
14
|
import { GeneralError } from '../errors/base.js';
|
|
14
|
-
import {
|
|
15
|
+
import { TestFailureError } from '../errors/build.js';
|
|
15
16
|
import { toError } from '../utils/errors.js';
|
|
16
17
|
import { info } from '../utils/logger.js';
|
|
17
18
|
import { getPlatform } from '../utils/platform.js';
|
|
@@ -132,7 +133,13 @@ function buildMochitestHttp3ServerMessage() {
|
|
|
132
133
|
* broader ones, so a fork-owned module failure is not reported as a stale
|
|
133
134
|
* build.
|
|
134
135
|
*/
|
|
135
|
-
function handleNonZeroTestExit(result, normalizedPaths, appdirInjectionAttempted, binaryName, postRebuildContext
|
|
136
|
+
function handleNonZeroTestExit(result, normalizedPaths, appdirInjectionAttempted, binaryName, postRebuildContext,
|
|
137
|
+
/**
|
|
138
|
+
* The classified verdict, when one was reached. Carries the failing-test
|
|
139
|
+
* evidence the final throw names; every branch ABOVE that throw is a
|
|
140
|
+
* different diagnosis and does not use it.
|
|
141
|
+
*/
|
|
142
|
+
verdict) {
|
|
136
143
|
if (result.exitCode === 0 || result.exitCode === 130)
|
|
137
144
|
return;
|
|
138
145
|
const combinedOutput = `${result.stdout}\n${result.stderr}`;
|
|
@@ -194,8 +201,10 @@ function handleNonZeroTestExit(result, normalizedPaths, appdirInjectionAttempted
|
|
|
194
201
|
// fail (exit code stays 5), so this only says WHICH KIND of failure it is.
|
|
195
202
|
// Every branch above is a different diagnosis and outranks it.
|
|
196
203
|
const changedPrefNoise = describeChangedPrefNoise(combinedOutput);
|
|
197
|
-
|
|
198
|
-
|
|
204
|
+
const failureBlocks = formatFailureBlocks(verdict?.realFailureBlocks);
|
|
205
|
+
const logPath = getActiveRunLogPath();
|
|
206
|
+
throw new TestFailureError(withContext(`Tests failed with exit code ${result.exitCode}.` +
|
|
207
|
+
(changedPrefNoise !== undefined ? `\n\n${changedPrefNoise}` : '')), 'mach test', failureBlocks, logPath);
|
|
199
208
|
}
|
|
200
209
|
/**
|
|
201
210
|
* Applies the harness-run verdict for a single (non-sharded) invocation:
|
|
@@ -259,7 +268,7 @@ function applySingleRunOutcome(outcome, normalizedPaths, binaryName, postRebuild
|
|
|
259
268
|
outcome.verdict.secondaryHarnessSignature.line);
|
|
260
269
|
}
|
|
261
270
|
}
|
|
262
|
-
handleNonZeroTestExit(outcome.result, normalizedPaths, outcome.appdirInjectionAttempted, binaryName, postRebuildContext);
|
|
271
|
+
handleNonZeroTestExit(outcome.result, normalizedPaths, outcome.appdirInjectionAttempted, binaryName, postRebuildContext, outcome.verdict);
|
|
263
272
|
}
|
|
264
273
|
/**
|
|
265
274
|
* Shard-mode adapter over {@link handleNonZeroTestExit}: produces the
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { loadConfig } from '../core/config.js';
|
|
2
1
|
import type { TestOptions } from '../types/commands/index.js';
|
|
2
|
+
import type { FireForgeConfig } from '../types/config.js';
|
|
3
3
|
import type { TestRunOutcome } from './test-run.js';
|
|
4
|
-
type ProjectConfig =
|
|
4
|
+
type ProjectConfig = FireForgeConfig;
|
|
5
5
|
/** Rejects pathless `fireforge test` unless the operator selected a pathless mode. */
|
|
6
6
|
export declare function assertPathlessTestMode(testPaths: readonly string[], options: TestOptions): void;
|
|
7
7
|
/** Rejects invalid combinations for mode-like `fireforge test` options. */
|
|
@@ -28,7 +28,7 @@ const TEST_HELP_TEXT = [
|
|
|
28
28
|
'Machine-readable verdict: every run (single, sharded, --canary,',
|
|
29
29
|
'--doctor) ends with exactly one raw stdout line',
|
|
30
30
|
' FIREFORGE-VERDICT: PASS|FAIL [reason=crash|test-failures|',
|
|
31
|
-
' no-tests|preflight|inconclusive|lock-timeout] [checks=<n>]',
|
|
31
|
+
' no-tests|preflight|inconclusive|lock-timeout|killed] [checks=<n>]',
|
|
32
32
|
' [unexpected=<n>] [shards=<p>/<t>] [(<note>)] [log=<path>]',
|
|
33
33
|
"log=<path> names this run's complete output, written to",
|
|
34
34
|
'.fireforge/logs/ as the run streams, so a piped or truncated run',
|
|
@@ -41,7 +41,9 @@ const TEST_HELP_TEXT = [
|
|
|
41
41
|
'errors); reason=inconclusive means engine/ changed while the',
|
|
42
42
|
'tests ran, so the harness result cannot be trusted;',
|
|
43
43
|
'reason=lock-timeout means the run never started because another',
|
|
44
|
-
'engine-mutating command held the lock past the wait budget
|
|
44
|
+
'engine-mutating command held the lock past the wait budget;',
|
|
45
|
+
'reason=killed means a signal terminated the run before it reached',
|
|
46
|
+
'any other outcome (written from the signal handler). A sharded',
|
|
45
47
|
'aggregate reason is the most structural failing shard (crash,',
|
|
46
48
|
'then no-tests, then test-failures). Count keys are omitted when',
|
|
47
49
|
'the embedded summary did not print them. A trailing parenthetical',
|
|
@@ -67,10 +69,11 @@ export function registerTest(program, { getProjectRoot, withErrorHandling }) {
|
|
|
67
69
|
.option('--allow-stale-build', 'Allow tests to run even when packageable engine files changed since the last successful FireForge build')
|
|
68
70
|
.option('--allow-stale-components', 'Run tests despite components.conf changes that only a full "fireforge build" compiles in (the packaged child process will resolve the OLD StaticComponents table)')
|
|
69
71
|
.option('--kill-stale-marionette', 'Terminate a recognized stale browser from this objdir or one holding the Marionette port before running tests')
|
|
72
|
+
.option('--reap-orphans', 'Terminate harness helper processes (httpd, pywebsocket, ssltunnel, moz-http2) from this objdir that survived an earlier run. The census itself runs on every test dispatch and is report-only; this flag opts into the kill.')
|
|
70
73
|
.option('--canary [path]', 'Run one short browser-chrome harness canary. Uses test.canaryPath from fireforge.json when no path is supplied.')
|
|
71
74
|
.option('--doctor', 'Run a marionette handshake preflight before tests (exit 1 on FAIL). With no paths, runs the preflight only.')
|
|
72
75
|
.option('--mach-arg <arg>', 'Forward this argument verbatim to `mach test` (repeatable). Escape valve for upstream xpcshell/mochitest flags FireForge does not model.', ...stringListOption())
|
|
73
|
-
.option('--harness-retries <n>', `Retry budget for recognized harness crashes (resource-monitor tracebacks, pre-test hangs, post-green shutdown re-entry). 0 disables retries. Default: ${
|
|
76
|
+
.option('--harness-retries <n>', `Retry budget for recognized harness crashes (resource-monitor tracebacks, pre-test hangs, post-green shutdown re-entry). 0 disables retries. Default: ${DEFAULT_HARNESS_RETRIES}.`, commanderArgParser((raw) => {
|
|
74
77
|
const n = Number.parseInt(raw, 10);
|
|
75
78
|
if (!Number.isFinite(n) || n < 0 || n > 10) {
|
|
76
79
|
throw new GeneralError(`--harness-retries must be an integer in 0..10 (got "${raw}")`);
|
|
@@ -11,25 +11,26 @@
|
|
|
11
11
|
* stays available via `--no-shard`.
|
|
12
12
|
*/
|
|
13
13
|
import { probeDisplaySleepState } from '../core/display-state.js';
|
|
14
|
-
import {
|
|
14
|
+
import { runMachTestSuite } from '../core/mach.js';
|
|
15
|
+
import { getActiveRunLogPath } from '../core/run-log.js';
|
|
15
16
|
import { changedPrefNoiseVerdictNote } from '../core/test-changed-prefs.js';
|
|
16
17
|
import { buildHarnessCrashMessage, classifyHarnessRun, headedDisplayAsleepVerdictNote, headedNoOutputTimeoutHint, } from '../core/test-harness-crash.js';
|
|
17
18
|
import { retryAfterXpcshellSymlinkRepair } from '../core/test-xpcshell-retry.js';
|
|
18
19
|
import { withXpcshellProfileDir } from '../core/xpcshell-profile-dir.js';
|
|
19
|
-
import {
|
|
20
|
+
import { TestFailureError } from '../errors/build.js';
|
|
20
21
|
import { info, note, warn } from '../utils/logger.js';
|
|
21
22
|
import { getPlatform } from '../utils/platform.js';
|
|
22
23
|
import { maybeInjectAppdirArg } from './test-appdir.js';
|
|
23
24
|
import { emitHarnessVerdict } from './test-verdict.js';
|
|
24
25
|
/** Default bounded retry budget for recognized harness crashes. */
|
|
25
26
|
export const DEFAULT_HARNESS_RETRIES = 2;
|
|
26
|
-
/** Resolves the
|
|
27
|
-
function
|
|
27
|
+
/** Resolves the mach test command a suite dispatches to. */
|
|
28
|
+
function machKindForSuite(suite) {
|
|
28
29
|
if (suite === 'xpcshell')
|
|
29
|
-
return
|
|
30
|
+
return 'xpcshell-test';
|
|
30
31
|
if (suite === 'mochitest')
|
|
31
|
-
return
|
|
32
|
-
return
|
|
32
|
+
return 'mochitest';
|
|
33
|
+
return 'test';
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
36
|
* Runs one mach test invocation for `paths`, retrying recognized harness
|
|
@@ -53,24 +54,31 @@ export async function runTestsWithRetries(ctx, paths) {
|
|
|
53
54
|
async function runTestsWithRetriesInner(ctx, paths, env) {
|
|
54
55
|
const extraArgs = [...ctx.baseExtraArgs];
|
|
55
56
|
const appdirInjectionAttempted = await maybeInjectAppdirArg(ctx.engineDir, paths, ctx.objDir, extraArgs);
|
|
56
|
-
const
|
|
57
|
+
const kind = machKindForSuite(ctx.suite);
|
|
57
58
|
const maxAttempts = Math.max(1, ctx.harnessRetries + 1);
|
|
58
59
|
let attempts = 0;
|
|
59
60
|
let result;
|
|
60
61
|
let verdict;
|
|
61
62
|
for (;;) {
|
|
62
63
|
attempts += 1;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
ctx.fullOutput
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
64
|
+
result = await runMachTestSuite(kind, {
|
|
65
|
+
engineDir: ctx.engineDir,
|
|
66
|
+
testPaths: paths,
|
|
67
|
+
args: extraArgs,
|
|
68
|
+
env,
|
|
69
|
+
fullOutput: ctx.fullOutput,
|
|
70
|
+
});
|
|
71
|
+
result = await retryAfterXpcshellSymlinkRepair({
|
|
72
|
+
engineDir: ctx.engineDir,
|
|
73
|
+
objDir: ctx.objDir,
|
|
74
|
+
result,
|
|
75
|
+
classification: ctx.classification,
|
|
76
|
+
normalizedPaths: paths,
|
|
77
|
+
extraArgs,
|
|
78
|
+
env,
|
|
79
|
+
kind,
|
|
80
|
+
fullOutput: ctx.fullOutput,
|
|
81
|
+
});
|
|
74
82
|
const combined = `${result.stdout}\n${result.stderr}`;
|
|
75
83
|
verdict = classifyHarnessRun(result.exitCode, combined, paths);
|
|
76
84
|
if (verdict.kind !== 'harness-crash' || attempts >= maxAttempts)
|
|
@@ -193,8 +201,8 @@ export function finalizeShardedOutcome(summary) {
|
|
|
193
201
|
emitHarnessVerdict(summary.aggregate, { passed: summary.passed, total: summary.total });
|
|
194
202
|
if (summary.passed < summary.total) {
|
|
195
203
|
const failing = summary.shards.filter(({ outcome }) => outcome.verdict.kind !== 'tests-ran-ok');
|
|
196
|
-
throw new
|
|
204
|
+
throw new TestFailureError(`${failing.length} of ${summary.total} sharded test run(s) did not pass: ` +
|
|
197
205
|
`${failing.map(({ label }) => label).join(', ')}. ` +
|
|
198
|
-
'See the per-shard diagnosis above. Use --no-shard to reproduce the combined single-invocation behaviour.', 'mach test');
|
|
206
|
+
'See the per-shard diagnosis above. Use --no-shard to reproduce the combined single-invocation behaviour.', 'mach test', undefined, getActiveRunLogPath());
|
|
199
207
|
}
|
|
200
208
|
}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* stays wiring; the probes and refusal copy live in
|
|
8
8
|
* `src/core/test-stale-check.ts`.
|
|
9
9
|
*/
|
|
10
|
-
import { checkStaleBuildForTest, checkStaticComponentsStale, findUncoveredRequestPaths, formatStaleBuildWarning, formatStaticComponentsRefusal, formatTestCoverageRefusal, } from '../core/test-stale-check.js';
|
|
11
|
-
import {
|
|
10
|
+
import { checkStaleBuildForTest, checkStaticComponentsStale, findChangedTestManifestsForPaths, findUncoveredRequestPaths, formatStaleBuildWarning, formatStaticComponentsRefusal, formatTestCoverageRefusal, } from '../core/test-stale-check.js';
|
|
11
|
+
import { PreflightRefusalError } from '../errors/base.js';
|
|
12
12
|
import { warn } from '../utils/logger.js';
|
|
13
13
|
/**
|
|
14
14
|
* Stale-build preflight — when `--build` was NOT requested, detect packageable
|
|
@@ -37,7 +37,10 @@ export async function enforceStaleBuildGate(projectRoot, engineDir, options, nor
|
|
|
37
37
|
const recordedCoverage = stale.baseline?.testPackagingCoverage;
|
|
38
38
|
const uncovered = findUncoveredRequestPaths(recordedCoverage, normalizedPaths);
|
|
39
39
|
if (uncovered.length > 0) {
|
|
40
|
-
|
|
40
|
+
// The refusal is correct on its own; naming the manifest that gained
|
|
41
|
+
// an entry is the triage step it otherwise leaves to the reader.
|
|
42
|
+
const changedManifests = await findChangedTestManifestsForPaths(engineDir, stale.baseline, uncovered);
|
|
43
|
+
throw new PreflightRefusalError(formatTestCoverageRefusal(uncovered, Array.isArray(recordedCoverage) ? recordedCoverage : [], changedManifests), 'coverage-replaced');
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
await enforceStaticComponentsGate(engineDir, stale.baseline, options);
|
|
@@ -56,7 +59,7 @@ export async function enforceStaleBuildGate(projectRoot, engineDir, options, nor
|
|
|
56
59
|
warn(staleMessage);
|
|
57
60
|
}
|
|
58
61
|
else {
|
|
59
|
-
throw new
|
|
62
|
+
throw new PreflightRefusalError(staleMessage, 'stale-build');
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
}
|
|
@@ -81,5 +84,5 @@ export async function enforceStaticComponentsGate(engineDir, baseline, options)
|
|
|
81
84
|
warn(message);
|
|
82
85
|
return;
|
|
83
86
|
}
|
|
84
|
-
throw new
|
|
87
|
+
throw new PreflightRefusalError(message, 'stale-components');
|
|
85
88
|
}
|
|
@@ -30,8 +30,22 @@ export declare function emitHarnessVerdict(verdict: HarnessRunVerdict, shards?:
|
|
|
30
30
|
}): void;
|
|
31
31
|
/** Emits the pathless `--doctor` PASS verdict. */
|
|
32
32
|
export declare function emitPassVerdict(): void;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Emits a FAIL verdict carrying an emission-layer reason code, and
|
|
35
|
+
* optionally the refusal class that produced it.
|
|
36
|
+
*
|
|
37
|
+
* `note=` is ADDITIVE, like the `log=`, `signal=` and `shards=` keys already
|
|
38
|
+
* on this line: `reason=` is unchanged and still comes from the closed set
|
|
39
|
+
* in `docs/machine-output.md`, so a consumer that tokenises `key=value`
|
|
40
|
+
* pairs is unaffected. It exists because `reason=preflight` covers every
|
|
41
|
+
* gate before the harness — a missing build, a peer's packaging record, a
|
|
42
|
+
* developer browser holding the objdir — and an unattended reader whose
|
|
43
|
+
* pipe kept only the verdict line could not tell those apart.
|
|
44
|
+
*
|
|
45
|
+
* @param reason - Closed-set verdict reason
|
|
46
|
+
* @param note - Stable refusal class, when the thrower named one
|
|
47
|
+
*/
|
|
48
|
+
export declare function emitFailVerdict(reason: FireforgeVerdictReason, note?: string): void;
|
|
35
49
|
/**
|
|
36
50
|
* Emits the terminal verdict for a run killed by a signal.
|
|
37
51
|
*
|
|
@@ -61,9 +61,24 @@ export function emitHarnessVerdict(verdict, shards) {
|
|
|
61
61
|
export function emitPassVerdict() {
|
|
62
62
|
writeVerdictLine('FIREFORGE-VERDICT: PASS');
|
|
63
63
|
}
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Emits a FAIL verdict carrying an emission-layer reason code, and
|
|
66
|
+
* optionally the refusal class that produced it.
|
|
67
|
+
*
|
|
68
|
+
* `note=` is ADDITIVE, like the `log=`, `signal=` and `shards=` keys already
|
|
69
|
+
* on this line: `reason=` is unchanged and still comes from the closed set
|
|
70
|
+
* in `docs/machine-output.md`, so a consumer that tokenises `key=value`
|
|
71
|
+
* pairs is unaffected. It exists because `reason=preflight` covers every
|
|
72
|
+
* gate before the harness — a missing build, a peer's packaging record, a
|
|
73
|
+
* developer browser holding the objdir — and an unattended reader whose
|
|
74
|
+
* pipe kept only the verdict line could not tell those apart.
|
|
75
|
+
*
|
|
76
|
+
* @param reason - Closed-set verdict reason
|
|
77
|
+
* @param note - Stable refusal class, when the thrower named one
|
|
78
|
+
*/
|
|
79
|
+
export function emitFailVerdict(reason, note) {
|
|
80
|
+
const suffix = note === undefined ? '' : ` note=${note}`;
|
|
81
|
+
writeVerdictLine(`FIREFORGE-VERDICT: FAIL reason=${reason}${suffix}`);
|
|
67
82
|
}
|
|
68
83
|
/**
|
|
69
84
|
* Emits the terminal verdict for a run killed by a signal.
|
|
@@ -3,17 +3,19 @@ import { join, resolve } from 'node:path';
|
|
|
3
3
|
import { getProjectPaths, loadConfig } from '../core/config.js';
|
|
4
4
|
import { assertEngineExists } from '../core/engine-precondition.js';
|
|
5
5
|
import { assertEngineGenerationUnchanged, snapshotEngineGeneration, } from '../core/engine-session-lock.js';
|
|
6
|
+
import { reportOrphanedHarnessProcesses } from '../core/harness-orphans.js';
|
|
6
7
|
import { hasBuildArtifacts, hasRunnableBundle } from '../core/mach.js';
|
|
7
8
|
import { assertBuildArtifacts } from '../core/mach-build-artifacts.js';
|
|
8
9
|
import { assertMarionettePortAvailable, ensureLaunchableBrowserNotRunning, ensureMarionettePortAvailable, extractForwardedMarionettePort, forwardedMachArgsIncludeMarionetteClient, shouldAutoForwardMarionettePortToMach, } from '../core/marionette-port.js';
|
|
9
10
|
import { formatMarionettePreflightLine, reportMarionettePreflight, runMarionettePreflight, } from '../core/marionette-preflight.js';
|
|
10
11
|
import { ensureMochitestServerPortAvailable } from '../core/mochitest-server-port.js';
|
|
11
|
-
import { closeActiveRunLog, openRunLog, setActiveRunLog } from '../core/run-log.js';
|
|
12
|
+
import { closeActiveRunLog, openRunLog, setActiveRunLog, writeToActiveRunLog, } from '../core/run-log.js';
|
|
12
13
|
import { createPostRebuildFailureContext } from '../core/test-harness-output.js';
|
|
13
14
|
import { analyzeTestPathScopes, formatScopeNotice, } from '../core/test-path-scope.js';
|
|
14
15
|
import { assertObjdirMatchesTreeMarker } from '../core/tree-store.js';
|
|
15
|
-
import { GeneralError } from '../errors/base.js';
|
|
16
|
+
import { FireForgeError, GeneralError, PreflightRefusalError } from '../errors/base.js';
|
|
16
17
|
import { BuildError } from '../errors/build.js';
|
|
18
|
+
import { toError } from '../utils/errors.js';
|
|
17
19
|
import { pathExists } from '../utils/fs.js';
|
|
18
20
|
import { info, intro, notice, outro, verbose } from '../utils/logger.js';
|
|
19
21
|
import { stripEnginePrefix } from '../utils/paths.js';
|
|
@@ -224,7 +226,7 @@ async function ensureTestMarionettePortAvailable(port, binaryName, options, skip
|
|
|
224
226
|
}
|
|
225
227
|
await assertMarionettePortAvailable(port, { binaryName });
|
|
226
228
|
}
|
|
227
|
-
async function ensureTestBrowserEnvironment(engineDir, launchablePath, xpcshellOnly, binaryName, options) {
|
|
229
|
+
async function ensureTestBrowserEnvironment(engineDir, launchablePath, xpcshellOnly, binaryName, options, objDir) {
|
|
228
230
|
// A timed-out mochitest can leave the built app alive after its Marionette
|
|
229
231
|
// listener has disappeared. The port probe cannot see that case, but the
|
|
230
232
|
// survivor can still steal focus and wedge every later headed run.
|
|
@@ -242,6 +244,12 @@ async function ensureTestBrowserEnvironment(engineDir, launchablePath, xpcshellO
|
|
|
242
244
|
killStaleServer: options.killStaleMarionette === true,
|
|
243
245
|
});
|
|
244
246
|
}
|
|
247
|
+
// Helpers that outlived an earlier run (httpd, pywebsocket, ssltunnel,
|
|
248
|
+
// moz-http2) slow every later run without appearing in its output. Both
|
|
249
|
+
// harnesses are affected, so this census is not gated on xpcshellOnly.
|
|
250
|
+
await reportOrphanedHarnessProcesses(objDir, {
|
|
251
|
+
reap: options.reapOrphans === true,
|
|
252
|
+
});
|
|
245
253
|
const forwardedPort = options.machArg
|
|
246
254
|
? extractForwardedMarionettePort(options.machArg)
|
|
247
255
|
: undefined;
|
|
@@ -285,14 +293,50 @@ export async function testCommand(projectRoot, testPaths, options = {}) {
|
|
|
285
293
|
await runTestCommandBody(projectRoot, testPaths, options);
|
|
286
294
|
}
|
|
287
295
|
catch (error) {
|
|
288
|
-
if (!verdictEmitted())
|
|
289
|
-
|
|
296
|
+
if (!verdictEmitted()) {
|
|
297
|
+
renderPreflightRefusal(error);
|
|
298
|
+
emitFailVerdict('preflight', refusalNote(error));
|
|
299
|
+
}
|
|
290
300
|
throw error;
|
|
291
301
|
}
|
|
292
302
|
finally {
|
|
293
303
|
await closeActiveRunLog();
|
|
294
304
|
}
|
|
295
305
|
}
|
|
306
|
+
/** The refusal class a preflight gate named, when it named one. */
|
|
307
|
+
function refusalNote(error) {
|
|
308
|
+
return error instanceof PreflightRefusalError ? error.note : undefined;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Puts a preflight refusal's own text on the operator's channel BEFORE the
|
|
312
|
+
* verdict line, and into the run log.
|
|
313
|
+
*
|
|
314
|
+
* Both halves are load-bearing, and neither happened before:
|
|
315
|
+
*
|
|
316
|
+
* - `withErrorHandling` renders `error.userMessage` back in `cli.ts`, but
|
|
317
|
+
* by then `emitFailVerdict` has called `setStdoutSealed(true)` — the seal
|
|
318
|
+
* that keeps the verdict the LAST stdout write — so `logError` routes to
|
|
319
|
+
* stderr. A run captured with `> file` therefore kept the verdict and
|
|
320
|
+
* dropped the reason.
|
|
321
|
+
* - That same rendering happens after this function's caller returns, and
|
|
322
|
+
* the `finally` below has already closed the run log. So the artifact the
|
|
323
|
+
* verdict's own `log=` key points at did not contain the refusal either,
|
|
324
|
+
* which is what left `.fireforge/logs/test-*.log` holding only the
|
|
325
|
+
* pre-test build.
|
|
326
|
+
*
|
|
327
|
+
* Writing here, before the seal, fixes both without trading away the
|
|
328
|
+
* contract: the refusal lands on stdout and in the log, and the verdict
|
|
329
|
+
* line still comes last.
|
|
330
|
+
*/
|
|
331
|
+
function renderPreflightRefusal(error) {
|
|
332
|
+
const text = error instanceof FireForgeError ? error.userMessage : toError(error).message;
|
|
333
|
+
const block = `Preflight refused:\n${text}\n`;
|
|
334
|
+
// Raw stdout rather than the clack logger: this must land on the captured
|
|
335
|
+
// stream verbatim, and clack's renderer can drop output under non-TTY
|
|
336
|
+
// capture — the same reason the verdict line is written this way.
|
|
337
|
+
process.stdout.write(block);
|
|
338
|
+
writeToActiveRunLog(block);
|
|
339
|
+
}
|
|
296
340
|
/**
|
|
297
341
|
* Verifies `engine/` did not change under the run before any PASS verdict
|
|
298
342
|
* may print. On failure the run's verdict is `FAIL reason=inconclusive` —
|
|
@@ -359,7 +403,7 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
|
|
|
359
403
|
// documented `--mach-arg --marionette-port=NNNN` route still hits the
|
|
360
404
|
// wrapper preflight refusing on 2828 before the forwarded arg reaches
|
|
361
405
|
// mach.
|
|
362
|
-
const { forwardedPort, effectivePort } = await ensureTestBrowserEnvironment(paths.engine, launchablePath, xpcshellOnly, projectConfig.binaryName, options);
|
|
406
|
+
const { forwardedPort, effectivePort } = await ensureTestBrowserEnvironment(paths.engine, launchablePath, xpcshellOnly, projectConfig.binaryName, options, buildCheck.objDir);
|
|
363
407
|
if (options.doctor) {
|
|
364
408
|
const doctorOutcome = await runDoctorPreflight({
|
|
365
409
|
engineDir: paths.engine,
|
|
@@ -385,7 +429,7 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
|
|
|
385
429
|
extraArgs.push('--auto');
|
|
386
430
|
}
|
|
387
431
|
if (canaryPath !== undefined) {
|
|
388
|
-
extraArgs.push(`--timeout=${
|
|
432
|
+
extraArgs.push(`--timeout=${canaryTimeoutSeconds(projectConfig)}`);
|
|
389
433
|
}
|
|
390
434
|
// --mach-arg is a verbatim passthrough for upstream mach/xpcshell/mochitest
|
|
391
435
|
// flags FireForge does not model directly (see the xpcshell appdir hint
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Options accepted by {@link tokenListCommand}. */
|
|
2
|
+
export interface TokenListOptions {
|
|
3
|
+
/** Restrict the report to one category. */
|
|
4
|
+
category?: string;
|
|
5
|
+
/** Emit the machine-readable envelope instead of the human report. */
|
|
6
|
+
json?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Lists the categories declared in the tokens CSS with their token names,
|
|
10
|
+
* in file order.
|
|
11
|
+
*
|
|
12
|
+
* @param projectRoot - Root directory of the project
|
|
13
|
+
* @param options - Filter and output-mode options
|
|
14
|
+
*/
|
|
15
|
+
export declare function tokenListCommand(projectRoot: string, options?: TokenListOptions): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Reports one token: the category that owns it and the value it takes in
|
|
18
|
+
* every block that declares it.
|
|
19
|
+
*
|
|
20
|
+
* @param projectRoot - Root directory of the project
|
|
21
|
+
* @param tokenName - Custom-property name, with or without the leading `--`
|
|
22
|
+
* @param options - Output-mode options
|
|
23
|
+
*/
|
|
24
|
+
export declare function tokenShowCommand(projectRoot: string, tokenName: string, options?: {
|
|
25
|
+
json?: boolean;
|
|
26
|
+
}): Promise<void>;
|