@launchmatic/cli 0.7.0 → 0.7.2

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 (2) hide show
  1. package/dist/index.js +129 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -21963,13 +21963,16 @@ function discoverServices(repoRoot = findRepoRoot()) {
21963
21963
  for (const absDir of dirs) {
21964
21964
  if (!isLikelyDeployable(absDir)) continue;
21965
21965
  const detection = detectLocal(absDir);
21966
+ const rootDir = toPosix(relative(repoRoot, absDir));
21967
+ const dockerfile = existsSync3(join2(absDir, "Dockerfile")) ? `${rootDir}/Dockerfile` : void 0;
21966
21968
  out.push({
21967
21969
  name: deriveName(repoRoot, absDir),
21968
- rootDir: toPosix(relative(repoRoot, absDir)),
21970
+ rootDir,
21969
21971
  framework: detection.framework,
21970
21972
  buildCmd: detection.buildCmd,
21971
21973
  startCmd: detection.startCmd,
21972
- port: detection.port
21974
+ port: detection.port,
21975
+ ...dockerfile ? { dockerfile } : {}
21973
21976
  });
21974
21977
  }
21975
21978
  out.sort((a, b) => a.rootDir.localeCompare(b.rootDir));
@@ -26221,6 +26224,74 @@ function prompt6(question) {
26221
26224
  });
26222
26225
  });
26223
26226
  }
