@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.
- package/dist/index.js +129 -5
- 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
|
|
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
|
-
|
|
26236
|
-
|
|
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({
|