@tablation/crew 0.19.4 → 0.19.5

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.
Files changed (2) hide show
  1. package/dist/cli.js +50 -11
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -6434,6 +6434,15 @@ function describeUnplaceable(unplaceable, verifiedStatus) {
6434
6434
  }
6435
6435
  return notes;
6436
6436
  }
6437
+ var unplaceableReported = /* @__PURE__ */ new Set();
6438
+ function reportUnplaceable(routeName, unplaceable, verified, emit) {
6439
+ if (unplaceableReported.has(routeName)) return;
6440
+ unplaceableReported.add(routeName);
6441
+ for (const note of describeUnplaceable(unplaceable, verified)) {
6442
+ if (note.level === "warn") emit.warn(note.message, { step: "release" });
6443
+ else emit.emit(note.message, { step: "release" });
6444
+ }
6445
+ }
6437
6446
  function checkGuards(cwd, base = "main") {
6438
6447
  const branch = currentBranch(cwd);
6439
6448
  if (branch !== base) {
@@ -6585,6 +6594,10 @@ function decideRelease(cwd, tickets, contract, opts = {}) {
6585
6594
  unseeded: lastTag === null
6586
6595
  };
6587
6596
  }
6597
+ function releaseIdle(i) {
6598
+ if (i.force || i.external || i.unseeded || !i.upToDate || i.unstamped > 0) return false;
6599
+ return !i.tickets.some((t) => t.status === i.verifiedStatus);
6600
+ }
6588
6601
  var renderTag = (template, version) => template.replace(/\{version\}/g, version);
6589
6602
 
6590
6603
  // src/stamp.ts
@@ -10526,15 +10539,8 @@ if (command === "passenger-sync-daemon") {
10526
10539
  const out = refreshBaseBranch(r.dir, remote, base, true);
10527
10540
  const unsafe = baseBranchUnsafe(out);
10528
10541
  return { action: out.action, unsafe, detail: unsafe ? describeUnsafeBase(out, remote, base) : out.detail };
10529
- }, reportUnplaceable = function(c, unplaceable, verified, emit2) {
10530
- if (unplaceableReported.has(c.route)) return;
10531
- unplaceableReported.add(c.route);
10532
- for (const note of describeUnplaceable(unplaceable, verified)) {
10533
- if (note.level === "warn") emit2.warn(note.message, { step: "release" });
10534
- else emit2.emit(note.message, { step: "release" });
10535
- }
10536
10542
  };
10537
- requireArmed2 = requireArmed, parseTicketNumber2 = parseTicketNumber, passengerApiKeys2 = passengerApiKeys, endpointApiFor2 = endpointApiFor, endpointReconcileDeps2 = endpointReconcileDeps, releaseRefused2 = releaseRefused, baseHealth2 = baseHealth, reportUnplaceable2 = reportUnplaceable;
10543
+ requireArmed2 = requireArmed, parseTicketNumber2 = parseTicketNumber, passengerApiKeys2 = passengerApiKeys, endpointApiFor2 = endpointApiFor, endpointReconcileDeps2 = endpointReconcileDeps, releaseRefused2 = releaseRefused, baseHealth2 = baseHealth;
10538
10544
  let cfg;
10539
10545
  let firstRun;
10540
10546
  try {
@@ -10668,6 +10674,7 @@ if (command === "passenger-sync-daemon") {
10668
10674
  }
10669
10675
  async function releaseFleet(opts = {}) {
10670
10676
  if (releaseRefused()) return;
10677
+ precheckTickets.clear();
10671
10678
  const summaries = [];
10672
10679
  if (!dryRun) state.releaseHeartbeat().touch();
10673
10680
  for (const c of cfg.routes) {
@@ -10679,6 +10686,7 @@ if (command === "passenger-sync-daemon") {
10679
10686
  }
10680
10687
  async function releaseTargets(opts = {}) {
10681
10688
  if (releaseRefused()) return;
10689
+ precheckTickets.clear();
10682
10690
  const only = value("repo");
10683
10691
  const targets = reposOf(route);
10684
10692
  const chosen = only ? targets.filter((t) => t.name === only) : targets;
@@ -10915,7 +10923,7 @@ ${changed2.map((c) => ` - ${c}
10915
10923
  }
10916
10924
  return `${who2}; ${lock2}`;
10917
10925
  }
10918
- const unplaceableReported = /* @__PURE__ */ new Set();
10926
+ const precheckTickets = /* @__PURE__ */ new Map();
10919
10927
  async function releasePhase(c, target, opts = {}) {
10920
10928
  const scope = releaseLockScope(c.route, target.name);
10921
10929
  const remit = emit.forRoute(c.route);
@@ -10950,6 +10958,38 @@ ${changed2.map((c) => ` - ${c}
10950
10958
  }
10951
10959
  if (!dryRun && !c.enabled) return { scope, tests: "skipped", outcome: "skipped", detail: "route not enabled" };
10952
10960
  const tracker = new Tracker(c, cfg.ship);
10961
+ if (!dryRun) {
10962
+ const force2 = command === "deploy" || flag("force");
10963
+ let seen = precheckTickets.get(c.route);
10964
+ if (!seen) precheckTickets.set(c.route, seen = tracker.openTickets());
10965
+ const { byRepo: preByRepo, unplaceable: preUnplaceable } = ticketsByRepo(c, await seen);
10966
+ const pre = preByRepo.get(target.name) ?? [];
10967
+ reportUnplaceable(c.route, preUnplaceable, tracker.contract.statuses.verified, remit);
10968
+ const d = decideRelease(target.dir, pre, tracker.contract, {
10969
+ tagPattern: repo.release.tagPattern ?? "v*",
10970
+ base: repo.branch.base
10971
+ });
10972
+ const unstamped = planReleasedBranches(
10973
+ target.dir,
10974
+ pre,
10975
+ tracker.contract,
10976
+ (t) => locateBranchForTicket(target.dir, repo, t)?.branch ?? null,
10977
+ repo.branch.base,
10978
+ repo.release.tagPattern ?? "v*"
10979
+ ).length;
10980
+ if (releaseIdle({
10981
+ tickets: pre,
10982
+ verifiedStatus: tracker.contract.statuses.verified,
10983
+ force: force2,
10984
+ external: repo.release.mode === "external",
10985
+ upToDate: d.upToDate,
10986
+ unseeded: d.unseeded,
10987
+ unstamped
10988
+ })) {
10989
+ remit.emit(`${target.name}: nothing verified \u2014 not locking`, { step: "release" });
10990
+ return { scope, tests: "skipped", outcome: "skipped", detail: "nothing verified \u2014 not locking" };
10991
+ }
10992
+ }
10953
10993
  if (!dryRun) {
10954
10994
  const holderLabel = `${cfg.ship.name}:${process.pid}`;
10955
10995
  const got = await tracker.acquireBoardLock(scope, holderLabel, RELEASE_LOCK_TTL_MS);
@@ -10972,7 +11012,7 @@ ${changed2.map((c) => ` - ${c}
10972
11012
  const all = await tracker.openTickets();
10973
11013
  const { byRepo, unplaceable } = ticketsByRepo(c, all);
10974
11014
  const tickets = byRepo.get(target.name) ?? [];
10975
- reportUnplaceable(c, unplaceable, tracker.contract.statuses.verified, remit);
11015
+ reportUnplaceable(c.route, unplaceable, tracker.contract.statuses.verified, remit);
10976
11016
  const outcome = await runRelease({
10977
11017
  cwd: target.dir,
10978
11018
  repo,
@@ -13258,4 +13298,3 @@ var endpointApiFor2;
13258
13298
  var endpointReconcileDeps2;
13259
13299
  var releaseRefused2;
13260
13300
  var baseHealth2;
13261
- var reportUnplaceable2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.19.4",
3
+ "version": "0.19.5",
4
4
  "description": "A standing team of headless agents that picks work off a Tablation board, does it on a machine you control, and reports back.",
5
5
  "type": "module",
6
6
  "license": "MIT",