@plexus-ms/cli 0.101.0 → 0.102.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/plx.js +172 -104
- package/package.json +3 -3
package/dist/plx.js
CHANGED
|
@@ -7761,7 +7761,7 @@ function realIo(prompt) {
|
|
|
7761
7761
|
stdout: process.stdout,
|
|
7762
7762
|
stderr: process.stderr,
|
|
7763
7763
|
prompt: prompt && isInteractive() ? prompt : void 0,
|
|
7764
|
-
exec: (command, args, options = {}) => new Promise((
|
|
7764
|
+
exec: (command, args, options = {}) => new Promise((resolve11, reject) => {
|
|
7765
7765
|
const child = spawn(command, args, {
|
|
7766
7766
|
cwd: options.cwd,
|
|
7767
7767
|
env: options.env,
|
|
@@ -7784,7 +7784,7 @@ function realIo(prompt) {
|
|
|
7784
7784
|
child.on("error", reject);
|
|
7785
7785
|
child.on("close", (code) => {
|
|
7786
7786
|
if (code === 0)
|
|
7787
|
-
|
|
7787
|
+
resolve11(stdout);
|
|
7788
7788
|
else
|
|
7789
7789
|
reject(new ExecError(render(command, args), code, stderr));
|
|
7790
7790
|
});
|
|
@@ -8683,22 +8683,22 @@ async function templateFacet(ctx, cwd) {
|
|
|
8683
8683
|
// ../lib/dist/propagate.js
|
|
8684
8684
|
import { join as join8, relative as relative3 } from "node:path";
|
|
8685
8685
|
var isClean = (s) => s.conflicted.length === 0 && s.failed.length === 0 && s.skipped.length === 0;
|
|
8686
|
-
var
|
|
8687
|
-
|
|
8688
|
-
|
|
8686
|
+
var emptySummary = (train, preview) => ({
|
|
8687
|
+
train,
|
|
8688
|
+
preview,
|
|
8689
|
+
clean: [],
|
|
8690
|
+
conflicted: [],
|
|
8691
|
+
failed: [],
|
|
8692
|
+
skipped: [],
|
|
8693
|
+
pulls: []
|
|
8694
|
+
});
|
|
8695
|
+
var trainBranch = (train) => `plexus/${train}`;
|
|
8696
|
+
var copierIn = (dir, args) => [
|
|
8689
8697
|
"env",
|
|
8690
|
-
[`MISE_IGNORED_CONFIG_PATHS=${
|
|
8698
|
+
[`MISE_IGNORED_CONFIG_PATHS=${dir}`, "mise", ...copierVia(args)]
|
|
8691
8699
|
];
|
|
8692
8700
|
async function propagate(ctx, workspace, train) {
|
|
8693
|
-
const summary =
|
|
8694
|
-
train,
|
|
8695
|
-
preview: ctx.dryRun,
|
|
8696
|
-
clean: [],
|
|
8697
|
-
conflicted: [],
|
|
8698
|
-
failed: [],
|
|
8699
|
-
skipped: [],
|
|
8700
|
-
pulls: []
|
|
8701
|
-
};
|
|
8701
|
+
const summary = emptySummary(train, ctx.dryRun);
|
|
8702
8702
|
const upstream = join8(workspace, UPSTREAM);
|
|
8703
8703
|
const tree = await overview(ctx, workspace);
|
|
8704
8704
|
const upstreamDir = tree.children.find((c) => c.path === upstream);
|
|
@@ -8713,6 +8713,7 @@ async function propagate(ctx, workspace, train) {
|
|
|
8713
8713
|
for (const preset of presets)
|
|
8714
8714
|
if (!consumers.some((c) => c.sites.some((s) => s.preset === preset)))
|
|
8715
8715
|
ctx.say(`\u2022 no consumers of ${presetSource(preset)} found under ${workspace}`);
|
|
8716
|
+
const take = { train, opener: "`plx ship`", ...ctx.dryRun ? { previewFrom: upstream } : {} };
|
|
8716
8717
|
const scratch = (await ctx.stage(run("mktemp", ["-d"])))?.trim() ?? "";
|
|
8717
8718
|
try {
|
|
8718
8719
|
for (const consumer of consumers) {
|
|
@@ -8722,17 +8723,12 @@ async function propagate(ctx, workspace, train) {
|
|
|
8722
8723
|
ctx.say(`\u2192 ${consumer.rel}: clone ${consumer.origin} at ${consumer.branch}`);
|
|
8723
8724
|
try {
|
|
8724
8725
|
await ctx.stage(run("git", ["clone", "--quiet", "--branch", consumer.branch, consumer.origin, clone]));
|
|
8725
|
-
await ctx.stage(run("git", ["tag", BASE_TAG], { cwd: clone }));
|
|
8726
8726
|
} catch (error) {
|
|
8727
8727
|
ctx.say(` \u2717 FAILED \u2014 clone${detail(error)}`);
|
|
8728
8728
|
summary.failed.push(consumer.rel);
|
|
8729
8729
|
continue;
|
|
8730
8730
|
}
|
|
8731
|
-
|
|
8732
|
-
await updateSite(ctx, consumer, site, clone, upstream, summary);
|
|
8733
|
-
await refreshLockfile(ctx, consumer, clone, summary);
|
|
8734
|
-
await bumpConsumerRefs(ctx, consumer, clone, train);
|
|
8735
|
-
await openPull(ctx, consumer, clone, train, summary);
|
|
8731
|
+
await takeTrain(ctx, consumer, clone, take, summary);
|
|
8736
8732
|
}
|
|
8737
8733
|
} finally {
|
|
8738
8734
|
if (scratch)
|
|
@@ -8740,7 +8736,15 @@ async function propagate(ctx, workspace, train) {
|
|
|
8740
8736
|
}
|
|
8741
8737
|
return summary;
|
|
8742
8738
|
}
|
|
8743
|
-
|
|
8739
|
+
async function takeTrain(ctx, consumer, dir, take, summary) {
|
|
8740
|
+
const base = (await ctx.read("git", ["rev-parse", "HEAD"], { cwd: dir })).trim();
|
|
8741
|
+
for (const site of consumer.sites)
|
|
8742
|
+
await updateSite(ctx, consumer, site, dir, take, summary);
|
|
8743
|
+
await refreshLockfile(ctx, consumer, dir, base, summary);
|
|
8744
|
+
await bumpConsumerRefs(ctx, consumer, dir, take.train);
|
|
8745
|
+
await openPull(ctx, consumer, dir, take, summary);
|
|
8746
|
+
}
|
|
8747
|
+
var previewCommit = (ctx, dir, message) => ctx.stage(run("git", ["add", "-A"], { cwd: dir })).then(() => ctx.stage(run("git", [
|
|
8744
8748
|
"-c",
|
|
8745
8749
|
"commit.gpgsign=false",
|
|
8746
8750
|
"-c",
|
|
@@ -8753,31 +8757,32 @@ var previewCommit = (ctx, clone, message) => ctx.stage(run("git", ["add", "-A"],
|
|
|
8753
8757
|
"--allow-empty",
|
|
8754
8758
|
"-m",
|
|
8755
8759
|
message
|
|
8756
|
-
], { cwd:
|
|
8757
|
-
async function updateSite(ctx, consumer, site,
|
|
8758
|
-
const target = join8(
|
|
8759
|
-
const localPreset = join8(upstream, site.preset);
|
|
8760
|
+
], { cwd: dir })));
|
|
8761
|
+
async function updateSite(ctx, consumer, site, dir, take, summary) {
|
|
8762
|
+
const target = join8(dir, relative3(consumer.path, site.path));
|
|
8760
8763
|
try {
|
|
8761
|
-
if (
|
|
8764
|
+
if (take.previewFrom) {
|
|
8765
|
+
const localPreset = join8(take.previewFrom, site.preset);
|
|
8762
8766
|
ctx.say(`\u2192 ${site.rel}: copier update (preview from ${localPreset}@main)`);
|
|
8763
8767
|
const answers = await ctx.readFile(join8(target, ANSWERS_FILE));
|
|
8764
8768
|
await ctx.stage(write(join8(target, ANSWERS_FILE), answers.replace(/^_src_path: .*$/m, `_src_path: ${localPreset}`)));
|
|
8765
|
-
await previewCommit(ctx,
|
|
8766
|
-
await ctx.stage(run(...copierIn(
|
|
8769
|
+
await previewCommit(ctx, dir, `plx preview: ${site.rel} reads ${localPreset} from the local checkout`);
|
|
8770
|
+
await ctx.stage(run(...copierIn(dir, ["update", "--skip-answered", "--trust", "--defaults", "--skip-tasks", "--vcs-ref", "main"]), { cwd: target }));
|
|
8771
|
+
} else {
|
|
8772
|
+
ctx.say(`\u2192 ${site.rel}: copier update${take.ref ? ` to ${take.ref}` : ""}`);
|
|
8773
|
+
const args = [
|
|
8767
8774
|
"update",
|
|
8768
8775
|
"--skip-answered",
|
|
8769
8776
|
"--trust",
|
|
8770
|
-
"--defaults",
|
|
8771
8777
|
"--skip-tasks",
|
|
8772
|
-
"--vcs-ref",
|
|
8773
|
-
"
|
|
8774
|
-
]
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
await ctx.apply([run(...copierIn(clone, args), { cwd: target, interactive: true })]);
|
|
8778
|
+
...take.ref ? ["--vcs-ref", take.ref] : [],
|
|
8779
|
+
...ctx.yes || ctx.dryRun ? ["--defaults"] : []
|
|
8780
|
+
];
|
|
8781
|
+
const step = run(...copierIn(dir, args), { cwd: target, interactive: !ctx.dryRun });
|
|
8782
|
+
if (ctx.dryRun)
|
|
8783
|
+
await ctx.stage(step);
|
|
8784
|
+
else
|
|
8785
|
+
await ctx.apply([step]);
|
|
8781
8786
|
}
|
|
8782
8787
|
} catch (error) {
|
|
8783
8788
|
ctx.say(` \u2717 FAILED \u2014 copier update exited nonzero${detail(error)}`);
|
|
@@ -8802,10 +8807,10 @@ async function updateSite(ctx, consumer, site, clone, upstream, summary) {
|
|
|
8802
8807
|
}
|
|
8803
8808
|
for (const line of status.split("\n").filter(Boolean))
|
|
8804
8809
|
ctx.say(` ${line}`);
|
|
8805
|
-
if (
|
|
8806
|
-
await previewCommit(ctx,
|
|
8810
|
+
if (take.previewFrom)
|
|
8811
|
+
await previewCommit(ctx, dir, `plx preview: ${site.rel} updated`);
|
|
8807
8812
|
else
|
|
8808
|
-
await ctx.stage(run("git", ["add", "-A"], { cwd:
|
|
8813
|
+
await ctx.stage(run("git", ["add", "-A"], { cwd: dir }));
|
|
8809
8814
|
}
|
|
8810
8815
|
async function syncSiteMarker(ctx, site, target) {
|
|
8811
8816
|
const marker = await ctx.readFile(join8(target, MARKER_FILE)).catch(() => void 0);
|
|
@@ -8820,77 +8825,71 @@ async function syncSiteMarker(ctx, site, target) {
|
|
|
8820
8825
|
ctx.say(` marker: plexus \u2192 ${commit} in ${site.rel}/${MARKER_FILE}`);
|
|
8821
8826
|
await ctx.stage(write(join8(target, MARKER_FILE), synced));
|
|
8822
8827
|
}
|
|
8823
|
-
async function refreshLockfile(ctx, consumer,
|
|
8824
|
-
if (await ctx.readFile(join8(
|
|
8828
|
+
async function refreshLockfile(ctx, consumer, dir, base, summary) {
|
|
8829
|
+
if (await ctx.readFile(join8(dir, "pnpm-workspace.yaml")).catch(() => void 0) === void 0)
|
|
8825
8830
|
return;
|
|
8826
8831
|
const manifests = ["*package.json", "pnpm-workspace.yaml"];
|
|
8827
|
-
const unchanged = await ctx.read("git", ["diff", "--quiet",
|
|
8832
|
+
const unchanged = await ctx.read("git", ["diff", "--quiet", base, "--", ...manifests], { cwd: dir }).then(() => true).catch(() => false);
|
|
8828
8833
|
if (unchanged)
|
|
8829
8834
|
return;
|
|
8830
8835
|
ctx.say(`\u2192 ${consumer.rel}: pnpm install (manifests changed)`);
|
|
8831
8836
|
try {
|
|
8832
|
-
await ctx.apply([run("mise", ["exec", "--", "pnpm", "install", "--reporter=silent"], { cwd:
|
|
8837
|
+
await ctx.apply([run("mise", ["exec", "--", "pnpm", "install", "--reporter=silent"], { cwd: dir })]);
|
|
8833
8838
|
} catch (error) {
|
|
8834
8839
|
ctx.say(` \u2717 pnpm install failed${detail(error)}`);
|
|
8835
8840
|
summary.failed.push(`${consumer.rel}/pnpm-lock.yaml`);
|
|
8836
8841
|
}
|
|
8837
8842
|
}
|
|
8838
|
-
async function bumpConsumerRefs(ctx, consumer,
|
|
8839
|
-
const
|
|
8840
|
-
const entries = await ctx.readDir(
|
|
8843
|
+
async function bumpConsumerRefs(ctx, consumer, dir, train) {
|
|
8844
|
+
const workflows = join8(dir, ".github", "workflows");
|
|
8845
|
+
const entries = await ctx.readDir(workflows).catch(() => []);
|
|
8841
8846
|
const files = entries.filter((e) => !e.directory && /\.ya?ml$/.test(e.name)).map((e) => e.name).sort();
|
|
8842
8847
|
for (const f of files) {
|
|
8843
|
-
const text = await ctx.readFile(join8(
|
|
8848
|
+
const text = await ctx.readFile(join8(workflows, f));
|
|
8844
8849
|
if (!text.includes(WORKFLOW_REF))
|
|
8845
8850
|
continue;
|
|
8846
8851
|
const bumped = bumpWorkflowRefs(text, train);
|
|
8847
8852
|
if (bumped === text)
|
|
8848
8853
|
continue;
|
|
8849
8854
|
ctx.say(`\u2192 ${consumer.rel}: ${f} workflow refs \u2192 @${train}`);
|
|
8850
|
-
await ctx.stage(write(join8(
|
|
8855
|
+
await ctx.stage(write(join8(workflows, f), bumped));
|
|
8851
8856
|
}
|
|
8852
8857
|
}
|
|
8853
|
-
async function
|
|
8858
|
+
async function openPullUrl(ctx, consumer, dir, train) {
|
|
8859
|
+
const args = ["pr", "list", "--head", trainBranch(train), "--base", consumer.branch, "--state", "open"];
|
|
8860
|
+
return (await ctx.read("gh", [...args, "--json", "url", "--jq", ".[0].url"], { cwd: dir }).catch(() => "")).trim();
|
|
8861
|
+
}
|
|
8862
|
+
async function openPull(ctx, consumer, dir, take, summary) {
|
|
8863
|
+
const { train } = take;
|
|
8854
8864
|
const branch = trainBranch(train);
|
|
8855
8865
|
if (ctx.dryRun) {
|
|
8856
8866
|
ctx.say(` (preview) ${consumer.rel}: would commit, push ${branch} and open a pull request against ${consumer.branch}`);
|
|
8857
8867
|
return;
|
|
8858
8868
|
}
|
|
8859
|
-
if ((await ctx.read("git", ["status", "--porcelain"], { cwd:
|
|
8869
|
+
if ((await ctx.read("git", ["status", "--porcelain"], { cwd: dir })).trim() === "") {
|
|
8860
8870
|
ctx.say(`\u2022 ${consumer.rel}: nothing changed \u2014 no pull request`);
|
|
8861
8871
|
return;
|
|
8862
8872
|
}
|
|
8863
|
-
const head = `${consumer.origin} ${branch}`;
|
|
8873
|
+
const head = `${consumer.origin ?? "origin"} ${branch}`;
|
|
8864
8874
|
try {
|
|
8865
8875
|
await ctx.apply([
|
|
8866
|
-
run("git", ["add", "-A"], { cwd:
|
|
8867
|
-
run("git", ["commit", "--quiet", "--no-verify", "-m", `chore: train ${train}`], { cwd:
|
|
8876
|
+
run("git", ["add", "-A"], { cwd: dir }),
|
|
8877
|
+
run("git", ["commit", "--quiet", "--no-verify", "-m", `chore: train ${train}`], { cwd: dir })
|
|
8868
8878
|
]);
|
|
8869
8879
|
await ctx.read("git", ["fetch", "--quiet", "origin", `+refs/heads/${branch}:refs/remotes/origin/${branch}`], {
|
|
8870
|
-
cwd:
|
|
8880
|
+
cwd: dir
|
|
8871
8881
|
}).catch(() => "");
|
|
8872
8882
|
await ctx.apply([
|
|
8873
|
-
run("git", ["push", "--quiet", "--force-with-lease", "origin", `HEAD:refs/heads/${branch}`], {
|
|
8883
|
+
run("git", ["push", "--quiet", "--no-verify", "--force-with-lease", "origin", `HEAD:refs/heads/${branch}`], {
|
|
8884
|
+
cwd: dir
|
|
8885
|
+
})
|
|
8874
8886
|
]);
|
|
8875
8887
|
} catch (error) {
|
|
8876
8888
|
ctx.say(` \u2717 FAILED \u2014 push to ${head}${detail(error)}`);
|
|
8877
8889
|
summary.failed.push(consumer.rel);
|
|
8878
8890
|
return;
|
|
8879
8891
|
}
|
|
8880
|
-
const existing =
|
|
8881
|
-
"pr",
|
|
8882
|
-
"list",
|
|
8883
|
-
"--head",
|
|
8884
|
-
branch,
|
|
8885
|
-
"--base",
|
|
8886
|
-
consumer.branch,
|
|
8887
|
-
"--state",
|
|
8888
|
-
"open",
|
|
8889
|
-
"--json",
|
|
8890
|
-
"url",
|
|
8891
|
-
"--jq",
|
|
8892
|
-
".[0].url"
|
|
8893
|
-
], { cwd: clone }).catch(() => "")).trim();
|
|
8892
|
+
const existing = await openPullUrl(ctx, consumer, dir, train);
|
|
8894
8893
|
if (existing) {
|
|
8895
8894
|
ctx.say(`\u2022 ${consumer.rel}: pull request updated: ${existing}`);
|
|
8896
8895
|
summary.pulls.push(existing);
|
|
@@ -8901,7 +8900,7 @@ async function openPull(ctx, consumer, clone, train, summary) {
|
|
|
8901
8900
|
const body2 = [
|
|
8902
8901
|
`Train ${train} (\xA7 1.5 PLX): \`copier update\` at ${sites.join(", ")}, the marker, the lockfile where manifests moved, and the workflow refs.`,
|
|
8903
8902
|
conflicted.length > 0 ? `Conflicts to resolve, committed with their markers: ${conflicted.join(", ")}.` : "Merged clean at every site.",
|
|
8904
|
-
|
|
8903
|
+
`Opened by ${take.opener}.`
|
|
8905
8904
|
].join("\n\n");
|
|
8906
8905
|
try {
|
|
8907
8906
|
await ctx.apply([
|
|
@@ -8916,29 +8915,14 @@ async function openPull(ctx, consumer, clone, train, summary) {
|
|
|
8916
8915
|
`chore: train ${train}`,
|
|
8917
8916
|
"--body",
|
|
8918
8917
|
body2
|
|
8919
|
-
], { cwd:
|
|
8918
|
+
], { cwd: dir })
|
|
8920
8919
|
]);
|
|
8921
8920
|
} catch (error) {
|
|
8922
8921
|
ctx.say(` \u2717 FAILED \u2014 pull request${detail(error)}`);
|
|
8923
8922
|
summary.failed.push(consumer.rel);
|
|
8924
8923
|
return;
|
|
8925
8924
|
}
|
|
8926
|
-
const url =
|
|
8927
|
-
"pr",
|
|
8928
|
-
"list",
|
|
8929
|
-
"--head",
|
|
8930
|
-
branch,
|
|
8931
|
-
"--base",
|
|
8932
|
-
consumer.branch,
|
|
8933
|
-
"--state",
|
|
8934
|
-
"open",
|
|
8935
|
-
"--json",
|
|
8936
|
-
"url",
|
|
8937
|
-
"--jq",
|
|
8938
|
-
".[0].url"
|
|
8939
|
-
], {
|
|
8940
|
-
cwd: clone
|
|
8941
|
-
}).catch(() => "")).trim();
|
|
8925
|
+
const url = await openPullUrl(ctx, consumer, dir, train);
|
|
8942
8926
|
ctx.say(`\u2022 ${consumer.rel}: pull request opened${url ? `: ${url}` : ""}`);
|
|
8943
8927
|
summary.pulls.push(url || `${consumer.rel} ${branch}`);
|
|
8944
8928
|
}
|
|
@@ -9218,7 +9202,7 @@ async function awaitPublished(ctx, next, wait) {
|
|
|
9218
9202
|
break;
|
|
9219
9203
|
if (Date.now() - started >= wait.timeout)
|
|
9220
9204
|
throw new Error(`${missing.join(", ")} not on npm at ${next} after ${Math.round(wait.timeout / 6e4)} min \u2014 check the release workflow (gh run list -R plexus-ms/${PRIMITIVES})`);
|
|
9221
|
-
await new Promise((
|
|
9205
|
+
await new Promise((resolve11) => setTimeout(resolve11, wait.interval));
|
|
9222
9206
|
}
|
|
9223
9207
|
ctx.say(` \u2713 ${list2} on npm`);
|
|
9224
9208
|
}
|
|
@@ -9280,6 +9264,76 @@ async function planBookkeeping(ctx, train, repos2, next, today2) {
|
|
|
9280
9264
|
return plan;
|
|
9281
9265
|
}
|
|
9282
9266
|
|
|
9267
|
+
// ../lib/dist/update.js
|
|
9268
|
+
import { basename, join as join11 } from "node:path";
|
|
9269
|
+
var PRESETS = TRAIN_REPOS.filter((r) => r.startsWith("preset-"));
|
|
9270
|
+
async function update(ctx, options) {
|
|
9271
|
+
const { repo } = options;
|
|
9272
|
+
const name = basename(repo);
|
|
9273
|
+
if (options.train !== void 0 && !isTrainVersion(options.train))
|
|
9274
|
+
throw new UsageError(`'${options.train}' is not plain semver (X.Y.Z, no v)`);
|
|
9275
|
+
const tree = await overview(ctx, repo);
|
|
9276
|
+
const consumer = (await findConsumers(ctx, tree, PRESETS)).find((c) => c.path === tree.path);
|
|
9277
|
+
if (!consumer)
|
|
9278
|
+
throw new Error(`${repo} is not a repo generated from the presets: no ${ANSWERS_FILE} at its root naming one of ${PRESETS.map(presetSource).join(", ")}`);
|
|
9279
|
+
if (consumer.skipped)
|
|
9280
|
+
throw new Error(`${name}: ${consumer.skipped}`);
|
|
9281
|
+
consumer.rel = name;
|
|
9282
|
+
for (const s of consumer.sites)
|
|
9283
|
+
s.rel = s.rel === "." ? name : join11(name, s.rel);
|
|
9284
|
+
const root = consumer.sites.find((s) => s.path === consumer.path);
|
|
9285
|
+
if (!root)
|
|
9286
|
+
throw new Error(`${name}: its root is not a site of a repo preset`);
|
|
9287
|
+
await preflightForge(ctx);
|
|
9288
|
+
const train = options.train ?? await newestTrain(ctx, root.preset);
|
|
9289
|
+
const summary = emptySummary(train, ctx.dryRun);
|
|
9290
|
+
const recorded = await Promise.all(consumer.sites.map(async (s) => parseAnswers(await ctx.readFile(join11(s.path, ANSWERS_FILE))).commit));
|
|
9291
|
+
if (recorded.every((c) => c === train)) {
|
|
9292
|
+
ctx.say(`\u2022 ${name}: already at ${train}`);
|
|
9293
|
+
return summary;
|
|
9294
|
+
}
|
|
9295
|
+
const past = recorded.find((c) => c && isTrainVersion(c) && compareTrains(c, train) > 0);
|
|
9296
|
+
if (past)
|
|
9297
|
+
throw new Error(`${name} is at ${past}, past ${train}; a repo is never taken back to an older train`);
|
|
9298
|
+
const branch = trainBranch(train);
|
|
9299
|
+
const onOrigin = await ctx.read("git", ["ls-remote", "--exit-code", "--heads", "origin", `refs/heads/${branch}`], { cwd: repo }).then(() => true).catch(() => false);
|
|
9300
|
+
if (onOrigin) {
|
|
9301
|
+
const url = await openPullUrl(ctx, consumer, repo, train);
|
|
9302
|
+
ctx.say(`\u2022 ${name}: ${branch} is already on origin${url ? ` (${url})` : ""} \u2014 nothing to do; delete the branch to pull the train again`);
|
|
9303
|
+
if (url)
|
|
9304
|
+
summary.pulls.push(url);
|
|
9305
|
+
return summary;
|
|
9306
|
+
}
|
|
9307
|
+
const scratch = (await ctx.stage(run("mktemp", ["-d"])))?.trim() ?? "";
|
|
9308
|
+
const dir = join11(scratch, name);
|
|
9309
|
+
try {
|
|
9310
|
+
ctx.say(`\u2192 ${name}: worktree of origin/${consumer.branch}`);
|
|
9311
|
+
try {
|
|
9312
|
+
await ctx.stage(run("git", ["fetch", "--quiet", "origin", consumer.branch], { cwd: repo }));
|
|
9313
|
+
await ctx.stage(run("git", ["worktree", "add", "--quiet", "--detach", dir, `origin/${consumer.branch}`], { cwd: repo }));
|
|
9314
|
+
} catch (error) {
|
|
9315
|
+
ctx.say(` \u2717 FAILED \u2014 worktree of origin/${consumer.branch}${detail(error)}`);
|
|
9316
|
+
summary.failed.push(name);
|
|
9317
|
+
return summary;
|
|
9318
|
+
}
|
|
9319
|
+
await takeTrain(ctx, consumer, dir, { train, ref: train, opener: "`plx update`" }, summary);
|
|
9320
|
+
} finally {
|
|
9321
|
+
await ctx.stage(run("git", ["worktree", "remove", "--force", dir], { cwd: repo })).catch(() => void 0);
|
|
9322
|
+
if (scratch)
|
|
9323
|
+
await ctx.stage(run("rm", ["-rf", scratch]));
|
|
9324
|
+
}
|
|
9325
|
+
return summary;
|
|
9326
|
+
}
|
|
9327
|
+
async function newestTrain(ctx, preset) {
|
|
9328
|
+
const source = presetSource(preset).replace(/^gh:/, "");
|
|
9329
|
+
const tag = (await ctx.read("gh", ["api", `repos/${source}/releases/latest`, "--jq", ".tag_name"]).catch(() => "")).trim();
|
|
9330
|
+
if (!tag)
|
|
9331
|
+
throw new Error(`no release of ${source} found \u2014 pass the train explicitly (--train <version>)`);
|
|
9332
|
+
if (!isTrainVersion(tag))
|
|
9333
|
+
throw new Error(`the newest release of ${source} is '${tag}', not a train`);
|
|
9334
|
+
return tag;
|
|
9335
|
+
}
|
|
9336
|
+
|
|
9283
9337
|
// src/program.ts
|
|
9284
9338
|
import { createRequire } from "node:module";
|
|
9285
9339
|
|
|
@@ -10226,13 +10280,13 @@ import { AsyncResource as AsyncResource3 } from "node:async_hooks";
|
|
|
10226
10280
|
|
|
10227
10281
|
// ../../node_modules/.pnpm/@inquirer+type@4.2.1_@types+node@26.6.5/node_modules/@inquirer/type/dist/utils.js
|
|
10228
10282
|
function withResolver() {
|
|
10229
|
-
let
|
|
10283
|
+
let resolve11;
|
|
10230
10284
|
let reject;
|
|
10231
10285
|
const promise = new Promise((res, rej) => {
|
|
10232
|
-
|
|
10286
|
+
resolve11 = res;
|
|
10233
10287
|
reject = rej;
|
|
10234
10288
|
});
|
|
10235
|
-
return { promise, resolve:
|
|
10289
|
+
return { promise, resolve: resolve11, reject };
|
|
10236
10290
|
}
|
|
10237
10291
|
|
|
10238
10292
|
// ../../node_modules/.pnpm/@inquirer+core@12.0.6_@types+node@26.6.5/node_modules/@inquirer/core/dist/lib/create-prompt.js
|
|
@@ -10611,7 +10665,7 @@ function createPrompt(view) {
|
|
|
10611
10665
|
});
|
|
10612
10666
|
output.mute();
|
|
10613
10667
|
const screen = new ScreenManager(rl);
|
|
10614
|
-
const { promise, resolve:
|
|
10668
|
+
const { promise, resolve: resolve11, reject } = withResolver();
|
|
10615
10669
|
return withHooks(rl, (cycle) => {
|
|
10616
10670
|
const clearEffects = AsyncResource3.bind(() => effectScheduler.clearAll());
|
|
10617
10671
|
const settlePrompt = (settle) => {
|
|
@@ -10622,7 +10676,7 @@ function createPrompt(view) {
|
|
|
10622
10676
|
reject(error);
|
|
10623
10677
|
}
|
|
10624
10678
|
};
|
|
10625
|
-
const resolvePrompt = (value) => settlePrompt(() =>
|
|
10679
|
+
const resolvePrompt = (value) => settlePrompt(() => resolve11(value));
|
|
10626
10680
|
const rejectPrompt = (error) => settlePrompt(() => reject(error));
|
|
10627
10681
|
const promptPromise = Object.assign(promise.finally(() => {
|
|
10628
10682
|
cleanups.forEach((cleanup) => cleanup());
|
|
@@ -14211,7 +14265,7 @@ function register4(program2) {
|
|
|
14211
14265
|
|
|
14212
14266
|
// src/commands/doctor.ts
|
|
14213
14267
|
import { existsSync } from "node:fs";
|
|
14214
|
-
import { join as
|
|
14268
|
+
import { join as join12, resolve as resolve5 } from "node:path";
|
|
14215
14269
|
|
|
14216
14270
|
// src/style.ts
|
|
14217
14271
|
function style(enabled) {
|
|
@@ -14229,8 +14283,8 @@ function register5(program2) {
|
|
|
14229
14283
|
).option("--color", "colour the report even when piped").option("--no-color", "never colour the report").action(async (dir, opts, command) => {
|
|
14230
14284
|
const ctx = contextOf2(command);
|
|
14231
14285
|
const root = resolve5(dir);
|
|
14232
|
-
const compendium = resolve5(opts.compendium ??
|
|
14233
|
-
if (!existsSync(
|
|
14286
|
+
const compendium = resolve5(opts.compendium ?? join12(root, WORKSPACE_COMPENDIUM));
|
|
14287
|
+
if (!existsSync(join12(compendium, "contracts")))
|
|
14234
14288
|
throw new Error(
|
|
14235
14289
|
`no compendium at ${compendium}; pass --compendium <path to a checkout of plexus-ms/compendium>`
|
|
14236
14290
|
);
|
|
@@ -14320,7 +14374,7 @@ function register7(program2) {
|
|
|
14320
14374
|
if (!isClean(result)) process.exitCode = 1;
|
|
14321
14375
|
});
|
|
14322
14376
|
}
|
|
14323
|
-
function renderSummary(s, realCommand) {
|
|
14377
|
+
function renderSummary(s, realCommand, verb = "propagate") {
|
|
14324
14378
|
const lines = ["\u2500\u2500 summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"];
|
|
14325
14379
|
for (const p of s.clean) lines.push(` \u2713 clean: ${p}`);
|
|
14326
14380
|
for (const p of s.conflicted) lines.push(` \u2717 conflicts: ${p}`);
|
|
@@ -14334,7 +14388,7 @@ function renderSummary(s, realCommand) {
|
|
|
14334
14388
|
} else if (clean) {
|
|
14335
14389
|
lines.push("\u2713 done \u2014 review and merge the pull requests");
|
|
14336
14390
|
}
|
|
14337
|
-
if (!clean) lines.push(
|
|
14391
|
+
if (!clean) lines.push(`\u2717 needs attention \u2014 see above; fix the consumer, then re-run ${verb}`);
|
|
14338
14392
|
return lines.join("\n");
|
|
14339
14393
|
}
|
|
14340
14394
|
|
|
@@ -14349,13 +14403,13 @@ function register8(program2) {
|
|
|
14349
14403
|
}
|
|
14350
14404
|
|
|
14351
14405
|
// src/commands/requirements.ts
|
|
14352
|
-
import { join as
|
|
14406
|
+
import { join as join13, resolve as resolve9 } from "node:path";
|
|
14353
14407
|
function register9(program2) {
|
|
14354
14408
|
program2.command("requirements").description("lint the standard's map and module pages, or extract one module's requirement lines").argument("[dir]", "a checkout of the compendium", ".").option("--extract <page>", "print a module page's requirement lines instead of linting (path relative to dir)").action(async (dir, opts, command) => {
|
|
14355
14409
|
const ctx = contextOf2(command);
|
|
14356
14410
|
const compendium = resolve9(dir);
|
|
14357
14411
|
if (opts.extract) {
|
|
14358
|
-
ctx.result(extractRequirements(await ctx.readFile(
|
|
14412
|
+
ctx.result(extractRequirements(await ctx.readFile(join13(compendium, opts.extract))));
|
|
14359
14413
|
return;
|
|
14360
14414
|
}
|
|
14361
14415
|
const check = await checkCompendium(ctx, compendium);
|
|
@@ -14368,12 +14422,26 @@ function renderCheck(c) {
|
|
|
14368
14422
|
return `\u2713 the map, ${c.contracts} contracts and ${c.approaches} approaches are well-formed`;
|
|
14369
14423
|
}
|
|
14370
14424
|
|
|
14425
|
+
// src/commands/update.ts
|
|
14426
|
+
import { resolve as resolve10 } from "node:path";
|
|
14427
|
+
function register10(program2) {
|
|
14428
|
+
program2.command("update").description(
|
|
14429
|
+
"bring this repo up to a train, as a pull request on plexus/<version>: copier update at every site, the marker, the lockfile, the workflow refs"
|
|
14430
|
+
).argument("[dir]", "a repo generated from the presets", ".").option("--train <version>", "the train to take (default: the preset's newest release)").action(async (dir, opts, command) => {
|
|
14431
|
+
const ctx = contextOf2(command);
|
|
14432
|
+
const result = await update(ctx, { repo: resolve10(dir), train: opts.train });
|
|
14433
|
+
ctx.result(result, (r) => renderSummary(r, `plx -y update --train ${r.train} ${dir}`, "update"));
|
|
14434
|
+
if (!isClean(result)) process.exitCode = 1;
|
|
14435
|
+
});
|
|
14436
|
+
}
|
|
14437
|
+
|
|
14371
14438
|
// src/commands/index.ts
|
|
14372
14439
|
var commands = [
|
|
14373
14440
|
register6,
|
|
14374
14441
|
register5,
|
|
14375
14442
|
register7,
|
|
14376
14443
|
register8,
|
|
14444
|
+
register10,
|
|
14377
14445
|
register9,
|
|
14378
14446
|
register2,
|
|
14379
14447
|
register,
|
|
@@ -14388,7 +14456,7 @@ function buildProgram() {
|
|
|
14388
14456
|
program2.addOption(new Option("-n, --dry-run", "print every effect this run would have, perform none").env("PLX_DRY_RUN")).addOption(
|
|
14389
14457
|
new Option("-v, --verbose", "say more: once for reads and inputs, twice for command output").argParser((_value, previous) => previous + 1).default(0)
|
|
14390
14458
|
).addOption(new Option("-q, --quiet", "say nothing but results and errors").env("PLX_QUIET")).addOption(new Option("-y, --yes", "answer every confirmation with yes (needed off a terminal)").env("PLX_YES")).addOption(new Option("--json", "print results as JSON").env("PLX_JSON"));
|
|
14391
|
-
for (const
|
|
14459
|
+
for (const register11 of commands) register11(program2);
|
|
14392
14460
|
return program2;
|
|
14393
14461
|
}
|
|
14394
14462
|
function contextOf2(command) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plexus-ms/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.102.0",
|
|
4
4
|
"description": "plx, the Plexus command-line tool: a single-script adapter over @plexus-ms/lib",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"node": ">=24.22.1"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@inquirer/prompts": "^8.7.
|
|
27
|
-
"@plexus-ms/lib": "0.
|
|
26
|
+
"@inquirer/prompts": "^8.7.5",
|
|
27
|
+
"@plexus-ms/lib": "0.102.0",
|
|
28
28
|
"commander": "^15.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|