@miosa/cli 1.1.16 → 1.1.19
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 +26 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +227 -77
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/devices.d.ts.map +1 -1
- package/dist/commands/devices.js +3 -7
- package/dist/commands/devices.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +127 -58
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/sandbox.d.ts.map +1 -1
- package/dist/commands/sandbox.js +91 -23
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/commands/templates.d.ts.map +1 -1
- package/dist/commands/templates.js +154 -11
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/util.d.ts +2 -0
- package/dist/commands/util.d.ts.map +1 -1
- package/dist/commands/util.js +30 -23
- package/dist/commands/util.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/net-diagnosis.d.ts +87 -0
- package/dist/net-diagnosis.d.ts.map +1 -0
- package/dist/net-diagnosis.js +408 -0
- package/dist/net-diagnosis.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -296,7 +296,30 @@ $ miosa deploy --docker-deploy
|
|
|
296
296
|
miosa deploy env set KEY=VALUE — set env var
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
+
For CI, agents, and scripts, use JSON mode.
|
|
300
|
+
JSON mode and non-TTY stdin never open interactive prompts.
|
|
301
|
+
Framework detection supplies build and run commands when it recognizes the project.
|
|
302
|
+
Unknown project shapes fail before the API and require both command flags instead of guessing.
|
|
303
|
+
Static sites use `--static`, which omits build and run commands completely.
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
miosa --organization acme deploy --docker-deploy --json
|
|
307
|
+
|
|
308
|
+
miosa --organization acme deploy --docker-deploy --json --yes \
|
|
309
|
+
--name my-project \
|
|
310
|
+
--branch main \
|
|
311
|
+
--build-command "npm run build" \
|
|
312
|
+
--run-command "npm start"
|
|
313
|
+
|
|
314
|
+
miosa --organization acme deploy --docker-deploy --static --json --yes \
|
|
315
|
+
--name callix-security-report \
|
|
316
|
+
--branch master
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
The JSON result is one document containing the deployment identity, queued build, App Engine host, public URL when known, and one-time webhook details for a new deployment.
|
|
320
|
+
|
|
299
321
|
On subsequent runs from the same directory, `miosa deploy` reads `.miosa.json` and skips all prompts — just queues a rebuild and streams logs.
|
|
322
|
+
The creation flags (`--name`, `--branch`, `--build-command`, `--run-command`, `--static`) only apply to the first deploy; passing them when `.miosa.json` exists is an error, so automation never silently deploys a configuration other than the one it asked for.
|
|
300
323
|
|
|
301
324
|
```bash
|
|
302
325
|
# Trigger a rebuild any time
|
|
@@ -626,6 +649,9 @@ Deploy a GitHub repo. See the [Deploy section](#deploy--60-seconds-to-first-depl
|
|
|
626
649
|
|
|
627
650
|
```bash
|
|
628
651
|
miosa deploy --docker-deploy # Recommended production deploy
|
|
652
|
+
miosa deploy --docker-deploy --json # Prompt-free CI or agent deploy
|
|
653
|
+
miosa deploy --docker-deploy --static --name report --branch main --yes --json
|
|
654
|
+
miosa deploy --name app --branch main --build-command "npm run build" --run-command "npm start" --yes --json
|
|
629
655
|
miosa deploy # First deploy or redeploy from .miosa.json
|
|
630
656
|
miosa deploy list [--json] # List all deployments
|
|
631
657
|
miosa deploy logs [id] # Tail live build logs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0oBzC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAy/B/C"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -6,7 +6,7 @@ import { request } from "undici";
|
|
|
6
6
|
import { loadConfig } from "../config.js";
|
|
7
7
|
import { MiosaClient, parseSse } from "../client.js";
|
|
8
8
|
import { ENV_FILE_OPTION_HELP, ENV_INLINE_SHELL_WARNING, ENV_STDIN_OPTION_HELP, resolveEnvInputs, } from "./env-input.js";
|
|
9
|
-
import { handleError, isJsonMode } from "./util.js";
|
|
9
|
+
import { errorExitCode, handleError, isJsonMode, jsonErrorPayload, } from "./util.js";
|
|
10
10
|
import { spin } from "../ui/spinner.js";
|
|
11
11
|
import { renderTable } from "../ui/table.js";
|
|
12
12
|
import { errorEnvelope, hintBlock, icon, kvPanel, printBanner, printElapsed, formatDuration, } from "../ui/render.js";
|
|
@@ -153,7 +153,11 @@ async function probePublicUrl(publicUrl, probePath, timeoutMs) {
|
|
|
153
153
|
signal: controller.signal,
|
|
154
154
|
});
|
|
155
155
|
res.body.resume();
|
|
156
|
-
return {
|
|
156
|
+
return {
|
|
157
|
+
ok: res.statusCode >= 200 && res.statusCode < 500,
|
|
158
|
+
status: res.statusCode,
|
|
159
|
+
url: url.toString(),
|
|
160
|
+
};
|
|
157
161
|
}
|
|
158
162
|
catch (error) {
|
|
159
163
|
return {
|
|
@@ -174,7 +178,10 @@ async function proveDeployment(client, deploymentId, opts) {
|
|
|
174
178
|
addProofCheck(checks, "deployment_row", true, `Deployment ${deployment.id} exists with state=${deployment.state}.`, { state: deployment.state });
|
|
175
179
|
addProofCheck(checks, "deployment_running", deployment.state === "running", deployment.state === "running"
|
|
176
180
|
? "Deployment is marked running."
|
|
177
|
-
: `Deployment state is ${deployment.state}, expected running.`, { state: deployment.state }, [
|
|
181
|
+
: `Deployment state is ${deployment.state}, expected running.`, { state: deployment.state }, [
|
|
182
|
+
"miosa deploy logs <deployment-id>",
|
|
183
|
+
"miosa deploy redeploy <deployment-id>",
|
|
184
|
+
]);
|
|
178
185
|
addProofCheck(checks, "public_url_present", Boolean(publicUrl), publicUrl ? `Public URL is ${publicUrl}.` : "Deployment has no public URL.", { public_url: publicUrl });
|
|
179
186
|
if (product === "docker_deploy") {
|
|
180
187
|
const app = dockerDeployApp(deployment);
|
|
@@ -183,20 +190,27 @@ async function proveDeployment(client, deploymentId, opts) {
|
|
|
183
190
|
stringField(deployment.metadata, "docker_deploy_host_id") ??
|
|
184
191
|
stringField(app, "docker_deploy_host_id") ??
|
|
185
192
|
stringField(app, "host_id");
|
|
186
|
-
addProofCheck(checks, "docker_deploy_host_link", Boolean(hostId), hostId
|
|
193
|
+
addProofCheck(checks, "docker_deploy_host_link", Boolean(hostId), hostId
|
|
194
|
+
? `Deployment links App Engine host ${hostId}.`
|
|
195
|
+
: "Deployment has no App Engine host id.", { docker_deploy_host_id: hostId }, ["miosa docker-deploy ensure --wait --json"]);
|
|
187
196
|
if (hostId) {
|
|
188
197
|
try {
|
|
189
198
|
const host = await client.apiGet(`/api/v1/docker-deploy/hosts/${encodeURIComponent(hostId)}`);
|
|
190
199
|
const hostRecord = asRecord(asRecord(host).host ?? asRecord(host).data ?? host);
|
|
191
200
|
const status = stringField(hostRecord, "status");
|
|
192
201
|
const applianceStatus = stringField(hostRecord, "appliance_status");
|
|
193
|
-
addProofCheck(checks, "docker_deploy_host_ready", status === "active" && applianceStatus === "healthy", `Host status=${status ?? "unknown"}, appliance=${applianceStatus ?? "unknown"}.`, { status, appliance_status: applianceStatus }, [
|
|
202
|
+
addProofCheck(checks, "docker_deploy_host_ready", status === "active" && applianceStatus === "healthy", `Host status=${status ?? "unknown"}, appliance=${applianceStatus ?? "unknown"}.`, { status, appliance_status: applianceStatus }, [
|
|
203
|
+
"miosa docker-deploy show <host-id> --json",
|
|
204
|
+
"miosa docker-deploy ensure --wait --json",
|
|
205
|
+
]);
|
|
194
206
|
}
|
|
195
207
|
catch (error) {
|
|
196
208
|
addProofCheck(checks, "docker_deploy_host_ready", false, error instanceof Error ? error.message : String(error), { docker_deploy_host_id: hostId });
|
|
197
209
|
}
|
|
198
210
|
}
|
|
199
|
-
addProofCheck(checks, "docker_deploy_app_row", Boolean(app), app
|
|
211
|
+
addProofCheck(checks, "docker_deploy_app_row", Boolean(app), app
|
|
212
|
+
? `App Engine app status=${stringField(app, "status") ?? "unknown"}.`
|
|
213
|
+
: "App Engine app row is missing.", app
|
|
200
214
|
? {
|
|
201
215
|
status: stringField(app, "status"),
|
|
202
216
|
app_id: stringField(app, "app_id"),
|
|
@@ -219,7 +233,10 @@ async function proveDeployment(client, deploymentId, opts) {
|
|
|
219
233
|
const probe = await probePublicUrl(publicUrl, opts.probePath, opts.timeoutMs);
|
|
220
234
|
addProofCheck(checks, "public_url_probe", probe.ok, probe.ok
|
|
221
235
|
? `Public URL returned HTTP ${probe.status}.`
|
|
222
|
-
: `Public URL probe failed: ${probe.error ?? `HTTP ${probe.status}`}.`, probe, [
|
|
236
|
+
: `Public URL probe failed: ${probe.error ?? `HTTP ${probe.status}`}.`, probe, [
|
|
237
|
+
"Check DNS/custom domain routing.",
|
|
238
|
+
"Check app logs and container health.",
|
|
239
|
+
]);
|
|
223
240
|
}
|
|
224
241
|
const nextActions = checks
|
|
225
242
|
.filter((check) => !check.ok)
|
|
@@ -420,16 +437,24 @@ function formatSeconds(value) {
|
|
|
420
437
|
return formatMetricValue(value);
|
|
421
438
|
return formatDuration(value * 1000);
|
|
422
439
|
}
|
|
423
|
-
// ── register ──────────────────────────────────────────────────────────────────
|
|
424
440
|
export function register(program) {
|
|
425
441
|
const deploy = program
|
|
426
442
|
.command("deploy")
|
|
427
443
|
.alias("launch")
|
|
428
444
|
.description("Deploy a GitHub repo; use --docker-deploy for the recommended production runtime")
|
|
429
445
|
.option("--docker-deploy", "Create the deployment on this workspace's dedicated App Engine runtime")
|
|
446
|
+
.option("--name <name>", "Deployment name (defaults to the directory name)")
|
|
447
|
+
.option("--branch <branch>", "Git branch to deploy (defaults to the current branch)")
|
|
448
|
+
.option("--build-command <cmd>", "Build command (defaults to framework detection)")
|
|
449
|
+
.option("--run-command <cmd>", "Run command (defaults to framework detection)")
|
|
450
|
+
.option("--static", "Deploy static files without build or run commands")
|
|
451
|
+
.option("-y, --yes", "Accept detected defaults and skip interactive confirmation")
|
|
430
452
|
.addHelpText("after", `
|
|
431
453
|
Examples:
|
|
432
454
|
miosa deploy --docker-deploy Recommended: deploy current directory to App Engine
|
|
455
|
+
miosa deploy --docker-deploy --json Prompt-free deploy for CI and agents
|
|
456
|
+
miosa deploy --docker-deploy --static --name report --branch main --yes --json
|
|
457
|
+
miosa deploy --name app --branch main --build-command "npm run build" --run-command "npm start" --yes --json
|
|
433
458
|
miosa deploy Deploy current directory (auto-detects framework)
|
|
434
459
|
miosa deploy list List all deployments
|
|
435
460
|
miosa deploy logs Tail build logs for this project
|
|
@@ -445,31 +470,49 @@ Examples:
|
|
|
445
470
|
const cwd = process.cwd();
|
|
446
471
|
const config = loadConfig();
|
|
447
472
|
const client = new MiosaClient(config);
|
|
473
|
+
const json = isJsonMode(opts);
|
|
448
474
|
// ── Check for existing .miosa.json first (skip git for redeploys) ──
|
|
449
475
|
let projectCfg = loadProjectConfig(cwd);
|
|
450
476
|
let deploymentId;
|
|
477
|
+
let queuedBuild = null;
|
|
478
|
+
let createdDeployment = null;
|
|
479
|
+
let webhookSecret = null;
|
|
480
|
+
let buildQueueError = null;
|
|
451
481
|
if (projectCfg) {
|
|
452
482
|
// ── Re-deploy from existing .miosa.json ──────────────────────
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
483
|
+
const firstDeployOnlyFlags = [
|
|
484
|
+
opts.name !== undefined ? "--name" : null,
|
|
485
|
+
opts.branch !== undefined ? "--branch" : null,
|
|
486
|
+
opts.buildCommand !== undefined ? "--build-command" : null,
|
|
487
|
+
opts.runCommand !== undefined ? "--run-command" : null,
|
|
488
|
+
opts.static ? "--static" : null,
|
|
489
|
+
].filter((flag) => flag !== null);
|
|
490
|
+
if (firstDeployOnlyFlags.length > 0) {
|
|
491
|
+
throw new UserError(`.miosa.json already exists; ${firstDeployOnlyFlags.join(", ")} only apply when creating a deployment.`, "Remove these flags to redeploy the saved configuration, or delete .miosa.json to create a new deployment.");
|
|
492
|
+
}
|
|
493
|
+
if (!json) {
|
|
494
|
+
console.log();
|
|
495
|
+
console.log(chalk.dim(" Found .miosa.json — redeploying existing deployment"));
|
|
496
|
+
console.log(` ${chalk.bold("Project")} ${projectCfg.name} (${projectCfg.framework})`);
|
|
497
|
+
console.log(` ${chalk.bold("Branch")} ${projectCfg.branch}`);
|
|
498
|
+
console.log();
|
|
499
|
+
}
|
|
458
500
|
deploymentId = projectCfg.deploymentId;
|
|
459
|
-
const buildSpinner = spin("Queuing build...");
|
|
501
|
+
const buildSpinner = json ? null : spin("Queuing build...");
|
|
460
502
|
try {
|
|
461
|
-
await client.redeployDeployment(deploymentId);
|
|
462
|
-
buildSpinner
|
|
503
|
+
queuedBuild = await client.redeployDeployment(deploymentId);
|
|
504
|
+
buildSpinner?.succeed("Build queued");
|
|
463
505
|
}
|
|
464
506
|
catch (err) {
|
|
465
|
-
buildSpinner
|
|
507
|
+
buildSpinner?.fail("Failed to queue build");
|
|
466
508
|
handleError(err);
|
|
467
509
|
}
|
|
468
510
|
}
|
|
469
511
|
else {
|
|
470
512
|
// ── First deploy: verify git repo + remote, then detect ───────
|
|
471
513
|
const { repoUrl, currentBranch } = getGitInfo(cwd);
|
|
472
|
-
|
|
514
|
+
if (!json)
|
|
515
|
+
console.log();
|
|
473
516
|
const detection = detectFramework(cwd);
|
|
474
517
|
let framework = "unknown";
|
|
475
518
|
let buildCommand = "npm run build";
|
|
@@ -477,60 +520,105 @@ Examples:
|
|
|
477
520
|
if (detection) {
|
|
478
521
|
const label = FRAMEWORK_LABELS[detection.framework] ??
|
|
479
522
|
detection.framework;
|
|
480
|
-
|
|
523
|
+
if (!json) {
|
|
524
|
+
console.log(` Detected: ${chalk.cyan(label)} (confidence ${detection.confidence}%)`);
|
|
525
|
+
}
|
|
481
526
|
framework = detection.framework;
|
|
482
527
|
buildCommand = detection.buildCommand;
|
|
483
528
|
runCommand = detection.runCommand;
|
|
484
529
|
}
|
|
485
530
|
else {
|
|
486
|
-
|
|
531
|
+
if (!json) {
|
|
532
|
+
console.log(chalk.yellow(" Could not auto-detect framework. You can set build/run commands manually."));
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (!json) {
|
|
536
|
+
console.log(` Repo: ${chalk.dim(repoUrl)}`);
|
|
537
|
+
console.log(` Branch: ${chalk.dim(currentBranch)}`);
|
|
538
|
+
console.log();
|
|
539
|
+
}
|
|
540
|
+
const requiresNonInteractiveInputs = !process.stdin.isTTY || json || Boolean(opts.yes);
|
|
541
|
+
if (opts.static &&
|
|
542
|
+
(opts.buildCommand !== undefined || opts.runCommand !== undefined)) {
|
|
543
|
+
throw new UserError("--static cannot be combined with build or run commands.", "Remove --build-command and --run-command, or remove --static.");
|
|
544
|
+
}
|
|
545
|
+
if (requiresNonInteractiveInputs &&
|
|
546
|
+
!opts.static &&
|
|
547
|
+
!detection &&
|
|
548
|
+
(!opts.buildCommand || !opts.runCommand)) {
|
|
549
|
+
throw new UserError("Could not determine deployment commands non-interactively.", "Pass both --build-command <cmd> and --run-command <cmd>, or use --static for static sites.");
|
|
487
550
|
}
|
|
488
|
-
console.log(` Repo: ${chalk.dim(repoUrl)}`);
|
|
489
|
-
console.log(` Branch: ${chalk.dim(currentBranch)}`);
|
|
490
|
-
console.log();
|
|
491
|
-
// ── Interactive prompts ──────────────────────────────────────
|
|
492
|
-
const { default: inquirer } = await import("inquirer");
|
|
493
551
|
const projectName = path.basename(cwd).replace(/[^a-z0-9-]/gi, "-");
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
},
|
|
514
|
-
{
|
|
515
|
-
type: "input",
|
|
516
|
-
name: "runCommand",
|
|
517
|
-
message: "Run command:",
|
|
518
|
-
default: runCommand,
|
|
519
|
-
},
|
|
520
|
-
{
|
|
552
|
+
let answers;
|
|
553
|
+
if (!requiresNonInteractiveInputs) {
|
|
554
|
+
const { default: inquirer } = await import("inquirer");
|
|
555
|
+
const identityQuestions = [
|
|
556
|
+
{
|
|
557
|
+
type: "input",
|
|
558
|
+
name: "name",
|
|
559
|
+
message: "Deployment name:",
|
|
560
|
+
default: opts.name ?? projectName,
|
|
561
|
+
validate: (v) => v.length > 0 ? true : "Name is required",
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
type: "input",
|
|
565
|
+
name: "branch",
|
|
566
|
+
message: "Branch to deploy:",
|
|
567
|
+
default: opts.branch ?? currentBranch,
|
|
568
|
+
},
|
|
569
|
+
];
|
|
570
|
+
const confirmQuestion = {
|
|
521
571
|
type: "confirm",
|
|
522
572
|
name: "confirm",
|
|
523
573
|
message: "Create deployment?",
|
|
524
574
|
default: true,
|
|
525
|
-
}
|
|
526
|
-
|
|
575
|
+
};
|
|
576
|
+
if (opts.static) {
|
|
577
|
+
const staticAnswers = await inquirer.prompt([...identityQuestions, confirmQuestion]);
|
|
578
|
+
answers = {
|
|
579
|
+
...staticAnswers,
|
|
580
|
+
buildCommand: "",
|
|
581
|
+
runCommand: "",
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
answers = await inquirer.prompt([
|
|
586
|
+
...identityQuestions,
|
|
587
|
+
{
|
|
588
|
+
type: "input",
|
|
589
|
+
name: "buildCommand",
|
|
590
|
+
message: "Build command:",
|
|
591
|
+
default: opts.buildCommand ?? buildCommand,
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
type: "input",
|
|
595
|
+
name: "runCommand",
|
|
596
|
+
message: "Run command:",
|
|
597
|
+
default: opts.runCommand ?? runCommand,
|
|
598
|
+
},
|
|
599
|
+
confirmQuestion,
|
|
600
|
+
]);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
answers = {
|
|
605
|
+
name: opts.name ?? projectName,
|
|
606
|
+
branch: opts.branch ?? currentBranch,
|
|
607
|
+
buildCommand: opts.static
|
|
608
|
+
? ""
|
|
609
|
+
: (opts.buildCommand ?? buildCommand),
|
|
610
|
+
runCommand: opts.static ? "" : (opts.runCommand ?? runCommand),
|
|
611
|
+
confirm: true,
|
|
612
|
+
};
|
|
613
|
+
}
|
|
527
614
|
if (!answers.confirm) {
|
|
528
615
|
console.log(chalk.dim(" Cancelled."));
|
|
529
616
|
process.exit(0);
|
|
530
617
|
}
|
|
531
618
|
// ── Step 3: POST /api/v1/deployments ─────────────────────────
|
|
532
|
-
const createSpinner =
|
|
533
|
-
|
|
619
|
+
const createSpinner = json
|
|
620
|
+
? null
|
|
621
|
+
: spin(`Creating deployment "${answers.name}"...`);
|
|
534
622
|
let deployment;
|
|
535
623
|
try {
|
|
536
624
|
const metadata = opts.dockerDeploy
|
|
@@ -547,10 +635,11 @@ Examples:
|
|
|
547
635
|
});
|
|
548
636
|
deployment = result.data;
|
|
549
637
|
webhookSecret = result.webhook_secret;
|
|
550
|
-
|
|
638
|
+
createdDeployment = deployment;
|
|
639
|
+
createSpinner?.succeed(`${productLabel(deploymentProduct(deployment))} deployment "${deployment.name}" created (slug: ${deployment.slug})`);
|
|
551
640
|
}
|
|
552
641
|
catch (err) {
|
|
553
|
-
createSpinner
|
|
642
|
+
createSpinner?.fail("Failed to create deployment");
|
|
554
643
|
handleError(err);
|
|
555
644
|
}
|
|
556
645
|
deploymentId = deployment.id;
|
|
@@ -566,29 +655,85 @@ Examples:
|
|
|
566
655
|
branch: answers.branch,
|
|
567
656
|
};
|
|
568
657
|
saveProjectConfig(cwd, projectCfg);
|
|
569
|
-
|
|
658
|
+
if (!json)
|
|
659
|
+
console.log(chalk.dim(` Saved .miosa.json`));
|
|
570
660
|
// ── Step 4b: Print webhook secret (one-time) ─────────────────
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
661
|
+
if (!json) {
|
|
662
|
+
console.log();
|
|
663
|
+
console.log(chalk.bold.yellow(" ACTION REQUIRED — GitHub Webhook"));
|
|
664
|
+
console.log(chalk.dim(" The webhook secret below is shown ONCE. Store it now."));
|
|
665
|
+
console.log();
|
|
666
|
+
console.log(` ${chalk.bold("Webhook URL:")} https://api.miosa.ai/api/v1/integrations/github/webhook`);
|
|
667
|
+
console.log(` ${chalk.bold("Content type:")} application/json`);
|
|
668
|
+
console.log(` ${chalk.bold("Secret:")} ${chalk.green(webhookSecret)}`);
|
|
669
|
+
console.log(` ${chalk.bold("Events:")} push`);
|
|
670
|
+
console.log();
|
|
671
|
+
console.log(chalk.dim(" Add this at: " + repoUrl + "/settings/hooks/new"));
|
|
672
|
+
console.log();
|
|
673
|
+
}
|
|
582
674
|
// ── Step 5: Trigger initial build ─────────────────────────────
|
|
583
|
-
const buildSpinner = spin("Queuing initial build...");
|
|
675
|
+
const buildSpinner = json ? null : spin("Queuing initial build...");
|
|
584
676
|
try {
|
|
585
|
-
await client.redeployDeployment(deploymentId);
|
|
586
|
-
buildSpinner
|
|
677
|
+
queuedBuild = await client.redeployDeployment(deploymentId);
|
|
678
|
+
buildSpinner?.succeed("Initial build queued");
|
|
587
679
|
}
|
|
588
680
|
catch (err) {
|
|
589
|
-
buildSpinner
|
|
590
|
-
|
|
681
|
+
buildSpinner?.fail("Failed to queue build");
|
|
682
|
+
if (!json)
|
|
683
|
+
handleError(err);
|
|
684
|
+
buildQueueError = err;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (json) {
|
|
688
|
+
let deployment = createdDeployment;
|
|
689
|
+
if (!deployment) {
|
|
690
|
+
try {
|
|
691
|
+
deployment = await client.getDeployment(deploymentId);
|
|
692
|
+
}
|
|
693
|
+
catch {
|
|
694
|
+
deployment = null;
|
|
695
|
+
}
|
|
591
696
|
}
|
|
697
|
+
console.log(JSON.stringify({
|
|
698
|
+
ok: buildQueueError === null,
|
|
699
|
+
deployment: deployment
|
|
700
|
+
? {
|
|
701
|
+
id: deployment.id,
|
|
702
|
+
name: deployment.name,
|
|
703
|
+
slug: deployment.slug,
|
|
704
|
+
state: deployment.state,
|
|
705
|
+
deployment_product: deploymentProduct(deployment),
|
|
706
|
+
docker_deploy_host_id: deployment.docker_deploy_host_id ?? null,
|
|
707
|
+
public_url: deploymentUrl(deployment),
|
|
708
|
+
}
|
|
709
|
+
: {
|
|
710
|
+
id: deploymentId,
|
|
711
|
+
name: projectCfg.name,
|
|
712
|
+
slug: null,
|
|
713
|
+
state: null,
|
|
714
|
+
deployment_product: null,
|
|
715
|
+
docker_deploy_host_id: null,
|
|
716
|
+
public_url: null,
|
|
717
|
+
},
|
|
718
|
+
build: queuedBuild
|
|
719
|
+
? { id: queuedBuild.id, state: queuedBuild.state }
|
|
720
|
+
: null,
|
|
721
|
+
webhook: webhookSecret
|
|
722
|
+
? {
|
|
723
|
+
url: "https://api.miosa.ai/api/v1/integrations/github/webhook",
|
|
724
|
+
secret: webhookSecret,
|
|
725
|
+
events: ["push"],
|
|
726
|
+
}
|
|
727
|
+
: null,
|
|
728
|
+
project_config: path.join(cwd, PROJECT_CONFIG_FILE),
|
|
729
|
+
...(buildQueueError === null
|
|
730
|
+
? {}
|
|
731
|
+
: { error: jsonErrorPayload(buildQueueError) }),
|
|
732
|
+
}, null, 2));
|
|
733
|
+
if (buildQueueError !== null) {
|
|
734
|
+
process.exit(errorExitCode(buildQueueError));
|
|
735
|
+
}
|
|
736
|
+
return;
|
|
592
737
|
}
|
|
593
738
|
// ── Step 6: Stream build logs ─────────────────────────────────────
|
|
594
739
|
console.log();
|
|
@@ -816,11 +961,16 @@ Examples:
|
|
|
816
961
|
}
|
|
817
962
|
printBanner({ subtitle: "Deployment proof" });
|
|
818
963
|
console.log(kvPanel([
|
|
819
|
-
{
|
|
964
|
+
{
|
|
965
|
+
label: "deployment_id",
|
|
966
|
+
value: chalk.dim(result.deployment_id),
|
|
967
|
+
},
|
|
820
968
|
{ label: "type", value: productLabel(result.deployment_product) },
|
|
821
969
|
{
|
|
822
970
|
label: "public_url",
|
|
823
|
-
value: result.public_url
|
|
971
|
+
value: result.public_url
|
|
972
|
+
? chalk.cyan(result.public_url)
|
|
973
|
+
: chalk.dim("missing"),
|
|
824
974
|
},
|
|
825
975
|
{
|
|
826
976
|
label: "proof",
|