@mutmutco/cli 4.3.43 → 4.3.44
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/main.cjs +117 -50
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -15710,10 +15710,10 @@ var rollout_plan_default = {
|
|
|
15710
15710
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
15711
15711
|
},
|
|
15712
15712
|
baseline: {
|
|
15713
|
-
version: "4.3.
|
|
15714
|
-
tag: "v4.3.
|
|
15715
|
-
commit: "
|
|
15716
|
-
npm: "@mutmutco/cli@4.3.
|
|
15713
|
+
version: "4.3.44",
|
|
15714
|
+
tag: "v4.3.44",
|
|
15715
|
+
commit: "405d6e3283b9",
|
|
15716
|
+
npm: "@mutmutco/cli@4.3.44"
|
|
15717
15717
|
},
|
|
15718
15718
|
exitCriterion: "fleet-n-of-n",
|
|
15719
15719
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15730,14 +15730,14 @@ var rollout_plan_default = {
|
|
|
15730
15730
|
repo: "mutmutco/mmi-hub",
|
|
15731
15731
|
role: "canary",
|
|
15732
15732
|
schedule: "train",
|
|
15733
|
-
v3Target: "v4.3.
|
|
15733
|
+
v3Target: "v4.3.44"
|
|
15734
15734
|
}
|
|
15735
15735
|
],
|
|
15736
15736
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
15737
15737
|
rollback: {
|
|
15738
15738
|
independent: true,
|
|
15739
|
-
mechanism: "npm dist-tag latest -> 4.3.
|
|
15740
|
-
v3Target: "v4.3.
|
|
15739
|
+
mechanism: "npm dist-tag latest -> 4.3.44 and redeploy the Hub Lambda from tag v4.3.44 (405d6e3283b9); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15740
|
+
v3Target: "v4.3.44 (@mutmutco/cli@4.3.44, tag commit 405d6e3283b9 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15741
15741
|
}
|
|
15742
15742
|
},
|
|
15743
15743
|
{
|
|
@@ -29159,7 +29159,7 @@ function registerDeployCommands(program3) {
|
|
|
29159
29159
|
}
|
|
29160
29160
|
|
|
29161
29161
|
// src/project-set.ts
|
|
29162
|
-
var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "requiredBuildSecrets", "tenantTasks", "secrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "dsManifestPath", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "requiredCheckBranches", "ciExemptReason", "gate", "seedCanary"];
|
|
29162
|
+
var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "requiredBuildSecrets", "tenantTasks", "secrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "releaseChannel", "releaseLanguage", "dsManifestPath", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "requiredCheckBranches", "ciExemptReason", "gate", "seedCanary"];
|
|
29163
29163
|
var UNSET_KEY_SET = new Set(UNSET_KEYS);
|
|
29164
29164
|
var RUNTIME_SECRET_STAGES = ["dev", "rc", "main"];
|
|
29165
29165
|
var SECRET_CONSUMERS = ["runtime", "build", "lambda", "actions", "agent", "box"];
|
|
@@ -29443,6 +29443,20 @@ function parsePublishDirVar(raw) {
|
|
|
29443
29443
|
}
|
|
29444
29444
|
return v;
|
|
29445
29445
|
}
|
|
29446
|
+
function parseReleaseChannelVar(raw) {
|
|
29447
|
+
const v = raw.trim();
|
|
29448
|
+
if (!/^[CG][A-Z0-9]{8,}$/.test(v)) {
|
|
29449
|
+
throw new Error("org project set: releaseChannel must be a Slack channel id (e.g. C0BE0BRGAT0); --unset releaseChannel disables release notes");
|
|
29450
|
+
}
|
|
29451
|
+
return v;
|
|
29452
|
+
}
|
|
29453
|
+
function parseReleaseLanguageVar(raw) {
|
|
29454
|
+
const v = raw.trim();
|
|
29455
|
+
if (!/^[a-z]{2}$/.test(v)) {
|
|
29456
|
+
throw new Error("org project set: releaseLanguage must be a 2-letter lowercase language code (e.g. tr); --unset releaseLanguage returns to en");
|
|
29457
|
+
}
|
|
29458
|
+
return v;
|
|
29459
|
+
}
|
|
29446
29460
|
function parseDsManifestPathVar(raw) {
|
|
29447
29461
|
const v = raw.trim();
|
|
29448
29462
|
if (v === "" || !/^[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/.test(v) || /(^|\/)\.\.(\/|$)/.test(v)) {
|
|
@@ -29559,6 +29573,8 @@ var SETTABLE_VAR_KEYS = [
|
|
|
29559
29573
|
"oauth",
|
|
29560
29574
|
"publishRequired",
|
|
29561
29575
|
"publishDir",
|
|
29576
|
+
"releaseChannel",
|
|
29577
|
+
"releaseLanguage",
|
|
29562
29578
|
"dsManifestPath",
|
|
29563
29579
|
"fofuEnabled",
|
|
29564
29580
|
"consumesDesignSystem",
|
|
@@ -29586,6 +29602,8 @@ var SETTABLE_VAR_HINTS = {
|
|
|
29586
29602
|
projectNumber: "numeric",
|
|
29587
29603
|
publishRequired: "true|false",
|
|
29588
29604
|
publishDir: "relative subpath, e.g. packages/ui",
|
|
29605
|
+
releaseChannel: "Slack channel id, e.g. C0BE0BRGAT0",
|
|
29606
|
+
releaseLanguage: "2-letter language code for release notes, e.g. tr (default en)",
|
|
29589
29607
|
dsManifestPath: "relative path to a package.json, e.g. web/package.json",
|
|
29590
29608
|
fofuEnabled: "true|false",
|
|
29591
29609
|
consumesDesignSystem: '"fofu"',
|
|
@@ -29698,6 +29716,10 @@ function buildProjectSetPatch(input) {
|
|
|
29698
29716
|
patch[key] = parseConsumesDesignSystemVar(raw);
|
|
29699
29717
|
} else if (key === "publishDir") {
|
|
29700
29718
|
patch[key] = parsePublishDirVar(raw);
|
|
29719
|
+
} else if (key === "releaseChannel") {
|
|
29720
|
+
patch[key] = parseReleaseChannelVar(raw);
|
|
29721
|
+
} else if (key === "releaseLanguage") {
|
|
29722
|
+
patch[key] = parseReleaseLanguageVar(raw);
|
|
29701
29723
|
} else if (key === "dsManifestPath") {
|
|
29702
29724
|
patch[key] = parseDsManifestPathVar(raw);
|
|
29703
29725
|
} else if (key === "ci") {
|
|
@@ -42398,7 +42420,6 @@ async function postToAlertsChannel(deps, text) {
|
|
|
42398
42420
|
|
|
42399
42421
|
// src/release-announce.ts
|
|
42400
42422
|
var ANNOUNCE_REPO = "mutmutco/MMI-Hub";
|
|
42401
|
-
var RELEASE_CHANNEL_KEY = "SLACK_RELEASE_CHANNEL";
|
|
42402
42423
|
var MAX_BULLETS = 6;
|
|
42403
42424
|
var MAX_SUMMARY_LINES = 8;
|
|
42404
42425
|
function neutralizeHubProductBrands(text) {
|
|
@@ -42406,13 +42427,6 @@ function neutralizeHubProductBrands(text) {
|
|
|
42406
42427
|
s = s.replace(/\bdesign-system\s+design-system\b/gi, "design-system");
|
|
42407
42428
|
return s.replace(/\s{2,}/g, " ").trim();
|
|
42408
42429
|
}
|
|
42409
|
-
function releaseChannelParam(repo) {
|
|
42410
|
-
return `/mmi-future/${slugOf(repo)}/${RELEASE_CHANNEL_KEY}`;
|
|
42411
|
-
}
|
|
42412
|
-
function isAbsentParameter(e) {
|
|
42413
|
-
const message2 = e instanceof Error ? e.message : String(e);
|
|
42414
|
-
return /ParameterNotFound/.test(message2) || /is empty$/.test(message2);
|
|
42415
|
-
}
|
|
42416
42430
|
function escapeMrkdwn(text) {
|
|
42417
42431
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
42418
42432
|
}
|
|
@@ -42467,14 +42481,20 @@ function curateReleaseNotes(notesMd, maxBullets = MAX_BULLETS, neutralize = true
|
|
|
42467
42481
|
if (dropped > 0) lines2.push(`\u2026and ${dropped} more`);
|
|
42468
42482
|
return lines2;
|
|
42469
42483
|
}
|
|
42484
|
+
var ANNOUNCE_FRAMES = {
|
|
42485
|
+
en: { released: "released", notes: "Release notes" },
|
|
42486
|
+
tr: { released: "yay\u0131nda", notes: "S\xFCr\xFCm notlar\u0131" }
|
|
42487
|
+
};
|
|
42470
42488
|
function formatAnnouncement(args) {
|
|
42471
42489
|
const name = args.repo.split("/")[1] ?? args.repo;
|
|
42490
|
+
const code = args.language ?? "en";
|
|
42491
|
+
const frame = Object.hasOwn(ANNOUNCE_FRAMES, code) ? ANNOUNCE_FRAMES[code] : ANNOUNCE_FRAMES.en;
|
|
42472
42492
|
return [
|
|
42473
|
-
`:rocket: *${name} ${args.tag} released*`,
|
|
42493
|
+
`:rocket: *${name} ${args.tag} ${frame.released}*`,
|
|
42474
42494
|
"",
|
|
42475
42495
|
...args.lines,
|
|
42476
42496
|
"",
|
|
42477
|
-
`<${args.releaseUrl}
|
|
42497
|
+
`<${args.releaseUrl}|${frame.notes}>`
|
|
42478
42498
|
].join("\n");
|
|
42479
42499
|
}
|
|
42480
42500
|
function summaryFileLines(content, neutralize = true) {
|
|
@@ -42485,18 +42505,12 @@ function summaryFileLines(content, neutralize = true) {
|
|
|
42485
42505
|
}
|
|
42486
42506
|
async function resolveAnnounceTarget(deps, repo) {
|
|
42487
42507
|
if (repo.toLowerCase() === ANNOUNCE_REPO.toLowerCase()) return { kind: "alerts" };
|
|
42488
|
-
const
|
|
42489
|
-
|
|
42490
|
-
const channel = await readSsmParameter(deps, param, false);
|
|
42491
|
-
return { kind: "channel", channel };
|
|
42492
|
-
} catch (e) {
|
|
42493
|
-
if (isAbsentParameter(e)) return { kind: "none", param };
|
|
42494
|
-
throw e;
|
|
42495
|
-
}
|
|
42508
|
+
const target = deps.fetchReleaseTarget ? await deps.fetchReleaseTarget(slugOf(repo)) : { channel: null, language: "en" };
|
|
42509
|
+
return target.channel ? { kind: "channel", channel: target.channel, language: target.language } : { kind: "none" };
|
|
42496
42510
|
}
|
|
42497
42511
|
function missingChannelNote(repo) {
|
|
42498
42512
|
const slug = slugOf(repo);
|
|
42499
|
-
return `no
|
|
42513
|
+
return `no releaseChannel configured for ${slug} \u2014 enable release notes with \`mmi-cli oracle org project set --var releaseChannel=<slack channel id> ${repo}\``;
|
|
42500
42514
|
}
|
|
42501
42515
|
async function announceRelease(deps, args) {
|
|
42502
42516
|
const neutralize = args.repo.toLowerCase() === ANNOUNCE_REPO.toLowerCase();
|
|
@@ -42517,9 +42531,20 @@ async function announceRelease(deps, args) {
|
|
|
42517
42531
|
}
|
|
42518
42532
|
}
|
|
42519
42533
|
}
|
|
42520
|
-
if (lines2.length === 0)
|
|
42534
|
+
if (lines2.length === 0) {
|
|
42535
|
+
if (target.kind !== "alerts") {
|
|
42536
|
+
return { status: "skipped", note: "no --announce-summary-file given \u2014 raw release notes are never posted to a project channel" };
|
|
42537
|
+
}
|
|
42538
|
+
lines2 = curateReleaseNotes(view.body ?? "", MAX_BULLETS, neutralize);
|
|
42539
|
+
}
|
|
42521
42540
|
if (lines2.length === 0) lines2 = ["\u2022 maintenance release \u2014 see the notes for details"];
|
|
42522
|
-
const text = formatAnnouncement({
|
|
42541
|
+
const text = formatAnnouncement({
|
|
42542
|
+
repo: args.repo,
|
|
42543
|
+
tag: args.tag,
|
|
42544
|
+
lines: lines2,
|
|
42545
|
+
releaseUrl,
|
|
42546
|
+
...target.kind === "channel" ? { language: target.language } : {}
|
|
42547
|
+
});
|
|
42523
42548
|
if (target.kind === "alerts") {
|
|
42524
42549
|
await postToAlertsChannel(deps, text);
|
|
42525
42550
|
return { status: "announced", note: `announced ${args.tag} to the alerts channel` };
|
|
@@ -43878,6 +43903,18 @@ var NODE_PREPARE_TIMEOUT_MS = 10 * 6e4;
|
|
|
43878
43903
|
var NODE_VERIFY_TIMEOUT_MS = 5 * 6e4;
|
|
43879
43904
|
var NPM_TRAIN_TIMEOUT_MS = 6e4;
|
|
43880
43905
|
var JERV_GATEWAY_DEPLOY_TIMEOUT_MS = 20 * 6e4;
|
|
43906
|
+
async function announceSummaryRefusal(path2) {
|
|
43907
|
+
let lines2;
|
|
43908
|
+
try {
|
|
43909
|
+
lines2 = summaryFileLines(await (0, import_promises10.readFile)(path2, "utf8"));
|
|
43910
|
+
} catch (e) {
|
|
43911
|
+
return `release: could not read --announce-summary-file ${path2}: ${e.message} \u2014 see docs/Guides/train-troubleshooting.md#announce-summary-missing`;
|
|
43912
|
+
}
|
|
43913
|
+
if (lines2.length < 3 || lines2.length > 6) {
|
|
43914
|
+
return `release: --announce-summary-file must contain 3-6 non-empty LLM-curated lines (found ${lines2.length}) \u2014 see docs/Guides/train-troubleshooting.md#announce-summary-missing`;
|
|
43915
|
+
}
|
|
43916
|
+
return null;
|
|
43917
|
+
}
|
|
43881
43918
|
function trainApplyDeps() {
|
|
43882
43919
|
return {
|
|
43883
43920
|
run: async (file, args) => {
|
|
@@ -43940,12 +43977,25 @@ function trainApplyDeps() {
|
|
|
43940
43977
|
// train lands the back-merge itself instead of leaving a manual step. Same enqueue path `pr land` uses,
|
|
43941
43978
|
// but method `--merge` (NOT squash): the misalignment guard needs the merge parentage to survive.
|
|
43942
43979
|
mergeAuto: (prNumber, repo) => ghMergeAutoEnqueue(prNumber, repo, "--merge"),
|
|
43943
|
-
// Slack release announcement (#883/#
|
|
43944
|
-
//
|
|
43980
|
+
// Slack release announcement (#883/#6521/#6523): the org alerts channel for the Hub, the project's own
|
|
43981
|
+
// registry releaseChannel META for a product repo — best-effort inside announceRelease itself.
|
|
43945
43982
|
announce: (args) => announceRelease({
|
|
43946
43983
|
run: async (file, cmdArgs) => (await execFileP(file, cmdArgs, { timeout: GH_TRAIN_TIMEOUT_MS })).stdout,
|
|
43947
43984
|
readFile: (path2) => (0, import_promises10.readFile)(path2, "utf8"),
|
|
43948
|
-
removeFile: (path2) => (0, import_promises10.unlink)(path2)
|
|
43985
|
+
removeFile: (path2) => (0, import_promises10.unlink)(path2),
|
|
43986
|
+
// #6521/#6523: the project's own release channel AND releaseLanguage, read from registry META in ONE
|
|
43987
|
+
// checked read. Same shape as fetchEdgeDomains below: a FAILED read refuses by name so the announce
|
|
43988
|
+
// note reports a failed read, never a project that configured nothing.
|
|
43989
|
+
fetchReleaseTarget: async (slug) => {
|
|
43990
|
+
const read = await fetchProjectBySlugChecked(slug, registryClientDeps(await loadConfig()));
|
|
43991
|
+
if (!read.ok) {
|
|
43992
|
+
throw new Error(`release announcement: Hub registry read FAILED for ${slug} (${read.error}) \u2014 releaseChannel is UNREAD, not unset`);
|
|
43993
|
+
}
|
|
43994
|
+
return {
|
|
43995
|
+
channel: read.project?.releaseChannel?.trim() || null,
|
|
43996
|
+
language: read.project?.releaseLanguage?.trim() || "en"
|
|
43997
|
+
};
|
|
43998
|
+
}
|
|
43949
43999
|
}, args),
|
|
43950
44000
|
// #4713 (I/O-boundary census): `null` used to mean BOTH "this project configures no edge domains"
|
|
43951
44001
|
// (a real answer) and "the registry read missed" — so a release verdict printed an environments block
|
|
@@ -44205,7 +44255,7 @@ function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
|
|
|
44205
44255
|
for (const commandName of ["rcand", "release"]) {
|
|
44206
44256
|
const trainCmd = program3.command(commandName).description(`plan ${commandName} train operations; mutations require explicit master-admin approval`).option("--json", "machine-readable output").option("--watch", "block on the deploy/publish workflow runs and report their outcomes").option("--apply", "execute the guarded master-only train after explicit approval").option("--resume", commandName === "rcand" ? "finish a candidate whose immutable public rc tag passed policy but origin/rc was not pushed (#3881)" : "finish a partial release or its protected post-release alignment without re-cutting, republishing, or redeploying (#3851/#3885)").option("--out <path>", "write the terminal result (--apply, --resume, --abort, --retry-publish) to this file as UTF-8 (no BOM) instead of stdout \u2014 the shell-free receipt path (#5983/#6068)");
|
|
44207
44257
|
const RELEASE_ONLY_FLAGS = [
|
|
44208
|
-
{ flags: "--announce-summary-file <path>", description: "agent-curated 3-6 line release Slack summary; required for a new MMI-Hub --apply (#883/#3901)
|
|
44258
|
+
{ flags: "--announce-summary-file <path>", description: "agent-curated 3-6 line release Slack summary; required for a new MMI-Hub --apply (#883/#3901) and for a product repo whose registry META sets `releaseChannel` (#6523), in its `releaseLanguage`; nothing is posted to a project channel without it" },
|
|
44209
44259
|
{ flags: "--ack <shas>", description: "comma-separated dev shas a human verified are in the candidate, overriding the hotfix-coverage guard for a conflicted port whose -x trailer was lost (#958)" },
|
|
44210
44260
|
{ flags: "--dev", description: "full-track repos release development -> main directly, skipping rc (refuses if rc carries content not in development; no-op on direct-track repos) (#1062)" },
|
|
44211
44261
|
{ flags: "--abort", description: "with --apply, delete only a proven unpublished failed release candidate on any registered deploy model and restore local main for a same-version recut (#3944/#5650/#5657)" },
|
|
@@ -44323,22 +44373,35 @@ function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
|
|
|
44323
44373
|
const guard = planTrainApplyRepoGuard(o.repo, await resolveRepo(), rerun);
|
|
44324
44374
|
if (!guard.ok) return fail(`${commandName}: ${guard.message}`);
|
|
44325
44375
|
}
|
|
44326
|
-
if (o.apply && commandName === "release"
|
|
44327
|
-
|
|
44328
|
-
|
|
44329
|
-
|
|
44330
|
-
|
|
44331
|
-
|
|
44332
|
-
|
|
44333
|
-
|
|
44334
|
-
|
|
44335
|
-
|
|
44336
|
-
|
|
44376
|
+
if (o.apply && commandName === "release") {
|
|
44377
|
+
const applyingRepo = await resolveRepo();
|
|
44378
|
+
const slug = applyingRepo ? slugOf(applyingRepo) : "";
|
|
44379
|
+
const isHub = applyingRepo?.toLowerCase() === ANNOUNCE_REPO.toLowerCase();
|
|
44380
|
+
let announcesToChannel = isHub;
|
|
44381
|
+
let releaseLanguage2 = "en";
|
|
44382
|
+
if (!isHub && slug) {
|
|
44383
|
+
let read;
|
|
44384
|
+
try {
|
|
44385
|
+
read = await fetchProjectBySlugChecked(slug, registryClientDeps(await loadConfig()));
|
|
44386
|
+
} catch (e) {
|
|
44387
|
+
read = { ok: false, error: e.message };
|
|
44388
|
+
}
|
|
44389
|
+
if (!read.ok) {
|
|
44390
|
+
return fail(
|
|
44391
|
+
`release: Hub registry read failed for ${slug} (${read.error}) \u2014 whether ${slug} announces to a project release channel is UNREAD, so the --announce-summary-file requirement is unproven. Likely transient (cold start, network, or auth blip); retry shortly.`
|
|
44392
|
+
);
|
|
44393
|
+
}
|
|
44394
|
+
announcesToChannel = Boolean(read.project?.releaseChannel?.trim());
|
|
44395
|
+
releaseLanguage2 = read.project?.releaseLanguage?.trim() || "en";
|
|
44337
44396
|
}
|
|
44338
|
-
if (
|
|
44339
|
-
|
|
44340
|
-
|
|
44341
|
-
|
|
44397
|
+
if (announcesToChannel) {
|
|
44398
|
+
if (!o.announceSummaryFile) {
|
|
44399
|
+
return fail(
|
|
44400
|
+
isHub ? "release: a new MMI-Hub release requires --announce-summary-file <path> with 3-6 short LLM-curated lines; create the summary file, then rerun the same release command \u2014 see docs/Guides/train-troubleshooting.md#announce-summary-missing" : `release: ${slug} announces to its project release channel, so a new release requires --announce-summary-file <path> with 3-6 short plain-language lines in the project's releaseLanguage (${releaseLanguage2}); create the summary file, then rerun the same release command \u2014 see docs/Guides/train-troubleshooting.md#announce-summary-missing`
|
|
44401
|
+
);
|
|
44402
|
+
}
|
|
44403
|
+
const refusal = await announceSummaryRefusal(o.announceSummaryFile);
|
|
44404
|
+
if (refusal) return fail(refusal);
|
|
44342
44405
|
}
|
|
44343
44406
|
}
|
|
44344
44407
|
if (o.apply) {
|
|
@@ -44370,6 +44433,8 @@ function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
|
|
|
44370
44433
|
const repo = o.repo ?? await resolveRepo();
|
|
44371
44434
|
const targets = commandName === "rcand" && !o.repo ? await resolveRcandPlanTargets() : void 0;
|
|
44372
44435
|
let releaseTrack;
|
|
44436
|
+
let releaseChannel = null;
|
|
44437
|
+
let releaseLanguage = "en";
|
|
44373
44438
|
if (repo) {
|
|
44374
44439
|
let read;
|
|
44375
44440
|
try {
|
|
@@ -44384,6 +44449,8 @@ function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
|
|
|
44384
44449
|
}
|
|
44385
44450
|
const raw = read.project?.releaseTrack;
|
|
44386
44451
|
if (isReleaseTrack(raw)) releaseTrack = raw;
|
|
44452
|
+
releaseChannel = read.project?.releaseChannel?.trim() || null;
|
|
44453
|
+
releaseLanguage = read.project?.releaseLanguage?.trim() || "en";
|
|
44387
44454
|
}
|
|
44388
44455
|
const steps = trainPlan(commandName, { ...targets ?? {}, repo, dev: o.dev, releaseTrack });
|
|
44389
44456
|
let doctor;
|
|
@@ -44395,7 +44462,7 @@ function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
|
|
|
44395
44462
|
}
|
|
44396
44463
|
}
|
|
44397
44464
|
console.log(
|
|
44398
|
-
o.json ? JSON.stringify({ command: commandName, ...targets ?? {}, repo, steps, ...doctor ? { doctor } : {} }, null, 2) : [renderSteps(`mmi-cli ${commandName}: dry-run plan`, steps), ...doctor ? ["", formatTrainDoctor(doctor)] : []].join("\n")
|
|
44465
|
+
o.json ? JSON.stringify({ command: commandName, ...targets ?? {}, repo, steps, ...commandName === "release" ? { releaseChannel, releaseLanguage } : {}, ...doctor ? { doctor } : {} }, null, 2) : [renderSteps(`mmi-cli ${commandName}: dry-run plan`, steps), ...doctor ? ["", formatTrainDoctor(doctor)] : []].join("\n")
|
|
44399
44466
|
);
|
|
44400
44467
|
});
|
|
44401
44468
|
}
|
|
@@ -45315,7 +45382,7 @@ projectDeploy.command("doctor").description("read-only estate scan for duplicate
|
|
|
45315
45382
|
if (report.error && report.status !== 403) return failGraceful(`org project deploy doctor: ${report.error}`);
|
|
45316
45383
|
if (!report.ok && !report.error) process.exitCode = 1;
|
|
45317
45384
|
});
|
|
45318
|
-
project.command("set [owner/repo]").description("upsert project META (idempotent merge; master-gated)").addOption(new Option("--class <class>", "deployable | content").choices(["deployable", "content"])).addOption(new Option("--project-type <type>", `${PROJECT_TYPES.join(" | ")} (capability shape)`).choices([...PROJECT_TYPES])).addOption(new Option("--deploy-model <model>", `${DEPLOY_MODELS.join(" | ")} (release/deploy path; none means no Hub deploy registration)`).choices([...DEPLOY_MODELS])).addOption(new Option("--release-track <track>", `${RELEASE_TRACKS.join(" | ")} (branch topology; direct skips rc)`).choices([...RELEASE_TRACKS])).option("--var <KEY=VALUE...>", settableVarHelp()).option("--set <KEY=VALUE...>", "alias of --var (one KEY=VALUE per flag; repeat the flag to set several)").option("--secrets-file <path>", 'read the #2244 secrets catalog map (JSON) from a file and merge it per entry into the existing catalog (clear all with --unset secrets). SHAPE: a JSON object keyed by env name, each entry {"key":"UPPER_SNAKE" (repeat the env name), "purpose":"<non-empty>", "group":"<e.g. auth|database>", "owner":"<github login>", "stages":[] (empty = the one stageless shared value; else any of dev/rc/main), "consumers":["runtime"|"box"|?], "provider":"<optional>"}').option("--unset <KEY...>", "META field to remove (repeatable): oauth, requiredRuntimeSecrets, requiredBuildSecrets, secrets, edgeDomains, requiredGcpApis, publishRequired").option("--clear-web-profile", "remove web-only registry fields (oauth, edgeDomains) for non-web/content projects").option("--json", "machine-readable output").action(async (repoOrSlug, o) => {
|
|
45385
|
+
project.command("set [owner/repo]").description("upsert project META (idempotent merge; master-gated)").addOption(new Option("--class <class>", "deployable | content").choices(["deployable", "content"])).addOption(new Option("--project-type <type>", `${PROJECT_TYPES.join(" | ")} (capability shape)`).choices([...PROJECT_TYPES])).addOption(new Option("--deploy-model <model>", `${DEPLOY_MODELS.join(" | ")} (release/deploy path; none means no Hub deploy registration)`).choices([...DEPLOY_MODELS])).addOption(new Option("--release-track <track>", `${RELEASE_TRACKS.join(" | ")} (branch topology; direct skips rc)`).choices([...RELEASE_TRACKS])).option("--var <KEY=VALUE...>", settableVarHelp()).option("--set <KEY=VALUE...>", "alias of --var (one KEY=VALUE per flag; repeat the flag to set several)").option("--secrets-file <path>", 'read the #2244 secrets catalog map (JSON) from a file and merge it per entry into the existing catalog (clear all with --unset secrets). SHAPE: a JSON object keyed by env name, each entry {"key":"UPPER_SNAKE" (repeat the env name), "purpose":"<non-empty>", "group":"<e.g. auth|database>", "owner":"<github login>", "stages":[] (empty = the one stageless shared value; else any of dev/rc/main), "consumers":["runtime"|"box"|?], "provider":"<optional>"}').option("--unset <KEY...>", "META field to remove (repeatable): oauth, requiredRuntimeSecrets, requiredBuildSecrets, secrets, edgeDomains, requiredGcpApis, publishRequired, releaseChannel, releaseLanguage").option("--clear-web-profile", "remove web-only registry fields (oauth, edgeDomains) for non-web/content projects").option("--json", "machine-readable output").action(async (repoOrSlug, o) => {
|
|
45319
45386
|
const cfg = await loadConfig();
|
|
45320
45387
|
let target;
|
|
45321
45388
|
try {
|
package/package.json
CHANGED