@hominis/fireforge 0.52.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 +26 -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.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 +8 -0
- package/dist/src/commands/test-build-phase.js +42 -7
- 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 +68 -7
- package/dist/src/commands/test-multi-verdict.js +1 -0
- package/dist/src/commands/test-orchestrate.d.ts +6 -0
- package/dist/src/commands/test-orchestrate.js +28 -0
- 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 +40 -2
- package/dist/src/commands/test-verdict.d.ts +5 -3
- package/dist/src/commands/test.js +10 -0
- 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 +24 -3
- package/dist/src/core/build-baseline-validate.d.ts +30 -1
- package/dist/src/core/build-baseline-validate.js +127 -35
- package/dist/src/core/build-baseline.d.ts +8 -2
- package/dist/src/core/build-baseline.js +25 -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-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/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 +13 -3
- package/dist/src/core/negative-control-compiled.js +27 -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-stale-check.d.ts +38 -0
- package/dist/src/core/test-stale-check.js +82 -1
- 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.js +1 -1
- 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/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 +21 -23
- package/docs/exit-codes.md +8 -11
- package/docs/furnace.md +3 -3
- package/docs/lifecycle-invariants.md +36 -45
- package/docs/machine-output.md +41 -24
- package/docs/patch-workflow.md +129 -24
- package/docs/run-logs.md +8 -9
- package/docs/testing.md +105 -46
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.53.0
|
|
4
|
+
|
|
5
|
+
### Test harness
|
|
6
|
+
|
|
7
|
+
- `test --jobs` gives each harness instance its own `MOZ_UPLOAD_DIR` (`<MOZ_UPLOAD_DIR>/job-<n>`, created up front) when the caller sets one, so instances no longer overwrite each other's fixed-name artifacts such as the `modifiedPrefs.json` pref census. The verdict names the directories as `upload-dirs=`.
|
|
8
|
+
- `test --jobs` holds the mochitest HTTP, ssltunnel and WebSocket ports (8888, 4443, 9988) for the whole parallel run, so each instance's harness falls back to server ports of its own instead of racing for 8888. Each `FIREFORGE-SHARD:` line names the ports its instance took as `ports=http:N,ssl:N,ws:N`.
|
|
9
|
+
- A harness whose mochitest server never starts (`could not start server on port`, `Timed out while waiting for server startup`) is an infrastructure failure, not `no-tests`: it is retried within `--harness-retries` and reports `reason=server-startup` once the budget is spent. A `--results` record for a harness-level result (`automation.py`) carries `shardFiles`, plus `file` when its shard has one file.
|
|
10
|
+
- `test` refuses with `note=stale-compiled` when C++, Rust, IDL, WebIDL, IPDL or YAML sources changed after the binary under test was linked (the newer of the binary and its `libxul`). `--allow-stale-build` turns the refusal into a warning, and `test --build` escalates to a full `mach build`. Every run that reaches dispatch stamps `build-id=<BuildID>` from `application.ini` on its verdict.
|
|
11
|
+
- A negative control on a header (`.h`, `.hh`, `.hpp`, `.ipdlh`) counts as compiled even when an `EXPORTS` manifest installs it, so it is applied before a full pre-test build instead of reporting `control=missed`.
|
|
12
|
+
- After a compiled negative control is restored, `test` rebuilds the binary under the same lock hold and adds `control-restore-build=done|failed` to the verdict. A binary that still carries a control (the run was killed, or the restore build failed) is refused with `note=control-built` until `fireforge build`, and `test --build` escalates to a full build.
|
|
13
|
+
- A scoped `test --build <dir>/` no longer leaves a baseline the next plain `test` refuses: coverage paths are recorded normalized, and non-ASCII dirty paths are fingerprinted unquoted. An invalid baseline's refusal names the failing field and its value, and offers `--build` when the field belongs to the coverage claim.
|
|
14
|
+
|
|
15
|
+
### Patch queue
|
|
16
|
+
|
|
17
|
+
- Every `patches.json` write puts every row and the manifest's own keys in the one canonical order, not only the rows it changed. A re-export no longer leaves an older writer's rows (`sourceProduct` after `filesAffected`) in the working copy while `patch stage` stages them canonical, so commits stop flipping key order on hundreds of rows. The `re-export --dry-run` purity guard hashes rows in canonical order.
|
|
18
|
+
- `patch reorder --shift <n> --from <order> [--through <order>]` renumbers a run of patches up by `n` in one transaction, to open room for inserts. Retired and reserved slots inside the run move with it, a shift onto an occupied order past the run is refused, and under `patchPolicy.allowGaps: false` the opened orders are recorded as reservations, which the inserts that follow fill. `--map-out <file>` on `reorder` and `split` writes the old-to-new filename map as JSON.
|
|
19
|
+
- `patch move-files --scan-file <path>` adopts new, unowned engine files into the destination in the same transaction, and both sides are linted as the transaction leaves them. `--retire-empty` lets a move empty the source: the declarations it owns re-point to the destination and its slot is retired as by `patch retire`. Without the flag, the refusal names it.
|
|
20
|
+
- The projected lint of `patch move-files`, `patch split` and a placed `export` uses the queue's whole lint configuration. With `forwardRegistration: "extended"`, a shared test manifest's suite entries (`["browser_*.js"]`) are projected and written to the `--declarations-out` report instead of surfacing only after the move.
|
|
21
|
+
- A refused `move-files --create` or `split` report names the patch the rerun creates as `owner`. The declarations `move-files` and `split` write, and every report entry, carry a `reason` naming the move, so the printed `--add --from` call needs no `--reason`.
|
|
22
|
+
- A per-patch size refusal from `move-files` or `split` names a tier change behind it, for example "the source becomes test tier (it was general tier): 9634 lines against 6000".
|
|
23
|
+
- `patch staged-dependency --add`, single or `--from`, on a declaration already present with a different `reason` replaces the reason in place, keeping the entry's position. The summary reports updated reasons apart from additions.
|
|
24
|
+
- `re-export --expect-removed` drops every staged registration and forward import, in any patch, whose `creates` path it retires, names each one (`would drop` on a dry run) and records `re-export-staged-prune`. Before, the stale declaration waited for the next `lint --per-patch`.
|
|
25
|
+
- A re-export keeps a staged registration whose `creates` file exists in `engine/` or is an `--expect-new` path of the run, and says so ("kept: file exists but no patch owns it yet"), instead of pruning the declaration the next scan needs.
|
|
26
|
+
- `fireforge register` inserts an xpcshell section ahead of the `#` comments that introduce the next entry, never between a comment and its entry. `--after <entry>` now works for `xpcshell.toml` and places the section after that entry's whole block.
|
|
27
|
+
- `--patches` on `lint --per-patch`, `status`, `verify` and `check` splits a list on whitespace as well as commas, so a list in one zsh word works. An unmatched name is refused with its nearest matches and the queue size instead of every patch in the queue.
|
|
28
|
+
|
|
3
29
|
## 0.52.0
|
|
4
30
|
|
|
5
31
|
### Test harness
|
package/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.
|
|
4
|
-
"commit": "
|
|
5
|
-
"shortCommit": "
|
|
3
|
+
"version": "0.53.0",
|
|
4
|
+
"commit": "2f2367bfe9c2b8a834cbf09f9b19b02d8dbd6b66",
|
|
5
|
+
"shortCommit": "2f2367bfe9c2",
|
|
6
6
|
"dirty": false,
|
|
7
7
|
"dirtyHash": null,
|
|
8
|
-
"buildTime": "2026-10-
|
|
8
|
+
"buildTime": "2026-10-22T20:59:15.472Z"
|
|
9
9
|
}
|
|
@@ -79,9 +79,8 @@ export async function bootstrapCommand(projectRoot) {
|
|
|
79
79
|
if (hasErrors) {
|
|
80
80
|
outro('Build dependencies installed with errors');
|
|
81
81
|
// Propagate the failure (mirroring doctor's exit-code handling)
|
|
82
|
-
// instead of exiting 0
|
|
83
|
-
// build that
|
|
84
|
-
// were discarded here.
|
|
82
|
+
// instead of exiting 0, so CI gating on bootstrap does not proceed to
|
|
83
|
+
// a build that cannot succeed.
|
|
85
84
|
return checksExitCode;
|
|
86
85
|
}
|
|
87
86
|
outro('Build dependencies installed with warnings');
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* session lock, not while holding it.
|
|
4
4
|
*
|
|
5
5
|
* A build queued behind a running objdir browser (a demo batch, an
|
|
6
|
-
* end-to-end harness)
|
|
7
|
-
* peer's build, test and re-export
|
|
8
|
-
* nothing. The wait
|
|
6
|
+
* end-to-end harness) that waited inside `withEngineSessionLock` would queue
|
|
7
|
+
* every peer's build, test and re-export behind a run that was doing
|
|
8
|
+
* nothing. The wait happens first, and the in-lock objdir preflight
|
|
9
9
|
* re-checks once (the spent budget is stripped from the options it gets).
|
|
10
10
|
*/
|
|
11
11
|
import type { BuildOptions } from '../types/commands/index.js';
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* session lock, not while holding it.
|
|
5
5
|
*
|
|
6
6
|
* A build queued behind a running objdir browser (a demo batch, an
|
|
7
|
-
* end-to-end harness)
|
|
8
|
-
* peer's build, test and re-export
|
|
9
|
-
* nothing. The wait
|
|
7
|
+
* end-to-end harness) that waited inside `withEngineSessionLock` would queue
|
|
8
|
+
* every peer's build, test and re-export behind a run that was doing
|
|
9
|
+
* nothing. The wait happens first, and the in-lock objdir preflight
|
|
10
10
|
* re-checks once (the spent budget is stripped from the options it gets).
|
|
11
11
|
*/
|
|
12
12
|
import { join } from 'node:path';
|
|
@@ -392,6 +392,10 @@ async function recordFullBuildBaseline(projectRoot, engineDir, binaryName, ui, p
|
|
|
392
392
|
recordedBy: ui ? 'fireforge build --ui' : 'fireforge build',
|
|
393
393
|
staticComponentsHandling: 'auto',
|
|
394
394
|
buildKind: ui ? 'faster' : 'full',
|
|
395
|
+
// A full build recompiles a negative control's restored source, so
|
|
396
|
+
// it drops the control-built stamp; `--ui` compiles nothing and
|
|
397
|
+
// keeps it.
|
|
398
|
+
controlBuild: ui ? previousBaseline?.controlBuild : undefined,
|
|
395
399
|
});
|
|
396
400
|
}
|
|
397
401
|
catch (baselineError) {
|
|
@@ -10,11 +10,14 @@ export interface DeclarationsReport {
|
|
|
10
10
|
commands: string[];
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* A declaration as the report records it. `owner` is
|
|
14
|
-
*
|
|
13
|
+
* A declaration as the report records it. `owner` is optional for renamers
|
|
14
|
+
* that cannot name one; `reason` is the rationale `staged-dependency --add
|
|
15
|
+
* --from` records with the declaration (an entry's own reason wins over the
|
|
16
|
+
* call's `--reason`).
|
|
15
17
|
*/
|
|
16
18
|
export type ReportedDeclaration = Omit<PatchLintStagedDeclaration, 'owner'> & {
|
|
17
19
|
owner?: string;
|
|
20
|
+
reason?: string;
|
|
18
21
|
};
|
|
19
22
|
/** Rewrites a projected declaration into the names the current queue uses. */
|
|
20
23
|
export type DeclarationRenamer = (declaration: PatchLintStagedDeclaration) => ReportedDeclaration;
|
|
@@ -26,8 +29,10 @@ export type DeclarationRenamer = (declaration: PatchLintStagedDeclaration) => Re
|
|
|
26
29
|
* @param issues - The refusal's findings
|
|
27
30
|
* @param out - `--declarations-out`, relative to the working directory
|
|
28
31
|
* @param rename - Maps projected patch names back to current ones
|
|
32
|
+
* @param reason - Rationale stamped on every declaration that carries none
|
|
33
|
+
* (`patch move-files` and `patch split` name the move that needs it)
|
|
29
34
|
*/
|
|
30
|
-
export declare function writeDeclarationsReport(projectRoot: string, issues: readonly PatchLintIssue[], out?: string, rename?: DeclarationRenamer): Promise<DeclarationsReport | undefined>;
|
|
35
|
+
export declare function writeDeclarationsReport(projectRoot: string, issues: readonly PatchLintIssue[], out?: string, rename?: DeclarationRenamer, reason?: string): Promise<DeclarationsReport | undefined>;
|
|
31
36
|
/** The refusal lines that point at a written report. */
|
|
32
37
|
export declare function formatDeclarationsReport(report: DeclarationsReport): string[];
|
|
33
38
|
/**
|
|
@@ -40,4 +45,5 @@ export declare function withDeclarationsReport(conflicts: ConflictReport | null,
|
|
|
40
45
|
regressions: readonly PatchLintIssue[];
|
|
41
46
|
out?: string | undefined;
|
|
42
47
|
rename?: DeclarationRenamer;
|
|
48
|
+
reason?: string;
|
|
43
49
|
}): Promise<ConflictReport | null>;
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* One `--from`-ready declaration report for a refused queue change.
|
|
4
4
|
*
|
|
5
|
-
* Moving a test out of a patch that owns a shared manifest
|
|
6
|
-
* `forward-registration` error per manifest line, and each line
|
|
7
|
-
* own `patch staged-dependency --add` call
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* into one lint-report-shaped JSON (`queueIssues[].stagedDeclarations`) and
|
|
5
|
+
* Moving a test out of a patch that owns a shared manifest refuses with one
|
|
6
|
+
* `forward-registration` error per manifest line, and each line would need
|
|
7
|
+
* its own `patch staged-dependency --add` call. `patch move-files`,
|
|
8
|
+
* `patch split` and `re-export --scan` write every declaration their refusal
|
|
9
|
+
* proposes into one lint-report-shaped JSON (`queueIssues[].stagedDeclarations`) and
|
|
11
10
|
* name the single `patch staged-dependency <holder> --add --from <file>`
|
|
12
11
|
* call per holding patch that discharges them.
|
|
13
12
|
*/
|
|
@@ -26,15 +25,20 @@ const DECLARABLE_CHECKS = new Set(['forward-import', 'forward-registration']);
|
|
|
26
25
|
* @param issues - The refusal's findings
|
|
27
26
|
* @param out - `--declarations-out`, relative to the working directory
|
|
28
27
|
* @param rename - Maps projected patch names back to current ones
|
|
28
|
+
* @param reason - Rationale stamped on every declaration that carries none
|
|
29
|
+
* (`patch move-files` and `patch split` name the move that needs it)
|
|
29
30
|
*/
|
|
30
|
-
export async function writeDeclarationsReport(projectRoot, issues, out, rename = (declaration) => declaration) {
|
|
31
|
+
export async function writeDeclarationsReport(projectRoot, issues, out, rename = (declaration) => declaration, reason) {
|
|
32
|
+
const withReason = (declaration) => reason === undefined || declaration.reason !== undefined
|
|
33
|
+
? declaration
|
|
34
|
+
: { ...declaration, reason };
|
|
31
35
|
const queueIssues = issues
|
|
32
36
|
.filter((issue) => DECLARABLE_CHECKS.has(issue.check))
|
|
33
37
|
.map((issue) => ({
|
|
34
38
|
check: issue.check,
|
|
35
39
|
file: issue.file,
|
|
36
40
|
message: issue.message,
|
|
37
|
-
stagedDeclarations: (issue.stagedDeclarations ?? []).map(rename),
|
|
41
|
+
stagedDeclarations: (issue.stagedDeclarations ?? []).map((declaration) => withReason(rename(declaration))),
|
|
38
42
|
}))
|
|
39
43
|
.filter((issue) => issue.stagedDeclarations.length > 0);
|
|
40
44
|
const declarations = queueIssues.flatMap((issue) => issue.stagedDeclarations);
|
|
@@ -46,11 +50,14 @@ export async function writeDeclarationsReport(projectRoot, issues, out, rename =
|
|
|
46
50
|
await ensureDir(resolve(path, '..'));
|
|
47
51
|
await writeJson(path, { queueIssues });
|
|
48
52
|
const holders = [...new Set(declarations.map((declaration) => declaration.patch))].sort();
|
|
53
|
+
// A report whose every entry carries its reason needs no `--reason`.
|
|
54
|
+
const reasonFlag = declarations.every((declaration) => declaration.reason !== undefined)
|
|
55
|
+
? ''
|
|
56
|
+
: ` ${STAGED_DEPENDENCY_REASON_PLACEHOLDER}`;
|
|
49
57
|
return {
|
|
50
58
|
path,
|
|
51
59
|
count: declarations.length,
|
|
52
|
-
commands: holders.map((holder) => `fireforge patch staged-dependency ${holder} --add --from ${path}
|
|
53
|
-
STAGED_DEPENDENCY_REASON_PLACEHOLDER),
|
|
60
|
+
commands: holders.map((holder) => `fireforge patch staged-dependency ${holder} --add --from ${path}${reasonFlag}`),
|
|
54
61
|
};
|
|
55
62
|
}
|
|
56
63
|
/** The refusal lines that point at a written report. */
|
|
@@ -69,7 +76,7 @@ export function formatDeclarationsReport(report) {
|
|
|
69
76
|
export async function withDeclarationsReport(conflicts, args) {
|
|
70
77
|
if (conflicts === null)
|
|
71
78
|
return null;
|
|
72
|
-
const report = await writeDeclarationsReport(args.projectRoot, args.regressions, args.out, args.rename);
|
|
79
|
+
const report = await writeDeclarationsReport(args.projectRoot, args.regressions, args.out, args.rename, args.reason);
|
|
73
80
|
if (report === undefined)
|
|
74
81
|
return conflicts;
|
|
75
82
|
return { ...conflicts, details: [...conflicts.details, ...formatDeclarationsReport(report)] };
|
|
@@ -33,7 +33,7 @@ async function confirmDiscard(message, hint, options) {
|
|
|
33
33
|
/**
|
|
34
34
|
* Plans the restore baseline for `entries`: the patch-applied baseline for
|
|
35
35
|
* patch-claimed paths, or pristine HEAD when `--to-upstream`
|
|
36
|
-
* explicitly requests
|
|
36
|
+
* explicitly requests it.
|
|
37
37
|
*/
|
|
38
38
|
async function planDiscards(patchesDir, engineDir, entries, options) {
|
|
39
39
|
if (options.toUpstream)
|
|
@@ -160,8 +160,8 @@ export async function discardCommand(projectRoot, file, options = {}) {
|
|
|
160
160
|
}
|
|
161
161
|
if (options.dryRun) {
|
|
162
162
|
// Show the rename pair regardless of which side the operator passed.
|
|
163
|
-
//
|
|
164
|
-
//
|
|
163
|
+
// Discarding the new path of a rename also resurrects the old path, so
|
|
164
|
+
// the preview names both, exactly when the full picture matters most.
|
|
165
165
|
info(`Would discard changes to: ${dryRunLabel(plan)}`);
|
|
166
166
|
outro('Dry run complete — no changes made');
|
|
167
167
|
return;
|
|
@@ -138,10 +138,10 @@ function emptyOutcome() {
|
|
|
138
138
|
* under `custom` would leave it in both maps, a state nothing validates.
|
|
139
139
|
* Every orphan is therefore re-checked against `freshConfig` inside the
|
|
140
140
|
* lock and skipped when it is no longer orphaned.
|
|
141
|
-
* 2. Delete custom directories outside the lock. `repairCustomOrphans`
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
141
|
+
* 2. Delete custom directories outside the lock. `repairCustomOrphans` runs
|
|
142
|
+
* after the lock is released, so it must not delete the directory of a
|
|
143
|
+
* name a concurrent `furnace create` has registered but not yet
|
|
144
|
+
* populated.
|
|
145
145
|
*/
|
|
146
146
|
async function repairOrphans(projectRoot, orphans) {
|
|
147
147
|
const outcome = emptyOutcome();
|
|
@@ -443,8 +443,8 @@ async function readFurnaceLockPid(lockPath) {
|
|
|
443
443
|
*
|
|
444
444
|
* This is the recovery path when the signal-handler sweep
|
|
445
445
|
* (`forceReleaseFurnaceLocksForActiveOperations` in `bin/fireforge.ts`)
|
|
446
|
-
* misses: a SIGKILL'd process that never ran the handler, or a lock
|
|
447
|
-
*
|
|
446
|
+
* misses: a SIGKILL'd process that never ran the handler, or a lock
|
|
447
|
+
* directory without a PID file. SIGINT'ing `furnace
|
|
448
448
|
* preview` leaves the lock behind, and the next `fireforge test --build`
|
|
449
449
|
* then times out waiting for it. `doctor --repair-furnace` clears it so the
|
|
450
450
|
* next command runs immediately.
|
|
@@ -464,9 +464,9 @@ const furnaceStaleLockCheck = {
|
|
|
464
464
|
const ageSuffix = ageMs !== undefined ? ` (age: ${Math.round(ageMs / 1000)}s)` : '';
|
|
465
465
|
// Two signals mark a lock as stale:
|
|
466
466
|
// 1. PID file says owner is dead → unambiguous, remove immediately.
|
|
467
|
-
// 2. PID file absent and lock is older than 60s →
|
|
468
|
-
//
|
|
469
|
-
// bucket. The age gate avoids false positives on a lock just
|
|
467
|
+
// 2. PID file absent and lock is older than 60s → a lock directory
|
|
468
|
+
// written without a PID file (for example created externally)
|
|
469
|
+
// falls into this bucket. The age gate avoids false positives on a lock just
|
|
470
470
|
// acquired by a concurrent process that has not written its PID yet.
|
|
471
471
|
//
|
|
472
472
|
// `isProcessAlive` treats EPERM as alive. Returning false for EPERM
|
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
* adopt-then-split for a real moved-code block, but only after checking
|
|
5
5
|
* that the adopt itself would pass.
|
|
6
6
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* line budget.
|
|
7
|
+
* The moved-code heuristic alone is not enough: it can advise adopting
|
|
8
|
+
* several new modules into an existing patch when the only error is the
|
|
9
|
+
* missing registration, and the adopt then refuses a module for importing
|
|
10
|
+
* later patches, or without it breaches the source patch's hard size limit.
|
|
11
|
+
* Split out of export-flow.ts for the line budget.
|
|
13
12
|
*/
|
|
14
13
|
import { type PatchQueueContext } from '../core/patch-lint.js';
|
|
15
14
|
import type { PatchLintIssue } from '../types/commands/index.js';
|
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
* adopt-then-split for a real moved-code block, but only after checking
|
|
6
6
|
* that the adopt itself would pass.
|
|
7
7
|
*
|
|
8
|
-
* The
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* line budget.
|
|
8
|
+
* The moved-code heuristic alone is not enough: it can advise adopting
|
|
9
|
+
* several new modules into an existing patch when the only error is the
|
|
10
|
+
* missing registration, and the adopt then refuses a module for importing
|
|
11
|
+
* later patches, or without it breaches the source patch's hard size limit.
|
|
12
|
+
* Split out of export-flow.ts for the line budget.
|
|
14
13
|
*/
|
|
15
14
|
import { detectMovedCodeOverlaps, formatMovedCodeAdvice } from '../core/export-moved-code-shape.js';
|
|
16
15
|
import { countNonBinaryDiffLines, getPatchSizeThresholds, lintPatchQueue, resolvePatchSizeTier, } from '../core/patch-lint.js';
|
|
@@ -180,7 +180,10 @@ export async function projectPlacementForLint(patchesDir, plan, diff, config) {
|
|
|
180
180
|
...pendingBody,
|
|
181
181
|
});
|
|
182
182
|
projectedEntries.sort((a, b) => a.order - b.order || a.filename.localeCompare(b.filename));
|
|
183
|
-
|
|
183
|
+
// The projection keeps every queue-wide lint setting of the baseline
|
|
184
|
+
// (patch policy, forward-registration scope, token scales), so a
|
|
185
|
+
// test-manifest suite entry is checked exactly as the committed gate
|
|
186
|
+
// checks it.
|
|
184
187
|
// A new module whose moz.build line is declared (staged registration)
|
|
185
188
|
// and present in the working tree, but not yet exported by its owner, is
|
|
186
189
|
// accepted with a "re-export the owner next" note instead of refused.
|
|
@@ -189,10 +192,7 @@ export async function projectPlacementForLint(patchesDir, plan, diff, config) {
|
|
|
189
192
|
baseCtx,
|
|
190
193
|
newFilename: plan.newFilename,
|
|
191
194
|
pendingNewFiles: new Set(pendingBody.newFiles.keys()),
|
|
192
|
-
projectedIssues: lintPatchQueue({
|
|
193
|
-
entries: projectedEntries,
|
|
194
|
-
...policyRest,
|
|
195
|
-
}).filter((i) => i.severity === 'error'),
|
|
195
|
+
projectedIssues: lintPatchQueue({ ...baseCtx, entries: projectedEntries }).filter((i) => i.severity === 'error'),
|
|
196
196
|
});
|
|
197
197
|
for (const note of registration.accepted)
|
|
198
198
|
warn(note);
|
|
@@ -203,10 +203,7 @@ export async function projectPlacementForLint(patchesDir, plan, diff, config) {
|
|
|
203
203
|
// pre-existing breakage rather than a consequence of this placement, and
|
|
204
204
|
// calling it one would misattribute. Entries are already in memory,
|
|
205
205
|
// so this second pass costs no additional IO.
|
|
206
|
-
const baselineIssues = lintPatchQueue(
|
|
207
|
-
entries: baseCtx.entries,
|
|
208
|
-
...policyRest,
|
|
209
|
-
}).filter((i) => i.severity === 'error');
|
|
206
|
+
const baselineIssues = lintPatchQueue(baseCtx).filter((i) => i.severity === 'error');
|
|
210
207
|
// Register-first and new-file + moved-code advice: name the working
|
|
211
208
|
// sequence instead of leaving the operator to derive it from two
|
|
212
209
|
// individually-correct guards that together dead-end, but only offer
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Lets `export --order` land a new system module whose moz.build line is
|
|
3
3
|
* still unexported working-tree drift in the patch that registers it.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* `unregistered-system-module` because no patch body
|
|
7
|
-
* line yet, and the registering patch
|
|
8
|
-
*
|
|
5
|
+
* Without this the two refusals deadlock: the module's export fails
|
|
6
|
+
* `unregistered-system-module` because no patch body carries its moz.build
|
|
7
|
+
* line yet, and the registering patch cannot be re-exported first because
|
|
8
|
+
* its line names a file no patch creates. The way through is
|
|
9
9
|
* declared intent plus evidence: when the registering patch carries a
|
|
10
10
|
* staged registration for the module and the working tree's moz.build has
|
|
11
11
|
* exactly that line, the export is accepted and the operator is told to
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Lets `export --order` land a new system module whose moz.build line is
|
|
4
4
|
* still unexported working-tree drift in the patch that registers it.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* `unregistered-system-module` because no patch body
|
|
8
|
-
* line yet, and the registering patch
|
|
9
|
-
*
|
|
6
|
+
* Without this the two refusals deadlock: the module's export fails
|
|
7
|
+
* `unregistered-system-module` because no patch body carries its moz.build
|
|
8
|
+
* line yet, and the registering patch cannot be re-exported first because
|
|
9
|
+
* its line names a file no patch creates. The way through is
|
|
10
10
|
* declared intent plus evidence: when the registering patch carries a
|
|
11
11
|
* staged registration for the module and the working tree's moz.build has
|
|
12
12
|
* exactly that line, the export is accepted and the operator is told to
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* can take as their own later patch, and the exact `patch staged-dependency
|
|
5
5
|
* --add` commands that declare the edges instead.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* the number and every flag of the declaration from the finding text.
|
|
7
|
+
* Both the order number and every flag of the declaration are spelled out,
|
|
8
|
+
* so the operator does not have to work them out from the finding text.
|
|
10
9
|
*/
|
|
11
10
|
import type { PatchesManifest, PatchLintIssue } from '../types/commands/index.js';
|
|
12
11
|
import type { FireForgeConfig } from '../types/config.js';
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* can take as their own later patch, and the exact `patch staged-dependency
|
|
6
6
|
* --add` commands that declare the edges instead.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* the number and every flag of the declaration from the finding text.
|
|
8
|
+
* Both the order number and every flag of the declaration are spelled out,
|
|
9
|
+
* so the operator does not have to work them out from the finding text.
|
|
11
10
|
*/
|
|
12
11
|
import { STAGED_DEPENDENCY_REASON_PLACEHOLDER } from '../core/patch-lint-staged-registration.js';
|
|
13
12
|
import { earliestLegalOrderAfter } from '../core/patch-order-legal.js';
|
|
@@ -19,8 +19,8 @@ export interface DryRunPlanInput {
|
|
|
19
19
|
* Resolved `--test-dir` override (engine-relative, already validated by
|
|
20
20
|
* `resolveValidatedTestDir`). Omit for the default `<binaryName>`-derived
|
|
21
21
|
* scaffold directory. The formatters must receive the same value the
|
|
22
|
-
* scaffolders get
|
|
23
|
-
*
|
|
22
|
+
* scaffolders get; recomputing the default from `binaryName` would name a
|
|
23
|
+
* directory the real run never writes to.
|
|
24
24
|
*/
|
|
25
25
|
testDir?: string;
|
|
26
26
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* When `<tag>` includes a shared CSS fragment that changed, every other
|
|
5
5
|
* deployed includer of that fragment still carries the old expansion after
|
|
6
6
|
* the targeted deploy. Deploy-all refreshes all of them as a side effect of
|
|
7
|
-
* deploying everything; the targeted form
|
|
8
|
-
* component
|
|
7
|
+
* deploying everything; the targeted form refreshes only the named
|
|
8
|
+
* component. This module refreshes the other
|
|
9
9
|
* stale includers through the same pipeline and reports them, so a stale
|
|
10
10
|
* expansion is never left behind silently.
|
|
11
11
|
*/
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* When `<tag>` includes a shared CSS fragment that changed, every other
|
|
6
6
|
* deployed includer of that fragment still carries the old expansion after
|
|
7
7
|
* the targeted deploy. Deploy-all refreshes all of them as a side effect of
|
|
8
|
-
* deploying everything; the targeted form
|
|
9
|
-
* component
|
|
8
|
+
* deploying everything; the targeted form refreshes only the named
|
|
9
|
+
* component. This module refreshes the other
|
|
10
10
|
* stale includers through the same pipeline and reports them, so a stale
|
|
11
11
|
* expansion is never left behind silently.
|
|
12
12
|
*/
|
|
@@ -24,8 +24,8 @@ import { parseMaxWarnings } from './validate-report.js';
|
|
|
24
24
|
* Splits the raw `--wait-lock` value off a furnace leaf's parsed options and
|
|
25
25
|
* resolves it into `waitLockSeconds` (flag, else `FIREFORGE_WAIT_LOCK`, else
|
|
26
26
|
* undefined) for the furnace lock `runFurnaceMutation` takes. Used by the
|
|
27
|
-
* leaves that take only Furnace's lock,
|
|
28
|
-
* and ignored.
|
|
27
|
+
* leaves that take only Furnace's lock, so the flag is honoured there rather
|
|
28
|
+
* than accepted and ignored.
|
|
29
29
|
*/
|
|
30
30
|
function withFurnaceLockBudget(options) {
|
|
31
31
|
const { waitLock, ...rest } = options;
|
|
@@ -377,7 +377,7 @@ async function reportLintOutcome(engineDir, issues, options) {
|
|
|
377
377
|
// with warnings" when only notices fired contradicts the preceding
|
|
378
378
|
// `0 warning(s)` summary line and reads as a regression. Errors suppressed
|
|
379
379
|
// by --only-introduced still warrant the "with warnings" outro: they print
|
|
380
|
-
// as ERROR rows but
|
|
380
|
+
// as ERROR rows but do not fail the run, which is the same contract the
|
|
381
381
|
// operator gets from a real warning.
|
|
382
382
|
const suppressedErrors = options.onlyIntroduced && errors.length > 0;
|
|
383
383
|
if (warnings.length > 0 || suppressedErrors) {
|
|
@@ -480,7 +480,7 @@ export function registerLint(program, { getProjectRoot, withErrorHandling }) {
|
|
|
480
480
|
.option('--since <git-rev>', 'Tag issues as [introduced] or [cumulative] based on whether the file changed since <git-rev> (e.g. HEAD, a branch, a SHA)')
|
|
481
481
|
.option('--only-introduced', 'Fail only on issues tagged [introduced] (requires --since). Cumulative errors still print but do not set a non-zero exit.')
|
|
482
482
|
.option('--per-patch', "Lint each patch in the queue as its own isolated diff. Rescopes patch-size rules so they fire against individual patches rather than the aggregate. Honours each patch's `lintIgnore` entries.")
|
|
483
|
-
.option('--patches <names...>', 'With --per-patch, lint only the named patches. Accepts repeated flags, comma lists, full filenames/stems, bare order numbers, manifest names, category-prefixed slugs, or bare slugs. Positional arguments after --per-patch are treated the same way.')
|
|
483
|
+
.option('--patches <names...>', 'With --per-patch, lint only the named patches. Accepts repeated flags, comma or whitespace lists, full filenames/stems, bare order numbers, manifest names, category-prefixed slugs, or bare slugs. Positional arguments after --per-patch are treated the same way.')
|
|
484
484
|
.option('--max-warnings <n>', 'Fail when lint reports more than <n> warning(s); use 0 for warning-clean release gates.')
|
|
485
485
|
.option('--no-cache', 'Bypass per-patch lint result cache reads and writes.')
|
|
486
486
|
.option('--report <path>', 'With --per-patch, write a machine-readable JSON report (per-patch size metrics, tier, thresholds, issues, and lintIgnore-suppressed issues) to <path>.')
|
|
@@ -527,8 +527,8 @@ export function registerLint(program, { getProjectRoot, withErrorHandling }) {
|
|
|
527
527
|
.description('Manage the per-patch lint result cache')
|
|
528
528
|
// Commander routes `fireforge lint cache` here even when the operator
|
|
529
529
|
// meant to lint an engine directory literally named `cache`. A bare
|
|
530
|
-
// `lint cache` (no subcommand)
|
|
531
|
-
// the ambiguity explicit instead of doing the wrong operation quietly.
|
|
530
|
+
// `lint cache` (no subcommand) would otherwise silently do nothing, so
|
|
531
|
+
// make the ambiguity explicit instead of doing the wrong operation quietly.
|
|
532
532
|
.action(withErrorHandling(() => {
|
|
533
533
|
info('Nothing to do: "lint cache" manages the lint result cache (try "lint cache clear"). ' +
|
|
534
534
|
'To lint a directory named cache/, disambiguate with a trailing slash: "fireforge lint cache/".');
|
|
@@ -22,7 +22,7 @@ import { addWaitLockOption, pickDefined, resolveWaitLockSeconds } from '../../ut
|
|
|
22
22
|
import { proceedAfterDecision } from '../destructive-decision.js';
|
|
23
23
|
import { renameMapsEqual } from '../patch-rename-map.js';
|
|
24
24
|
import { requirePatchQueue } from './patch-context.js';
|
|
25
|
-
import { rebuildFilenameForOrder } from './reorder.js';
|
|
25
|
+
import { rebuildFilenameForOrder } from './reorder-projection.js';
|
|
26
26
|
/** True when `order` falls inside a configured reserved range. */
|
|
27
27
|
function isReservedOrder(policyCfg, order) {
|
|
28
28
|
return (policyCfg.reservedRanges ?? []).some((r) => order >= r.from && order <= r.to);
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Batch and per-entry input for `patch lint-ignore --add`. Split out of
|
|
3
3
|
* `lint-ignore.ts` for the per-file line budget.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Two forms lift that:
|
|
5
|
+
* `--max` applies to every `--add` of a call, so a rebaseline that sets a
|
|
6
|
+
* ceiling per rule would take one call per rule, each taking the patch lock
|
|
7
|
+
* and rewriting `patches.json`. Two forms avoid that:
|
|
9
8
|
*
|
|
10
9
|
* - `--add <rule>=<max>` gives each entry its own ceiling in one call.
|
|
11
10
|
* - `--from <json-file>` reads every entry from a file, under one lock hold
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
* Batch and per-entry input for `patch lint-ignore --add`. Split out of
|
|
4
4
|
* `lint-ignore.ts` for the per-file line budget.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Two forms lift that:
|
|
6
|
+
* `--max` applies to every `--add` of a call, so a rebaseline that sets a
|
|
7
|
+
* ceiling per rule would take one call per rule, each taking the patch lock
|
|
8
|
+
* and rewriting `patches.json`. Two forms avoid that:
|
|
10
9
|
*
|
|
11
10
|
* - `--add <rule>=<max>` gives each entry its own ceiling in one call.
|
|
12
11
|
* - `--from <json-file>` reads every entry from a file, under one lock hold
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `patch move-files --scan-file <path>`: adopt new engine files into the
|
|
3
|
+
* move's destination in the same transaction.
|
|
4
|
+
*
|
|
5
|
+
* Splitting a widget across patches moved existing files and adopted the
|
|
6
|
+
* seam modules that appeared beside them. Adopting first (`re-export
|
|
7
|
+
* --scan --scan-file`) grew the source past its own `large-patch-lines`
|
|
8
|
+
* ceiling, which refused although the move that followed would have
|
|
9
|
+
* shrunk it again. Adopting straight into the destination of the move
|
|
10
|
+
* means no patch ever carries the intermediate body: both sides are linted
|
|
11
|
+
* on what the transaction leaves behind.
|
|
12
|
+
*/
|
|
13
|
+
import type { PatchMetadata } from '../../types/commands/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* Validates `--scan-file` paths: each must be engine-relative, exist in
|
|
16
|
+
* `engine/`, be owned by no patch and not be one of the moved files.
|
|
17
|
+
* Returns the sorted, de-duplicated list.
|
|
18
|
+
*
|
|
19
|
+
* @param rawFiles - The `--scan-file` values
|
|
20
|
+
* @param patches - Manifest rows
|
|
21
|
+
* @param enginePath - Engine directory
|
|
22
|
+
* @param movedFiles - The `--file` paths of the same move
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveAdoptedFiles(rawFiles: readonly string[] | undefined, patches: readonly PatchMetadata[], enginePath: string, movedFiles: readonly string[]): Promise<string[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Re-checks under the patch-directory lock that no patch claimed an
|
|
27
|
+
* adopted file while the move waited for confirmation.
|
|
28
|
+
*
|
|
29
|
+
* @param patches - Manifest rows read under the lock
|
|
30
|
+
* @param adoptedFiles - Files the move adopts
|
|
31
|
+
* @param command - Command name for the error
|
|
32
|
+
*/
|
|
33
|
+
export declare function assertAdoptedStillUnowned(patches: readonly PatchMetadata[], adoptedFiles: readonly string[] | undefined, command: string): void;
|