@revturbine/cli 0.5.1 → 0.6.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 +64 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3979,6 +3979,13 @@ var RevTurbineConfigSchema = z19.object({
|
|
|
3979
3979
|
// The change set this export represents: the active change set by default,
|
|
3980
3980
|
// or a specific change set when one is requested. Null for an unscoped export.
|
|
3981
3981
|
change_set_id: z19.string().nullable().default(null).meta({ ...Unrestricted16, readOnly: true }),
|
|
3982
|
+
// Origin target identity (plan 131 TASK-10, cli.md "Target-aware, portable"):
|
|
3983
|
+
// stamped by the server on export so a downloaded Config File records where
|
|
3984
|
+
// it came from; upload tooling targets these by default and flags a tenant
|
|
3985
|
+
// mismatch against the session before sending. Optional — hand-authored and
|
|
3986
|
+
// pre-existing configs carry no target.
|
|
3987
|
+
tenant_id: z19.string().optional().meta({ ...Unrestricted16, readOnly: true }),
|
|
3988
|
+
environment_id: z19.string().optional().meta({ ...Unrestricted16, readOnly: true }),
|
|
3982
3989
|
plans: z19.array(RevTurbineConfigPlansItemSchema).meta(Unrestricted16),
|
|
3983
3990
|
// Optional for back-compat: pre-plan-88 configs (and the live export until web
|
|
3984
3991
|
// adopts the new @revt-eng/schema) omit it. Add-on definitions only; pricing
|
|
@@ -5562,7 +5569,7 @@ function evaluate(graph, opts = {}) {
|
|
|
5562
5569
|
}
|
|
5563
5570
|
|
|
5564
5571
|
// src/schema/version.ts
|
|
5565
|
-
var SCHEMA_VERSION = "0.1.
|
|
5572
|
+
var SCHEMA_VERSION = "0.1.108";
|
|
5566
5573
|
|
|
5567
5574
|
// src/lib/credentials.ts
|
|
5568
5575
|
import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
@@ -6024,6 +6031,36 @@ function requireSelectors(opts, positionalFiles, {
|
|
|
6024
6031
|
return found;
|
|
6025
6032
|
}
|
|
6026
6033
|
|
|
6034
|
+
// src/lib/target.ts
|
|
6035
|
+
function resolveUploadTarget(params) {
|
|
6036
|
+
const embedded = params.embedded ?? void 0;
|
|
6037
|
+
const explicit = params.explicit ?? void 0;
|
|
6038
|
+
if (explicit) {
|
|
6039
|
+
return {
|
|
6040
|
+
ok: true,
|
|
6041
|
+
tenantId: explicit,
|
|
6042
|
+
note: embedded && embedded !== explicit ? `retargeting deliberately: config was exported from ${embedded}, sending to ${explicit} (-t)` : void 0
|
|
6043
|
+
};
|
|
6044
|
+
}
|
|
6045
|
+
if (!embedded || embedded === params.session) {
|
|
6046
|
+
return { ok: true, tenantId: params.session };
|
|
6047
|
+
}
|
|
6048
|
+
return {
|
|
6049
|
+
ok: false,
|
|
6050
|
+
error: `this config was exported from tenant ${embedded}, but the session targets ${params.session}. Pass -t ${embedded} to send it back where it came from, or -t ${params.session} to retarget it deliberately.`
|
|
6051
|
+
};
|
|
6052
|
+
}
|
|
6053
|
+
|
|
6054
|
+
// src/lib/version-trail.ts
|
|
6055
|
+
function serverSchemaIsNewer(config, bundledVersion) {
|
|
6056
|
+
const server = config?.schema_version;
|
|
6057
|
+
if (typeof server !== "string" || !server) return null;
|
|
6058
|
+
const parse = (v) => v.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
6059
|
+
const [a, b] = [parse(server), parse(bundledVersion)];
|
|
6060
|
+
const newer = a[0] !== b[0] ? a[0] > b[0] : a[1] !== b[1] ? a[1] > b[1] : (a[2] ?? 0) > (b[2] ?? 0);
|
|
6061
|
+
return newer ? server : null;
|
|
6062
|
+
}
|
|
6063
|
+
|
|
6027
6064
|
// src/cli.ts
|
|
6028
6065
|
var DOCS_URL = "https://github.com/revt-eng/revturbine-cli#readme";
|
|
6029
6066
|
var DEFAULT_URL = "https://revturbine.com/app";
|
|
@@ -6076,6 +6113,17 @@ function connect(rawUrl, explicitTenantId) {
|
|
|
6076
6113
|
}
|
|
6077
6114
|
};
|
|
6078
6115
|
}
|
|
6116
|
+
function uploadTenantFor(rawUrl, config, explicit) {
|
|
6117
|
+
const cred = getCredential(normalizeBaseUrl(rawUrl));
|
|
6118
|
+
const target = resolveUploadTarget({
|
|
6119
|
+
embedded: config?.tenant_id,
|
|
6120
|
+
explicit,
|
|
6121
|
+
session: cred?.tenant_id ?? "dev-tenant-001"
|
|
6122
|
+
});
|
|
6123
|
+
if (!target.ok) fail(EXIT.VALIDATION, target.error);
|
|
6124
|
+
if (target.note) diag(target.note);
|
|
6125
|
+
return target.tenantId;
|
|
6126
|
+
}
|
|
6079
6127
|
function authHint(url, status) {
|
|
6080
6128
|
if (status === 401 || status === 403) {
|
|
6081
6129
|
diag(`Authentication required for ${url}. Log in with:
|
|
@@ -6104,11 +6152,21 @@ async function getJson(conn, pathname) {
|
|
|
6104
6152
|
const json = await res.json().catch(() => ({}));
|
|
6105
6153
|
return { res, json };
|
|
6106
6154
|
}
|
|
6155
|
+
function warnIfSchemaBehind(config) {
|
|
6156
|
+
const server = serverSchemaIsNewer(config, SCHEMA_VERSION);
|
|
6157
|
+
if (server) {
|
|
6158
|
+
diag(
|
|
6159
|
+
`WARNING: the server's schema (${server}) is newer than this CLI's bundled snapshot (${SCHEMA_VERSION}) \u2014 offline validation may be missing rules. Update: npm i -g @revturbine/cli`
|
|
6160
|
+
);
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6107
6163
|
async function downloadConfig(conn, playbookVersionId) {
|
|
6108
6164
|
const qs = playbookVersionId ? `?playbookVersionId=${encodeURIComponent(playbookVersionId)}` : "";
|
|
6109
6165
|
const res = await request(conn, `/api/config/export${qs}`);
|
|
6110
6166
|
if (!res.ok) httpFail(conn, "download", res.status);
|
|
6111
|
-
|
|
6167
|
+
const config = await res.json().catch(() => ({}));
|
|
6168
|
+
warnIfSchemaBehind(config);
|
|
6169
|
+
return config;
|
|
6112
6170
|
}
|
|
6113
6171
|
async function requireOpenDraft(conn) {
|
|
6114
6172
|
const { ok, status, draft } = await resolveActiveDraft(conn.url, conn.headers);
|
|
@@ -6506,7 +6564,7 @@ program.command("show").description(`Render a summary view of a config version.
|
|
|
6506
6564
|
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)").action(async (configFile2, opts) => {
|
|
6507
6565
|
const config = verifyConfig(configFile2);
|
|
6508
6566
|
if (config === null) fail(EXIT.VALIDATION, `Fix the issues above in ${configFile2}, then re-run.`);
|
|
6509
|
-
const conn = connect(opts.url, opts.tenantId);
|
|
6567
|
+
const conn = connect(opts.url, uploadTenantFor(opts.url, config, opts.tenantId));
|
|
6510
6568
|
diag(`Staging ${configFile2} as the open draft (${conn.url}/api/config/import) \u2026`);
|
|
6511
6569
|
const { res, json } = await postJson(conn, "/api/config/import", config);
|
|
6512
6570
|
if (!res.ok) {
|
|
@@ -6526,11 +6584,12 @@ program.command("upload").description("Stage a Config File as the open draft (PO
|
|
|
6526
6584
|
});
|
|
6527
6585
|
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) => {
|
|
6528
6586
|
const [sel] = requireSelectors(opts, file ? [file] : [], { count: 1, allowed: ["file", "draft"], command: "launch" });
|
|
6529
|
-
|
|
6587
|
+
let conn;
|
|
6530
6588
|
let playbookVersionId;
|
|
6531
6589
|
if (sel.kind === "file") {
|
|
6532
6590
|
const config = verifyConfig(sel.path);
|
|
6533
6591
|
if (config === null) fail(EXIT.VALIDATION, `Fix the issues above in ${sel.path}, then re-run.`);
|
|
6592
|
+
conn = connect(opts.url, uploadTenantFor(opts.url, config, opts.tenantId));
|
|
6534
6593
|
diag(`Staging ${sel.path} as the open draft \u2026`);
|
|
6535
6594
|
const { res, json } = await postJson(conn, "/api/config/import", config);
|
|
6536
6595
|
if (!res.ok) {
|
|
@@ -6541,6 +6600,7 @@ program.command("launch").description("Take a config live as a new Release: vali
|
|
|
6541
6600
|
if (!playbookVersionId) fail(EXIT.SERVER, "No playbook_version_id returned by the import \u2014 cannot launch.");
|
|
6542
6601
|
diag(`\u2713 Staged (${playbookVersionId})`);
|
|
6543
6602
|
} else {
|
|
6603
|
+
conn = connect(opts.url, opts.tenantId);
|
|
6544
6604
|
playbookVersionId = await requireOpenDraft(conn);
|
|
6545
6605
|
}
|
|
6546
6606
|
await launchDraft(conn, playbookVersionId);
|
package/package.json
CHANGED