@hominis/fireforge 0.51.0 → 0.53.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 +46 -0
- package/dist/build-info.json +4 -4
- package/dist/src/commands/bootstrap.js +2 -3
- package/dist/src/commands/build-prelock.d.ts +3 -3
- package/dist/src/commands/build-prelock.js +3 -3
- package/dist/src/commands/build.js +4 -0
- package/dist/src/commands/declarations-report.d.ts +9 -3
- package/dist/src/commands/declarations-report.js +18 -11
- package/dist/src/commands/discard.js +3 -3
- package/dist/src/commands/doctor-furnace-config-sync.js +4 -4
- package/dist/src/commands/doctor-furnace.js +5 -5
- package/dist/src/commands/export-adopt-check.d.ts +5 -6
- package/dist/src/commands/export-adopt-check.js +5 -6
- package/dist/src/commands/export-flow.js +6 -9
- package/dist/src/commands/export-staged-registration.d.ts +4 -4
- package/dist/src/commands/export-staged-registration.js +4 -4
- package/dist/src/commands/forward-import-remedy.d.ts +2 -3
- package/dist/src/commands/forward-import-remedy.js +2 -3
- package/dist/src/commands/furnace/create-dry-run.d.ts +2 -2
- package/dist/src/commands/furnace/deploy-fragment-includers.d.ts +2 -2
- package/dist/src/commands/furnace/deploy-fragment-includers.js +2 -2
- package/dist/src/commands/furnace/index.js +2 -2
- package/dist/src/commands/lint.js +4 -4
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/lint-ignore-from.d.ts +3 -4
- package/dist/src/commands/patch/lint-ignore-from.js +3 -4
- package/dist/src/commands/patch/move-files-adopt.d.ts +33 -0
- package/dist/src/commands/patch/move-files-adopt.js +65 -0
- package/dist/src/commands/patch/move-files-create.js +41 -20
- package/dist/src/commands/patch/move-files-into.d.ts +18 -0
- package/dist/src/commands/patch/move-files-into.js +125 -60
- package/dist/src/commands/patch/move-files-retire.d.ts +39 -0
- package/dist/src/commands/patch/move-files-retire.js +91 -0
- package/dist/src/commands/patch/move-files.d.ts +3 -0
- package/dist/src/commands/patch/move-files.js +42 -12
- package/dist/src/commands/patch/move-size-tier.d.ts +27 -0
- package/dist/src/commands/patch/move-size-tier.js +66 -0
- package/dist/src/commands/patch/rename.js +1 -1
- package/dist/src/commands/patch/reorder-projection.d.ts +17 -0
- package/dist/src/commands/patch/reorder-projection.js +49 -0
- package/dist/src/commands/patch/reorder-shift.d.ts +30 -0
- package/dist/src/commands/patch/reorder-shift.js +307 -0
- package/dist/src/commands/patch/reorder.d.ts +9 -15
- package/dist/src/commands/patch/reorder.js +52 -50
- package/dist/src/commands/patch/split-plan.d.ts +31 -3
- package/dist/src/commands/patch/split-plan.js +36 -12
- package/dist/src/commands/patch/split-staged.d.ts +2 -2
- package/dist/src/commands/patch/split-staged.js +2 -2
- package/dist/src/commands/patch/split.js +18 -5
- package/dist/src/commands/patch/staged-dependency-entries.d.ts +9 -1
- package/dist/src/commands/patch/staged-dependency-entries.js +32 -4
- package/dist/src/commands/patch/staged-dependency-from.js +15 -9
- package/dist/src/commands/patch/staged-dependency.js +13 -9
- package/dist/src/commands/patch/tier.js +2 -2
- package/dist/src/commands/patch-rename-map.d.ts +14 -3
- package/dist/src/commands/patch-rename-map.js +21 -3
- package/dist/src/commands/re-export-adjacent.d.ts +4 -5
- package/dist/src/commands/re-export-lint.d.ts +4 -3
- package/dist/src/commands/re-export-lint.js +4 -3
- package/dist/src/commands/re-export-preflight.js +1 -2
- package/dist/src/commands/re-export-purity-scope.d.ts +1 -1
- package/dist/src/commands/re-export-purity-scope.js +13 -7
- package/dist/src/commands/re-export-retired-declarations.d.ts +22 -0
- package/dist/src/commands/re-export-retired-declarations.js +113 -0
- package/dist/src/commands/re-export-single.js +2 -2
- package/dist/src/commands/re-export-stale-registrations.d.ts +27 -6
- package/dist/src/commands/re-export-stale-registrations.js +65 -21
- package/dist/src/commands/re-export.js +4 -0
- package/dist/src/commands/rebase/continue.js +3 -3
- package/dist/src/commands/register.js +5 -4
- package/dist/src/commands/status-output.js +5 -1
- package/dist/src/commands/status.js +1 -1
- package/dist/src/commands/test-build-furnace.d.ts +1 -2
- package/dist/src/commands/test-build-furnace.js +1 -2
- package/dist/src/commands/test-build-phase.d.ts +10 -0
- package/dist/src/commands/test-build-phase.js +51 -16
- package/dist/src/commands/test-control-restore.d.ts +40 -0
- package/dist/src/commands/test-control-restore.js +86 -0
- package/dist/src/commands/test-dispatch.js +83 -13
- package/dist/src/commands/test-multi-verdict.js +1 -0
- package/dist/src/commands/test-orchestrate.d.ts +11 -0
- package/dist/src/commands/test-orchestrate.js +33 -2
- package/dist/src/commands/test-perf-scope.d.ts +1 -1
- package/dist/src/commands/test-perf-scope.js +1 -1
- package/dist/src/commands/test-prelock.d.ts +7 -8
- package/dist/src/commands/test-prelock.js +15 -12
- package/dist/src/commands/test-register.js +2 -2
- package/dist/src/commands/test-results.d.ts +10 -1
- package/dist/src/commands/test-results.js +20 -3
- package/dist/src/commands/test-run.d.ts +6 -0
- package/dist/src/commands/test-run.js +23 -4
- package/dist/src/commands/test-shards.d.ts +7 -3
- package/dist/src/commands/test-shards.js +24 -7
- package/dist/src/commands/test-stale-gate.d.ts +6 -1
- package/dist/src/commands/test-stale-gate.js +47 -2
- package/dist/src/commands/test-verdict.d.ts +5 -3
- package/dist/src/commands/test.js +14 -1
- package/dist/src/commands/token.js +2 -2
- package/dist/src/commands/verify.js +1 -1
- package/dist/src/commands/watch.js +1 -1
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/build-audit-resolve.d.ts +4 -5
- package/dist/src/core/build-audit-resolve.js +4 -5
- package/dist/src/core/build-audit-skip.d.ts +2 -2
- package/dist/src/core/build-audit.d.ts +3 -4
- package/dist/src/core/build-baseline-types.d.ts +37 -3
- package/dist/src/core/build-baseline-validate.d.ts +30 -1
- package/dist/src/core/build-baseline-validate.js +134 -33
- package/dist/src/core/build-baseline.d.ts +8 -2
- package/dist/src/core/build-baseline.js +32 -16
- package/dist/src/core/build-jar-escalation.d.ts +4 -4
- package/dist/src/core/build-jar-escalation.js +4 -4
- package/dist/src/core/build-prepare.js +4 -4
- package/dist/src/core/config-validate.js +4 -4
- package/dist/src/core/coverage-extend.d.ts +5 -3
- package/dist/src/core/coverage-extend.js +8 -3
- package/dist/src/core/coverage-records.d.ts +4 -5
- package/dist/src/core/coverage-records.js +4 -5
- package/dist/src/core/destructive.d.ts +2 -2
- package/dist/src/core/destructive.js +2 -2
- package/dist/src/core/discard-baseline.d.ts +2 -2
- package/dist/src/core/discard-baseline.js +3 -3
- package/dist/src/core/engine-session-lock.d.ts +1 -1
- package/dist/src/core/engine-session-lock.js +1 -1
- package/dist/src/core/file-lock-owner.d.ts +5 -5
- package/dist/src/core/file-lock-owner.js +5 -5
- package/dist/src/core/file-lock-queue.js +6 -8
- package/dist/src/core/file-lock-shared.d.ts +4 -4
- package/dist/src/core/file-lock-shared.js +4 -4
- package/dist/src/core/file-lock.js +7 -10
- package/dist/src/core/firefox.js +2 -2
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +1 -1
- package/dist/src/core/furnace-apply-overwrite-warn.js +1 -1
- package/dist/src/core/furnace-apply.js +3 -3
- package/dist/src/core/furnace-config-validate-exceptions.d.ts +4 -3
- package/dist/src/core/furnace-config-validate-exceptions.js +26 -6
- package/dist/src/core/furnace-operation.js +5 -5
- package/dist/src/core/furnace-registration-jar-inplace.js +5 -6
- package/dist/src/core/furnace-registration-rename.d.ts +5 -5
- package/dist/src/core/furnace-registration-rename.js +5 -5
- package/dist/src/core/furnace-registration-validate.d.ts +2 -1
- package/dist/src/core/furnace-registration-validate.js +2 -1
- package/dist/src/core/furnace-registration.js +2 -2
- package/dist/src/core/furnace-validate-accessibility.d.ts +1 -1
- package/dist/src/core/furnace-validate-accessibility.js +22 -11
- package/dist/src/core/furnace-validate-exceptions.d.ts +2 -1
- package/dist/src/core/furnace-validate-exceptions.js +31 -13
- package/dist/src/core/git-base.js +4 -3
- package/dist/src/core/git-diff.js +1 -1
- package/dist/src/core/git.js +1 -1
- package/dist/src/core/harness-orphans.d.ts +6 -6
- package/dist/src/core/harness-orphans.js +6 -6
- package/dist/src/core/harness-port-reservation.d.ts +60 -0
- package/dist/src/core/harness-port-reservation.js +122 -0
- package/dist/src/core/history-log-file.d.ts +9 -9
- package/dist/src/core/history-log-file.js +15 -15
- package/dist/src/core/history-log.d.ts +3 -3
- package/dist/src/core/history-log.js +3 -3
- package/dist/src/core/launchable-build.d.ts +39 -0
- package/dist/src/core/launchable-build.js +85 -0
- package/dist/src/core/marionette-port.js +1 -3
- package/dist/src/core/moz-manifest-rules.js +3 -2
- package/dist/src/core/negative-control-compiled.d.ts +22 -3
- package/dist/src/core/negative-control-compiled.js +41 -5
- package/dist/src/core/parser-fallback.d.ts +5 -5
- package/dist/src/core/parser-fallback.js +5 -5
- package/dist/src/core/patch-identifier-suggest.d.ts +6 -0
- package/dist/src/core/patch-identifier-suggest.js +11 -4
- package/dist/src/core/patch-lint-checkjs.d.ts +1 -1
- package/dist/src/core/patch-lint-checkjs.js +1 -1
- package/dist/src/core/patch-lint-css.js +2 -2
- package/dist/src/core/patch-lint-file-size.d.ts +5 -7
- package/dist/src/core/patch-lint-file-size.js +5 -7
- package/dist/src/core/patch-lint-ignore.d.ts +3 -3
- package/dist/src/core/patch-lint-ignore.js +3 -3
- package/dist/src/core/patch-lint-prettier.d.ts +4 -6
- package/dist/src/core/patch-lint-prettier.js +4 -6
- package/dist/src/core/patch-lint-projection.d.ts +1 -1
- package/dist/src/core/patch-lint-projection.js +1 -1
- package/dist/src/core/patch-lint-queue-types.d.ts +2 -2
- package/dist/src/core/patch-lint-queue-types.js +2 -2
- package/dist/src/core/patch-manifest-consistency.d.ts +2 -2
- package/dist/src/core/patch-manifest-consistency.js +2 -2
- package/dist/src/core/patch-manifest-io.d.ts +5 -1
- package/dist/src/core/patch-manifest-io.js +12 -10
- package/dist/src/core/patch-manifest-key-order.d.ts +3 -4
- package/dist/src/core/patch-manifest-key-order.js +3 -4
- package/dist/src/core/patch-parse.d.ts +3 -3
- package/dist/src/core/patch-parse.js +3 -3
- package/dist/src/core/patch-policy.d.ts +1 -1
- package/dist/src/core/patch-policy.js +1 -1
- package/dist/src/core/patch-source-metadata.d.ts +1 -1
- package/dist/src/core/patch-source-metadata.js +1 -1
- package/dist/src/core/patch-subset.d.ts +5 -3
- package/dist/src/core/patch-subset.js +8 -7
- package/dist/src/core/patch-transform.d.ts +2 -2
- package/dist/src/core/patch-transform.js +2 -2
- package/dist/src/core/rebase-session.js +4 -6
- package/dist/src/core/register-xpcshell-test.d.ts +28 -7
- package/dist/src/core/register-xpcshell-test.js +76 -27
- package/dist/src/core/run-log.d.ts +8 -8
- package/dist/src/core/run-log.js +8 -8
- package/dist/src/core/status-classify.d.ts +1 -2
- package/dist/src/core/status-classify.js +1 -2
- package/dist/src/core/test-harness-crash.d.ts +5 -3
- package/dist/src/core/test-harness-crash.js +13 -14
- package/dist/src/core/test-harness-infra.d.ts +32 -0
- package/dist/src/core/test-harness-infra.js +69 -0
- package/dist/src/core/test-harness-signature.d.ts +6 -0
- package/dist/src/core/test-run-completeness.d.ts +12 -5
- package/dist/src/core/test-run-completeness.js +15 -8
- package/dist/src/core/test-stale-check.d.ts +48 -1
- package/dist/src/core/test-stale-check.js +97 -2
- package/dist/src/core/test-stall-triage.js +5 -7
- package/dist/src/core/token-category.js +2 -2
- package/dist/src/core/token-inventory.js +3 -3
- package/dist/src/core/token-manager.d.ts +2 -2
- package/dist/src/core/token-manager.js +5 -7
- package/dist/src/core/token-variant.d.ts +6 -6
- package/dist/src/core/token-variant.js +7 -7
- package/dist/src/core/typecheck-shim.d.ts +2 -1
- package/dist/src/core/typecheck-shim.js +29 -5
- package/dist/src/core/wire-destroy.d.ts +1 -1
- package/dist/src/core/wire-destroy.js +1 -1
- package/dist/src/core/wire-dom-fragment.js +1 -1
- package/dist/src/core/wire-init.d.ts +1 -1
- package/dist/src/core/wire-init.js +1 -1
- package/dist/src/core/wire-subscript.d.ts +1 -1
- package/dist/src/core/wire-subscript.js +1 -1
- package/dist/src/core/wire-utils.d.ts +2 -2
- package/dist/src/core/wire-utils.js +3 -3
- package/dist/src/errors/base.d.ts +1 -1
- package/dist/src/errors/base.js +1 -1
- package/dist/src/errors/rebase.d.ts +1 -1
- package/dist/src/errors/rebase.js +1 -1
- package/dist/src/types/commands/options.d.ts +26 -3
- package/dist/src/types/config.d.ts +5 -7
- package/dist/src/types/furnace.d.ts +9 -0
- package/dist/src/utils/options.js +2 -2
- package/dist/src/utils/process.js +2 -2
- package/dist/src/utils/regex.d.ts +2 -2
- package/dist/src/utils/regex.js +3 -3
- package/dist/src/utils/sleep.d.ts +5 -6
- package/dist/src/utils/sleep.js +5 -6
- package/dist/src/utils/validation.js +2 -2
- package/docs/configuration.md +40 -26
- package/docs/exit-codes.md +8 -11
- package/docs/furnace.md +21 -3
- package/docs/lifecycle-invariants.md +36 -45
- package/docs/machine-output.md +43 -22
- package/docs/patch-workflow.md +129 -24
- package/docs/run-logs.md +8 -9
- package/docs/testing.md +118 -44
- package/package.json +1 -1
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Optional Prettier pass over patch-owned `.sys.mjs` modules.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* module formatting drift
|
|
7
|
-
*
|
|
8
|
-
* direction: a fork's root `.prettierignore` typically excludes `engine/`,
|
|
5
|
+
* Without this pass no tier of the chain runs Prettier on `.sys.mjs`, so
|
|
6
|
+
* module formatting drift survives to a human reviewer. The obvious manual
|
|
7
|
+
* check is misleading in the same direction: a fork's root `.prettierignore` typically excludes `engine/`,
|
|
9
8
|
* so `prettier --check --config engine/.prettierrc.js <engine files>` run
|
|
10
9
|
* from the repo root reports "all files use Prettier code style" for files
|
|
11
|
-
* that fail the identical check run from inside `engine/`.
|
|
12
|
-
* spot-check falsely refuted a correct reviewer finding on exactly this.
|
|
10
|
+
* that fail the identical check run from inside `engine/`.
|
|
13
11
|
*
|
|
14
12
|
* This pass therefore runs prettier with `cwd` set to the engine directory,
|
|
15
13
|
* so the engine's own `.prettierrc*` and `.prettierignore` resolve the way
|
|
@@ -8,7 +8,7 @@ import type { PatchLintIssue } from '../types/commands/index.js';
|
|
|
8
8
|
* whose message text can drift between otherwise-equivalent runs (for
|
|
9
9
|
* example because the message embeds later-owner filenames or positional
|
|
10
10
|
* detail). Falling back to the full tuple keeps the helper conservative
|
|
11
|
-
* for
|
|
11
|
+
* for non-fingerprinted rules: if their message changes, we would
|
|
12
12
|
* rather surface a potential regression than silently swallow it.
|
|
13
13
|
*
|
|
14
14
|
* Consumption order within the projected list is stable (the input
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* whose message text can drift between otherwise-equivalent runs (for
|
|
8
8
|
* example because the message embeds later-owner filenames or positional
|
|
9
9
|
* detail). Falling back to the full tuple keeps the helper conservative
|
|
10
|
-
* for
|
|
10
|
+
* for non-fingerprinted rules: if their message changes, we would
|
|
11
11
|
* rather surface a potential regression than silently swallow it.
|
|
12
12
|
*
|
|
13
13
|
* Consumption order within the projected list is stable (the input
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A leaf module by design: it imports nothing, so the individual rule
|
|
5
5
|
* modules can describe the slice of `PatchQueueContext` they read without
|
|
6
|
-
* importing `patch-lint-cross.ts` (which imports them back).
|
|
7
|
-
*
|
|
6
|
+
* importing `patch-lint-cross.ts` (which imports them back). Sharing them
|
|
7
|
+
* here instead of re-declaring a private `{ entries }` interface per rule
|
|
8
8
|
* keeps the dependency edge one-way and `dpdm` clean while stating the shape
|
|
9
9
|
* once.
|
|
10
10
|
*/
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* A leaf module by design: it imports nothing, so the individual rule
|
|
6
6
|
* modules can describe the slice of `PatchQueueContext` they read without
|
|
7
|
-
* importing `patch-lint-cross.ts` (which imports them back).
|
|
8
|
-
*
|
|
7
|
+
* importing `patch-lint-cross.ts` (which imports them back). Sharing them
|
|
8
|
+
* here instead of re-declaring a private `{ entries }` interface per rule
|
|
9
9
|
* keeps the dependency edge one-way and `dpdm` clean while stating the shape
|
|
10
10
|
* once.
|
|
11
11
|
*/
|
|
@@ -20,7 +20,7 @@ export declare function validatePatchesManifestConsistency(patchesDir: string):
|
|
|
20
20
|
*
|
|
21
21
|
* Drift that is only in `filesAffected` is a derived value disagreeing with
|
|
22
22
|
* the diff it describes, and the narrow repair fixes exactly that. Naming the
|
|
23
|
-
* whole-manifest rebuild for it
|
|
23
|
+
* whole-manifest rebuild for it puts
|
|
24
24
|
* an operator one keystroke from rewriting every row in the manifest to
|
|
25
25
|
* correct one list.
|
|
26
26
|
*/
|
|
@@ -80,7 +80,7 @@ export interface RebuildPatchesManifestOptions extends PatchDirectoryLockOptions
|
|
|
80
80
|
* becomes a whole-manifest reinvention. Pass `allowMetadataLoss` to accept it.
|
|
81
81
|
*
|
|
82
82
|
* @param patchesDir - Path to the patches directory
|
|
83
|
-
* @param fallbackSourceEsrVersion - source version to use for recovered
|
|
83
|
+
* @param fallbackSourceEsrVersion - source version to use for recovered entries that carry none
|
|
84
84
|
* @param options - Lock options plus `allowMetadataLoss` / `dryRun`
|
|
85
85
|
* @returns {@link RebuildPatchesManifestResult}: the rebuilt manifest, the
|
|
86
86
|
* filenames that were reconstructed from generic defaults, and the rows
|
|
@@ -87,7 +87,7 @@ export async function validatePatchesManifestConsistency(patchesDir) {
|
|
|
87
87
|
*
|
|
88
88
|
* Drift that is only in `filesAffected` is a derived value disagreeing with
|
|
89
89
|
* the diff it describes, and the narrow repair fixes exactly that. Naming the
|
|
90
|
-
* whole-manifest rebuild for it
|
|
90
|
+
* whole-manifest rebuild for it puts
|
|
91
91
|
* an operator one keystroke from rewriting every row in the manifest to
|
|
92
92
|
* correct one list.
|
|
93
93
|
*/
|
|
@@ -115,7 +115,7 @@ export function recommendManifestRepair(issues) {
|
|
|
115
115
|
* becomes a whole-manifest reinvention. Pass `allowMetadataLoss` to accept it.
|
|
116
116
|
*
|
|
117
117
|
* @param patchesDir - Path to the patches directory
|
|
118
|
-
* @param fallbackSourceEsrVersion - source version to use for recovered
|
|
118
|
+
* @param fallbackSourceEsrVersion - source version to use for recovered entries that carry none
|
|
119
119
|
* @param options - Lock options plus `allowMetadataLoss` / `dryRun`
|
|
120
120
|
* @returns {@link RebuildPatchesManifestResult}: the rebuilt manifest, the
|
|
121
121
|
* filenames that were reconstructed from generic defaults, and the rows
|
|
@@ -65,10 +65,14 @@ export declare function loadPatchesManifestForWrite(patchesDir: string): Promise
|
|
|
65
65
|
*/
|
|
66
66
|
export declare function savePatchesManifest(patchesDir: string, manifest: PatchesManifest): Promise<void>;
|
|
67
67
|
/**
|
|
68
|
-
* Mutates selected manifest rows while preserving the raw JSON
|
|
68
|
+
* Mutates selected manifest rows while preserving the raw JSON fields of every
|
|
69
69
|
* untouched row. This avoids serializing reader-only fallback fields, such as
|
|
70
70
|
* `sourceVersion` derived from legacy `sourceEsrVersion`, into unrelated patch
|
|
71
71
|
* entries during partial metadata updates.
|
|
72
|
+
*
|
|
73
|
+
* Every row's keys (and the manifest's own) are written in canonical order,
|
|
74
|
+
* not only the changed rows', so the working copy matches what `patch stage`
|
|
75
|
+
* and full saves write and no commit flips untouched rows' key order.
|
|
72
76
|
*/
|
|
73
77
|
export declare function mutatePatchRowsInManifest(patchesDir: string, filenames: readonly string[], mutator: (existing: PatchMetadata, rawExisting: Readonly<JsonObject>) => PatchManifestRowMutation | null): Promise<PatchManifestRowMutationResult[] | null>;
|
|
74
78
|
/**
|
|
@@ -19,7 +19,7 @@ import { pathExistsStrict, readJson, removeFile, writeJson } from '../utils/fs.j
|
|
|
19
19
|
import { warn } from '../utils/logger.js';
|
|
20
20
|
import { isArray, isObject } from '../utils/validation.js';
|
|
21
21
|
import { assertPatchDirectoryLockHeld } from './patch-lock.js';
|
|
22
|
-
import { canonicalizeManifest
|
|
22
|
+
import { canonicalizeManifest } from './patch-manifest-key-order.js';
|
|
23
23
|
import { validatePatchesManifest } from './patch-manifest-validate.js';
|
|
24
24
|
import { manifestWithRetiredSlots } from './patch-retired.js';
|
|
25
25
|
/** Filename for the patches manifest */
|
|
@@ -90,10 +90,14 @@ export async function savePatchesManifest(patchesDir, manifest) {
|
|
|
90
90
|
await writeJson(manifestPath, canonicalizeManifest(manifest));
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
|
-
* Mutates selected manifest rows while preserving the raw JSON
|
|
93
|
+
* Mutates selected manifest rows while preserving the raw JSON fields of every
|
|
94
94
|
* untouched row. This avoids serializing reader-only fallback fields, such as
|
|
95
95
|
* `sourceVersion` derived from legacy `sourceEsrVersion`, into unrelated patch
|
|
96
96
|
* entries during partial metadata updates.
|
|
97
|
+
*
|
|
98
|
+
* Every row's keys (and the manifest's own) are written in canonical order,
|
|
99
|
+
* not only the changed rows', so the working copy matches what `patch stage`
|
|
100
|
+
* and full saves write and no commit flips untouched rows' key order.
|
|
97
101
|
*/
|
|
98
102
|
export async function mutatePatchRowsInManifest(patchesDir, filenames, mutator) {
|
|
99
103
|
const manifestPath = join(patchesDir, PATCHES_MANIFEST);
|
|
@@ -140,16 +144,14 @@ export async function mutatePatchRowsInManifest(patchesDir, filenames, mutator)
|
|
|
140
144
|
}
|
|
141
145
|
if (changedIndexes.length === 0)
|
|
142
146
|
return [];
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
const nextRawManifest = {
|
|
147
|
+
// Every row is put in canonical key order, not only the changed ones:
|
|
148
|
+
// `patch stage` and full saves canonicalize the whole manifest, so a
|
|
149
|
+
// row left in any other order flips back and forth between the
|
|
150
|
+
// working copy and the index. Reordering keys adds no field.
|
|
151
|
+
const nextRawManifest = canonicalizeManifest({
|
|
150
152
|
...rawManifest,
|
|
151
153
|
patches: rawPatches,
|
|
152
|
-
};
|
|
154
|
+
});
|
|
153
155
|
const afterManifest = validatePatchesManifest(nextRawManifest);
|
|
154
156
|
await writeJson(manifestPath, nextRawManifest);
|
|
155
157
|
return changedIndexes.map((index) => ({
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one key order every `patches.json` writer uses for a patch row and
|
|
3
|
-
* for the manifest itself
|
|
4
|
-
* `
|
|
5
|
-
*
|
|
6
|
-
* the manifest.
|
|
3
|
+
* for the manifest itself, so that every writer (`export`, full-manifest
|
|
4
|
+
* saves, `patch stage`) agrees and a no-op rewrite leaves no key-order-only
|
|
5
|
+
* hunk in the manifest.
|
|
7
6
|
*/
|
|
8
7
|
/**
|
|
9
8
|
* Returns a copy of a patch row with its keys in canonical order.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
3
|
* The one key order every `patches.json` writer uses for a patch row and
|
|
4
|
-
* for the manifest itself
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
7
|
-
* the manifest.
|
|
4
|
+
* for the manifest itself, so that every writer (`export`, full-manifest
|
|
5
|
+
* saves, `patch stage`) agrees and a no-op rewrite leaves no key-order-only
|
|
6
|
+
* hunk in the manifest.
|
|
8
7
|
*/
|
|
9
8
|
/** Patch-row keys in the order of the `PatchMetadata` interface. */
|
|
10
9
|
const PATCH_ROW_KEY_ORDER = [
|
|
@@ -34,10 +34,10 @@ export declare function extractOrder(filename: string): number;
|
|
|
34
34
|
* The write-side counterpart to {@link extractOrder}. That one answers
|
|
35
35
|
* `Infinity` for a prefix-less filename, which sorts such a patch last and
|
|
36
36
|
* is the right answer for a read: an unparseable name should not crash a
|
|
37
|
-
* status listing. Persisting `Infinity` (or
|
|
38
|
-
*
|
|
37
|
+
* status listing. Persisting `Infinity` (or a fallback `0`) is a different
|
|
38
|
+
* matter: it puts an order in the manifest
|
|
39
39
|
* that no filename on disk agrees with, and the queue then applies in an
|
|
40
|
-
* order the operator cannot see. Callers here have
|
|
40
|
+
* order the operator cannot see. Callers here have just built or
|
|
41
41
|
* looked up a real prefixed filename, so absence is a bug, not input.
|
|
42
42
|
*
|
|
43
43
|
* @param filename - Patch filename carrying a numeric order prefix
|
|
@@ -56,10 +56,10 @@ export function extractOrder(filename) {
|
|
|
56
56
|
* The write-side counterpart to {@link extractOrder}. That one answers
|
|
57
57
|
* `Infinity` for a prefix-less filename, which sorts such a patch last and
|
|
58
58
|
* is the right answer for a read: an unparseable name should not crash a
|
|
59
|
-
* status listing. Persisting `Infinity` (or
|
|
60
|
-
*
|
|
59
|
+
* status listing. Persisting `Infinity` (or a fallback `0`) is a different
|
|
60
|
+
* matter: it puts an order in the manifest
|
|
61
61
|
* that no filename on disk agrees with, and the queue then applies in an
|
|
62
|
-
* order the operator cannot see. Callers here have
|
|
62
|
+
* order the operator cannot see. Callers here have just built or
|
|
63
63
|
* looked up a real prefixed filename, so absence is a bug, not input.
|
|
64
64
|
*
|
|
65
65
|
* @param filename - Patch filename carrying a numeric order prefix
|
|
@@ -42,7 +42,7 @@ export interface PatchPolicyEnforcementInput {
|
|
|
42
42
|
}
|
|
43
43
|
/** Returns valid categories for prompts and CLI validation under the config. */
|
|
44
44
|
export declare function getPatchPolicyCategories(config: FireForgeConfig): string[];
|
|
45
|
-
/** Checks whether a category is accepted by
|
|
45
|
+
/** Checks whether a category is accepted by the built-in defaults or the policy ranges. */
|
|
46
46
|
export declare function isCategoryAllowedByConfig(config: FireForgeConfig, category: string): boolean;
|
|
47
47
|
/**
|
|
48
48
|
* Human-readable label for a category's configured ranges, e.g. `300-399`.
|
|
@@ -28,7 +28,7 @@ export function getPatchPolicyCategories(config) {
|
|
|
28
28
|
return [...PATCH_CATEGORIES];
|
|
29
29
|
return Array.from(new Set(cfg.ranges.map((range) => range.category))).sort((a, b) => a.localeCompare(b));
|
|
30
30
|
}
|
|
31
|
-
/** Checks whether a category is accepted by
|
|
31
|
+
/** Checks whether a category is accepted by the built-in defaults or the policy ranges. */
|
|
32
32
|
export function isCategoryAllowedByConfig(config, category) {
|
|
33
33
|
if (!/^[a-z][a-z0-9-]*$/.test(category))
|
|
34
34
|
return false;
|
|
@@ -2,5 +2,5 @@ import type { PatchMetadata } from '../types/commands/index.js';
|
|
|
2
2
|
import type { FirefoxConfig } from '../types/config.js';
|
|
3
3
|
/** Metadata fields stamped on new or refreshed patch entries. */
|
|
4
4
|
export declare function buildPatchSourceMetadata(firefox: Pick<FirefoxConfig, 'product' | 'version'>): Pick<PatchMetadata, 'sourceEsrVersion' | 'sourceProduct' | 'sourceVersion'>;
|
|
5
|
-
/**
|
|
5
|
+
/** Source version reader that also accepts rows carrying only `sourceEsrVersion`. */
|
|
6
6
|
export declare function getPatchSourceVersion(patch: Pick<PatchMetadata, 'sourceEsrVersion' | 'sourceVersion'>): string;
|
|
@@ -6,7 +6,7 @@ export function buildPatchSourceMetadata(firefox) {
|
|
|
6
6
|
sourceVersion: firefox.version,
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
9
|
+
/** Source version reader that also accepts rows carrying only `sourceEsrVersion`. */
|
|
10
10
|
export function getPatchSourceVersion(patch) {
|
|
11
11
|
return patch.sourceVersion ?? patch.sourceEsrVersion;
|
|
12
12
|
}
|
|
@@ -3,12 +3,14 @@ import type { PatchesManifest, PatchMetadata } from '../types/commands/index.js'
|
|
|
3
3
|
* Resolves a `--patches <name…>` subset against the manifest, matching each
|
|
4
4
|
* requested name tolerantly (exact filename, filename ± `.patch`, the bare
|
|
5
5
|
* order number, the manifest `name` field, or the slug). Accepts repeated
|
|
6
|
-
* values and
|
|
6
|
+
* values and lists separated by commas or whitespace, so a list passed as
|
|
7
|
+
* one shell word (`--patches "$P"` under zsh) still splits. Throws when a
|
|
7
8
|
* requested name matches none, so a typo fails loud rather than silently
|
|
8
|
-
* judging nothing
|
|
9
|
+
* judging nothing; the refusal names that name and its nearest matches,
|
|
10
|
+
* not the whole queue.
|
|
9
11
|
*
|
|
10
12
|
* @param manifest - The loaded patch manifest
|
|
11
|
-
* @param requested - Raw `--patches` values (each may be a comma list)
|
|
13
|
+
* @param requested - Raw `--patches` values (each may be a comma or whitespace list)
|
|
12
14
|
* @param refusalHint - Sentence inserted into the no-match refusal, naming
|
|
13
15
|
* what the caller's flag selects
|
|
14
16
|
* @returns The matching manifest rows, de-duplicated, in request order
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* one gate selects the same patch in the others.
|
|
6
6
|
*/
|
|
7
7
|
import { GeneralError } from '../errors/base.js';
|
|
8
|
+
import { formatPatchSuggestions } from './patch-identifier-suggest.js';
|
|
8
9
|
/** Every spelling an operator may use for one patch. */
|
|
9
10
|
function patchAliases(p) {
|
|
10
11
|
const aliases = new Set([p.filename, p.filename.replace(/\.patch$/, ''), p.name]);
|
|
@@ -31,29 +32,29 @@ function matchesPatch(p, name) {
|
|
|
31
32
|
* Resolves a `--patches <name…>` subset against the manifest, matching each
|
|
32
33
|
* requested name tolerantly (exact filename, filename ± `.patch`, the bare
|
|
33
34
|
* order number, the manifest `name` field, or the slug). Accepts repeated
|
|
34
|
-
* values and
|
|
35
|
+
* values and lists separated by commas or whitespace, so a list passed as
|
|
36
|
+
* one shell word (`--patches "$P"` under zsh) still splits. Throws when a
|
|
35
37
|
* requested name matches none, so a typo fails loud rather than silently
|
|
36
|
-
* judging nothing
|
|
38
|
+
* judging nothing; the refusal names that name and its nearest matches,
|
|
39
|
+
* not the whole queue.
|
|
37
40
|
*
|
|
38
41
|
* @param manifest - The loaded patch manifest
|
|
39
|
-
* @param requested - Raw `--patches` values (each may be a comma list)
|
|
42
|
+
* @param requested - Raw `--patches` values (each may be a comma or whitespace list)
|
|
40
43
|
* @param refusalHint - Sentence inserted into the no-match refusal, naming
|
|
41
44
|
* what the caller's flag selects
|
|
42
45
|
* @returns The matching manifest rows, de-duplicated, in request order
|
|
43
46
|
*/
|
|
44
47
|
export function selectPatchSubset(manifest, requested, refusalHint = '') {
|
|
45
48
|
const normalizedRequests = requested
|
|
46
|
-
.flatMap((entry) => entry.split(
|
|
47
|
-
.map((entry) => entry.trim())
|
|
49
|
+
.flatMap((entry) => entry.split(/[\s,]+/))
|
|
48
50
|
.filter((entry) => entry.length > 0);
|
|
49
51
|
const selected = [];
|
|
50
52
|
const seen = new Set();
|
|
51
53
|
for (const name of normalizedRequests) {
|
|
52
54
|
const found = manifest.patches.filter((p) => matchesPatch(p, name));
|
|
53
55
|
if (found.length === 0) {
|
|
54
|
-
const available = manifest.patches.map((p) => p.filename).join(', ');
|
|
55
56
|
throw new GeneralError(`No patch in the queue matches "${name}".${refusalHint ? ` ${refusalHint}` : ''} ` +
|
|
56
|
-
|
|
57
|
+
formatPatchSuggestions(name, manifest.patches));
|
|
57
58
|
}
|
|
58
59
|
for (const p of found) {
|
|
59
60
|
if (!seen.has(p.filename)) {
|
|
@@ -45,8 +45,8 @@ export declare function extractNewFileContentsFromDiff(diff: string, targetFiles
|
|
|
45
45
|
* `binary-body-not-reconstructable` queue lint, and
|
|
46
46
|
* `buildPatchQueueContext` already tolerates them for real queue entries.
|
|
47
47
|
*
|
|
48
|
-
* One parse for the whole diff, rather than one per new file
|
|
49
|
-
* call
|
|
48
|
+
* One parse for the whole diff, rather than one per new file, shared by
|
|
49
|
+
* every call site.
|
|
50
50
|
*/
|
|
51
51
|
export declare function buildNewFileTextProjection(diff: string): Map<string, string>;
|
|
52
52
|
/**
|
|
@@ -101,8 +101,8 @@ function contentFromSections(sections) {
|
|
|
101
101
|
* `binary-body-not-reconstructable` queue lint, and
|
|
102
102
|
* `buildPatchQueueContext` already tolerates them for real queue entries.
|
|
103
103
|
*
|
|
104
|
-
* One parse for the whole diff, rather than one per new file
|
|
105
|
-
* call
|
|
104
|
+
* One parse for the whole diff, rather than one per new file, shared by
|
|
105
|
+
* every call site.
|
|
106
106
|
*/
|
|
107
107
|
export function buildNewFileTextProjection(diff) {
|
|
108
108
|
const newFiles = new Map();
|
|
@@ -29,9 +29,8 @@ const REBASE_PATCH_STATUSES = [
|
|
|
29
29
|
/**
|
|
30
30
|
* Drops payload that does not belong to an entry's status.
|
|
31
31
|
*
|
|
32
|
-
* Applied on read so a session
|
|
33
|
-
* `
|
|
34
|
-
* entry, loads cleanly and is corrected, instead of being refused by a
|
|
32
|
+
* Applied on read so a session whose `resolved` entry still carries
|
|
33
|
+
* `error`/`conflictingFiles` loads cleanly and is corrected, instead of being refused by a
|
|
35
34
|
* stricter validator mid-rebase.
|
|
36
35
|
*
|
|
37
36
|
* @param entry - A structurally valid entry, possibly carrying stale payload
|
|
@@ -145,11 +144,10 @@ export async function readRebaseSession(projectRoot) {
|
|
|
145
144
|
if (!isValidSession(data)) {
|
|
146
145
|
return { present: true, valid: false, reason: 'the file is not a valid rebase session' };
|
|
147
146
|
}
|
|
148
|
-
// Normalize on read:
|
|
147
|
+
// Normalize on read: a session can carry a failure's
|
|
149
148
|
// `error`/`conflictingFiles` on an entry whose status has since been
|
|
150
149
|
// flipped to `resolved`. Correcting it here is what lets the validator
|
|
151
|
-
// stay permissive, so an in-flight rebase
|
|
152
|
-
// loads.
|
|
150
|
+
// stay permissive, so such an in-flight rebase still loads.
|
|
153
151
|
return {
|
|
154
152
|
present: true,
|
|
155
153
|
valid: true,
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* xpcshell test-file registration. Without it, xpcshell test files (e.g.
|
|
3
3
|
* `<module-dir>/test/unit/test_*.js`) are rejected by `fireforge register`
|
|
4
4
|
* as "Unknown file pattern". This writer inserts the `["test_*.js"]` section
|
|
5
|
-
* into the directory's `xpcshell.toml` (alphabetically
|
|
5
|
+
* into the directory's `xpcshell.toml` (alphabetically or after the
|
|
6
|
+
* `--after` entry, idempotently). With
|
|
6
7
|
* `--create-manifest` it also creates the manifest and wires
|
|
7
8
|
* `XPCSHELL_TESTS_MANIFESTS` into the nearest moz.build.
|
|
8
9
|
*/
|
|
@@ -14,16 +15,36 @@ import type { RegisterResult } from './register-result.js';
|
|
|
14
15
|
* missing rather than the file as unregistered).
|
|
15
16
|
*/
|
|
16
17
|
export declare function isXpcshellTestRegistered(engineDir: string, dirRel: string, fileName: string): Promise<boolean>;
|
|
18
|
+
/** Where a new section goes and what placed it there. */
|
|
19
|
+
export interface XpcshellSectionPlacement {
|
|
20
|
+
/** The manifest content with the section inserted. */
|
|
21
|
+
content: string;
|
|
22
|
+
/** The `["…"]` header of the `--after` entry the section follows. */
|
|
23
|
+
previousEntry?: string | undefined;
|
|
24
|
+
/** `--after` named no entry, so the section went in sort order. */
|
|
25
|
+
afterFallback?: boolean | undefined;
|
|
26
|
+
}
|
|
17
27
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
28
|
+
* Places the `["<fileName>"]` section in the manifest content.
|
|
29
|
+
*
|
|
30
|
+
* Without `after`, the section goes in mozbuild's case-insensitive sort
|
|
31
|
+
* order relative to the other test sections. With `after`, it goes right
|
|
32
|
+
* after the named entry's whole block (its keys included). Either way it
|
|
33
|
+
* is inserted ahead of the `#` comment lines that introduce the next
|
|
34
|
+
* entry, never between a comment and its entry, keeping one
|
|
35
|
+
* blank line between sections.
|
|
22
36
|
*/
|
|
23
|
-
export declare function
|
|
37
|
+
export declare function placeXpcshellManifestSection(content: string, fileName: string, after?: string): XpcshellSectionPlacement;
|
|
38
|
+
/**
|
|
39
|
+
* Inserts the `["<fileName>"]` section into the manifest content; see
|
|
40
|
+
* {@link placeXpcshellManifestSection}. Exported for direct unit testing.
|
|
41
|
+
*
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export declare function insertXpcshellManifestSection(content: string, fileName: string, after?: string): string;
|
|
24
45
|
/**
|
|
25
46
|
* Registers an xpcshell test file in its directory's `xpcshell.toml`.
|
|
26
47
|
* With `createManifest`, a missing manifest is scaffolded and wired into
|
|
27
48
|
* the nearest moz.build via `XPCSHELL_TESTS_MANIFESTS`.
|
|
28
49
|
*/
|
|
29
|
-
export declare function registerXpcshellTest(engineDir: string, dirRel: string, fileName: string, dryRun?: boolean, createManifest?: boolean): Promise<RegisterResult>;
|
|
50
|
+
export declare function registerXpcshellTest(engineDir: string, dirRel: string, fileName: string, dryRun?: boolean, createManifest?: boolean, after?: string): Promise<RegisterResult>;
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* xpcshell test-file registration. Without it, xpcshell test files (e.g.
|
|
4
4
|
* `<module-dir>/test/unit/test_*.js`) are rejected by `fireforge register`
|
|
5
5
|
* as "Unknown file pattern". This writer inserts the `["test_*.js"]` section
|
|
6
|
-
* into the directory's `xpcshell.toml` (alphabetically
|
|
6
|
+
* into the directory's `xpcshell.toml` (alphabetically or after the
|
|
7
|
+
* `--after` entry, idempotently). With
|
|
7
8
|
* `--create-manifest` it also creates the manifest and wires
|
|
8
9
|
* `XPCSHELL_TESTS_MANIFESTS` into the nearest moz.build.
|
|
9
10
|
*/
|
|
@@ -32,40 +33,82 @@ export async function isXpcshellTestRegistered(engineDir, dirRel, fileName) {
|
|
|
32
33
|
const content = await readText(manifestPath);
|
|
33
34
|
return content.includes(`["${fileName}"]`);
|
|
34
35
|
}
|
|
36
|
+
const SECTION_HEADER = /^\["([^"]+)"\]\s*$/;
|
|
35
37
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* The line where the block headed at `headerIndex` starts: the header
|
|
39
|
+
* itself, or the first of the `#` comment lines directly above it. A
|
|
40
|
+
* comment describes the entry below it, so nothing is inserted between
|
|
41
|
+
* them.
|
|
40
42
|
*/
|
|
41
|
-
|
|
43
|
+
function blockStart(lines, headerIndex) {
|
|
44
|
+
let start = headerIndex;
|
|
45
|
+
while (start > 0 && (lines[start - 1] ?? '').trimStart().startsWith('#'))
|
|
46
|
+
start -= 1;
|
|
47
|
+
return start;
|
|
48
|
+
}
|
|
49
|
+
/** Index of the section header `after` names: exact name first, then a substring. */
|
|
50
|
+
function findAfterHeader(lines, after) {
|
|
51
|
+
const headers = lines
|
|
52
|
+
.map((line, index) => ({ index, line, name: SECTION_HEADER.exec(line)?.[1] }))
|
|
53
|
+
.filter((header) => header.name !== undefined);
|
|
54
|
+
const exact = headers.find((header) => header.name === after || header.line.trim() === after);
|
|
55
|
+
return (exact ?? headers.find((header) => header.line.includes(after)))?.index ?? -1;
|
|
56
|
+
}
|
|
57
|
+
function spliceSection(lines, index, fileName) {
|
|
58
|
+
if (index === -1) {
|
|
59
|
+
// Append after the last section (or at end of file when there are no
|
|
60
|
+
// sections yet), keeping exactly one trailing newline.
|
|
61
|
+
while (lines.length > 0 && (lines.at(-1) ?? '').trim() === '')
|
|
62
|
+
lines.pop();
|
|
63
|
+
return [...lines, '', `["${fileName}"]`, ''].join('\n');
|
|
64
|
+
}
|
|
65
|
+
lines.splice(index, 0, `["${fileName}"]`, '');
|
|
66
|
+
return lines.join('\n');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Places the `["<fileName>"]` section in the manifest content.
|
|
70
|
+
*
|
|
71
|
+
* Without `after`, the section goes in mozbuild's case-insensitive sort
|
|
72
|
+
* order relative to the other test sections. With `after`, it goes right
|
|
73
|
+
* after the named entry's whole block (its keys included). Either way it
|
|
74
|
+
* is inserted ahead of the `#` comment lines that introduce the next
|
|
75
|
+
* entry, never between a comment and its entry, keeping one
|
|
76
|
+
* blank line between sections.
|
|
77
|
+
*/
|
|
78
|
+
export function placeXpcshellManifestSection(content, fileName, after) {
|
|
42
79
|
const lines = content.split('\n');
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
80
|
+
const headerIndexes = lines.flatMap((line, index) => (SECTION_HEADER.test(line) ? [index] : []));
|
|
81
|
+
if (after !== undefined) {
|
|
82
|
+
const afterIndex = findAfterHeader(lines, after);
|
|
83
|
+
if (afterIndex !== -1) {
|
|
84
|
+
const next = headerIndexes.find((index) => index > afterIndex);
|
|
85
|
+
return {
|
|
86
|
+
content: spliceSection(lines, next === undefined ? -1 : blockStart(lines, next), fileName),
|
|
87
|
+
previousEntry: (lines[afterIndex] ?? '').trim(),
|
|
88
|
+
};
|
|
51
89
|
}
|
|
52
90
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
91
|
+
const before = headerIndexes.find((index) => mozbuildSortCompare(fileName, SECTION_HEADER.exec(lines[index] ?? '')?.[1] ?? '') < 0);
|
|
92
|
+
return {
|
|
93
|
+
content: spliceSection(lines, before === undefined ? -1 : blockStart(lines, before), fileName),
|
|
94
|
+
...(after !== undefined ? { afterFallback: true } : {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Inserts the `["<fileName>"]` section into the manifest content; see
|
|
99
|
+
* {@link placeXpcshellManifestSection}. Exported for direct unit testing.
|
|
100
|
+
*
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
export function insertXpcshellManifestSection(content, fileName, after) {
|
|
104
|
+
return placeXpcshellManifestSection(content, fileName, after).content;
|
|
62
105
|
}
|
|
63
106
|
/**
|
|
64
107
|
* Registers an xpcshell test file in its directory's `xpcshell.toml`.
|
|
65
108
|
* With `createManifest`, a missing manifest is scaffolded and wired into
|
|
66
109
|
* the nearest moz.build via `XPCSHELL_TESTS_MANIFESTS`.
|
|
67
110
|
*/
|
|
68
|
-
export async function registerXpcshellTest(engineDir, dirRel, fileName, dryRun = false, createManifest = false) {
|
|
111
|
+
export async function registerXpcshellTest(engineDir, dirRel, fileName, dryRun = false, createManifest = false, after) {
|
|
69
112
|
const manifestRel = `${dirRel}/xpcshell.toml`;
|
|
70
113
|
const manifestPath = join(engineDir, manifestRel);
|
|
71
114
|
const entry = `["${fileName}"]`;
|
|
@@ -86,9 +129,15 @@ export async function registerXpcshellTest(engineDir, dirRel, fileName, dryRun =
|
|
|
86
129
|
if (content.includes(entry)) {
|
|
87
130
|
return { manifest: manifestRel, entry, skipped: true };
|
|
88
131
|
}
|
|
89
|
-
const
|
|
132
|
+
const placement = placeXpcshellManifestSection(content, fileName, after);
|
|
90
133
|
if (!dryRun) {
|
|
91
|
-
await writeText(manifestPath,
|
|
134
|
+
await writeText(manifestPath, placement.content);
|
|
92
135
|
}
|
|
93
|
-
return {
|
|
136
|
+
return {
|
|
137
|
+
manifest: manifestRel,
|
|
138
|
+
entry,
|
|
139
|
+
skipped: false,
|
|
140
|
+
previousEntry: placement.previousEntry,
|
|
141
|
+
afterFallback: placement.afterFallback,
|
|
142
|
+
};
|
|
94
143
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Per-run output logs under `.fireforge/logs/`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* through `tail`/`grep`, the ergonomic default when output is long,
|
|
6
|
-
* the summary and discards the `TEST-UNEXPECTED-FAIL` lines that say
|
|
7
|
-
* broke, and it launders the exit code besides.
|
|
8
|
-
* pipe a run")
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* Without a log, a run's diagnosis exists in exactly one place: the terminal.
|
|
5
|
+
* Piping through `tail`/`grep`, the ergonomic default when output is long,
|
|
6
|
+
* keeps the summary and discards the `TEST-UNEXPECTED-FAIL` lines that say
|
|
7
|
+
* what broke, and it launders the exit code besides. An operator rule
|
|
8
|
+
* ("never pipe a run") does not hold in practice, so this is not an operator
|
|
9
|
+
* problem: the tool is the only party that can make the log survive the
|
|
10
|
+
* mistake.
|
|
11
11
|
*
|
|
12
12
|
* So `test` and `build` write their own complete copy as they stream, and the
|
|
13
13
|
* `FIREFORGE-VERDICT:` line names the path. A piped, truncated, or
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* Everything here is best-effort. A log is a diagnostic aid, and a run must
|
|
17
17
|
* never fail because one could not be opened, written, or pruned.
|
|
18
18
|
* Every entry point swallows its errors and degrades to "no log", which is
|
|
19
|
-
* exactly the behaviour
|
|
19
|
+
* exactly the behaviour of a run without this module.
|
|
20
20
|
*/
|
|
21
21
|
/** A run log sink. `write` never throws. */
|
|
22
22
|
export interface RunLog {
|