@envsync-cloud/deploy-cli 0.6.5 → 0.6.6

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.
Files changed (3) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +39 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -40,7 +40,7 @@ bunx @envsync-cloud/deploy-cli <command>
40
40
  ```text
41
41
  envsync-deploy preinstall
42
42
  envsync-deploy setup
43
- envsync-deploy bootstrap [--dry-run]
43
+ envsync-deploy bootstrap [--dry-run] [--force]
44
44
  envsync-deploy deploy [--dry-run]
45
45
  envsync-deploy health [--json]
46
46
  envsync-deploy upgrade [--dry-run]
@@ -71,7 +71,7 @@ Bootstrap infra, migrations, RustFS, and OpenFGA:
71
71
  npx @envsync-cloud/deploy-cli bootstrap
72
72
  ```
73
73
 
74
- `bootstrap` is destructive. It removes the existing EnvSync stack, matching containers, network, and managed volumes before rebuilding, and requires typing `ARE YOU SURE?` to continue.
74
+ `bootstrap` is destructive. It removes the existing EnvSync stack, matching containers, network, and managed volumes before rebuilding, and requires typing `yes` to continue. Use `--force` to bypass the prompt in automation or other non-interactive environments.
75
75
 
76
76
  Deploy the pending API and frontend services:
77
77
 
@@ -106,6 +106,7 @@ Preview mutating commands without changing the host:
106
106
 
107
107
  ```bash
108
108
  npx @envsync-cloud/deploy-cli bootstrap --dry-run
109
+ npx @envsync-cloud/deploy-cli bootstrap --force
109
110
  npx @envsync-cloud/deploy-cli deploy --dry-run
110
111
  ```
111
112
 
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ var REQUIRED_BOOTSTRAP_ENV_KEYS = [
48
48
  "OPENFGA_MODEL_ID"
49
49
  ];
50
50
  var SEMVER_VERSION_RE = /^\d+\.\d+\.\d+$/;
51
- var currentOptions = { dryRun: false };
51
+ var currentOptions = { dryRun: false, force: false };
52
52
  function formatShellArg(arg) {
53
53
  if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(arg)) return arg;
54
54
  return JSON.stringify(arg);
@@ -221,7 +221,7 @@ async function ask(question, fallback = "") {
221
221
  }