26227
+ function parseIndices(spec, max) {
26228
+ const out = /* @__PURE__ */ new Set();
26229
+ for (const token of spec.split(",").map((s) => s.trim()).filter(Boolean)) {
26230
+ const range = token.match(/^(\d+)-(\d+)$/);
26231
+ if (range) {
26232
+ const lo = parseInt(range[1], 10) - 1;
26233
+ const hi = parseInt(range[2], 10) - 1;
26234
+ if (lo >= 0 && hi < max && lo <= hi) {
26235
+ for (let i = lo; i <= hi; i++) out.add(i);
26236
+ }
26237
+ continue;
26238
+ }
26239
+ const n = parseInt(token, 10);
26240
+ if (Number.isFinite(n) && n >= 1 && n <= max) out.add(n - 1);
26241
+ }
26242
+ return [...out].sort((a, b) => a - b);
26243
+ }
26244
+ async function reviewList(label, items, render, editable) {
26245
+ if (items.length === 0) return items;
26246
+ let current = [...items];
26247
+ for (let round = 0; round < 5; round++) {
26248
+ console.log();
26249
+ console.log(source_default.bold(`Review ${label}:`));
26250
+ current.forEach((item, i) => {
26251
+ console.log(` ${source_default.dim(String(i + 1).padStart(2))}. ${render(item)}`);
26252
+ });
26253
+ const action = (await prompt6(
26254
+ `Action \u2014 [Enter] accept, [r] remove, [e] edit, [a] add? `
26255
+ )).toLowerCase();
26256
+ if (!action || action === "a" && current.length === items.length) {
26257
+ if (!action) break;
26258
+ }
26259
+ if (action === "r") {
26260
+ const spec = await prompt6("Indices to remove (e.g. 1,3-4): ");
26261
+ const drop = new Set(parseIndices(spec, current.length));
26262
+ if (drop.size > 0) {
26263
+ current = current.filter((_, i) => !drop.has(i));
26264
+ console.log(source_default.dim(`Removed ${drop.size} item${drop.size === 1 ? "" : "s"}.`));
26265
+ }
26266
+ continue;
26267
+ }
26268
+ if (action === "e") {
26269
+ const spec = await prompt6("Indices to edit (e.g. 2): ");
26270
+ const editIdx = parseIndices(spec, current.length);
26271
+ for (const idx of editIdx) {
26272
+ const item = { ...current[idx] };
26273
+ console.log(source_default.dim(`
26274
+ Editing ${render(item)}`));
26275
+ for (const field of editable) {
26276
+ const cur = item[field.key];
26277
+ const display = cur === void 0 || cur === null ? source_default.dim("unset") : source_default.cyan(String(cur));
26278
+ const ans = await prompt6(` ${field.label} [${display}]: `);
26279
+ if (ans) {
26280
+ if (field.numeric) {
26281
+ const n = parseInt(ans, 10);
26282
+ if (Number.isFinite(n)) item[field.key] = n;
26283
+ } else {
26284
+ item[field.key] = ans;
26285
+ }
26286
+ }
26287
+ }
26288
+ current[idx] = item;
26289
+ }
26290
+ continue;
26291
+ }
26292
+ }
26293
+ return current;
26294
+ }
26224
26295
  async function initManifest(opts) {
26225
26296
  if (!requireLogin3()) return;
26226
26297
  const repoRoot = findRepoRoot();
@@ -26232,8 +26303,8 @@ async function initManifest(opts) {
26232
26303
  return;
26233
26304
  }
26234
26305
  const spin = ora("Discovering services and infra...").start();
26235
- const discovered = discoverServices(repoRoot);
26236
- const discoveredInfra = discoverInfra(repoRoot);
26306
+ let discovered = discoverServices(repoRoot);
26307
+ let discoveredInfra = discoverInfra(repoRoot);
26237
26308
  spin.stop();
26238
26309
  if (discovered.length === 0) {
26239
26310
  console.error(source_default.red("No services discovered."));
@@ -26256,6 +26327,43 @@ Discovered ${discoveredInfra.length} infra dependenc${discoveredInfra.length ===
26256
26327
  console.log(` ${source_default.magenta(i.name)} ${source_default.dim(i.engine)}${v}`);
26257
26328
  }
26258
26329
  }
26330
+ if (!opts.yes) {
26331
+ discovered = await reviewList(
26332
+ `services`,
26333
+ discovered,
26334
+ (s) => {
26335
+ const fw = s.framework ? source_default.dim(` [${s.framework}]`) : "";
26336
+ const df = s.dockerfile ? source_default.dim(` Dockerfile=${s.dockerfile}`) : "";
26337
+ return `${source_default.cyan(s.name)} ${source_default.dim(s.rootDir)}${fw}${df}`;
26338
+ },
26339
+ [
26340
+ { key: "name", label: "name" },
26341
+ { key: "rootDir", label: "rootDir" },
26342
+ { key: "dockerfile", label: "dockerfile (path from repo root)" },
26343
+ { key: "framework", label: "framework" },
26344
+ { key: "buildCmd", label: "buildCmd" },
26345
+ { key: "startCmd", label: "startCmd" },
26346
+ { key: "port", label: "port", numeric: true }
26347
+ ]
26348
+ );
26349
+ if (discovered.length === 0) {
26350
+ console.error(source_default.red("All services removed. Nothing to create."));
26351
+ process.exitCode = 1;
26352
+ return;
26353
+ }
26354
+ if (discoveredInfra.length > 0) {
26355
+ discoveredInfra = await reviewList(
26356
+ `infra`,
26357
+ discoveredInfra,
26358
+ (i) => `${source_default.magenta(i.name)} ${source_default.dim(i.engine)}${i.version ? source_default.dim(` ${i.version}`) : ""}`,
26359
+ [
26360
+ { key: "name", label: "name" },
26361
+ { key: "engine", label: "engine (POSTGRESQL/POSTGIS/REDIS/MONGODB/MYSQL)" },
26362
+ { key: "version", label: "version" }
26363
+ ]
26364
+ );
26365
+ }
26366
+ }
26259
26367
  const { data: teams } = await api("/api/teams");
26260
26368
  if (!teams || teams.length === 0) {
26261
26369
  console.error(source_default.red("No teams found on your account."));
@@ -26326,6 +26434,7 @@ Discovered ${discoveredInfra.length} infra dependenc${discoveredInfra.length ===
26326
26434
  if (s.framework) payload.framework = s.framework;
26327
26435
  if (s.buildCmd) payload.buildCmd = s.buildCmd;
26328
26436
  if (s.startCmd) payload.startCmd = s.startCmd;
26437
+ if (s.dockerfile) payload.dockerfilePath = s.dockerfile;
26329
26438
  if (gitInfo.repoOwner && gitInfo.repoName) {
26330
26439
  payload.repoOwner = gitInfo.repoOwner;
26331
26440
  payload.repoName = gitInfo.repoName;
@@ -26353,7 +26462,8 @@ Discovered ${discoveredInfra.length} infra dependenc${discoveredInfra.length ===
26353
26462
  framework: s.framework,
26354
26463
  buildCmd: s.buildCmd,
26355
26464
  startCmd: s.startCmd,
26356
- port: s.port
26465
+ port: s.port,
26466
+ ...s.dockerfile ? { dockerfile: s.dockerfile } : {}
26357
26467
  });
26358
26468
  }
26359
26469
  const infra = [];
@@ -26512,6 +26622,20 @@ async function up(opts) {
26512
26622
  console.log();
26513
26623
  const results = await Promise.allSettled(
26514
26624
  selected.map(async ({ entry }) => {
26625
+ const patch = {};
26626
+ if (entry.dockerfile !== void 0) patch.dockerfilePath = entry.dockerfile || null;
26627
+ if (entry.rootDir) patch.rootDir = `/${entry.rootDir.replace(/^\/+/, "")}`;
26628
+ if (entry.buildCmd) patch.buildCmd = entry.buildCmd;
26629
+ if (entry.startCmd) patch.startCmd = entry.startCmd;
26630
+ if (Object.keys(patch).length > 0) {
26631
+ try {
26632
+ await api(`/api/services/${entry.serviceId}`, {
26633
+ method: "PATCH",
26634
+ body: JSON.stringify(patch)
26635
+ });
26636
+ } catch {
26637
+ }
26638
+ }
26515
26639
  const res = await api("/api/deployments", {
26516
26640
  method: "POST",
26517
26641
  body: JSON.stringify({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchmatic/cli",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Launchmatic CLI — deploy from your terminal",
5
5
  "private": false,
6
6
  "type": "module",