@feigi/fleet-ctl 3.23.14 → 3.23.16
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/package.json
CHANGED
|
@@ -499,7 +499,16 @@ const FILES = [
|
|
|
499
499
|
// other number straight back in, and this file already carried the
|
|
500
500
|
// identical stale number at two independent sites.
|
|
501
501
|
path: ["scripts", "fleet-heartbeat.mjs"],
|
|
502
|
-
|
|
502
|
+
// #2667. The header once said run-merge-bot.md's CI gate holds its wait
|
|
503
|
+
// "and re-issuing it", and the several-holds paragraph once called the
|
|
504
|
+
// heartbeat "the same remedy the CI gate reached for". The CI wait holds
|
|
505
|
+
// in one `eval` cell and re-issues nothing. Tolerant of a re-wrap: the
|
|
506
|
+
// comment is hard-wrapped, so either phrase can break across a `//` line.
|
|
507
|
+
stale: [
|
|
508
|
+
/run-merge-bot\.md:\d+/,
|
|
509
|
+
/re-issuing\s+(?:\/\/\s*)?it\b/,
|
|
510
|
+
/same remedy the\s+(?:\/\/\s*)?CI gate/,
|
|
511
|
+
],
|
|
503
512
|
// One needle per SITE — either can revert independently of the other.
|
|
504
513
|
live: [
|
|
505
514
|
"run-merge-bot.md's CI wait rule already states",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// roughly two hours; neither ever woke it. run-merge-bot.md's CI gate states
|
|
19
19
|
// the same rule as a rule — "whatever wakes you is external and may never
|
|
20
20
|
// come" — and cures it the same way this file does, by holding the wait
|
|
21
|
-
// inside one blocking
|
|
21
|
+
// inside one blocking call.
|
|
22
22
|
//
|
|
23
23
|
// So the heartbeat is not a Monitor, not a cron entry and not a paragraph of
|
|
24
24
|
// prose. A cron entry that ran the reconcile would print its rows to nobody:
|
|
@@ -66,9 +66,8 @@ export function interval({ quiet, base, ceiling, multiplier }) {
|
|
|
66
66
|
// rule already states.
|
|
67
67
|
//
|
|
68
68
|
// So a long interval is served by SEVERAL holds, and the elapsed total is
|
|
69
|
-
// persisted rather than counted in prose
|
|
70
|
-
//
|
|
71
|
-
// controller re-issues without tracking arithmetic across turns.
|
|
69
|
+
// persisted rather than counted in prose: the script says how much remains, so
|
|
70
|
+
// the controller re-issues without tracking arithmetic across turns.
|
|
72
71
|
export function heldThisCall({ elapsed, target, hold }) {
|
|
73
72
|
return Math.min(hold, Math.max(0, target - elapsed));
|
|
74
73
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// release-ticket.sh's comment above its branch delete contrasts the release's
|
|
2
|
+
// pairing (the `ahead` and `git cherry` guards, the recount at the delete, the
|
|
3
|
+
// fresh worktree check) with reap.sh's. It said reap.sh authorizes its own
|
|
4
|
+
// [gone] deletes with `git cherry` ALONE, but reap.sh also re-reads the
|
|
5
|
+
// worktree listing and keeps any branch `wt_holding` reports held or cannot
|
|
6
|
+
// resolve, before the same kind of compare-and-swap delete. What reap.sh does
|
|
7
|
+
// lack is the `ahead` count and the recount: `git cherry` is the only check
|
|
8
|
+
// there that asks whether the branch is merged.
|
|
9
|
+
import { test } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { phrase, runAbove, stripHashGutter } from "./prose-pin.mjs";
|
|
14
|
+
|
|
15
|
+
const RELEASE = readFileSync(join(import.meta.dirname, "release-ticket.sh"), "utf8");
|
|
16
|
+
// reap.sh's code lines only: a whole-line `#` comment that mentions a command
|
|
17
|
+
// is neither a call nor a guard, so it must satisfy no check below and fail none.
|
|
18
|
+
const REAP = readFileSync(join(import.meta.dirname, "reap.sh"), "utf8")
|
|
19
|
+
.split("\n")
|
|
20
|
+
.filter((line) => !/^\s*#/.test(line))
|
|
21
|
+
.join("\n");
|
|
22
|
+
|
|
23
|
+
const deleteComment = () => {
|
|
24
|
+
const comment = stripHashGutter(
|
|
25
|
+
runAbove(RELEASE, 'echo "\\$ git update-ref -d refs/heads/$branch $tip" >&2', "release-ticket.sh branch delete", "#"),
|
|
26
|
+
);
|
|
27
|
+
// runAbove returns "" rather than throwing when no comment run sits directly
|
|
28
|
+
// above the anchor; without this the negative pin would pass on nothing.
|
|
29
|
+
assert.notEqual(comment, "", "no comment run sits directly above release-ticket.sh's branch delete — the pins have nothing to read");
|
|
30
|
+
return comment;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
test("release-ticket.sh: the delete comment does not say reap.sh deletes on `git cherry` alone", () => {
|
|
34
|
+
assert.doesNotMatch(
|
|
35
|
+
deleteComment(),
|
|
36
|
+
new RegExp(phrase("deletes with `git cherry` alone").source, "i"),
|
|
37
|
+
"release-ticket.sh's delete comment says reap.sh authorizes its [gone] deletes with `git cherry` alone — reap.sh also re-checks the worktree with `wt_holding` before its delete",
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("release-ticket.sh: the delete comment still says how reap.sh's pairing differs", () => {
|
|
42
|
+
// Input the pin above must ACCEPT: the contrast the sentence exists for —
|
|
43
|
+
// reap.sh has no `ahead` count and no recount — survives, beside the
|
|
44
|
+
// worktree check reap.sh shares with the release.
|
|
45
|
+
const comment = deleteComment();
|
|
46
|
+
assert.match(comment, phrase("with `git cherry` alone — no `ahead` count, no recount"));
|
|
47
|
+
assert.match(comment, phrase("re-checks the worktree with `wt_holding`"));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("reap.sh: the branch delete still follows a `wt_holding` check and has no `ahead` recount", () => {
|
|
51
|
+
// The target side of the comment's claim, so a change to reap.sh that makes
|
|
52
|
+
// it false reds here rather than leaving release-ticket.sh's prose stale.
|
|
53
|
+
const held = REAP.indexOf('if wt_holding "refs/heads/$b"');
|
|
54
|
+
const del = REAP.indexOf('git update-ref --no-deref -d "refs/heads/$b" "$tip"');
|
|
55
|
+
assert.ok(held !== -1, "reap.sh no longer checks `wt_holding` on the [gone] branch");
|
|
56
|
+
assert.ok(del !== -1, "reap.sh no longer deletes the [gone] branch with a compare-and-swap `update-ref -d`");
|
|
57
|
+
assert.ok(held < del, "reap.sh's `wt_holding` check no longer runs before its branch delete");
|
|
58
|
+
assert.doesNotMatch(
|
|
59
|
+
REAP,
|
|
60
|
+
/rev-list\b[^\n]*--count|--count[^\n]*rev-list/,
|
|
61
|
+
"reap.sh now counts commits ahead — release-ticket.sh's comment says it has no `ahead` count",
|
|
62
|
+
);
|
|
63
|
+
});
|
|
@@ -1679,9 +1679,11 @@ else
|
|
|
1679
1679
|
|
|
1680
1680
|
# update-ref, authorized by the `ahead` and `git cherry` guards above,
|
|
1681
1681
|
# this recount, and the worktree check above — and carrying its own
|
|
1682
|
-
# compare-and-swap on $tip on top, which `-D` never had. reap.sh
|
|
1683
|
-
#
|
|
1684
|
-
#
|
|
1682
|
+
# compare-and-swap on $tip on top, which `-D` never had. reap.sh asks
|
|
1683
|
+
# whether its own [gone] branches are merged with `git cherry` alone — no
|
|
1684
|
+
# `ahead` count, no recount — so not this pairing, though it too
|
|
1685
|
+
# re-checks the worktree with `wt_holding` before its own compare-and-swap
|
|
1686
|
+
# delete. `-d` measures against HEAD and the branch's upstream, and a
|
|
1685
1687
|
# claim has no upstream until its first push (claim-ticket.sh passes
|
|
1686
1688
|
# --no-track), so `-d` falls back to local HEAD alone and refuses a
|
|
1687
1689
|
# pristine claim whenever local main is behind origin/main —
|