@groundfloorcloud/cli 0.2.0 → 0.2.1
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/README.md +1 -1
- package/dist/index.js +72 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -180,7 +180,7 @@ wrong identity for testing Coderunner Vault/Files as the workload.
|
|
|
180
180
|
| `--app-id <uuid>` | Bind a **new** coderunner to an App as a helper. Ignored on reuse. |
|
|
181
181
|
| `--secret <NAME>` | Inject a workspace secret (repeatable). Only works where the platform has injection enabled; prefer runtime reads via M2M `secrets:read`. |
|
|
182
182
|
| `--api-url <url>` | Control Plane base URL override. |
|
|
183
|
-
| `-y, --yes` | Skip the reuse confirmation (required without a terminal). |
|
|
183
|
+
| `-y, --yes` | Skip the reuse confirmation (required without a terminal) and the prompt shown with `-c` when the deploy would drop previously deployed env variables (key names only; values are not stored). |
|
|
184
184
|
| `-p, --path <dir>` | Directory to package (default: cwd). |
|
|
185
185
|
| `--git <url>` / `--ref <ref>` | Clone and deploy a remote repo. |
|
|
186
186
|
| `--subdir <dir>` | Package a subdirectory of the source. |
|
package/dist/index.js
CHANGED
|
@@ -752,6 +752,26 @@ async function getDeployment(apiUrl, workspaceId, coderunnerId) {
|
|
|
752
752
|
}
|
|
753
753
|
return await res.json();
|
|
754
754
|
}
|
|
755
|
+
async function getDeploymentById(apiUrl, workspaceId, coderunnerId, deploymentId) {
|
|
756
|
+
const token = await getValidAccessToken();
|
|
757
|
+
const res = await fetch(
|
|
758
|
+
`${apiUrl}/v1/workspaces/${encodeURIComponent(
|
|
759
|
+
workspaceId
|
|
760
|
+
)}/coderunners/${encodeURIComponent(
|
|
761
|
+
coderunnerId
|
|
762
|
+
)}/deployments/${encodeURIComponent(deploymentId)}`,
|
|
763
|
+
{
|
|
764
|
+
headers: {
|
|
765
|
+
Authorization: `Bearer ${token}`,
|
|
766
|
+
Accept: "application/json"
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
);
|
|
770
|
+
if (!res.ok) {
|
|
771
|
+
throw new CpError(res.status, await parseError(res));
|
|
772
|
+
}
|
|
773
|
+
return await res.json();
|
|
774
|
+
}
|
|
755
775
|
function deleteCoderunnerDeployment(apiUrl, workspaceId, coderunnerId, deploymentId) {
|
|
756
776
|
return cpDelete(
|
|
757
777
|
apiUrl,
|
|
@@ -2041,9 +2061,12 @@ function priorEnvKeys(coderunner2) {
|
|
|
2041
2061
|
const keys = manifest?.coderunner?.deploy?.env_keys;
|
|
2042
2062
|
return Array.isArray(keys) ? keys.map(String) : [];
|
|
2043
2063
|
}
|
|
2044
|
-
function
|
|
2064
|
+
function envKeysNotResent(priorKeys, sentKeys) {
|
|
2045
2065
|
const sent = new Set(sentKeys);
|
|
2046
|
-
|
|
2066
|
+
return priorKeys.filter((k) => !sent.has(k)).sort();
|
|
2067
|
+
}
|
|
2068
|
+
function envRedeployWarning(priorKeys, sentKeys) {
|
|
2069
|
+
const missing = envKeysNotResent(priorKeys, sentKeys);
|
|
2047
2070
|
const base = 'Environment variable VALUES are not stored by Groundfloor: every deploy must resend them with -e KEY=VALUE or groundfloor.json "env".';
|
|
2048
2071
|
if (priorKeys.length > 0) {
|
|
2049
2072
|
if (missing.length === 0) return [];
|
|
@@ -2076,6 +2099,7 @@ var VERSION_POLL_INTERVAL_MS = 2e3;
|
|
|
2076
2099
|
var VERSION_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2077
2100
|
var DEPLOY_POLL_INTERVAL_MS = 2e3;
|
|
2078
2101
|
var DEPLOY_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2102
|
+
var DEPLOY_TERMINAL_FAILURE = /* @__PURE__ */ new Set([4, 5, 6]);
|
|
2079
2103
|
function slugify(input) {
|
|
2080
2104
|
const slug = input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2081
2105
|
return slug || "app";
|
|
@@ -2235,19 +2259,30 @@ async function deployCommand(opts) {
|
|
|
2235
2259
|
const injectSecretKeys = (opts.secret ?? []).map((key) => key.trim()).filter(Boolean);
|
|
2236
2260
|
let coderunnerId = opts.coderunner;
|
|
2237
2261
|
if (coderunnerId && !opts.skipDeploy) {
|
|
2262
|
+
let known;
|
|
2238
2263
|
try {
|
|
2239
|
-
|
|
2264
|
+
known = (await listCoderunners(cfg.apiUrl, ws)).find(
|
|
2240
2265
|
(c) => c.id === coderunnerId
|
|
2241
2266
|
);
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2267
|
+
} catch {
|
|
2268
|
+
}
|
|
2269
|
+
if (known) {
|
|
2270
|
+
const prior = priorEnvKeys(known);
|
|
2271
|
+
const sentKeys = Object.keys(envVariable);
|
|
2272
|
+
const warning = envRedeployWarning(prior, sentKeys);
|
|
2273
|
+
if (envKeysNotResent(prior, sentKeys).length > 0) {
|
|
2274
|
+
if (io.isTTY && !opts.yes) {
|
|
2275
|
+
await confirmAction({
|
|
2276
|
+
summary: warning,
|
|
2277
|
+
question: "Deploy anyway and clear these variables?",
|
|
2278
|
+
io
|
|
2279
|
+
});
|
|
2280
|
+
} else {
|
|
2281
|
+
for (const line of warning) log(line);
|
|
2248
2282
|
}
|
|
2283
|
+
} else {
|
|
2284
|
+
for (const line of warning) log(line);
|
|
2249
2285
|
}
|
|
2250
|
-
} catch {
|
|
2251
2286
|
}
|
|
2252
2287
|
}
|
|
2253
2288
|
if (opts.appId && coderunnerId) {
|
|
@@ -2400,24 +2435,43 @@ async function deployCommand(opts) {
|
|
|
2400
2435
|
throw err;
|
|
2401
2436
|
}
|
|
2402
2437
|
log("Waiting for deployment...");
|
|
2438
|
+
const newDeploymentId = result.deployment_id || void 0;
|
|
2439
|
+
const readNewDeployment = async () => {
|
|
2440
|
+
if (newDeploymentId) {
|
|
2441
|
+
try {
|
|
2442
|
+
return await getDeploymentById(
|
|
2443
|
+
cfg.apiUrl,
|
|
2444
|
+
ws,
|
|
2445
|
+
coderunnerId,
|
|
2446
|
+
newDeploymentId
|
|
2447
|
+
);
|
|
2448
|
+
} catch (err) {
|
|
2449
|
+
if (err instanceof CpError && err.status === 404) return null;
|
|
2450
|
+
throw err;
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
const current = await getDeployment(cfg.apiUrl, ws, coderunnerId);
|
|
2454
|
+
return current?.version_id === uploaded.version_id ? current : null;
|
|
2455
|
+
};
|
|
2403
2456
|
const deployDeadline = Date.now() + DEPLOY_POLL_TIMEOUT_MS;
|
|
2404
2457
|
let deployOk = false;
|
|
2405
2458
|
while (Date.now() < deployDeadline) {
|
|
2406
|
-
const deployment = await
|
|
2459
|
+
const deployment = await readNewDeployment();
|
|
2407
2460
|
const dStatus = deployment?.status ?? 0;
|
|
2408
2461
|
if (dStatus === 3) {
|
|
2409
2462
|
deployOk = true;
|
|
2410
2463
|
break;
|
|
2411
2464
|
}
|
|
2412
|
-
if (dStatus
|
|
2465
|
+
if (DEPLOY_TERMINAL_FAILURE.has(dStatus)) {
|
|
2466
|
+
process.stderr.write("\n");
|
|
2413
2467
|
return await failDeploy({
|
|
2414
2468
|
apiUrl: cfg.apiUrl,
|
|
2415
2469
|
workspaceId: ws,
|
|
2416
|
-
headline: `Deployment failed for coderunner ${coderunnerId} (${statusLabel(
|
|
2470
|
+
headline: `Deployment failed for coderunner ${coderunnerId} (${statusLabel(dStatus)}).`,
|
|
2417
2471
|
coderunnerId,
|
|
2418
2472
|
versionId: uploaded.version_id,
|
|
2419
|
-
deploymentId:
|
|
2420
|
-
status:
|
|
2473
|
+
deploymentId: newDeploymentId ?? deployment?.id,
|
|
2474
|
+
status: dStatus
|
|
2421
2475
|
});
|
|
2422
2476
|
}
|
|
2423
2477
|
process.stderr.write(".");
|
|
@@ -2426,9 +2480,9 @@ async function deployCommand(opts) {
|
|
|
2426
2480
|
process.stderr.write("\n");
|
|
2427
2481
|
if (!deployOk) {
|
|
2428
2482
|
let lastStatus = null;
|
|
2429
|
-
let deploymentId =
|
|
2483
|
+
let deploymentId = newDeploymentId;
|
|
2430
2484
|
try {
|
|
2431
|
-
const latest = await
|
|
2485
|
+
const latest = await readNewDeployment();
|
|
2432
2486
|
lastStatus = latest?.status ?? null;
|
|
2433
2487
|
deploymentId = latest?.id ?? deploymentId;
|
|
2434
2488
|
} catch {
|
|
@@ -4164,7 +4218,7 @@ program.command("deploy").description(
|
|
|
4164
4218
|
[]
|
|
4165
4219
|
).option(
|
|
4166
4220
|
"-y, --yes",
|
|
4167
|
-
"Confirm updating an existing same-named coderunner (required with no interactive terminal). Does not bypass the saved-default-workspace check: pass -w"
|
|
4221
|
+
"Confirm updating an existing same-named coderunner (required with no interactive terminal), and skip the prompt about previously deployed env variables that this deploy does not resend (-c). Does not bypass the saved-default-workspace check: pass -w"
|
|
4168
4222
|
).option("-m, --message <text>", "Version description").option("--skip-deploy", "Upload a new version but do not deploy it").action((opts) => run(() => deployCommand(opts)));
|
|
4169
4223
|
program.command("usage").description(
|
|
4170
4224
|
"Show account quota/usage and the billing estimate (read-only). The account is the billing parent of the workspace, not the workspace itself"
|
package/package.json
CHANGED