@canaryai/cli 0.1.12 → 0.1.14
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/{feature-flag-MFTRYRYX.js → feature-flag-ESPSOSKG.js} +102 -16
- package/dist/feature-flag-ESPSOSKG.js.map +1 -0
- package/dist/index.js +22 -3
- package/dist/index.js.map +1 -1
- package/dist/{knobs-T3O4Z3ZB.js → knobs-HKONHY55.js} +148 -62
- package/dist/knobs-HKONHY55.js.map +1 -0
- package/dist/release-WOD3DAX4.js +249 -0
- package/dist/release-WOD3DAX4.js.map +1 -0
- package/package.json +1 -1
- package/dist/feature-flag-MFTRYRYX.js.map +0 -1
- package/dist/knobs-T3O4Z3ZB.js.map +0 -1
|
@@ -20,6 +20,24 @@ function getArgValue(argv, key) {
|
|
|
20
20
|
function hasFlag(argv, ...flags) {
|
|
21
21
|
return flags.some((flag) => argv.includes(flag));
|
|
22
22
|
}
|
|
23
|
+
function toLifecycleLabel(stage) {
|
|
24
|
+
switch (stage) {
|
|
25
|
+
case "deprecated":
|
|
26
|
+
return "deprecated";
|
|
27
|
+
case "ready_for_cleanup":
|
|
28
|
+
return "ready_for_cleanup";
|
|
29
|
+
default:
|
|
30
|
+
return "active";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function parseLifecycleStage(argv) {
|
|
34
|
+
const stage = getArgValue(argv, "--stage");
|
|
35
|
+
if (!stage || !["active", "deprecated", "ready_for_cleanup"].includes(stage)) {
|
|
36
|
+
console.error("Error: --stage is required and must be one of: active, deprecated, ready_for_cleanup");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
return stage;
|
|
40
|
+
}
|
|
23
41
|
async function resolveConfig(argv) {
|
|
24
42
|
const storedApiUrl = await readStoredApiUrl();
|
|
25
43
|
const env = getArgValue(argv, "--env");
|
|
@@ -54,8 +72,7 @@ async function apiRequest(apiUrl, token, method, path, body) {
|
|
|
54
72
|
const json = await res.json();
|
|
55
73
|
return json;
|
|
56
74
|
}
|
|
57
|
-
async function
|
|
58
|
-
const jsonOutput = hasFlag(argv, "--json");
|
|
75
|
+
async function fetchFlags(apiUrl, token) {
|
|
59
76
|
const res = await fetch(`${apiUrl}/superadmin/feature-flags`, {
|
|
60
77
|
headers: { Authorization: `Bearer ${token}` }
|
|
61
78
|
});
|
|
@@ -69,7 +86,11 @@ async function handleList(argv, apiUrl, token) {
|
|
|
69
86
|
console.error(`Error: ${json.error}`);
|
|
70
87
|
process.exit(1);
|
|
71
88
|
}
|
|
72
|
-
|
|
89
|
+
return json.flags ?? [];
|
|
90
|
+
}
|
|
91
|
+
async function handleList(argv, apiUrl, token) {
|
|
92
|
+
const jsonOutput = hasFlag(argv, "--json");
|
|
93
|
+
const flags = await fetchFlags(apiUrl, token);
|
|
73
94
|
if (jsonOutput) {
|
|
74
95
|
console.log(JSON.stringify(flags, null, 2));
|
|
75
96
|
return;
|
|
@@ -79,9 +100,10 @@ async function handleList(argv, apiUrl, token) {
|
|
|
79
100
|
return;
|
|
80
101
|
}
|
|
81
102
|
for (const flag of flags) {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
103
|
+
const orgCount = flag.organizations?.length ?? 0;
|
|
104
|
+
const lifecycle = `lifecycle=${toLifecycleLabel(flag.lifecycleStage)}`;
|
|
105
|
+
const finalValue = flag.lifecycleStage === "active" ? "" : ` final=${flag.finalValue === true ? "true" : "false"}`;
|
|
106
|
+
console.log(` ${flag.name} ${flag.description ?? ""} (${lifecycle}${finalValue}) [orgs=${orgCount}]`);
|
|
85
107
|
}
|
|
86
108
|
}
|
|
87
109
|
async function handleCreate(argv, apiUrl, token) {
|
|
@@ -171,23 +193,84 @@ async function handleDisable(argv, apiUrl, token) {
|
|
|
171
193
|
}
|
|
172
194
|
console.log(`Disabled ${name} for org ${orgId}`);
|
|
173
195
|
}
|
|
196
|
+
async function handleLifecycle(argv, apiUrl, token) {
|
|
197
|
+
const name = argv[0];
|
|
198
|
+
if (!name || name.startsWith("--")) {
|
|
199
|
+
console.error("Error: Missing flag name.");
|
|
200
|
+
console.error(
|
|
201
|
+
"Usage: canary feature-flag lifecycle <name> --stage <active|deprecated|ready_for_cleanup> [--final-value true|false]"
|
|
202
|
+
);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
const stage = parseLifecycleStage(argv);
|
|
206
|
+
const rawFinalValue = getArgValue(argv, "--final-value");
|
|
207
|
+
const clearFinalValue = hasFlag(argv, "--clear-final-value");
|
|
208
|
+
if (rawFinalValue !== void 0 && clearFinalValue) {
|
|
209
|
+
console.error("Error: use either --final-value or --clear-final-value, not both.");
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
let finalValue = void 0;
|
|
213
|
+
if (stage === "active") {
|
|
214
|
+
if (rawFinalValue !== void 0) {
|
|
215
|
+
console.error("Error: active stage does not accept --final-value.");
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
finalValue = void 0;
|
|
219
|
+
} else {
|
|
220
|
+
if (clearFinalValue) {
|
|
221
|
+
console.error("Error: --clear-final-value can only be used with --stage active.");
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
if (!rawFinalValue) {
|
|
225
|
+
console.error("Error: --final-value true|false is required for deprecated or ready_for_cleanup.");
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
if (rawFinalValue !== "true" && rawFinalValue !== "false") {
|
|
229
|
+
console.error("Error: --final-value must be true or false.");
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
finalValue = rawFinalValue === "true";
|
|
233
|
+
}
|
|
234
|
+
const result = await apiRequest(
|
|
235
|
+
apiUrl,
|
|
236
|
+
token,
|
|
237
|
+
"POST",
|
|
238
|
+
`/superadmin/feature-flags/${encodeURIComponent(name)}/lifecycle`,
|
|
239
|
+
{
|
|
240
|
+
stage,
|
|
241
|
+
finalValue
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
if (!result.ok || !result.flag) {
|
|
245
|
+
console.error(`Error: ${result.error ?? "Failed to update lifecycle"}`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
const final = result.flag.lifecycleStage === "active" ? "(none)" : result.flag.finalValue === true ? "true" : "false";
|
|
249
|
+
console.log(`Updated lifecycle for ${name}: stage=${toLifecycleLabel(result.flag.lifecycleStage)}, final=${final}`);
|
|
250
|
+
}
|
|
174
251
|
function printFeatureFlagHelp() {
|
|
175
252
|
console.log(
|
|
176
253
|
[
|
|
177
254
|
"Usage: canary feature-flag <sub-command> [options]",
|
|
178
255
|
"",
|
|
179
256
|
"Sub-commands:",
|
|
180
|
-
" list
|
|
181
|
-
" create <name> [--description <text>]
|
|
182
|
-
" delete <name>
|
|
183
|
-
" enable <name> --org <orgId>
|
|
184
|
-
" disable <name> --org <orgId>
|
|
257
|
+
" list List all feature flags",
|
|
258
|
+
" create <name> [--description <text>] Create a new flag",
|
|
259
|
+
" delete <name> Delete a flag and all its gates",
|
|
260
|
+
" enable <name> --org <orgId> Enable a flag for an organization",
|
|
261
|
+
" disable <name> --org <orgId> Disable a flag for an organization",
|
|
262
|
+
" lifecycle <name> --stage <stage> [--final-value true|false]",
|
|
263
|
+
" Mark lifecycle + final value",
|
|
264
|
+
"",
|
|
265
|
+
"Stages: active, deprecated, ready_for_cleanup",
|
|
185
266
|
"",
|
|
186
267
|
"Options:",
|
|
187
|
-
" --
|
|
188
|
-
" --
|
|
189
|
-
" --
|
|
190
|
-
" --
|
|
268
|
+
" --final-value <true|false> Final value for deprecated/ready_for_cleanup",
|
|
269
|
+
" --clear-final-value Clear final value (only valid with --stage active)",
|
|
270
|
+
" --env <env> Target environment (prod, dev, local)",
|
|
271
|
+
" --json Output as JSON (list only)",
|
|
272
|
+
" --api-url <url> API URL override (takes precedence over --env)",
|
|
273
|
+
" --token <key> API token override"
|
|
191
274
|
].join("\n")
|
|
192
275
|
);
|
|
193
276
|
}
|
|
@@ -214,6 +297,9 @@ async function runFeatureFlag(argv) {
|
|
|
214
297
|
case "disable":
|
|
215
298
|
await handleDisable(rest, apiUrl, token);
|
|
216
299
|
break;
|
|
300
|
+
case "lifecycle":
|
|
301
|
+
await handleLifecycle(rest, apiUrl, token);
|
|
302
|
+
break;
|
|
217
303
|
default:
|
|
218
304
|
console.error(`Unknown sub-command: ${subCommand}`);
|
|
219
305
|
printFeatureFlagHelp();
|
|
@@ -223,4 +309,4 @@ async function runFeatureFlag(argv) {
|
|
|
223
309
|
export {
|
|
224
310
|
runFeatureFlag
|
|
225
311
|
};
|
|
226
|
-
//# sourceMappingURL=feature-flag-
|
|
312
|
+
//# sourceMappingURL=feature-flag-ESPSOSKG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/feature-flag.ts"],"sourcesContent":["/**\n * CLI Feature Flag Management\n *\n * Allows superadmins to manage feature flags via the CLI.\n */\n\nimport process from \"node:process\";\nimport { readStoredToken, readStoredApiUrl } from \"./auth.js\";\n\nconst ENV_URLS: Record<string, string> = {\n prod: \"https://api.trycanary.ai\",\n production: \"https://api.trycanary.ai\",\n dev: \"https://api.dev.trycanary.ai\",\n local: \"http://localhost:3000\",\n};\n\ntype LifecycleStage = \"active\" | \"deprecated\" | \"ready_for_cleanup\";\n\ntype FeatureFlag = {\n id: string;\n name: string;\n description: string | null;\n lifecycleStage: LifecycleStage;\n finalValue: boolean | null;\n createdAt: string;\n organizations?: Array<{\n gateId: string;\n orgId: string;\n orgName: string;\n createdAt: string;\n }>;\n};\n\ntype FeatureFlagListResponse = {\n ok: boolean;\n flags?: FeatureFlag[];\n error?: string;\n};\n\ntype ApiResponse = {\n ok: boolean;\n error?: string;\n flag?: FeatureFlag;\n};\n\nfunction getArgValue(argv: string[], key: string): string | undefined {\n const index = argv.indexOf(key);\n if (index === -1 || index >= argv.length - 1) return undefined;\n return argv[index + 1];\n}\n\nfunction hasFlag(argv: string[], ...flags: string[]): boolean {\n return flags.some((flag) => argv.includes(flag));\n}\n\nfunction toLifecycleLabel(stage: LifecycleStage): string {\n switch (stage) {\n case \"deprecated\":\n return \"deprecated\";\n case \"ready_for_cleanup\":\n return \"ready_for_cleanup\";\n default:\n return \"active\";\n }\n}\n\nfunction parseLifecycleStage(argv: string[]): LifecycleStage {\n const stage = getArgValue(argv, \"--stage\");\n if (!stage || ![\"active\", \"deprecated\", \"ready_for_cleanup\"].includes(stage)) {\n console.error(\"Error: --stage is required and must be one of: active, deprecated, ready_for_cleanup\");\n process.exit(1);\n }\n return stage as LifecycleStage;\n}\n\nasync function resolveConfig(argv: string[]) {\n const storedApiUrl = await readStoredApiUrl();\n const env = getArgValue(argv, \"--env\");\n\n if (env && !ENV_URLS[env]) {\n console.error(`Unknown environment: ${env}`);\n console.error(\"Valid environments: prod, dev, local\");\n process.exit(1);\n }\n\n const apiUrl =\n getArgValue(argv, \"--api-url\") ??\n (env ? ENV_URLS[env] : undefined) ??\n process.env.CANARY_API_URL ??\n storedApiUrl ??\n \"https://api.trycanary.ai\";\n\n const token =\n getArgValue(argv, \"--token\") ?? process.env.CANARY_API_TOKEN ?? (await readStoredToken());\n\n if (!token) {\n console.error(\"Error: No API token found.\");\n console.error(\"Run: canary login\");\n process.exit(1);\n }\n\n return { apiUrl, token };\n}\n\nasync function apiRequest(\n apiUrl: string,\n token: string,\n method: string,\n path: string,\n body?: Record<string, unknown>\n): Promise<ApiResponse> {\n const res = await fetch(`${apiUrl}${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Your session may have expired.\");\n console.error(\"Run: canary login\");\n process.exit(1);\n }\n\n const json = (await res.json()) as ApiResponse;\n return json;\n}\n\nasync function fetchFlags(apiUrl: string, token: string): Promise<FeatureFlag[]> {\n const res = await fetch(`${apiUrl}/superadmin/feature-flags`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Your session may have expired.\");\n console.error(\"Run: canary login\");\n process.exit(1);\n }\n\n const json = (await res.json()) as FeatureFlagListResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n return json.flags ?? [];\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, \"--json\");\n const flags = await fetchFlags(apiUrl, token);\n\n if (jsonOutput) {\n console.log(JSON.stringify(flags, null, 2));\n return;\n }\n\n if (flags.length === 0) {\n console.log(\"No feature flags found.\");\n return;\n }\n\n for (const flag of flags) {\n const orgCount = flag.organizations?.length ?? 0;\n const lifecycle = `lifecycle=${toLifecycleLabel(flag.lifecycleStage)}`;\n const finalValue =\n flag.lifecycleStage === \"active\" ? \"\" : ` final=${flag.finalValue === true ? \"true\" : \"false\"}`;\n console.log(` ${flag.name} ${flag.description ?? \"\"} (${lifecycle}${finalValue}) [orgs=${orgCount}]`);\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag create <name> [--description <text>]\");\n process.exit(1);\n }\n\n const description = getArgValue(argv, \"--description\") ?? null;\n const result = await apiRequest(apiUrl, token, \"POST\", \"/superadmin/feature-flags\", {\n name,\n description,\n });\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Created feature flag: ${name}`);\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag delete <name>\");\n process.exit(1);\n }\n\n const result = await apiRequest(\n apiUrl,\n token,\n \"DELETE\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted feature flag: ${name}`);\n}\n\nasync function handleEnable(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n const orgId = getArgValue(argv, \"--org\");\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag enable <name> --org <orgId>\");\n process.exit(1);\n }\n\n if (!orgId) {\n console.error(\"Error: Missing --org <orgId>.\");\n console.error(\"Usage: canary feature-flag enable <name> --org <orgId>\");\n process.exit(1);\n }\n\n const result = await apiRequest(\n apiUrl,\n token,\n \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/organizations/${encodeURIComponent(orgId)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Enabled ${name} for org ${orgId}`);\n}\n\nasync function handleDisable(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n const orgId = getArgValue(argv, \"--org\");\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag disable <name> --org <orgId>\");\n process.exit(1);\n }\n\n if (!orgId) {\n console.error(\"Error: Missing --org <orgId>.\");\n console.error(\"Usage: canary feature-flag disable <name> --org <orgId>\");\n process.exit(1);\n }\n\n const result = await apiRequest(\n apiUrl,\n token,\n \"DELETE\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/organizations/${encodeURIComponent(orgId)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Disabled ${name} for org ${orgId}`);\n}\n\nasync function handleLifecycle(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\n \"Usage: canary feature-flag lifecycle <name> --stage <active|deprecated|ready_for_cleanup> [--final-value true|false]\"\n );\n process.exit(1);\n }\n\n const stage = parseLifecycleStage(argv);\n const rawFinalValue = getArgValue(argv, \"--final-value\");\n const clearFinalValue = hasFlag(argv, \"--clear-final-value\");\n\n if (rawFinalValue !== undefined && clearFinalValue) {\n console.error(\"Error: use either --final-value or --clear-final-value, not both.\");\n process.exit(1);\n }\n\n let finalValue: boolean | undefined = undefined;\n\n if (stage === \"active\") {\n if (rawFinalValue !== undefined) {\n console.error(\"Error: active stage does not accept --final-value.\");\n process.exit(1);\n }\n finalValue = undefined;\n } else {\n if (clearFinalValue) {\n console.error(\"Error: --clear-final-value can only be used with --stage active.\");\n process.exit(1);\n }\n if (!rawFinalValue) {\n console.error(\"Error: --final-value true|false is required for deprecated or ready_for_cleanup.\");\n process.exit(1);\n }\n if (rawFinalValue !== \"true\" && rawFinalValue !== \"false\") {\n console.error(\"Error: --final-value must be true or false.\");\n process.exit(1);\n }\n finalValue = rawFinalValue === \"true\";\n }\n\n const result = await apiRequest(\n apiUrl,\n token,\n \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/lifecycle`,\n {\n stage,\n finalValue,\n }\n );\n\n if (!result.ok || !result.flag) {\n console.error(`Error: ${result.error ?? \"Failed to update lifecycle\"}`);\n process.exit(1);\n }\n\n const final =\n result.flag.lifecycleStage === \"active\"\n ? \"(none)\"\n : result.flag.finalValue === true\n ? \"true\"\n : \"false\";\n console.log(`Updated lifecycle for ${name}: stage=${toLifecycleLabel(result.flag.lifecycleStage)}, final=${final}`);\n}\n\nfunction printFeatureFlagHelp(): void {\n console.log(\n [\n \"Usage: canary feature-flag <sub-command> [options]\",\n \"\",\n \"Sub-commands:\",\n \" list List all feature flags\",\n \" create <name> [--description <text>] Create a new flag\",\n \" delete <name> Delete a flag and all its gates\",\n \" enable <name> --org <orgId> Enable a flag for an organization\",\n \" disable <name> --org <orgId> Disable a flag for an organization\",\n \" lifecycle <name> --stage <stage> [--final-value true|false]\",\n \" Mark lifecycle + final value\",\n \"\",\n \"Stages: active, deprecated, ready_for_cleanup\",\n \"\",\n \"Options:\",\n \" --final-value <true|false> Final value for deprecated/ready_for_cleanup\",\n \" --clear-final-value Clear final value (only valid with --stage active)\",\n \" --env <env> Target environment (prod, dev, local)\",\n \" --json Output as JSON (list only)\",\n \" --api-url <url> API URL override (takes precedence over --env)\",\n \" --token <key> API token override\",\n ].join(\"\\n\")\n );\n}\n\nexport async function runFeatureFlag(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === \"help\" || hasFlag(argv, \"--help\", \"-h\")) {\n printFeatureFlagHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n switch (subCommand) {\n case \"list\":\n await handleList(rest, apiUrl, token);\n break;\n case \"create\":\n await handleCreate(rest, apiUrl, token);\n break;\n case \"delete\":\n await handleDelete(rest, apiUrl, token);\n break;\n case \"enable\":\n await handleEnable(rest, apiUrl, token);\n break;\n case \"disable\":\n await handleDisable(rest, apiUrl, token);\n break;\n case \"lifecycle\":\n await handleLifecycle(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printFeatureFlagHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -1002,6 +1002,9 @@ function printHelp({ isSuperadmin }) {
|
|
|
1002
1002
|
" canary login [--org <name>] [--app-url https://app.trycanary.ai] [--no-open]",
|
|
1003
1003
|
" canary orgs List organizations"
|
|
1004
1004
|
];
|
|
1005
|
+
lines.push(
|
|
1006
|
+
" canary release <sub-command> Release QA gate (CI/CD)"
|
|
1007
|
+
);
|
|
1005
1008
|
if (isSuperadmin) {
|
|
1006
1009
|
lines.push(
|
|
1007
1010
|
" canary debug-session [--env dev|local] [--json] Create browser debug session",
|
|
@@ -1040,6 +1043,13 @@ function printHelp({ isSuperadmin }) {
|
|
|
1040
1043
|
" Or set CANARY_API_URL env var for non-production environments:",
|
|
1041
1044
|
" export CANARY_API_URL=http://localhost:3000"
|
|
1042
1045
|
);
|
|
1046
|
+
lines.push(
|
|
1047
|
+
"",
|
|
1048
|
+
"Release sub-commands:",
|
|
1049
|
+
" trigger --property-id <uuid> Trigger a Release QA run",
|
|
1050
|
+
" status <run-id> [--json] Check run status",
|
|
1051
|
+
" run --property-id <uuid> [--timeout N] Trigger and poll until complete"
|
|
1052
|
+
);
|
|
1043
1053
|
if (isSuperadmin) {
|
|
1044
1054
|
lines.push(
|
|
1045
1055
|
"",
|
|
@@ -1056,13 +1066,17 @@ function printHelp({ isSuperadmin }) {
|
|
|
1056
1066
|
" delete <name> Delete a flag and its gates",
|
|
1057
1067
|
" enable <name> --org <orgId> Enable for an org",
|
|
1058
1068
|
" disable <name> --org <orgId> Disable for an org",
|
|
1069
|
+
" lifecycle <name> --stage <stage> [--final-value true|false]",
|
|
1070
|
+
" Set lifecycle metadata",
|
|
1059
1071
|
"",
|
|
1060
1072
|
"Knobs sub-commands:",
|
|
1061
1073
|
" list List all knobs",
|
|
1062
1074
|
" get <key> Get a knob value",
|
|
1063
1075
|
" set <key> <value> --type <type> Set a knob value",
|
|
1064
1076
|
" delete <key> Delete a knob",
|
|
1065
|
-
" toggle <key> Toggle a boolean knob"
|
|
1077
|
+
" toggle <key> Toggle a boolean knob",
|
|
1078
|
+
" lifecycle <key> --stage <stage> [--final-value <value>]",
|
|
1079
|
+
" Set lifecycle metadata"
|
|
1066
1080
|
);
|
|
1067
1081
|
}
|
|
1068
1082
|
lines.push(
|
|
@@ -1190,13 +1204,18 @@ async function main(argv) {
|
|
|
1190
1204
|
await runRedis(rest);
|
|
1191
1205
|
return;
|
|
1192
1206
|
}
|
|
1207
|
+
if (command === "release") {
|
|
1208
|
+
const { runRelease } = await import("./release-WOD3DAX4.js");
|
|
1209
|
+
await runRelease(rest);
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1193
1212
|
if (command === "feature-flag") {
|
|
1194
|
-
const { runFeatureFlag } = await import("./feature-flag-
|
|
1213
|
+
const { runFeatureFlag } = await import("./feature-flag-ESPSOSKG.js");
|
|
1195
1214
|
await runFeatureFlag(rest);
|
|
1196
1215
|
return;
|
|
1197
1216
|
}
|
|
1198
1217
|
if (command === "knobs") {
|
|
1199
|
-
const { runKnobs } = await import("./knobs-
|
|
1218
|
+
const { runKnobs } = await import("./knobs-HKONHY55.js");
|
|
1200
1219
|
await runKnobs(rest);
|
|
1201
1220
|
return;
|
|
1202
1221
|
}
|