222
222
  async function askRequired(question) {
223
223
  if (!process.stdin.isTTY) {
224
- throw new Error(`${question} confirmation requires an interactive terminal.`);
224
+ throw new Error("Bootstrap confirmation requires an interactive terminal. Re-run with --force to bypass the prompt.");
225
225
  }
226
226
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
227
227
  return await new Promise((resolve) => {
@@ -1090,7 +1090,29 @@ function waitForTcpService(config, label, host, port, timeoutSeconds = 120) {
1090
1090
  throw new Error(`Timed out waiting for ${label} at ${host}:${port}`);
1091
1091
  }
1092
1092
  function waitForHttpService(config, label, url, timeoutSeconds = 120) {
1093
- waitForCommand(config, `${label} HTTP readiness`, "alpine:3.20", `wget -q -O /dev/null ${JSON.stringify(url)}`, timeoutSeconds);
1093
+ if (currentOptions.dryRun) {
1094
+ logDryRun(`Would wait for ${label} at ${url}`);
1095
+ return;
1096
+ }
1097
+ logStep(`Waiting for ${label} on ${url}`);
1098
+ const deadline = Date.now() + timeoutSeconds * 1e3;
1099
+ while (Date.now() < deadline) {
1100
+ if (commandSucceeds("docker", [
1101
+ "run",
1102
+ "--rm",
1103
+ "--network",
1104
+ stackNetworkName(config),
1105
+ "alpine:3.20",
1106
+ "sh",
1107
+ "-lc",
1108
+ `wget -q -O /dev/null ${JSON.stringify(url)}`
1109
+ ])) {
1110
+ logSuccess(`${label} is ready`);
1111
+ return;
1112
+ }
1113
+ sleepSeconds(2);
1114
+ }
1115
+ throw new Error(`Timed out waiting for ${label} at ${url}`);
1094
1116
  }
1095
1117
  function runOpenFgaMigrate(config, runtimeEnv) {
1096
1118
  logStep("Running OpenFGA datastore migrations");
@@ -1307,9 +1329,14 @@ async function confirmBootstrapReset(config) {
1307
1329
  logWarn("Containers: none currently matched");
1308
1330
  }
1309
1331
  logWarn("This removes existing deployment data for the managed EnvSync services.");
1310
- const response = await askRequired(chalk.bold.red('Type "ARE YOU SURE?" to continue:'));
1311
- if (response !== "ARE YOU SURE?") {
1312
- throw new Error("Bootstrap aborted. Confirmation did not match 'ARE YOU SURE?'.");
1332
+ if (currentOptions.force) {
1333
+ logWarn("Skipping confirmation because --force was provided.");
1334
+ logSuccess("Destructive bootstrap reset confirmed");
1335
+ return;
1336
+ }
1337
+ const response = await askRequired(chalk.bold.red('Type "yes" to continue:'));
1338
+ if (response !== "yes") {
1339
+ throw new Error("Bootstrap aborted. Confirmation did not match 'yes'.");
1313
1340
  }
1314
1341
  logSuccess("Destructive bootstrap reset confirmed");
1315
1342
  }
@@ -1480,9 +1507,8 @@ async function cmdBootstrap() {
1480
1507
  assertSwarmManager();
1481
1508
  if (currentOptions.dryRun) {
1482
1509
  logWarn("Dry-run mode: bootstrap reset will be previewed but not executed.");
1483
- } else {
1484
- await confirmBootstrapReset(config);
1485
1510
  }
1511
+ await confirmBootstrapReset(config);
1486
1512
  cleanupBootstrapState(config);
1487
1513
  ensureRepoCheckout(config);
1488
1514
  writeDeployArtifacts(config, nextGenerated);
@@ -1513,7 +1539,7 @@ async function cmdBootstrap() {
1513
1539
  run("docker", ["stack", "deploy", "-c", BOOTSTRAP_STACK_FILE, config.services.stack_name]);
1514
1540
  logSuccess("Runtime bootstrap stack deployed");
1515
1541
  }
1516
- waitForHttpService(config, "keycloak", "http://keycloak:8080/health/ready", 180);
1542
+ waitForHttpService(config, "keycloak management readiness", "http://keycloak:9000/health/ready", 180);
1517
1543
  waitForHttpService(config, "openfga", "http://openfga:8090/stores");
1518
1544
  waitForTcpService(config, "minikms", "minikms", 50051);
1519
1545
  const initResult = runBootstrapInit(config);
@@ -1770,9 +1796,10 @@ async function main() {
1770
1796
  const command = argv[0];
1771
1797
  const args = argv.slice(1);
1772
1798
  currentOptions = {
1773
- dryRun: args.includes("--dry-run")
1799
+ dryRun: args.includes("--dry-run"),
1800
+ force: args.includes("--force")
1774
1801
  };
1775
- const positionals = args.filter((arg) => arg !== "--dry-run");
1802
+ const positionals = args.filter((arg) => arg !== "--dry-run" && arg !== "--force");
1776
1803
  switch (command) {
1777
1804
  case "preinstall":
1778
1805
  await cmdPreinstall();
@@ -1803,7 +1830,7 @@ async function main() {
1803
1830
  break;
1804
1831
  default:
1805
1832
  console.log(
1806
- "Usage: envsync-deploy <preinstall|setup|bootstrap|deploy|health|upgrade|upgrade-deps|backup|restore> [--dry-run]"
1833
+ "Usage: envsync-deploy <preinstall|setup|bootstrap|deploy|health|upgrade|upgrade-deps|backup|restore> [--dry-run] [--force]"
1807
1834
  );
1808
1835
  process.exit(command ? 1 : 0);
1809
1836
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envsync-cloud/deploy-cli",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "CLI for self-hosted EnvSync deployment on Docker Swarm",
5
5
  "type": "module",
6
6
  "bin": {