@revturbine/cli 0.11.0 → 0.12.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 +28 -13
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9041,13 +9041,21 @@ function formatDiff(diff) {
|
|
|
9041
9041
|
return lines.join("\n");
|
|
9042
9042
|
}
|
|
9043
9043
|
|
|
9044
|
+
// src/lib/prune.ts
|
|
9045
|
+
function pruneQuery(prune) {
|
|
9046
|
+
if (prune === false) return "?prune=false";
|
|
9047
|
+
if (prune === true) return "?prune=force";
|
|
9048
|
+
return "";
|
|
9049
|
+
}
|
|
9050
|
+
|
|
9044
9051
|
// src/lib/config-validate.ts
|
|
9045
9052
|
var BLOCKING_SEVERITIES = /* @__PURE__ */ new Set(["error_draft", "error_launch"]);
|
|
9046
|
-
function isBlockingFinding(finding2) {
|
|
9053
|
+
function isBlockingFinding(finding2, force = false) {
|
|
9054
|
+
if (force && finding2.severity === "error_launch") return false;
|
|
9047
9055
|
return BLOCKING_SEVERITIES.has(finding2.severity);
|
|
9048
9056
|
}
|
|
9049
|
-
function hasBlockingFindings(findings) {
|
|
9050
|
-
return findings.some(isBlockingFinding);
|
|
9057
|
+
function hasBlockingFindings(findings, force = false) {
|
|
9058
|
+
return findings.some((f) => isBlockingFinding(f, force));
|
|
9051
9059
|
}
|
|
9052
9060
|
function formatFindings(findings) {
|
|
9053
9061
|
if (findings.length === 0) return "No validation findings.";
|
|
@@ -9733,17 +9741,22 @@ async function loadVersion(conn, sel) {
|
|
|
9733
9741
|
return downloadConfig(conn, await requireOpenDraft(conn));
|
|
9734
9742
|
}
|
|
9735
9743
|
}
|
|
9736
|
-
async function launchDraft(conn, playbookVersionId) {
|
|
9744
|
+
async function launchDraft(conn, playbookVersionId, force = false) {
|
|
9737
9745
|
diag(`Launch gate: validating draft ${playbookVersionId} \u2026`);
|
|
9738
9746
|
const validation = await fetchValidation(conn.url, playbookVersionId, conn.headers);
|
|
9739
9747
|
if (!validation.ok) httpFail(conn, "validate", validation.status, validation.error);
|
|
9740
9748
|
if (validation.findings.length > 0) diagRaw(formatFindings(validation.findings));
|
|
9741
|
-
if (hasBlockingFindings(validation.findings)) {
|
|
9749
|
+
if (hasBlockingFindings(validation.findings, force)) {
|
|
9742
9750
|
fail(EXIT.VALIDATION, "blocking findings \u2014 this draft cannot launch.");
|
|
9743
9751
|
}
|
|
9752
|
+
const overridden = force ? validation.findings.filter((f) => f.severity === "error_launch") : [];
|
|
9753
|
+
if (overridden.length > 0) {
|
|
9754
|
+
diag(`--force: overriding ${overridden.length} launch-gate finding(s) (error_launch).`);
|
|
9755
|
+
}
|
|
9744
9756
|
diag(`Launching playbook version ${playbookVersionId} (submit \u2192 approve \u2192 deploy) \u2026`);
|
|
9745
9757
|
for (const step of ["submit", "approve", "deploy"]) {
|
|
9746
|
-
const
|
|
9758
|
+
const body = step === "deploy" ? { force } : {};
|
|
9759
|
+
const { res, json } = await postJson(conn, `/api/playbook-versions/${playbookVersionId}/${step}`, body);
|
|
9747
9760
|
if (!res.ok) {
|
|
9748
9761
|
diag(`\u2717 ${step} failed (${res.status}). The draft is staged but NOT live.`);
|
|
9749
9762
|
diagRaw(` ${JSON.stringify(json)}`);
|
|
@@ -10266,12 +10279,14 @@ program.command("show").description(`Render a summary view of a config version.
|
|
|
10266
10279
|
emit(data, Boolean(opts.json), text);
|
|
10267
10280
|
}
|
|
10268
10281
|
);
|
|
10269
|
-
|
|
10282
|
+
var PRUNE_OPTION = ["--prune", "Confirm a convergent delete past the mass-deletion guard (removes entities absent from the file)"];
|
|
10283
|
+
var NO_PRUNE_OPTION = ["--no-prune", "Additive import \u2014 keep entities that are absent from the file (disables convergent delete)"];
|
|
10284
|
+
program.command("upload").description("Stage a Config File as the open draft (POST /api/config/import).").argument("<config>", "Path to a Config File").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option(...PRUNE_OPTION).option(...NO_PRUNE_OPTION).action(async (configFile2, opts) => {
|
|
10270
10285
|
const config = verifyConfig(configFile2);
|
|
10271
10286
|
if (config === null) fail(EXIT.VALIDATION, `Fix the issues above in ${configFile2}, then re-run.`);
|
|
10272
10287
|
const conn = connect(opts.url, uploadTenantFor(opts.url, config, opts.tenantId));
|
|
10273
10288
|
diag(`Staging ${configFile2} as the open draft (${conn.url}/api/config/import) \u2026`);
|
|
10274
|
-
const { res, json } = await postJson(conn,
|
|
10289
|
+
const { res, json } = await postJson(conn, `/api/config/import${pruneQuery(opts.prune)}`, config);
|
|
10275
10290
|
if (!res.ok) {
|
|
10276
10291
|
if (json && typeof json === "object" && json.stage) {
|
|
10277
10292
|
diagRaw(` stage: ${json.stage}`);
|
|
@@ -10287,7 +10302,7 @@ program.command("upload").description("Stage a Config File as the open draft (PO
|
|
|
10287
10302
|
if (playbookVersionId) diagRaw(` playbook_version_id: ${playbookVersionId}`);
|
|
10288
10303
|
diag("Launch it with `revturbine launch --draft`, or from the UI (Drafts & Releases).");
|
|
10289
10304
|
});
|
|
10290
|
-
program.command("launch").description("Take a config live as a new Release: validate (launch gate), then submit \u2192 approve \u2192 deploy. Synchronous.").argument("[file]", "Config File to upload and launch directly").option("--draft", "Launch the already-open draft").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option("--yes", "Accepted for parity with discard/restore; launch has no confirmation prompt").action(async (file, opts) => {
|
|
10305
|
+
program.command("launch").description("Take a config live as a new Release: validate (launch gate), then submit \u2192 approve \u2192 deploy. Synchronous.").argument("[file]", "Config File to upload and launch directly").option("--draft", "Launch the already-open draft").option("--force", "Launch past incomplete-but-valid findings (error_launch); structural errors (error_draft) still block").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option(...PRUNE_OPTION).option(...NO_PRUNE_OPTION).option("--yes", "Accepted for parity with discard/restore; launch has no confirmation prompt").action(async (file, opts) => {
|
|
10291
10306
|
const [sel] = requireSelectors(opts, file ? [file] : [], { count: 1, allowed: ["file", "draft"], command: "launch" });
|
|
10292
10307
|
let conn;
|
|
10293
10308
|
let playbookVersionId;
|
|
@@ -10296,7 +10311,7 @@ program.command("launch").description("Take a config live as a new Release: vali
|
|
|
10296
10311
|
if (config === null) fail(EXIT.VALIDATION, `Fix the issues above in ${sel.path}, then re-run.`);
|
|
10297
10312
|
conn = connect(opts.url, uploadTenantFor(opts.url, config, opts.tenantId));
|
|
10298
10313
|
diag(`Staging ${sel.path} as the open draft \u2026`);
|
|
10299
|
-
const { res, json } = await postJson(conn,
|
|
10314
|
+
const { res, json } = await postJson(conn, `/api/config/import${pruneQuery(opts.prune)}`, config);
|
|
10300
10315
|
if (!res.ok) {
|
|
10301
10316
|
diagRaw(` ${JSON.stringify(json)}`);
|
|
10302
10317
|
httpFail(conn, "upload", res.status);
|
|
@@ -10308,7 +10323,7 @@ program.command("launch").description("Take a config live as a new Release: vali
|
|
|
10308
10323
|
conn = connect(opts.url, opts.tenantId);
|
|
10309
10324
|
playbookVersionId = await requireOpenDraft(conn);
|
|
10310
10325
|
}
|
|
10311
|
-
await launchDraft(conn, playbookVersionId);
|
|
10326
|
+
await launchDraft(conn, playbookVersionId, !!opts.force);
|
|
10312
10327
|
});
|
|
10313
10328
|
program.command("discard").description("Discard (archive) the open draft so a fresh one can start.").argument("[playbook-version-id]", "A specific draft id (default: the open draft)").option("--draft", "The open draft (explicit form of the default)").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option("--yes", "Skip the confirmation prompt").action(async (id, opts) => {
|
|
10314
10329
|
const conn = connect(opts.url, opts.tenantId);
|
|
@@ -10318,7 +10333,7 @@ program.command("discard").description("Discard (archive) the open draft so a fr
|
|
|
10318
10333
|
if (!res.ok) httpFail(conn, "discard", res.status, json);
|
|
10319
10334
|
diag(`\u2713 Discarded draft ${playbookVersionId}.`);
|
|
10320
10335
|
});
|
|
10321
|
-
program.command("restore").description("Stage a draft that restores a past release (from its frozen snapshot); `--launch` takes it live. Halts if a draft is already open.").argument("<playbook-version-id>", "The deployed playbook version to restore (see `history`)").option("--launch", "Launch the restoring draft immediately (gate + submit \u2192 approve \u2192 deploy)").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option("--yes", "Skip the confirmation prompt").action(async (playbookVersionId, opts) => {
|
|
10336
|
+
program.command("restore").description("Stage a draft that restores a past release (from its frozen snapshot); `--launch` takes it live. Halts if a draft is already open.").argument("<playbook-version-id>", "The deployed playbook version to restore (see `history`)").option("--launch", "Launch the restoring draft immediately (gate + submit \u2192 approve \u2192 deploy)").option("--force", "With --launch, launch past incomplete-but-valid findings (error_launch); error_draft still blocks").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option("--yes", "Skip the confirmation prompt").action(async (playbookVersionId, opts) => {
|
|
10322
10337
|
const conn = connect(opts.url, opts.tenantId);
|
|
10323
10338
|
await confirmOrExit(
|
|
10324
10339
|
`Restore playbook version ${playbookVersionId} on ${conn.url}?${opts.launch ? " --launch will take it LIVE." : " (stages a draft; launch separately)"}`,
|
|
@@ -10333,7 +10348,7 @@ program.command("restore").description("Stage a draft that restores a past relea
|
|
|
10333
10348
|
return;
|
|
10334
10349
|
}
|
|
10335
10350
|
if (!reverting) fail(EXIT.SERVER, "No reverting draft id returned \u2014 cannot launch.");
|
|
10336
|
-
await launchDraft(conn, reverting);
|
|
10351
|
+
await launchDraft(conn, reverting, !!opts.force);
|
|
10337
10352
|
});
|
|
10338
10353
|
program.command("status").description("The current live Release and the open draft, side by side.").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option("--json", "Machine-readable output").action(async (opts) => {
|
|
10339
10354
|
const conn = connect(opts.url, opts.tenantId);
|
package/package.json
CHANGED