@rtrentjones/greenlight 0.2.21 → 0.2.22
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/bin.js +47 -7
- package/package.json +5 -5
package/dist/bin.js
CHANGED
|
@@ -443,7 +443,7 @@ function tokensForTool(tool) {
|
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
// src/version.ts
|
|
446
|
-
var MODULE_REF = "v0.2.
|
|
446
|
+
var MODULE_REF = "v0.2.22";
|
|
447
447
|
var MODULE_SOURCE_BASE = "git::https://github.com/RTrentJones/greenlight.git//infra/modules";
|
|
448
448
|
function moduleSource(module, ref = MODULE_REF) {
|
|
449
449
|
return `${MODULE_SOURCE_BASE}/${module}?ref=${ref}`;
|
|
@@ -2607,8 +2607,21 @@ function git(repoDir, args) {
|
|
|
2607
2607
|
function gitOut(repoDir, args) {
|
|
2608
2608
|
return execFileSync5("git", args, { cwd: repoDir, encoding: "utf8" }).trim();
|
|
2609
2609
|
}
|
|
2610
|
+
function tryRev(repoDir, ref) {
|
|
2611
|
+
try {
|
|
2612
|
+
return gitOut(repoDir, ["rev-parse", "--verify", "--quiet", ref]);
|
|
2613
|
+
} catch {
|
|
2614
|
+
return null;
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
function fetchRefs(repoDir, branches) {
|
|
2618
|
+
try {
|
|
2619
|
+
git(repoDir, ["fetch", "--no-tags", "origin", ...branches]);
|
|
2620
|
+
} catch {
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2610
2623
|
function resolveRef(repoDir, branch) {
|
|
2611
|
-
for (const ref of [
|
|
2624
|
+
for (const ref of [`origin/${branch}`, branch]) {
|
|
2612
2625
|
try {
|
|
2613
2626
|
git(repoDir, ["rev-parse", "--verify", "--quiet", ref]);
|
|
2614
2627
|
return ref;
|
|
@@ -2617,19 +2630,35 @@ function resolveRef(repoDir, branch) {
|
|
|
2617
2630
|
}
|
|
2618
2631
|
return null;
|
|
2619
2632
|
}
|
|
2633
|
+
function staleLocalWarnings(repoDir, branches) {
|
|
2634
|
+
const warnings = [];
|
|
2635
|
+
for (const branch of branches) {
|
|
2636
|
+
const local = tryRev(repoDir, branch);
|
|
2637
|
+
const origin = tryRev(repoDir, `origin/${branch}`);
|
|
2638
|
+
if (local && origin && local !== origin) {
|
|
2639
|
+
warnings.push(
|
|
2640
|
+
`local "${branch}" (${local.slice(0, 7)}) differs from origin/${branch} (${origin.slice(0, 7)}) \u2014 promoting the origin (verified) state. Sync with \`git fetch && git branch -f ${branch} origin/${branch}\`.`
|
|
2641
|
+
);
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
return warnings;
|
|
2645
|
+
}
|
|
2620
2646
|
function canPromote(repoDir, from = "develop", to = "main") {
|
|
2647
|
+
fetchRefs(repoDir, [from, to]);
|
|
2621
2648
|
const fromRef = resolveRef(repoDir, from);
|
|
2622
2649
|
const toRef = resolveRef(repoDir, to);
|
|
2623
2650
|
if (!fromRef || !toRef) {
|
|
2624
2651
|
return { canPromote: false, reason: `branch "${from}" or "${to}" not found in ${repoDir}` };
|
|
2625
2652
|
}
|
|
2653
|
+
const warnings = staleLocalWarnings(repoDir, [from, to]);
|
|
2626
2654
|
try {
|
|
2627
2655
|
git(repoDir, ["merge-base", "--is-ancestor", toRef, fromRef]);
|
|
2628
|
-
return { canPromote: true, reason: `"${to}" can fast-forward to "${from}"
|
|
2656
|
+
return { canPromote: true, reason: `"${to}" can fast-forward to "${from}"`, warnings };
|
|
2629
2657
|
} catch {
|
|
2630
2658
|
return {
|
|
2631
2659
|
canPromote: false,
|
|
2632
|
-
reason: `"${to}" has diverged from "${from}" \u2014 fast-forward refused. Reconcile first (rebase "${from}" onto "${to}", or merge "${to}" into "${from}") before promoting
|
|
2660
|
+
reason: `"${to}" has diverged from "${from}" \u2014 fast-forward refused. Reconcile first (rebase "${from}" onto "${to}", or merge "${to}" into "${from}") before promoting.`,
|
|
2661
|
+
warnings
|
|
2633
2662
|
};
|
|
2634
2663
|
}
|
|
2635
2664
|
}
|
|
@@ -2637,7 +2666,10 @@ function promote(repoDir, opts = {}) {
|
|
|
2637
2666
|
const from = opts.from ?? "develop";
|
|
2638
2667
|
const to = opts.to ?? "main";
|
|
2639
2668
|
const check = canPromote(repoDir, from, to);
|
|
2640
|
-
if (!check.canPromote)
|
|
2669
|
+
if (!check.canPromote) {
|
|
2670
|
+
return { promoted: false, from, to, reason: check.reason, warnings: check.warnings };
|
|
2671
|
+
}
|
|
2672
|
+
const warnings = check.warnings;
|
|
2641
2673
|
const fromRef = resolveRef(repoDir, from);
|
|
2642
2674
|
const fromCommit = gitOut(repoDir, ["rev-parse", fromRef]);
|
|
2643
2675
|
const current = gitOut(repoDir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
@@ -2649,14 +2681,20 @@ function promote(repoDir, opts = {}) {
|
|
|
2649
2681
|
} catch {
|
|
2650
2682
|
}
|
|
2651
2683
|
}
|
|
2652
|
-
return {
|
|
2684
|
+
return {
|
|
2685
|
+
promoted: true,
|
|
2686
|
+
from,
|
|
2687
|
+
to,
|
|
2688
|
+
reason: `"${to}" fast-forwarded to "${from}" and pushed`,
|
|
2689
|
+
warnings
|
|
2690
|
+
};
|
|
2653
2691
|
}
|
|
2654
2692
|
if (current === to) {
|
|
2655
2693
|
git(repoDir, ["merge", "--ff-only", fromRef]);
|
|
2656
2694
|
} else {
|
|
2657
2695
|
git(repoDir, ["update-ref", `refs/heads/${to}`, fromCommit]);
|
|
2658
2696
|
}
|
|
2659
|
-
return { promoted: true, from, to, reason: `"${to}" fast-forwarded to "${from}"
|
|
2697
|
+
return { promoted: true, from, to, reason: `"${to}" fast-forwarded to "${from}"`, warnings };
|
|
2660
2698
|
}
|
|
2661
2699
|
|
|
2662
2700
|
// src/commands/promote.ts
|
|
@@ -2666,11 +2704,13 @@ async function promoteCommand(args) {
|
|
|
2666
2704
|
const cwd = process.cwd();
|
|
2667
2705
|
if (!perform) {
|
|
2668
2706
|
const check = canPromote(cwd);
|
|
2707
|
+
for (const w of check.warnings ?? []) console.warn(`\u26A0 ${w}`);
|
|
2669
2708
|
console.log(`${check.canPromote ? "\u2714" : "\u2718"} ${check.reason}`);
|
|
2670
2709
|
if (check.canPromote) console.log("\nEligible. Re-run with --perform (and --push) to promote.");
|
|
2671
2710
|
process.exit(check.canPromote ? 0 : 1);
|
|
2672
2711
|
}
|
|
2673
2712
|
const result = promote(cwd, { push });
|
|
2713
|
+
for (const w of result.warnings ?? []) console.warn(`\u26A0 ${w}`);
|
|
2674
2714
|
console.log(`${result.promoted ? "\u2714" : "\u2718"} ${result.reason}`);
|
|
2675
2715
|
process.exit(result.promoted ? 0 : 1);
|
|
2676
2716
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rtrentjones/greenlight",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.22",
|
|
4
4
|
"description": "Greenlight CLI — setup and lifecycle for the harness.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"@anthropic-ai/sdk": "^0.69.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@rtrentjones/greenlight-adapters": "0.2.
|
|
35
|
-
"@rtrentjones/greenlight-
|
|
36
|
-
"@rtrentjones/greenlight-
|
|
37
|
-
"@rtrentjones/greenlight-
|
|
34
|
+
"@rtrentjones/greenlight-adapters": "0.2.22",
|
|
35
|
+
"@rtrentjones/greenlight-verify": "0.2.22",
|
|
36
|
+
"@rtrentjones/greenlight-loop": "0.2.22",
|
|
37
|
+
"@rtrentjones/greenlight-shared": "0.2.22"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "node scripts/copy-assets.mjs && tsup",
|