@tablation/crew 0.47.3 → 0.48.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/dist/cli.js +75 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9081,6 +9081,30 @@ function releaseIdle(i) {
|
|
|
9081
9081
|
}
|
|
9082
9082
|
var renderTag = (template, version) => template.replace(/\{version\}/g, version);
|
|
9083
9083
|
|
|
9084
|
+
// src/verified-tip.ts
|
|
9085
|
+
var PUSHED_RE = /^pushed ([0-9a-f]{40}) to \S+$/;
|
|
9086
|
+
function parsePushedSha(message) {
|
|
9087
|
+
return PUSHED_RE.exec((message ?? "").trim())?.[1] ?? null;
|
|
9088
|
+
}
|
|
9089
|
+
function verifiedShaFor(ticket, verifiedShaColumn, pushedEvents) {
|
|
9090
|
+
const col = ticket[verifiedShaColumn];
|
|
9091
|
+
if (typeof col === "string" && /^[0-9a-f]{7,40}$/i.test(col.trim())) return col.trim();
|
|
9092
|
+
const when = (e) => Date.parse(e.occurred_at ?? e.created_at ?? "") || 0;
|
|
9093
|
+
const newest = pushedEvents.filter((e) => e.record_id === ticket.id && parsePushedSha(e.message)).sort((a, b) => when(b) - when(a))[0];
|
|
9094
|
+
return newest ? parsePushedSha(newest.message) : null;
|
|
9095
|
+
}
|
|
9096
|
+
function movedPastVerified(cwd, branch, verified) {
|
|
9097
|
+
const tip = gitOk(cwd, ["rev-parse", "-q", "--verify", `refs/heads/${branch}^{commit}`]);
|
|
9098
|
+
const ver = gitOk(cwd, ["rev-parse", "-q", "--verify", `${verified}^{commit}`]);
|
|
9099
|
+
if (!tip || !ver || tip === ver) return null;
|
|
9100
|
+
if (isAncestor(cwd, tip, ver)) return null;
|
|
9101
|
+
if (isAncestor(cwd, ver, tip)) {
|
|
9102
|
+
const own = gitOk(cwd, ["rev-list", "--first-parent", "--no-merges", "--count", `${ver}..${tip}`]);
|
|
9103
|
+
if (own === "0") return null;
|
|
9104
|
+
}
|
|
9105
|
+
return { tip, verified: ver };
|
|
9106
|
+
}
|
|
9107
|
+
|
|
9084
9108
|
// src/stamp.ts
|
|
9085
9109
|
function planStamp(cwd, tickets, contract, fromSha, toSha, merged = /* @__PURE__ */ new Map()) {
|
|
9086
9110
|
const range = fromSha ? `${fromSha.slice(0, 8)}..${toSha.slice(0, 8)}` : null;
|
|
@@ -9280,7 +9304,7 @@ ${h.prFailure.tail}
|
|
|
9280
9304
|
}
|
|
9281
9305
|
for (const q of outcome.requeues) {
|
|
9282
9306
|
const t = q.ticket;
|
|
9283
|
-
const body = `The branch is no longer what was verified:
|
|
9307
|
+
const body = `The branch is no longer what was verified: QA verified ${q.verified.slice(0, 8)}, the branch is now at ${q.head.slice(0, 8)}. Returned to ${contract.statuses.handoff} for QA to check what changed.`;
|
|
9284
9308
|
if (dryRun) {
|
|
9285
9309
|
emit.emit(`would return to ${contract.statuses.handoff} \u2014 branch moved past ${q.verified.slice(0, 8)}`, { ticket: t.issue_id });
|
|
9286
9310
|
continue;
|
|
@@ -9691,6 +9715,11 @@ function reportHeld(o, held) {
|
|
|
9691
9715
|
o.state?.noteHeldReported?.(signature);
|
|
9692
9716
|
}
|
|
9693
9717
|
async function runRelease(o) {
|
|
9718
|
+
const movedPast2 = [];
|
|
9719
|
+
const out = await runReleaseCycle(o, movedPast2);
|
|
9720
|
+
return movedPast2.length ? { ...out, movedPast: movedPast2 } : out;
|
|
9721
|
+
}
|
|
9722
|
+
async function runReleaseCycle(o, movedPast2) {
|
|
9694
9723
|
const scoped = (msg) => o.scope ? `${o.scope}: ${msg}` : msg;
|
|
9695
9724
|
const tagPattern = o.repo.release.tagPattern ?? "v*";
|
|
9696
9725
|
o.emit.enter("release");
|
|
@@ -9707,6 +9736,23 @@ async function runRelease(o) {
|
|
|
9707
9736
|
}
|
|
9708
9737
|
if (skipped.size) releasable = o.tickets.filter((t) => !skipped.has(t.id));
|
|
9709
9738
|
}
|
|
9739
|
+
if (o.verifiedShas?.size) {
|
|
9740
|
+
const drop = /* @__PURE__ */ new Set();
|
|
9741
|
+
for (const t of releasable) {
|
|
9742
|
+
const verified = o.verifiedShas.get(t.id);
|
|
9743
|
+
if (t.status !== o.contract.statuses.verified || !verified) continue;
|
|
9744
|
+
const branch = locateBranchForTicket(o.cwd, o.repo, t)?.branch;
|
|
9745
|
+
const moved = branch ? movedPastVerified(o.cwd, branch, verified) : null;
|
|
9746
|
+
if (!moved) continue;
|
|
9747
|
+
drop.add(t.id);
|
|
9748
|
+
movedPast2.push({ ticket: t, verified: moved.verified, head: moved.tip });
|
|
9749
|
+
o.emit.error(
|
|
9750
|
+
`not releasing ${t.issue_id}: ${branch} is at ${moved.tip.slice(0, 8)}, past the ${moved.verified.slice(0, 8)} QA verified`,
|
|
9751
|
+
{ ticket: t.issue_id }
|
|
9752
|
+
);
|
|
9753
|
+
}
|
|
9754
|
+
if (drop.size) releasable = releasable.filter((t) => !drop.has(t.id));
|
|
9755
|
+
}
|
|
9710
9756
|
const decision = decideRelease(o.cwd, releasable, o.contract, {
|
|
9711
9757
|
tagPattern,
|
|
9712
9758
|
base: o.repo.branch.base,
|
|
@@ -13462,6 +13508,21 @@ ${changed2.map((c) => ` - ${c}
|
|
|
13462
13508
|
);
|
|
13463
13509
|
reportUnplaceable(c.route, unplaceable, tracker.contract.statuses.verified, remit);
|
|
13464
13510
|
const blockerInfo = blockerInfoMap(all, await tracker.ticketsByIds(missingBlockerIds(all)));
|
|
13511
|
+
const verifiedStatus = tracker.contract.statuses.verified;
|
|
13512
|
+
const verifiedTickets = tickets.filter((t) => t.status === verifiedStatus);
|
|
13513
|
+
const verifiedShas = /* @__PURE__ */ new Map();
|
|
13514
|
+
if (verifiedTickets.length && repo.release.mode !== "external") {
|
|
13515
|
+
let pushedEvents = [];
|
|
13516
|
+
try {
|
|
13517
|
+
pushedEvents = await tracker.events("pushed");
|
|
13518
|
+
} catch (e) {
|
|
13519
|
+
remit.warn(`could not read hand-off events; not checking branches against what QA verified: ${e.message}`);
|
|
13520
|
+
}
|
|
13521
|
+
for (const t of verifiedTickets) {
|
|
13522
|
+
const sha = verifiedShaFor(t, tracker.contract.columns.verifiedSha, pushedEvents);
|
|
13523
|
+
if (sha) verifiedShas.set(t.id, sha);
|
|
13524
|
+
}
|
|
13525
|
+
}
|
|
13465
13526
|
const outcome = await runRelease({
|
|
13466
13527
|
cwd: target.dir,
|
|
13467
13528
|
repo,
|
|
@@ -13470,6 +13531,7 @@ ${changed2.map((c) => ` - ${c}
|
|
|
13470
13531
|
blockerInfo,
|
|
13471
13532
|
emit: remit,
|
|
13472
13533
|
scope,
|
|
13534
|
+
verifiedShas,
|
|
13473
13535
|
state: state.release(scope),
|
|
13474
13536
|
reviewColumns: repo.release.mode === "external" ? await tracker.reviewColumns() : void 0,
|
|
13475
13537
|
dryRun,
|
|
@@ -13565,6 +13627,18 @@ ${changed2.map((c) => ` - ${c}
|
|
|
13565
13627
|
dryRun
|
|
13566
13628
|
);
|
|
13567
13629
|
}
|
|
13630
|
+
if (outcome.movedPast?.length) {
|
|
13631
|
+
await applyReview(
|
|
13632
|
+
tracker,
|
|
13633
|
+
tracker.contract,
|
|
13634
|
+
{ handoffs: [], requeues: outcome.movedPast },
|
|
13635
|
+
repo.branch.remote,
|
|
13636
|
+
remit,
|
|
13637
|
+
releaseSeat(c),
|
|
13638
|
+
{ verifiedSha: false, prRef: false },
|
|
13639
|
+
dryRun
|
|
13640
|
+
);
|
|
13641
|
+
}
|
|
13568
13642
|
const news = describeRelease(outcome, scope);
|
|
13569
13643
|
if (news) {
|
|
13570
13644
|
const notified = await notify(c, cfg.ship, news, remit, dryRun);
|
package/package.json
CHANGED