@tablation/crew 0.9.0 → 0.10.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
CHANGED
|
@@ -3955,6 +3955,13 @@ function fastForward(cwd, branch) {
|
|
|
3955
3955
|
if (!s.canFastForward) return false;
|
|
3956
3956
|
return gitOk(cwd, ["merge", "--ff-only", s.upstream]) !== null;
|
|
3957
3957
|
}
|
|
3958
|
+
function baseBranchUnsafe(r) {
|
|
3959
|
+
return r.action === "diverged" || r.action === "ahead" || r.action === "ff-failed";
|
|
3960
|
+
}
|
|
3961
|
+
function describeUnsafeBase(r, remote, base) {
|
|
3962
|
+
const counts = r.action === "diverged" ? `${r.ahead} ahead, ${r.behind} behind ${remote}/${base}` : r.action === "ahead" ? `${r.ahead} ahead of ${remote}/${base}` : `${r.behind} behind ${remote}/${base}, cannot fast-forward`;
|
|
3963
|
+
return `${r.detail} [${counts}] \u2014 reconcile it (\`crew sync\` afterwards), or \`git reset --hard ${remote}/${base}\` if the local commits duplicate a release`;
|
|
3964
|
+
}
|
|
3958
3965
|
function refreshBaseBranch(cwd, remote, base, dryRun = false) {
|
|
3959
3966
|
if (currentBranch(cwd) !== base || status(cwd).length > 0) {
|
|
3960
3967
|
return { action: "not-applicable", detail: `${cwd} is not on a clean ${base}` };
|
|
@@ -3981,6 +3988,9 @@ function refreshBaseBranch(cwd, remote, base, dryRun = false) {
|
|
|
3981
3988
|
detail: `${base} has diverged from ${upstream} (${ahead} ahead, ${behind} behind)`
|
|
3982
3989
|
};
|
|
3983
3990
|
}
|
|
3991
|
+
if (behind === 0 && ahead > 0) {
|
|
3992
|
+
return { action: "ahead", ahead, detail: `${base} has ${ahead} commit(s) ${upstream} does not` };
|
|
3993
|
+
}
|
|
3984
3994
|
if (behind === 0) return { action: "level", detail: `${base} is level with ${upstream}` };
|
|
3985
3995
|
if (dryRun) {
|
|
3986
3996
|
return { action: "would-fast-forward", behind, detail: `would fast-forward ${base}: ${behind} behind ${upstream}` };
|
|
@@ -5979,9 +5989,13 @@ function refreshBase(o) {
|
|
|
5979
5989
|
// base. Fast-forwarding is impossible and merging would be this crew
|
|
5980
5990
|
// inventing a resolution nobody asked for, on the branch everything
|
|
5981
5991
|
// ships from.
|
|
5992
|
+
// AHEAD is a stop too (CREW-1379): local commits nobody asked for on the
|
|
5993
|
+
// base are how a second ship's release came to diverge from origin's.
|
|
5994
|
+
// Releasing on top of a hand commit is the failure; reconcile it first.
|
|
5995
|
+
case "ahead":
|
|
5982
5996
|
case "diverged":
|
|
5983
5997
|
case "ff-failed":
|
|
5984
|
-
return { ok: false, why: r.
|
|
5998
|
+
return { ok: false, why: describeUnsafeBase(r, o.repo.branch.remote, o.repo.branch.base) };
|
|
5985
5999
|
}
|
|
5986
6000
|
}
|
|
5987
6001
|
async function reconfirmLastRelease(o, decision) {
|
|
@@ -9270,6 +9284,11 @@ if (command === "passenger-sync-daemon") {
|
|
|
9270
9284
|
if (!why) return false;
|
|
9271
9285
|
emit.emit(`${why} \u2014 release skipped`, { step: "release" });
|
|
9272
9286
|
return true;
|
|
9287
|
+
}, baseHealth = function(r) {
|
|
9288
|
+
const { remote, base } = r.config.branch;
|
|
9289
|
+
const out = refreshBaseBranch(r.dir, remote, base, true);
|
|
9290
|
+
const unsafe = baseBranchUnsafe(out);
|
|
9291
|
+
return { action: out.action, unsafe, detail: unsafe ? describeUnsafeBase(out, remote, base) : out.detail };
|
|
9273
9292
|
}, reportUnplaceable = function(c, unplaceable, verified, emit2) {
|
|
9274
9293
|
if (unplaceableReported.has(c.route)) return;
|
|
9275
9294
|
unplaceableReported.add(c.route);
|
|
@@ -9278,7 +9297,7 @@ if (command === "passenger-sync-daemon") {
|
|
|
9278
9297
|
else emit2.emit(note.message, { step: "release" });
|
|
9279
9298
|
}
|
|
9280
9299
|
};
|
|
9281
|
-
requireArmed2 = requireArmed, parseTicketNumber2 = parseTicketNumber, passengerApiKeys2 = passengerApiKeys, endpointApiFor2 = endpointApiFor, endpointReconcileDeps2 = endpointReconcileDeps, releaseRefused2 = releaseRefused, reportUnplaceable2 = reportUnplaceable;
|
|
9300
|
+
requireArmed2 = requireArmed, parseTicketNumber2 = parseTicketNumber, passengerApiKeys2 = passengerApiKeys, endpointApiFor2 = endpointApiFor, endpointReconcileDeps2 = endpointReconcileDeps, releaseRefused2 = releaseRefused, baseHealth2 = baseHealth, reportUnplaceable2 = reportUnplaceable;
|
|
9282
9301
|
let cfg;
|
|
9283
9302
|
let firstRun;
|
|
9284
9303
|
try {
|
|
@@ -11318,14 +11337,16 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
11318
11337
|
let acted = 0;
|
|
11319
11338
|
let baseChecked = 0;
|
|
11320
11339
|
let baseActed = 0;
|
|
11340
|
+
let baseUnsafe = 0;
|
|
11321
11341
|
for (const r of await resolvedRepos(route)) {
|
|
11322
11342
|
const base = refreshBaseBranch(r.dir, r.config.branch.remote, r.config.branch.base, dryRun);
|
|
11323
11343
|
if (base.action !== "not-applicable") {
|
|
11324
11344
|
baseChecked++;
|
|
11325
11345
|
if (base.action === "fetch-failed") emit.warn(base.detail);
|
|
11326
|
-
else if (base
|
|
11346
|
+
else if (baseBranchUnsafe(base)) {
|
|
11327
11347
|
baseActed++;
|
|
11328
|
-
|
|
11348
|
+
baseUnsafe++;
|
|
11349
|
+
emit.error(`${r.name}: DO NOT CUT A WORKTREE FROM THIS BASE \u2014 ${describeUnsafeBase(base, r.config.branch.remote, r.config.branch.base)}`);
|
|
11329
11350
|
} else if (base.action === "would-fast-forward" || base.action === "fast-forwarded") {
|
|
11330
11351
|
baseActed++;
|
|
11331
11352
|
emit.emit(base.detail);
|
|
@@ -11357,6 +11378,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
11357
11378
|
}
|
|
11358
11379
|
}
|
|
11359
11380
|
}
|
|
11381
|
+
if (baseUnsafe > 0) process.exitCode = 1;
|
|
11360
11382
|
if (baseChecked > 0 && baseActed === 0) emit.emit(`${baseChecked} base branch(es) checked, all level with the remote`);
|
|
11361
11383
|
if (tracked === 0) emit.emit("no worktree tracks a remote branch \u2014 nothing to sync");
|
|
11362
11384
|
else if (acted === 0) emit.emit(`${tracked} worktree(s) tracking a remote, all level with it`);
|
|
@@ -11487,6 +11509,9 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
11487
11509
|
repos: repos.map((r) => ({
|
|
11488
11510
|
name: r.name,
|
|
11489
11511
|
dir: r.dir,
|
|
11512
|
+
// Additive (CREW-1379): `unsafe` means a ship must not cut a
|
|
11513
|
+
// worktree or release from this base. `version` stays 1.
|
|
11514
|
+
baseBranch: baseHealth(r),
|
|
11490
11515
|
worktreePrefix: r.config.worktrees.prefix,
|
|
11491
11516
|
// A repo with no explicit `worktrees.prefix` no longer names its
|
|
11492
11517
|
// worktrees `<prefix><number>` (ISSUE-969) — the checkout's own
|
|
@@ -11527,6 +11552,11 @@ watermark: ${state.watermark()}
|
|
|
11527
11552
|
}
|
|
11528
11553
|
for (const i of openShipAttention(state)) {
|
|
11529
11554
|
process.stdout.write(`attention: ${i.kind} \u2014 ${i.message}
|
|
11555
|
+
`);
|
|
11556
|
+
}
|
|
11557
|
+
for (const r of await resolvedRepos(route)) {
|
|
11558
|
+
const bh = baseHealth(r);
|
|
11559
|
+
if (bh.unsafe) process.stdout.write(`base: ${r.name} \u2014 UNSAFE, no worktree cuts or releases: ${bh.detail}
|
|
11530
11560
|
`);
|
|
11531
11561
|
}
|
|
11532
11562
|
if (waiting) {
|
|
@@ -11581,6 +11611,12 @@ routes: ${cfg.routes.map((c) => c.route).join(", ")}
|
|
|
11581
11611
|
process.stdout.write(` - ${p2}
|
|
11582
11612
|
`);
|
|
11583
11613
|
}
|
|
11614
|
+
const bh = baseHealth(r);
|
|
11615
|
+
if (bh.action !== "not-applicable") {
|
|
11616
|
+
process.stdout.write(` base ${config.branch.base}: ${bh.unsafe ? "ERROR \u2014 " : ""}${bh.detail}
|
|
11617
|
+
`);
|
|
11618
|
+
if (bh.unsafe) process.exitCode = 1;
|
|
11619
|
+
}
|
|
11584
11620
|
}
|
|
11585
11621
|
const missingAuthorship = await tracker.missingAuthorshipColumns();
|
|
11586
11622
|
process.stdout.write(
|
|
@@ -11761,4 +11797,5 @@ var passengerApiKeys2;
|
|
|
11761
11797
|
var endpointApiFor2;
|
|
11762
11798
|
var endpointReconcileDeps2;
|
|
11763
11799
|
var releaseRefused2;
|
|
11800
|
+
var baseHealth2;
|
|
11764
11801
|
var reportUnplaceable2;
|
package/package.json
CHANGED
|
@@ -346,10 +346,13 @@ if `report_type` is either of those.
|
|
|
346
346
|
missing commits another ship or a reviewer pushed since the last sync. It
|
|
347
347
|
is quiet, not an alert, about a primary checkout that isn't cleanly on the
|
|
348
348
|
base branch (something else may be mid-edit there) — that's expected, not
|
|
349
|
-
a fault, and just means this sync is a no-op. A
|
|
350
|
-
branch
|
|
351
|
-
|
|
352
|
-
|
|
349
|
+
a fault, and just means this sync is a no-op. A DIVERGED base
|
|
350
|
+
branch (local commits the remote lacks, or one that cannot fast-forward)
|
|
351
|
+
makes `crew sync` print `DO NOT CUT A WORKTREE FROM THIS BASE` and exit
|
|
352
|
+
non-zero. That is a hard stop: do not run `git worktree add`, do not try to
|
|
353
|
+
reconcile it yourself. Post a comment on the ticket naming the repo and the
|
|
354
|
+
counts `crew sync` printed, leave the ticket as you found it, and end the
|
|
355
|
+
run — the operator reconciles the checkout. Otherwise, from
|
|
353
356
|
the primary checkout, `git worktree add` a sibling worktree for this
|
|
354
357
|
ticket, on a new branch cut from the base branch's current HEAD. The
|
|
355
358
|
digest's `worktree` and `branch` columns give this ticket's own directory
|
|
@@ -327,10 +327,13 @@ if `report_type` is either of those.
|
|
|
327
327
|
missing commits another ship or a reviewer pushed since the last sync. It
|
|
328
328
|
is quiet, not an alert, about a primary checkout that isn't cleanly on the
|
|
329
329
|
base branch (something else may be mid-edit there) — that's expected, not
|
|
330
|
-
a fault, and just means this sync is a no-op. A
|
|
331
|
-
branch
|
|
332
|
-
|
|
333
|
-
|
|
330
|
+
a fault, and just means this sync is a no-op. A DIVERGED base
|
|
331
|
+
branch (local commits the remote lacks, or one that cannot fast-forward)
|
|
332
|
+
makes `crew sync` print `DO NOT CUT A WORKTREE FROM THIS BASE` and exit
|
|
333
|
+
non-zero. That is a hard stop: do not run `git worktree add`, do not try to
|
|
334
|
+
reconcile it yourself. Post a comment on the ticket naming the repo and the
|
|
335
|
+
counts `crew sync` printed, leave the ticket as you found it, and end the
|
|
336
|
+
run — the operator reconciles the checkout. Otherwise, from
|
|
334
337
|
the primary checkout, `git worktree add` a sibling worktree for this
|
|
335
338
|
ticket, on a new branch cut from the base branch's current HEAD. The
|
|
336
339
|
digest's `worktree` and `branch` columns give this ticket's own directory
|