onveloz 0.0.0-beta.15 → 0.0.0-beta.17
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.mjs +553 -123
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -29,7 +29,6 @@ const BUILD_TIMEOUT_MS = 600 * 1e3;
|
|
|
29
29
|
const DEPLOY_TIMEOUT_MS = 300 * 1e3;
|
|
30
30
|
const DATABASE_PROVISION_TIMEOUT_MS = 300 * 1e3;
|
|
31
31
|
const DATABASE_WAITING_ON_PROVIDER_AFTER_MS = 60 * 1e3;
|
|
32
|
-
const DATABASE_HEALTH_POLL_INTERVAL_MS = 60 * 1e3;
|
|
33
32
|
const DATABASE_ENGINES = [
|
|
34
33
|
"postgresql",
|
|
35
34
|
"mysql",
|
|
@@ -52,7 +51,6 @@ const DATABASE_ENGINE_DEFAULTS = {
|
|
|
52
51
|
defaultVersion: "7"
|
|
53
52
|
}
|
|
54
53
|
};
|
|
55
|
-
const DEFAULT_SLEEP_CHECK_INTERVAL_MS = 300 * 1e3;
|
|
56
54
|
|
|
57
55
|
//#endregion
|
|
58
56
|
//#region ../../packages/config/veloz-config.ts
|
|
@@ -65,17 +63,22 @@ const PackageManagerSchema = z$1.enum([
|
|
|
65
63
|
"bun",
|
|
66
64
|
"auto"
|
|
67
65
|
]);
|
|
66
|
+
const BuildMethodSchema = z$1.enum(["nixpacks", "dockerfile"]);
|
|
68
67
|
const BuildConfigSchema = z$1.object({
|
|
68
|
+
method: BuildMethodSchema.default("nixpacks").optional(),
|
|
69
69
|
command: z$1.string().nullable().optional(),
|
|
70
70
|
nodeVersion: z$1.string().regex(/^[0-9]+(\.[0-9]+){0,2}(\.x)?$/).default("20").optional(),
|
|
71
71
|
nixpkgsArchive: z$1.string().regex(/^[a-f0-9]{40}$/).optional(),
|
|
72
72
|
packageManager: PackageManagerSchema.default("auto").optional(),
|
|
73
73
|
installCommand: z$1.string().nullable().optional(),
|
|
74
74
|
outputDir: z$1.string().nullable().optional(),
|
|
75
|
-
aptPackages: z$1.array(z$1.string().regex(/^[a-z0-9][a-z0-9.+-]+$/, "Nome de pacote inválido")).optional()
|
|
75
|
+
aptPackages: z$1.array(z$1.string().regex(/^[a-z0-9][a-z0-9.+-]+$/, "Nome de pacote inválido")).optional(),
|
|
76
|
+
dockerfile: z$1.string().optional(),
|
|
77
|
+
context: z$1.string().optional()
|
|
76
78
|
});
|
|
77
79
|
const RuntimeConfigSchema = z$1.object({
|
|
78
80
|
command: z$1.string().nullable().optional(),
|
|
81
|
+
preStartCommand: z$1.string().nullable().optional(),
|
|
79
82
|
port: z$1.number().min(1).max(65535).default(3e3).optional(),
|
|
80
83
|
fsGroup: z$1.number().int().min(0).max(65534).default(1001).optional(),
|
|
81
84
|
healthCheck: z$1.object({
|
|
@@ -111,6 +114,20 @@ const VolumeConfigSchema = z$1.object({
|
|
|
111
114
|
].some((p) => value === p || value.startsWith(p + "/")), "Caminho de montagem não permitido por segurança"),
|
|
112
115
|
sizeGb: z$1.number().int().min(10).max(100).optional().default(10)
|
|
113
116
|
});
|
|
117
|
+
const DatabaseResourcesSchema = z$1.object({
|
|
118
|
+
cpu: z$1.string().regex(/^[0-9]+(\.[0-9]+)?|[0-9]+m$/).default("500m").optional(),
|
|
119
|
+
memory: z$1.string().regex(/^[0-9]+(Mi|Gi)$/).default("512Mi").optional()
|
|
120
|
+
});
|
|
121
|
+
const PoolerConfigSchema = z$1.object({
|
|
122
|
+
enabled: z$1.boolean().default(false),
|
|
123
|
+
poolMode: z$1.enum([
|
|
124
|
+
"transaction",
|
|
125
|
+
"session",
|
|
126
|
+
"statement"
|
|
127
|
+
]).default("transaction").optional(),
|
|
128
|
+
defaultPoolSize: z$1.number().int().min(1).max(200).default(20).optional(),
|
|
129
|
+
maxClientConn: z$1.number().int().min(1).max(1e4).default(100).optional()
|
|
130
|
+
});
|
|
114
131
|
const DatabaseConfigSchema = z$1.object({
|
|
115
132
|
id: z$1.string().optional(),
|
|
116
133
|
name: z$1.string().optional(),
|
|
@@ -121,10 +138,12 @@ const DatabaseConfigSchema = z$1.object({
|
|
|
121
138
|
]),
|
|
122
139
|
version: z$1.string().optional(),
|
|
123
140
|
storage: z$1.string().regex(/^[0-9]+(Gi)$/).default("10Gi").optional(),
|
|
141
|
+
resources: DatabaseResourcesSchema.optional(),
|
|
142
|
+
pooler: PoolerConfigSchema.optional(),
|
|
124
143
|
fromTemplate: z$1.string().optional()
|
|
125
144
|
});
|
|
126
145
|
const ServiceConfigSchema = z$1.object({
|
|
127
|
-
id: z$1.string(),
|
|
146
|
+
id: z$1.string().optional(),
|
|
128
147
|
name: z$1.string(),
|
|
129
148
|
type: ServiceTypeSchema.default("web"),
|
|
130
149
|
root: z$1.string().default(".").optional(),
|
|
@@ -542,7 +561,9 @@ async function pollForToken(authClient, deviceCode, interval) {
|
|
|
542
561
|
let pollingInterval = interval;
|
|
543
562
|
const maxAttempts = Math.ceil(300 / pollingInterval);
|
|
544
563
|
for (let i = 0; i < maxAttempts; i++) {
|
|
545
|
-
await new Promise((r) =>
|
|
564
|
+
await new Promise((r) => {
|
|
565
|
+
setTimeout(r, pollingInterval * 1e3);
|
|
566
|
+
});
|
|
546
567
|
try {
|
|
547
568
|
const { data, error } = await authClient.device.token({
|
|
548
569
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
@@ -795,6 +816,10 @@ function throwNotFound(flag, entries) {
|
|
|
795
816
|
* 3. Default from `veloz use` → remembered choice
|
|
796
817
|
* 4. Interactive prompt → last resort
|
|
797
818
|
*/
|
|
819
|
+
function requireServiceId(service) {
|
|
820
|
+
if (!service.id) throw new Error(`Serviço "${service.name}" não possui ID. Execute 'veloz deploy' para vincular o serviço.`);
|
|
821
|
+
return service;
|
|
822
|
+
}
|
|
798
823
|
async function resolveService(serviceFlag) {
|
|
799
824
|
const config = requireConfig();
|
|
800
825
|
const entries = Object.entries(config.services);
|
|
@@ -805,7 +830,7 @@ async function resolveService(serviceFlag) {
|
|
|
805
830
|
const [key, service] = found;
|
|
806
831
|
return {
|
|
807
832
|
key,
|
|
808
|
-
service: mergeServiceWithDefaults(service, config.defaults),
|
|
833
|
+
service: requireServiceId(mergeServiceWithDefaults(service, config.defaults)),
|
|
809
834
|
config
|
|
810
835
|
};
|
|
811
836
|
}
|
|
@@ -813,7 +838,7 @@ async function resolveService(serviceFlag) {
|
|
|
813
838
|
const [key, service] = entries[0];
|
|
814
839
|
return {
|
|
815
840
|
key,
|
|
816
|
-
service: mergeServiceWithDefaults(service, config.defaults),
|
|
841
|
+
service: requireServiceId(mergeServiceWithDefaults(service, config.defaults)),
|
|
817
842
|
config
|
|
818
843
|
};
|
|
819
844
|
}
|
|
@@ -822,7 +847,7 @@ async function resolveService(serviceFlag) {
|
|
|
822
847
|
const service = config.services[defaultKey];
|
|
823
848
|
return {
|
|
824
849
|
key: defaultKey,
|
|
825
|
-
service: mergeServiceWithDefaults(service, config.defaults),
|
|
850
|
+
service: requireServiceId(mergeServiceWithDefaults(service, config.defaults)),
|
|
826
851
|
config
|
|
827
852
|
};
|
|
828
853
|
}
|
|
@@ -832,7 +857,7 @@ async function resolveService(serviceFlag) {
|
|
|
832
857
|
})));
|
|
833
858
|
return {
|
|
834
859
|
key: selectedKey,
|
|
835
|
-
service: mergeServiceWithDefaults(config.services[selectedKey], config.defaults),
|
|
860
|
+
service: requireServiceId(mergeServiceWithDefaults(config.services[selectedKey], config.defaults)),
|
|
836
861
|
config
|
|
837
862
|
};
|
|
838
863
|
}
|
|
@@ -1437,6 +1462,7 @@ function printServiceConfig(service) {
|
|
|
1437
1462
|
console.log(` ${chalk.bold("Root Dir:")} ${formatValue(service.rootDirectory || "/")}`);
|
|
1438
1463
|
console.log(` ${chalk.bold("Build Command:")} ${formatValue(service.buildCommand)}`);
|
|
1439
1464
|
console.log(` ${chalk.bold("Start Command:")} ${formatValue(service.startCommand)}`);
|
|
1465
|
+
console.log(` ${chalk.bold("Pre-Start Cmd:")} ${formatValue(service.preStartCommand)}`);
|
|
1440
1466
|
console.log(` ${chalk.bold("Porta:")} ${formatValue(service.port)}`);
|
|
1441
1467
|
console.log(` ${chalk.bold("Instâncias:")} ${formatValue(service.instanceCount)}`);
|
|
1442
1468
|
console.log(` ${chalk.bold("CPU Limit:")} ${formatValue(service.cpuLimit)}`);
|
|
@@ -1454,6 +1480,7 @@ configGroup.command("show", {
|
|
|
1454
1480
|
rootDirectory: z.string().nullable(),
|
|
1455
1481
|
buildCommand: z.string().nullable(),
|
|
1456
1482
|
startCommand: z.string().nullable(),
|
|
1483
|
+
preStartCommand: z.string().nullable(),
|
|
1457
1484
|
port: z.number().nullable(),
|
|
1458
1485
|
instanceCount: z.number().nullable(),
|
|
1459
1486
|
cpuLimit: z.string().nullable(),
|
|
@@ -1482,6 +1509,7 @@ configGroup.command("show", {
|
|
|
1482
1509
|
rootDirectory: svc.rootDirectory ?? null,
|
|
1483
1510
|
buildCommand: svc.buildCommand ?? null,
|
|
1484
1511
|
startCommand: svc.startCommand ?? null,
|
|
1512
|
+
preStartCommand: svc.preStartCommand ?? null,
|
|
1485
1513
|
port: svc.port ?? null,
|
|
1486
1514
|
instanceCount: svc.instanceCount ?? null,
|
|
1487
1515
|
cpuLimit: svc.cpuLimit ?? null,
|
|
@@ -1496,6 +1524,7 @@ configGroup.command("set", {
|
|
|
1496
1524
|
name: z.string().optional().describe("Nome do serviço"),
|
|
1497
1525
|
build: z.string().optional().describe("Comando de build"),
|
|
1498
1526
|
start: z.string().optional().describe("Comando de start"),
|
|
1527
|
+
preStart: z.string().optional().describe("Comando executado antes de iniciar o serviço (ex: migrations)"),
|
|
1499
1528
|
port: z.string().optional().describe("Porta do serviço"),
|
|
1500
1529
|
root: z.string().optional().describe("Diretório raiz"),
|
|
1501
1530
|
instances: z.string().optional().describe("Número de instâncias"),
|
|
@@ -1519,6 +1548,7 @@ configGroup.command("set", {
|
|
|
1519
1548
|
if (c.options.name) updates.name = c.options.name;
|
|
1520
1549
|
if (c.options.build !== void 0) updates.buildCommand = c.options.build === "none" ? null : c.options.build;
|
|
1521
1550
|
if (c.options.start !== void 0) updates.startCommand = c.options.start === "none" ? null : c.options.start;
|
|
1551
|
+
if (c.options.preStart !== void 0) updates.preStartCommand = c.options.preStart === "none" ? null : c.options.preStart;
|
|
1522
1552
|
if (c.options.port) updates.port = parseInt(c.options.port, 10);
|
|
1523
1553
|
if (c.options.root !== void 0) updates.rootDirectory = c.options.root === "/" ? null : c.options.root;
|
|
1524
1554
|
if (c.options.instances) updates.instanceCount = parseInt(c.options.instances, 10);
|
|
@@ -1567,6 +1597,8 @@ configGroup.command("edit", {
|
|
|
1567
1597
|
if (buildCmd) updates.buildCommand = buildCmd === "none" ? null : buildCmd;
|
|
1568
1598
|
const startCmd = await prompt(`Start command ${chalk.dim(`(${svc.startCommand || "—"})`)}: `);
|
|
1569
1599
|
if (startCmd) updates.startCommand = startCmd === "none" ? null : startCmd;
|
|
1600
|
+
const preStartCmd = await prompt(`Pre-start command ${chalk.dim(`(${svc.preStartCommand || "—"})`)}: `);
|
|
1601
|
+
if (preStartCmd) updates.preStartCommand = preStartCmd === "none" ? null : preStartCmd;
|
|
1570
1602
|
const port = await prompt(`Porta ${chalk.dim(`(${svc.port})`)}: `);
|
|
1571
1603
|
if (port) updates.port = parseInt(port, 10);
|
|
1572
1604
|
const rootDir = await prompt(`Diretório raiz ${chalk.dim(`(${svc.rootDirectory || "/"})`)}: `);
|
|
@@ -1598,6 +1630,7 @@ configGroup.command("reset", {
|
|
|
1598
1630
|
options: z.object({
|
|
1599
1631
|
build: z.boolean().default(false).describe("Resetar comando de build"),
|
|
1600
1632
|
start: z.boolean().default(false).describe("Resetar comando de start"),
|
|
1633
|
+
preStart: z.boolean().default(false).describe("Resetar comando de pre-start"),
|
|
1601
1634
|
all: z.boolean().default(false).describe("Resetar todas as configurações opcionais"),
|
|
1602
1635
|
service: z.string().optional().describe("Serviço alvo (chave ou nome)")
|
|
1603
1636
|
}),
|
|
@@ -1608,13 +1641,15 @@ configGroup.command("reset", {
|
|
|
1608
1641
|
if (c.options.all) {
|
|
1609
1642
|
updates.buildCommand = null;
|
|
1610
1643
|
updates.startCommand = null;
|
|
1644
|
+
updates.preStartCommand = null;
|
|
1611
1645
|
updates.rootDirectory = null;
|
|
1612
1646
|
} else {
|
|
1613
1647
|
if (c.options.build) updates.buildCommand = null;
|
|
1614
1648
|
if (c.options.start) updates.startCommand = null;
|
|
1649
|
+
if (c.options.preStart) updates.preStartCommand = null;
|
|
1615
1650
|
}
|
|
1616
1651
|
if (Object.keys(updates).length === 0) {
|
|
1617
|
-
warn("Especifique o que resetar: --build, --start, ou --all");
|
|
1652
|
+
warn("Especifique o que resetar: --build, --start, --pre-start, ou --all");
|
|
1618
1653
|
return;
|
|
1619
1654
|
}
|
|
1620
1655
|
await withSpinner({
|
|
@@ -1847,7 +1882,10 @@ dbGroup.command("create", {
|
|
|
1847
1882
|
name: z.string().optional().describe("Nome do banco de dados"),
|
|
1848
1883
|
engine: z.string().optional().describe("Engine (postgresql, mysql, redis)"),
|
|
1849
1884
|
engineVersion: z.string().optional().describe("Versão do engine"),
|
|
1850
|
-
storage: z.string().optional().describe("Armazenamento (ex: 10Gi, 20Gi)")
|
|
1885
|
+
storage: z.string().optional().describe("Armazenamento (ex: 10Gi, 20Gi)"),
|
|
1886
|
+
cpu: z.string().optional().describe("Limite de CPU (ex: 500m, 1)"),
|
|
1887
|
+
memory: z.string().optional().describe("Limite de memória (ex: 512Mi, 1Gi)"),
|
|
1888
|
+
pooler: z.boolean().optional().describe("Habilitar PgBouncer (apenas PostgreSQL)")
|
|
1851
1889
|
}),
|
|
1852
1890
|
async run(c) {
|
|
1853
1891
|
const projectId = getProjectId$1();
|
|
@@ -1896,7 +1934,10 @@ dbGroup.command("create", {
|
|
|
1896
1934
|
name,
|
|
1897
1935
|
engine: validEngine,
|
|
1898
1936
|
engineVersion: version,
|
|
1899
|
-
storage
|
|
1937
|
+
storage,
|
|
1938
|
+
cpuLimit: c.options.cpu,
|
|
1939
|
+
memoryLimit: c.options.memory,
|
|
1940
|
+
poolerEnabled: c.options.pooler
|
|
1900
1941
|
})
|
|
1901
1942
|
});
|
|
1902
1943
|
success(`Banco de dados ${chalk.bold(db.name)} criado! Provisionando...`);
|
|
@@ -1908,7 +1949,12 @@ dbGroup.command("create", {
|
|
|
1908
1949
|
id: db.id,
|
|
1909
1950
|
engine: validEngine,
|
|
1910
1951
|
version: version ?? void 0,
|
|
1911
|
-
storage: storage ?? void 0
|
|
1952
|
+
storage: storage ?? void 0,
|
|
1953
|
+
...c.options.cpu || c.options.memory ? { resources: {
|
|
1954
|
+
...c.options.cpu && { cpu: c.options.cpu },
|
|
1955
|
+
...c.options.memory && { memory: c.options.memory }
|
|
1956
|
+
} } : {},
|
|
1957
|
+
...c.options.pooler ? { pooler: { enabled: true } } : {}
|
|
1912
1958
|
};
|
|
1913
1959
|
config.databases = updatedDatabases;
|
|
1914
1960
|
config.updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2219,7 +2265,7 @@ function registerLink(cli$1) {
|
|
|
2219
2265
|
},
|
|
2220
2266
|
services: services.map(([key, service]) => ({
|
|
2221
2267
|
key,
|
|
2222
|
-
id: service.id,
|
|
2268
|
+
id: service.id ?? "",
|
|
2223
2269
|
name: service.name,
|
|
2224
2270
|
type: service.type
|
|
2225
2271
|
}))
|
|
@@ -2256,13 +2302,16 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2256
2302
|
...pkg.dependencies,
|
|
2257
2303
|
...pkg.devDependencies
|
|
2258
2304
|
};
|
|
2305
|
+
const scripts = pkg.scripts ?? {};
|
|
2259
2306
|
const hasReact = !!allDeps["react"];
|
|
2307
|
+
const buildCmd = scripts.build ? pmRun(pm, "build") : null;
|
|
2308
|
+
const startCmd = scripts.start ? pmRun(pm, "start") : null;
|
|
2260
2309
|
if (allDeps["next"]) return {
|
|
2261
2310
|
name: "nextjs",
|
|
2262
2311
|
label: "Next.js",
|
|
2263
2312
|
type: "WEB",
|
|
2264
|
-
buildCommand: pmRun(pm, "build"),
|
|
2265
|
-
startCommand: pmRun(pm, "start"),
|
|
2313
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2314
|
+
startCommand: startCmd ?? pmRun(pm, "start"),
|
|
2266
2315
|
outputDir: ".next",
|
|
2267
2316
|
port: 3e3
|
|
2268
2317
|
};
|
|
@@ -2270,8 +2319,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2270
2319
|
name: "nuxt",
|
|
2271
2320
|
label: "Nuxt",
|
|
2272
2321
|
type: "WEB",
|
|
2273
|
-
buildCommand: pmRun(pm, "build"),
|
|
2274
|
-
startCommand: pmRun(pm, "start"),
|
|
2322
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2323
|
+
startCommand: startCmd ?? pmRun(pm, "start"),
|
|
2275
2324
|
outputDir: ".output",
|
|
2276
2325
|
port: 3e3
|
|
2277
2326
|
};
|
|
@@ -2279,8 +2328,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2279
2328
|
name: "remix",
|
|
2280
2329
|
label: "Remix",
|
|
2281
2330
|
type: "WEB",
|
|
2282
|
-
buildCommand: pmRun(pm, "build"),
|
|
2283
|
-
startCommand: pmRun(pm, "start"),
|
|
2331
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2332
|
+
startCommand: startCmd ?? pmRun(pm, "start"),
|
|
2284
2333
|
outputDir: "build",
|
|
2285
2334
|
port: 3e3
|
|
2286
2335
|
};
|
|
@@ -2288,7 +2337,7 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2288
2337
|
name: "astro",
|
|
2289
2338
|
label: "Astro",
|
|
2290
2339
|
type: "STATIC",
|
|
2291
|
-
buildCommand: pmRun(pm, "build"),
|
|
2340
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2292
2341
|
startCommand: null,
|
|
2293
2342
|
outputDir: "dist",
|
|
2294
2343
|
port: 3e3
|
|
@@ -2297,8 +2346,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2297
2346
|
name: "sveltekit",
|
|
2298
2347
|
label: "SvelteKit",
|
|
2299
2348
|
type: "WEB",
|
|
2300
|
-
buildCommand: pmRun(pm, "build"),
|
|
2301
|
-
startCommand: pmRun(pm, "preview"),
|
|
2349
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2350
|
+
startCommand: scripts.preview ? pmRun(pm, "preview") : startCmd ?? pmRun(pm, "start"),
|
|
2302
2351
|
outputDir: "build",
|
|
2303
2352
|
port: 3e3
|
|
2304
2353
|
};
|
|
@@ -2306,7 +2355,7 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2306
2355
|
name: "gatsby",
|
|
2307
2356
|
label: "Gatsby",
|
|
2308
2357
|
type: "STATIC",
|
|
2309
|
-
buildCommand: pmRun(pm, "build"),
|
|
2358
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2310
2359
|
startCommand: null,
|
|
2311
2360
|
outputDir: "public",
|
|
2312
2361
|
port: 3e3
|
|
@@ -2315,8 +2364,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2315
2364
|
name: "angular",
|
|
2316
2365
|
label: "Angular",
|
|
2317
2366
|
type: "WEB",
|
|
2318
|
-
buildCommand: pmRun(pm, "build"),
|
|
2319
|
-
startCommand: pmRun(pm, "start"),
|
|
2367
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2368
|
+
startCommand: startCmd ?? pmRun(pm, "start"),
|
|
2320
2369
|
outputDir: "dist",
|
|
2321
2370
|
port: 4200
|
|
2322
2371
|
};
|
|
@@ -2324,8 +2373,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2324
2373
|
name: "hono",
|
|
2325
2374
|
label: "Hono",
|
|
2326
2375
|
type: "WEB",
|
|
2327
|
-
buildCommand:
|
|
2328
|
-
startCommand:
|
|
2376
|
+
buildCommand: buildCmd,
|
|
2377
|
+
startCommand: startCmd,
|
|
2329
2378
|
outputDir: null,
|
|
2330
2379
|
port: 3e3
|
|
2331
2380
|
};
|
|
@@ -2333,8 +2382,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2333
2382
|
name: "express",
|
|
2334
2383
|
label: "Express",
|
|
2335
2384
|
type: "WEB",
|
|
2336
|
-
buildCommand:
|
|
2337
|
-
startCommand:
|
|
2385
|
+
buildCommand: buildCmd,
|
|
2386
|
+
startCommand: startCmd,
|
|
2338
2387
|
outputDir: null,
|
|
2339
2388
|
port: 3e3
|
|
2340
2389
|
};
|
|
@@ -2342,8 +2391,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2342
2391
|
name: "fastify",
|
|
2343
2392
|
label: "Fastify",
|
|
2344
2393
|
type: "WEB",
|
|
2345
|
-
buildCommand:
|
|
2346
|
-
startCommand:
|
|
2394
|
+
buildCommand: buildCmd,
|
|
2395
|
+
startCommand: startCmd,
|
|
2347
2396
|
outputDir: null,
|
|
2348
2397
|
port: 3e3
|
|
2349
2398
|
};
|
|
@@ -2351,8 +2400,8 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2351
2400
|
name: "nestjs",
|
|
2352
2401
|
label: "NestJS",
|
|
2353
2402
|
type: "WEB",
|
|
2354
|
-
buildCommand: pmRun(pm, "build"),
|
|
2355
|
-
startCommand: pmRun(pm, "start:prod"),
|
|
2403
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2404
|
+
startCommand: scripts["start:prod"] ? pmRun(pm, "start:prod") : startCmd ?? pmRun(pm, "start:prod"),
|
|
2356
2405
|
outputDir: "dist",
|
|
2357
2406
|
port: 3e3
|
|
2358
2407
|
};
|
|
@@ -2360,7 +2409,7 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2360
2409
|
name: hasReact ? "vite-react" : "vite",
|
|
2361
2410
|
label: hasReact ? "Vite + React" : "Vite",
|
|
2362
2411
|
type: "STATIC",
|
|
2363
|
-
buildCommand: pmRun(pm, "build"),
|
|
2412
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2364
2413
|
startCommand: null,
|
|
2365
2414
|
outputDir: "dist",
|
|
2366
2415
|
port: 3e3
|
|
@@ -2369,17 +2418,17 @@ function detectFramework(pkgJsonStr, pm) {
|
|
|
2369
2418
|
name: "cra",
|
|
2370
2419
|
label: "Create React App",
|
|
2371
2420
|
type: "STATIC",
|
|
2372
|
-
buildCommand: pmRun(pm, "build"),
|
|
2421
|
+
buildCommand: buildCmd ?? pmRun(pm, "build"),
|
|
2373
2422
|
startCommand: null,
|
|
2374
2423
|
outputDir: "build",
|
|
2375
2424
|
port: 3e3
|
|
2376
2425
|
};
|
|
2377
|
-
if (
|
|
2426
|
+
if (buildCmd || startCmd) return {
|
|
2378
2427
|
name: "node",
|
|
2379
2428
|
label: "Node.js",
|
|
2380
2429
|
type: "WEB",
|
|
2381
|
-
buildCommand:
|
|
2382
|
-
startCommand:
|
|
2430
|
+
buildCommand: buildCmd ?? "",
|
|
2431
|
+
startCommand: startCmd,
|
|
2383
2432
|
outputDir: "dist",
|
|
2384
2433
|
port: 3e3
|
|
2385
2434
|
};
|
|
@@ -2453,7 +2502,7 @@ function analyzeRepo(files) {
|
|
|
2453
2502
|
name: appName,
|
|
2454
2503
|
path: appPath,
|
|
2455
2504
|
framework: appFramework,
|
|
2456
|
-
usesNodeFs: sourceEntries.some(([
|
|
2505
|
+
usesNodeFs: sourceEntries.some(([srcPath, fileContent]) => srcPath.startsWith(`${appPath}/`) && usesNodeFs(fileContent))
|
|
2457
2506
|
});
|
|
2458
2507
|
}
|
|
2459
2508
|
return {
|
|
@@ -2610,10 +2659,14 @@ async function withRetry(fn, maxRetries = 3) {
|
|
|
2610
2659
|
const rateLimit = isRateLimitError(error);
|
|
2611
2660
|
if (rateLimit) {
|
|
2612
2661
|
const waitMs = Math.min(rateLimit.retryAfterMs, 3e4);
|
|
2613
|
-
await new Promise((r) =>
|
|
2662
|
+
await new Promise((r) => {
|
|
2663
|
+
setTimeout(r, waitMs);
|
|
2664
|
+
});
|
|
2614
2665
|
} else {
|
|
2615
2666
|
const delay = Math.min(1e3 * Math.pow(2, attempt), 1e4);
|
|
2616
|
-
await new Promise((r) =>
|
|
2667
|
+
await new Promise((r) => {
|
|
2668
|
+
setTimeout(r, delay);
|
|
2669
|
+
});
|
|
2617
2670
|
}
|
|
2618
2671
|
}
|
|
2619
2672
|
throw new Error("Max retries exceeded");
|
|
@@ -2623,7 +2676,7 @@ async function withRetry(fn, maxRetries = 3) {
|
|
|
2623
2676
|
//#region src/lib/deploy-constants.ts
|
|
2624
2677
|
const statusLabels = {
|
|
2625
2678
|
QUEUED: "Na fila",
|
|
2626
|
-
BUILDING: "
|
|
2679
|
+
BUILDING: "Compilando",
|
|
2627
2680
|
BUILD_FAILED: "Falha na construção",
|
|
2628
2681
|
DEPLOYING: "Implantando",
|
|
2629
2682
|
LIVE: "Ativo",
|
|
@@ -2724,8 +2777,7 @@ function renderProgress(progressMap, prevLineCount) {
|
|
|
2724
2777
|
if (nonEmptyLines.length > 0) {
|
|
2725
2778
|
const tail = nonEmptyLines.slice(-3);
|
|
2726
2779
|
for (const line of tail) {
|
|
2727
|
-
|
|
2728
|
-
process.stdout.write(` ${chalk.dim(truncated)}\n`);
|
|
2780
|
+
process.stdout.write(` ${chalk.dim(line)}\n`);
|
|
2729
2781
|
lineCount++;
|
|
2730
2782
|
}
|
|
2731
2783
|
} else if (progress.status === "BUILDING") {
|
|
@@ -2811,7 +2863,9 @@ async function deployServicesInParallel(services) {
|
|
|
2811
2863
|
if (isTTY) lineCount = renderProgress(progressMap, lineCount);
|
|
2812
2864
|
const streamPromises = activeDeployments.map(async ({ service, deploymentId }) => {
|
|
2813
2865
|
try {
|
|
2814
|
-
await new Promise((resolve$1) =>
|
|
2866
|
+
await new Promise((resolve$1) => {
|
|
2867
|
+
setTimeout(resolve$1, 1e3);
|
|
2868
|
+
});
|
|
2815
2869
|
const stream = await client.logs.streamBuildLogs({ deploymentId });
|
|
2816
2870
|
for await (const event of stream) {
|
|
2817
2871
|
const progress = progressMap.get(service.serviceId);
|
|
@@ -2960,6 +3014,310 @@ function getFailureHints(status) {
|
|
|
2960
3014
|
default: return ["Execute 'veloz logs -f' para mais detalhes."];
|
|
2961
3015
|
}
|
|
2962
3016
|
}
|
|
3017
|
+
/** Raw BuildKit line: `#N content` */
|
|
3018
|
+
const BUILDKIT_PREFIX_RE = /^#(\d+)\s+(.*)/;
|
|
3019
|
+
/** Docker build step: `[stage step/total] COMMAND` */
|
|
3020
|
+
const DOCKER_STEP_RE = /^\[(\S+)\s+(\d+)\/(\d+)\]\s+(.+)$/;
|
|
3021
|
+
/** Platform timestamp: `[2026-03-23T02:37:13.795Z] message` */
|
|
3022
|
+
const TIMESTAMP_RE = /^\[(\d{4}-\d{2}-\d{2}T[\d:.]+Z)\]\s+(.+)$/;
|
|
3023
|
+
/** DONE marker: `DONE 4.2s` */
|
|
3024
|
+
const DONE_RE = /^DONE\s+([\d.]+s?)$/;
|
|
3025
|
+
/** Timing prefix: `0.543 actual content` */
|
|
3026
|
+
const TIMING_RE = /^(\d+\.\d+)\s+(.*)/;
|
|
3027
|
+
/** Infrastructure / deploy orchestration messages to hide from user output */
|
|
3028
|
+
const HIDDEN_MESSAGES = [
|
|
3029
|
+
/^Ensuring namespace\b/i,
|
|
3030
|
+
/^Updating deployment\b/i,
|
|
3031
|
+
/^Syncing ingress\b/i,
|
|
3032
|
+
/^Waiting for rollout\b/i,
|
|
3033
|
+
/^Deploy complete\b/i,
|
|
3034
|
+
/^→\s+https?:\/\//,
|
|
3035
|
+
/\bnamespace\b.*\bsvc\.cluster\.local\b/i,
|
|
3036
|
+
/\bpod\b/i,
|
|
3037
|
+
/\bkubernetes\b/i,
|
|
3038
|
+
/\bk8s\b/i,
|
|
3039
|
+
/\brollout\b/i
|
|
3040
|
+
];
|
|
3041
|
+
function isHiddenMessage(text) {
|
|
3042
|
+
return HIDDEN_MESSAGES.some((p) => p.test(text));
|
|
3043
|
+
}
|
|
3044
|
+
/**
|
|
3045
|
+
* Try to extract a human-readable message from a structured JSON log line.
|
|
3046
|
+
* Returns null if the line is not JSON or has no message.
|
|
3047
|
+
*/
|
|
3048
|
+
function parseJsonLog(text) {
|
|
3049
|
+
if (!text.startsWith("{")) return null;
|
|
3050
|
+
try {
|
|
3051
|
+
const parsed = JSON.parse(text);
|
|
3052
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.msg === "string") return parsed.msg;
|
|
3053
|
+
} catch {}
|
|
3054
|
+
return null;
|
|
3055
|
+
}
|
|
3056
|
+
/** Clean a display line — parse JSON, filter infra */
|
|
3057
|
+
function cleanDisplayLine(text) {
|
|
3058
|
+
if (isHiddenMessage(text)) return null;
|
|
3059
|
+
const jsonMsg = parseJsonLog(text);
|
|
3060
|
+
if (jsonMsg !== null) {
|
|
3061
|
+
if (isHiddenMessage(jsonMsg)) return null;
|
|
3062
|
+
return jsonMsg;
|
|
3063
|
+
}
|
|
3064
|
+
return text;
|
|
3065
|
+
}
|
|
3066
|
+
function parseBuildLine(raw) {
|
|
3067
|
+
const trimmed = raw.trim();
|
|
3068
|
+
const bkMatch = BUILDKIT_PREFIX_RE.exec(trimmed);
|
|
3069
|
+
if (bkMatch) {
|
|
3070
|
+
const stepNum = parseInt(bkMatch[1], 10);
|
|
3071
|
+
const content = bkMatch[2];
|
|
3072
|
+
if (content.trim() === "CACHED") return {
|
|
3073
|
+
kind: "cached",
|
|
3074
|
+
stepNum
|
|
3075
|
+
};
|
|
3076
|
+
const doneMatch = DONE_RE.exec(content);
|
|
3077
|
+
if (doneMatch) return {
|
|
3078
|
+
kind: "done",
|
|
3079
|
+
stepNum,
|
|
3080
|
+
duration: doneMatch[1]
|
|
3081
|
+
};
|
|
3082
|
+
const stepMatch = DOCKER_STEP_RE.exec(content);
|
|
3083
|
+
if (stepMatch) return {
|
|
3084
|
+
kind: "step",
|
|
3085
|
+
stepNum,
|
|
3086
|
+
stage: stepMatch[1],
|
|
3087
|
+
step: parseInt(stepMatch[2], 10),
|
|
3088
|
+
total: parseInt(stepMatch[3], 10),
|
|
3089
|
+
command: stepMatch[4]
|
|
3090
|
+
};
|
|
3091
|
+
const timingMatch = TIMING_RE.exec(content);
|
|
3092
|
+
if (timingMatch) {
|
|
3093
|
+
const text = timingMatch[2];
|
|
3094
|
+
if (text.trim()) return {
|
|
3095
|
+
kind: "output",
|
|
3096
|
+
stepNum,
|
|
3097
|
+
text
|
|
3098
|
+
};
|
|
3099
|
+
return {
|
|
3100
|
+
kind: "other",
|
|
3101
|
+
text: ""
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
if (content.trim()) return {
|
|
3105
|
+
kind: "output",
|
|
3106
|
+
stepNum,
|
|
3107
|
+
text: content
|
|
3108
|
+
};
|
|
3109
|
+
return {
|
|
3110
|
+
kind: "other",
|
|
3111
|
+
text: ""
|
|
3112
|
+
};
|
|
3113
|
+
}
|
|
3114
|
+
const tsMatch = TIMESTAMP_RE.exec(trimmed);
|
|
3115
|
+
if (tsMatch) return {
|
|
3116
|
+
kind: "platform",
|
|
3117
|
+
message: tsMatch[2]
|
|
3118
|
+
};
|
|
3119
|
+
return {
|
|
3120
|
+
kind: "other",
|
|
3121
|
+
text: trimmed
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
const BAR_WIDTH = 20;
|
|
3125
|
+
const BRAND = chalk.rgb(255, 77, 0);
|
|
3126
|
+
function renderProgressBar(filled, total, allCached, allDone) {
|
|
3127
|
+
const ratio = total > 0 ? filled / total : 0;
|
|
3128
|
+
const filledChars = Math.round(ratio * BAR_WIDTH);
|
|
3129
|
+
const emptyChars = BAR_WIDTH - filledChars;
|
|
3130
|
+
const counter = `${filled}/${total}`;
|
|
3131
|
+
if (allCached) return `${BRAND("━".repeat(BAR_WIDTH))} ${BRAND(`${counter} ◆ cached`)}`;
|
|
3132
|
+
if (allDone) return `${chalk.green("━".repeat(BAR_WIDTH))} ${chalk.green(`${counter} ✓`)}`;
|
|
3133
|
+
return chalk.cyan("━".repeat(filledChars)) + chalk.dim("─".repeat(emptyChars)) + ` ${chalk.dim(counter)}`;
|
|
3134
|
+
}
|
|
3135
|
+
const SPINNER_FRAMES = [
|
|
3136
|
+
"⠋",
|
|
3137
|
+
"⠙",
|
|
3138
|
+
"⠹",
|
|
3139
|
+
"⠸",
|
|
3140
|
+
"⠼",
|
|
3141
|
+
"⠴",
|
|
3142
|
+
"⠦",
|
|
3143
|
+
"⠧",
|
|
3144
|
+
"⠇",
|
|
3145
|
+
"⠏"
|
|
3146
|
+
];
|
|
3147
|
+
/**
|
|
3148
|
+
* Dashboard-style renderer for compact TTY mode.
|
|
3149
|
+
* Redraws the entire build progress block on each update.
|
|
3150
|
+
* Includes an integrated spinner that animates via setInterval.
|
|
3151
|
+
*/
|
|
3152
|
+
var BuildProgressRenderer = class {
|
|
3153
|
+
stages = /* @__PURE__ */ new Map();
|
|
3154
|
+
stageOrder = [];
|
|
3155
|
+
platformMessages = [];
|
|
3156
|
+
renderLineCount = 0;
|
|
3157
|
+
phase = "waiting";
|
|
3158
|
+
runtimeHeaderPrinted = false;
|
|
3159
|
+
serviceName;
|
|
3160
|
+
spinnerFrame = 0;
|
|
3161
|
+
spinnerInterval = null;
|
|
3162
|
+
spinnerText = "Aguardando início do build...";
|
|
3163
|
+
/** External ora spinner reference — used to pause/resume during runtime log output */
|
|
3164
|
+
externalSpinner = null;
|
|
3165
|
+
constructor(serviceName) {
|
|
3166
|
+
this.serviceName = serviceName;
|
|
3167
|
+
this.startSpinner();
|
|
3168
|
+
}
|
|
3169
|
+
setExternalSpinner(spinner$1) {
|
|
3170
|
+
this.externalSpinner = spinner$1;
|
|
3171
|
+
}
|
|
3172
|
+
startSpinner() {
|
|
3173
|
+
if (this.spinnerInterval) return;
|
|
3174
|
+
this.spinnerInterval = setInterval(() => {
|
|
3175
|
+
this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
3176
|
+
this.render();
|
|
3177
|
+
}, 80);
|
|
3178
|
+
}
|
|
3179
|
+
stopSpinner() {
|
|
3180
|
+
if (this.spinnerInterval) {
|
|
3181
|
+
clearInterval(this.spinnerInterval);
|
|
3182
|
+
this.spinnerInterval = null;
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
setBuilding() {
|
|
3186
|
+
this.phase = "building";
|
|
3187
|
+
this.spinnerText = "Compilando...";
|
|
3188
|
+
}
|
|
3189
|
+
switchToRuntime() {
|
|
3190
|
+
if (this.phase === "runtime") return;
|
|
3191
|
+
for (const stage of this.stages.values()) if (stage.steps.size > 0 && stage.steps.size < stage.total) stage.total = stage.steps.size;
|
|
3192
|
+
this.stopSpinner();
|
|
3193
|
+
this.render();
|
|
3194
|
+
this.renderLineCount = 0;
|
|
3195
|
+
this.phase = "runtime";
|
|
3196
|
+
}
|
|
3197
|
+
processLine(raw) {
|
|
3198
|
+
const trimmed = raw.trim();
|
|
3199
|
+
if (!trimmed) return;
|
|
3200
|
+
if (this.phase === "runtime") {
|
|
3201
|
+
this.printRuntimeLine(trimmed);
|
|
3202
|
+
return;
|
|
3203
|
+
}
|
|
3204
|
+
if (this.phase === "waiting") {
|
|
3205
|
+
this.phase = "building";
|
|
3206
|
+
this.spinnerText = "Compilando...";
|
|
3207
|
+
}
|
|
3208
|
+
const parsed = parseBuildLine(trimmed);
|
|
3209
|
+
switch (parsed.kind) {
|
|
3210
|
+
case "step": {
|
|
3211
|
+
let stage = this.stages.get(parsed.stage);
|
|
3212
|
+
if (!stage) {
|
|
3213
|
+
stage = {
|
|
3214
|
+
name: parsed.stage,
|
|
3215
|
+
total: parsed.total,
|
|
3216
|
+
steps: /* @__PURE__ */ new Map(),
|
|
3217
|
+
stepNumMap: /* @__PURE__ */ new Map(),
|
|
3218
|
+
cachedStepNums: /* @__PURE__ */ new Set(),
|
|
3219
|
+
doneStepNums: /* @__PURE__ */ new Set()
|
|
3220
|
+
};
|
|
3221
|
+
this.stages.set(parsed.stage, stage);
|
|
3222
|
+
this.stageOrder.push(parsed.stage);
|
|
3223
|
+
}
|
|
3224
|
+
stage.steps.set(parsed.step, parsed.command);
|
|
3225
|
+
stage.stepNumMap.set(parsed.stepNum, parsed.step);
|
|
3226
|
+
stage.total = Math.max(stage.total, parsed.total);
|
|
3227
|
+
break;
|
|
3228
|
+
}
|
|
3229
|
+
case "cached":
|
|
3230
|
+
for (const stage of this.stages.values()) if (stage.stepNumMap.has(parsed.stepNum)) {
|
|
3231
|
+
stage.cachedStepNums.add(parsed.stepNum);
|
|
3232
|
+
break;
|
|
3233
|
+
}
|
|
3234
|
+
break;
|
|
3235
|
+
case "done":
|
|
3236
|
+
for (const stage of this.stages.values()) if (stage.stepNumMap.has(parsed.stepNum)) {
|
|
3237
|
+
stage.doneStepNums.add(parsed.stepNum);
|
|
3238
|
+
break;
|
|
3239
|
+
}
|
|
3240
|
+
break;
|
|
3241
|
+
case "platform": {
|
|
3242
|
+
const cleaned = cleanDisplayLine(parsed.message);
|
|
3243
|
+
if (cleaned) this.platformMessages.push(cleaned);
|
|
3244
|
+
break;
|
|
3245
|
+
}
|
|
3246
|
+
case "output":
|
|
3247
|
+
case "other": break;
|
|
3248
|
+
}
|
|
3249
|
+
this.render();
|
|
3250
|
+
}
|
|
3251
|
+
printRuntimeLine(line) {
|
|
3252
|
+
const parsed = parseBuildLine(line);
|
|
3253
|
+
let text = null;
|
|
3254
|
+
if (parsed.kind === "platform") text = parsed.message;
|
|
3255
|
+
else if (parsed.kind === "other" && parsed.text) text = parsed.text;
|
|
3256
|
+
else if (parsed.kind === "output") text = parsed.text;
|
|
3257
|
+
if (!text) return;
|
|
3258
|
+
if (isHiddenMessage(text)) return;
|
|
3259
|
+
if (this.externalSpinner) this.externalSpinner.clear();
|
|
3260
|
+
if (!this.runtimeHeaderPrinted) {
|
|
3261
|
+
this.runtimeHeaderPrinted = true;
|
|
3262
|
+
console.log(chalk.cyan.bold(`\n RUNTIME`));
|
|
3263
|
+
}
|
|
3264
|
+
console.log(` ${text}`);
|
|
3265
|
+
if (this.externalSpinner) this.externalSpinner.render();
|
|
3266
|
+
}
|
|
3267
|
+
isStageComplete(stage) {
|
|
3268
|
+
return stage.steps.size >= stage.total;
|
|
3269
|
+
}
|
|
3270
|
+
render() {
|
|
3271
|
+
if (this.renderLineCount > 0) process.stdout.write(`\x1b[${this.renderLineCount}A\x1b[J`);
|
|
3272
|
+
let lines = 0;
|
|
3273
|
+
const label = this.serviceName ? `BUILD ${chalk.dim(`(${this.serviceName})`)}` : "BUILD";
|
|
3274
|
+
process.stdout.write(`${chalk.cyan.bold(` ${label}`)}\n`);
|
|
3275
|
+
lines++;
|
|
3276
|
+
for (const msg of this.platformMessages) {
|
|
3277
|
+
process.stdout.write(` ${msg}\n`);
|
|
3278
|
+
lines++;
|
|
3279
|
+
}
|
|
3280
|
+
if (this.stageOrder.length > 0) {
|
|
3281
|
+
process.stdout.write("\n");
|
|
3282
|
+
lines++;
|
|
3283
|
+
}
|
|
3284
|
+
const maxNameLen = Math.max(...this.stageOrder.map((n) => n.length), 4);
|
|
3285
|
+
for (let i = 0; i < this.stageOrder.length; i++) {
|
|
3286
|
+
const stageName = this.stageOrder[i];
|
|
3287
|
+
const stage = this.stages.get(stageName);
|
|
3288
|
+
const complete = this.isStageComplete(stage);
|
|
3289
|
+
const allCached = complete && stage.cachedStepNums.size === stage.steps.size;
|
|
3290
|
+
const allDone = complete && !allCached;
|
|
3291
|
+
const bar = renderProgressBar(stage.steps.size, stage.total, allCached, allDone);
|
|
3292
|
+
const paddedName = chalk.bold(stageName.padEnd(maxNameLen));
|
|
3293
|
+
process.stdout.write(` ${paddedName} ${bar}\n`);
|
|
3294
|
+
lines++;
|
|
3295
|
+
const sortedSteps = [...stage.steps.entries()].sort((a, b) => a[0] - b[0]);
|
|
3296
|
+
for (const [stepNum, command] of sortedSteps) {
|
|
3297
|
+
let stepStatus = "";
|
|
3298
|
+
for (const [bkNum, dockerStep] of stage.stepNumMap.entries()) if (dockerStep === stepNum) {
|
|
3299
|
+
if (stage.cachedStepNums.has(bkNum)) stepStatus = ` ${BRAND("◆")}`;
|
|
3300
|
+
else if (stage.doneStepNums.has(bkNum)) stepStatus = ` ${chalk.green("✓")}`;
|
|
3301
|
+
break;
|
|
3302
|
+
}
|
|
3303
|
+
process.stdout.write(` ${command}${stepStatus}\n`);
|
|
3304
|
+
lines++;
|
|
3305
|
+
}
|
|
3306
|
+
if (i < this.stageOrder.length - 1) {
|
|
3307
|
+
process.stdout.write("\n");
|
|
3308
|
+
lines++;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
if (this.spinnerInterval) {
|
|
3312
|
+
if (!(this.stageOrder.length > 0 && this.stageOrder.every((name) => this.isStageComplete(this.stages.get(name))))) {
|
|
3313
|
+
const frame = SPINNER_FRAMES[this.spinnerFrame];
|
|
3314
|
+
process.stdout.write(`\n ${chalk.cyan(frame)} ${this.spinnerText}\n`);
|
|
3315
|
+
lines += 2;
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
this.renderLineCount = lines;
|
|
3319
|
+
}
|
|
3320
|
+
};
|
|
2963
3321
|
async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
2964
3322
|
const client = await getClient();
|
|
2965
3323
|
const isVerbose = process.env.VELOZ_VERBOSE === "true";
|
|
@@ -2968,12 +3326,10 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
2968
3326
|
const isGHA = !mcp && process.env.GITHUB_ACTIONS === "true";
|
|
2969
3327
|
const allLogLines = [];
|
|
2970
3328
|
let buildSpinner = null;
|
|
3329
|
+
let renderer = null;
|
|
2971
3330
|
if (mcp) log(serviceName ? `[deploy] Build: ${serviceName}` : "[deploy] Build iniciando...");
|
|
2972
3331
|
else if (isGHA) startGroup(serviceName ? `Build: ${serviceName}` : "Build");
|
|
2973
|
-
else if (isTTY && !isVerbose)
|
|
2974
|
-
text: "Aguardando início do build...",
|
|
2975
|
-
color: "cyan"
|
|
2976
|
-
}).start();
|
|
3332
|
+
else if (isTTY && !isVerbose) renderer = new BuildProgressRenderer(serviceName);
|
|
2977
3333
|
else if (isTTY) {
|
|
2978
3334
|
const header = serviceName ? `Build: ${chalk.bold(serviceName)}` : "Build";
|
|
2979
3335
|
console.log(chalk.cyan(`\n${header}`));
|
|
@@ -2989,19 +3345,24 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
2989
3345
|
const label = statusLabels[event.content] ?? event.content;
|
|
2990
3346
|
finalStatus = event.content;
|
|
2991
3347
|
if (mcp) log(`[deploy] Status: ${label}`);
|
|
2992
|
-
else if (
|
|
2993
|
-
if (
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3348
|
+
else if (renderer) {
|
|
3349
|
+
if (event.content === "BUILDING") renderer.setBuilding();
|
|
3350
|
+
else if (event.content === "DEPLOYING") {
|
|
3351
|
+
renderer.switchToRuntime();
|
|
3352
|
+
buildSpinner = ora({
|
|
3353
|
+
text: "Publicando...",
|
|
3354
|
+
color: "cyan"
|
|
3355
|
+
}).start();
|
|
3356
|
+
renderer.setExternalSpinner(buildSpinner);
|
|
3357
|
+
} else if (event.content === "LIVE") {
|
|
3358
|
+
if (buildSpinner) {
|
|
3359
|
+
renderer.setExternalSpinner(null);
|
|
3002
3360
|
buildSpinner.succeed("Publicado");
|
|
3003
3361
|
buildSpinner = null;
|
|
3004
|
-
}
|
|
3362
|
+
}
|
|
3363
|
+
} else if (TERMINAL_STATUSES.has(event.content) && event.content !== "LIVE") {
|
|
3364
|
+
if (buildSpinner) {
|
|
3365
|
+
renderer.setExternalSpinner(null);
|
|
3005
3366
|
buildSpinner.fail(label);
|
|
3006
3367
|
buildSpinner = null;
|
|
3007
3368
|
}
|
|
@@ -3015,16 +3376,11 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
3015
3376
|
allLogLines.push(...lines);
|
|
3016
3377
|
if (mcp) {
|
|
3017
3378
|
for (const line of lines) if (line.trim()) log(`[build] ${line.trim()}`);
|
|
3018
|
-
} else if (
|
|
3019
|
-
const trimmed = line.trim();
|
|
3020
|
-
if (trimmed) {
|
|
3021
|
-
const display = trimmed.length > 60 ? trimmed.substring(0, 57) + "..." : trimmed;
|
|
3022
|
-
if (buildSpinner) buildSpinner.text = display;
|
|
3023
|
-
}
|
|
3024
|
-
}
|
|
3379
|
+
} else if (renderer) for (const line of lines) renderer.processLine(line);
|
|
3025
3380
|
else for (const line of lines) if (line.trim()) process.stdout.write(` ${line}\n`);
|
|
3026
3381
|
}
|
|
3027
3382
|
} catch {
|
|
3383
|
+
if (renderer) renderer.stopSpinner();
|
|
3028
3384
|
if (buildSpinner) {
|
|
3029
3385
|
buildSpinner.stop();
|
|
3030
3386
|
buildSpinner = null;
|
|
@@ -3038,6 +3394,7 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
3038
3394
|
} catch {}
|
|
3039
3395
|
}
|
|
3040
3396
|
if (isGHA) endGroup();
|
|
3397
|
+
if (renderer) renderer.stopSpinner();
|
|
3041
3398
|
const urls = finalStatus === "LIVE" ? await fetchDeployUrls(client, serviceId) : [];
|
|
3042
3399
|
if (finalStatus === "LIVE") {
|
|
3043
3400
|
if (buildSpinner) {
|
|
@@ -3056,7 +3413,7 @@ async function streamDeploymentLogs(deploymentId, serviceId, serviceName) {
|
|
|
3056
3413
|
if (mcp) {
|
|
3057
3414
|
log(`✗ Deploy finalizou: ${label}`);
|
|
3058
3415
|
for (const hint of hints) log(` → ${hint}`);
|
|
3059
|
-
} else if (isTTY && allLogLines.length > 0) {
|
|
3416
|
+
} else if (isTTY && !renderer && allLogLines.length > 0) {
|
|
3060
3417
|
console.log();
|
|
3061
3418
|
console.log(chalk.red(` ${"─".repeat(50)}`));
|
|
3062
3419
|
console.log(chalk.red.bold(" Logs de build:"));
|
|
@@ -3150,7 +3507,7 @@ const LOGO_LINES = [
|
|
|
3150
3507
|
];
|
|
3151
3508
|
const BRAND_COLOR = "#FF4D00";
|
|
3152
3509
|
function getVersion() {
|
|
3153
|
-
return "0.0.0-beta.
|
|
3510
|
+
return "0.0.0-beta.17";
|
|
3154
3511
|
}
|
|
3155
3512
|
function printBanner(subtitle) {
|
|
3156
3513
|
const version = getVersion();
|
|
@@ -3178,22 +3535,29 @@ function resolveServiceConf(velozConfig, serviceId) {
|
|
|
3178
3535
|
if (!velozConfig) return void 0;
|
|
3179
3536
|
for (const [, conf] of Object.entries(velozConfig.services)) if (conf.id === serviceId) {
|
|
3180
3537
|
const merged = mergeServiceWithDefaults(conf, velozConfig.defaults);
|
|
3538
|
+
const build = merged.build;
|
|
3539
|
+
const isDockerfile = build?.method === "dockerfile";
|
|
3181
3540
|
return {
|
|
3182
3541
|
type: merged.type?.toUpperCase(),
|
|
3183
3542
|
branch: merged.branch,
|
|
3184
|
-
buildCommand:
|
|
3543
|
+
buildCommand: build?.command ?? void 0,
|
|
3185
3544
|
startCommand: merged.runtime?.command ?? void 0,
|
|
3545
|
+
preStartCommand: merged.runtime?.preStartCommand ?? void 0,
|
|
3186
3546
|
port: merged.runtime?.port ?? void 0,
|
|
3187
3547
|
rootDirectory: merged.root,
|
|
3548
|
+
docker: isDockerfile ? {
|
|
3549
|
+
dockerfile: build.dockerfile ?? "Dockerfile",
|
|
3550
|
+
context: build.context ?? merged.root ?? "."
|
|
3551
|
+
} : void 0,
|
|
3188
3552
|
instanceCount: merged.resources?.instances ?? void 0,
|
|
3189
3553
|
cpuLimit: merged.resources?.cpu ?? void 0,
|
|
3190
3554
|
memoryLimit: merged.resources?.memory ?? void 0,
|
|
3191
3555
|
healthCheckPath: merged.runtime?.healthCheck?.path ?? null,
|
|
3192
|
-
aptPackages:
|
|
3193
|
-
nodeVersion:
|
|
3194
|
-
nixpkgsArchive:
|
|
3195
|
-
packageManager:
|
|
3196
|
-
installCommand:
|
|
3556
|
+
aptPackages: build?.aptPackages ?? void 0,
|
|
3557
|
+
nodeVersion: build?.nodeVersion ?? void 0,
|
|
3558
|
+
nixpkgsArchive: build?.nixpkgsArchive ?? void 0,
|
|
3559
|
+
packageManager: build?.packageManager,
|
|
3560
|
+
installCommand: build?.installCommand ?? void 0,
|
|
3197
3561
|
volumes: merged.volumes ?? void 0
|
|
3198
3562
|
};
|
|
3199
3563
|
}
|
|
@@ -3622,7 +3986,7 @@ async function autoUpdate() {
|
|
|
3622
3986
|
if (process.env.VELOZ_MCP === "true") return;
|
|
3623
3987
|
const pm = detectPackageManager();
|
|
3624
3988
|
if (!pm) return;
|
|
3625
|
-
const currentVersion = "0.0.0-beta.
|
|
3989
|
+
const currentVersion = "0.0.0-beta.17";
|
|
3626
3990
|
const latestVersion = await fetchLatestVersion();
|
|
3627
3991
|
if (!latestVersion || latestVersion === currentVersion) return;
|
|
3628
3992
|
const installCmd = getInstallCommand(pm, latestVersion);
|
|
@@ -3698,7 +4062,13 @@ async function provisionDatabases(config, opts) {
|
|
|
3698
4062
|
name: key,
|
|
3699
4063
|
engine: dbConfig.engine,
|
|
3700
4064
|
engineVersion: dbConfig.version,
|
|
3701
|
-
storage: dbConfig.storage
|
|
4065
|
+
storage: dbConfig.storage,
|
|
4066
|
+
cpuLimit: dbConfig.resources?.cpu,
|
|
4067
|
+
memoryLimit: dbConfig.resources?.memory,
|
|
4068
|
+
poolerEnabled: dbConfig.pooler?.enabled,
|
|
4069
|
+
poolerPoolMode: dbConfig.pooler?.poolMode,
|
|
4070
|
+
poolerDefaultPoolSize: dbConfig.pooler?.defaultPoolSize,
|
|
4071
|
+
poolerMaxClientConn: dbConfig.pooler?.maxClientConn
|
|
3702
4072
|
})
|
|
3703
4073
|
});
|
|
3704
4074
|
success(`Banco de dados "${key}" criado (provisionando...).`);
|
|
@@ -3733,9 +4103,13 @@ function getDatabaseUrlHints(config) {
|
|
|
3733
4103
|
const databases = config.databases ?? {};
|
|
3734
4104
|
const entries = Object.entries(databases);
|
|
3735
4105
|
if (entries.length === 0) return [];
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
4106
|
+
const hints = [];
|
|
4107
|
+
for (const [key, db] of entries) if (db.engine === "postgresql" || db.engine === "mysql") {
|
|
4108
|
+
const prefix = key.toUpperCase().replace(/-/g, "_");
|
|
4109
|
+
hints.push(`${prefix}_DATABASE_URL será injetado automaticamente de "${key}"`);
|
|
4110
|
+
if (db.pooler?.enabled && db.engine === "postgresql") hints.push(`${prefix}_POOLER_URL será injetado automaticamente (PgBouncer)`);
|
|
4111
|
+
}
|
|
4112
|
+
return hints;
|
|
3739
4113
|
}
|
|
3740
4114
|
|
|
3741
4115
|
//#endregion
|
|
@@ -3752,6 +4126,14 @@ const SERVICE_TYPE_LABELS = {
|
|
|
3752
4126
|
* the server will generate one with nixpacks.
|
|
3753
4127
|
*/
|
|
3754
4128
|
function prepareExtraFiles(_detection, serviceConfig) {
|
|
4129
|
+
if (serviceConfig?.docker) {
|
|
4130
|
+
const dockerfilePath = resolve(process.cwd(), serviceConfig.docker.dockerfile);
|
|
4131
|
+
if (!existsSync(dockerfilePath)) throw new Error(`Dockerfile não encontrado: ${serviceConfig.docker.dockerfile}`);
|
|
4132
|
+
return [{
|
|
4133
|
+
name: "Dockerfile",
|
|
4134
|
+
content: readFileSync(dockerfilePath, "utf-8")
|
|
4135
|
+
}];
|
|
4136
|
+
}
|
|
3755
4137
|
if (existsSync(resolve(process.cwd(), "Dockerfile"))) return [];
|
|
3756
4138
|
const rootDir = serviceConfig?.rootDirectory || ".";
|
|
3757
4139
|
const serviceDockerfilePath = resolve(process.cwd(), rootDir, "Dockerfile");
|
|
@@ -3789,21 +4171,18 @@ async function computeExtraFilesForServices(services) {
|
|
|
3789
4171
|
return results;
|
|
3790
4172
|
}
|
|
3791
4173
|
async function triggerDeploy(serviceId, serviceName, preDetection) {
|
|
3792
|
-
const spinUpload = spinner(serviceName ? `Fazendo upload ${chalk.bold(serviceName)}...` : "Fazendo upload do código...");
|
|
3793
4174
|
const sizeInBytes = await calculateDirectorySize(process.cwd());
|
|
3794
4175
|
const sizeMB = Math.round(sizeInBytes / (1024 * 1024) * 10) / 10;
|
|
3795
|
-
if (sizeMB > 5) spinUpload.text = `Fazendo upload (${sizeMB} MB)...`;
|
|
3796
4176
|
const client = await getClient();
|
|
3797
|
-
const
|
|
4177
|
+
const velozConfig = loadConfig();
|
|
4178
|
+
const serviceConf = resolveServiceConf(velozConfig, serviceId);
|
|
3798
4179
|
const detection = preDetection ?? detectLocalRepo();
|
|
3799
4180
|
warnIfEphemeralFsDetected(detection, serviceConf, serviceName ?? void 0);
|
|
3800
4181
|
const extraFiles = prepareExtraFiles(detection, serviceConf);
|
|
3801
4182
|
const warnings = runPreDeployChecks(serviceConf?.rootDirectory || ".");
|
|
3802
|
-
if (warnings.length > 0)
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
spinUpload.start();
|
|
3806
|
-
}
|
|
4183
|
+
if (warnings.length > 0) printDeployWarnings(warnings);
|
|
4184
|
+
const spinUpload = spinner(serviceName ? `Fazendo upload ${chalk.bold(serviceName)}...` : "Fazendo upload do código...");
|
|
4185
|
+
if (sizeMB > 5) spinUpload.text = `Fazendo upload (${sizeMB} MB)...`;
|
|
3807
4186
|
spinUpload.text = "Iniciando deploy...";
|
|
3808
4187
|
const deployment = await withRetry(() => client.deployments.create({
|
|
3809
4188
|
serviceId,
|
|
@@ -3816,7 +4195,12 @@ async function triggerDeploy(serviceId, serviceName, preDetection) {
|
|
|
3816
4195
|
setupSigintHandler();
|
|
3817
4196
|
trackDeployment(deployment.id);
|
|
3818
4197
|
try {
|
|
3819
|
-
|
|
4198
|
+
const result = await streamDeploymentLogs(deployment.id, serviceId, serviceName);
|
|
4199
|
+
if (result.status === "LIVE" && velozConfig?.project?.id) {
|
|
4200
|
+
const dashUrl = `${process.env.VELOZ_WEB_URL || "https://app.onveloz.com"}/projetos/${velozConfig.project.id}`;
|
|
4201
|
+
info(`Dashboard: ${chalk.dim(dashUrl)}`);
|
|
4202
|
+
}
|
|
4203
|
+
return result;
|
|
3820
4204
|
} finally {
|
|
3821
4205
|
untrackDeployment(deployment.id);
|
|
3822
4206
|
}
|
|
@@ -3876,15 +4260,56 @@ async function maybeConfigurePersistentVolume(serviceConfig, detection, opts, se
|
|
|
3876
4260
|
async function findServicesFromConfig() {
|
|
3877
4261
|
const config = loadConfig();
|
|
3878
4262
|
if (!config) return [];
|
|
4263
|
+
const missingIds = Object.entries(config.services).filter(([_, svc]) => !svc.id);
|
|
4264
|
+
if (missingIds.length > 0 && config.project.id) {
|
|
4265
|
+
const client = await getClient();
|
|
4266
|
+
const remoteServices = await withRetry(() => client.services.list({ projectId: config.project.id }));
|
|
4267
|
+
let configUpdated = false;
|
|
4268
|
+
for (const [key, serviceConfig] of missingIds) {
|
|
4269
|
+
const match = remoteServices.find((rs) => rs.name.toLowerCase() === serviceConfig.name.toLowerCase() || rs.name.toLowerCase() === key.toLowerCase());
|
|
4270
|
+
if (match) {
|
|
4271
|
+
serviceConfig.id = match.id;
|
|
4272
|
+
config.services[key] = serviceConfig;
|
|
4273
|
+
configUpdated = true;
|
|
4274
|
+
info(`Serviço "${serviceConfig.name}" vinculado (ID: ${match.id})`);
|
|
4275
|
+
} else {
|
|
4276
|
+
info(`Serviço "${serviceConfig.name}" não encontrado no projeto.`);
|
|
4277
|
+
if (await promptConfirm(`Criar serviço "${serviceConfig.name}" no projeto "${config.project.name}"?`)) {
|
|
4278
|
+
const branch = getGitBranch();
|
|
4279
|
+
const serviceType = serviceConfig.type?.toUpperCase() ?? "WEB";
|
|
4280
|
+
serviceConfig.id = (await withSpinner({
|
|
4281
|
+
text: `Criando serviço "${serviceConfig.name}"...`,
|
|
4282
|
+
fn: () => withRetry(() => client.services.create({
|
|
4283
|
+
projectId: config.project.id,
|
|
4284
|
+
name: serviceConfig.name,
|
|
4285
|
+
type: serviceType,
|
|
4286
|
+
branch,
|
|
4287
|
+
rootDirectory: serviceConfig.root ?? "."
|
|
4288
|
+
}))
|
|
4289
|
+
})).id;
|
|
4290
|
+
config.services[key] = serviceConfig;
|
|
4291
|
+
configUpdated = true;
|
|
4292
|
+
success(`Serviço "${serviceConfig.name}" criado.`);
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
if (configUpdated) {
|
|
4297
|
+
saveConfig(config);
|
|
4298
|
+
info(`Arquivo ${getConfigFileName()} atualizado com IDs dos serviços.`);
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
3879
4301
|
const services = [];
|
|
3880
|
-
for (const [key, serviceConfig] of Object.entries(config.services))
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
4302
|
+
for (const [key, serviceConfig] of Object.entries(config.services)) {
|
|
4303
|
+
if (!serviceConfig.id) continue;
|
|
4304
|
+
services.push({
|
|
4305
|
+
path: resolve(process.cwd(), serviceConfig.root ?? "."),
|
|
4306
|
+
serviceId: serviceConfig.id,
|
|
4307
|
+
projectId: config.project.id,
|
|
4308
|
+
serviceName: serviceConfig.name,
|
|
4309
|
+
projectName: config.project.name,
|
|
4310
|
+
key
|
|
4311
|
+
});
|
|
4312
|
+
}
|
|
3888
4313
|
return services;
|
|
3889
4314
|
}
|
|
3890
4315
|
function readLocalFile(path) {
|
|
@@ -4063,6 +4488,7 @@ async function createServiceFlow(projectId, projectName, repoName, opts = {}) {
|
|
|
4063
4488
|
const allApps = detection.monorepoApps.map((a) => ({
|
|
4064
4489
|
name: a.name,
|
|
4065
4490
|
root: a.path,
|
|
4491
|
+
type: a.framework?.type ?? "WEB",
|
|
4066
4492
|
framework: a.framework?.name ?? null,
|
|
4067
4493
|
buildCommand: a.framework?.buildCommand ?? null,
|
|
4068
4494
|
startCommand: a.framework?.startCommand ?? null,
|
|
@@ -4128,7 +4554,7 @@ async function createServiceFlow(projectId, projectName, repoName, opts = {}) {
|
|
|
4128
4554
|
fn: () => withRetry(() => client.services.create({
|
|
4129
4555
|
projectId,
|
|
4130
4556
|
name: app.name,
|
|
4131
|
-
type:
|
|
4557
|
+
type: app.type,
|
|
4132
4558
|
branch,
|
|
4133
4559
|
rootDirectory: app.root,
|
|
4134
4560
|
buildCommand: app.buildCommand ?? void 0,
|
|
@@ -4341,6 +4767,7 @@ async function addServiceFlow(existingConfig, opts) {
|
|
|
4341
4767
|
const availableApps = detection.monorepoApps.map((a) => ({
|
|
4342
4768
|
name: a.name,
|
|
4343
4769
|
root: a.path,
|
|
4770
|
+
type: a.framework?.type ?? "WEB",
|
|
4344
4771
|
framework: a.framework?.name ?? null,
|
|
4345
4772
|
buildCommand: a.framework?.buildCommand ?? null,
|
|
4346
4773
|
startCommand: a.framework?.startCommand ?? null,
|
|
@@ -4408,7 +4835,7 @@ async function addServiceFlow(existingConfig, opts) {
|
|
|
4408
4835
|
fn: () => withRetry(() => client.services.create({
|
|
4409
4836
|
projectId,
|
|
4410
4837
|
name: app.name,
|
|
4411
|
-
type:
|
|
4838
|
+
type: app.type,
|
|
4412
4839
|
branch,
|
|
4413
4840
|
rootDirectory: app.root,
|
|
4414
4841
|
buildCommand: app.buildCommand ?? void 0,
|
|
@@ -4640,7 +5067,8 @@ async function cliDeployFlow(opts) {
|
|
|
4640
5067
|
const available = configuredServices.map((s) => ` • ${s.key} (${s.serviceName})`).join("\n");
|
|
4641
5068
|
throw new Error(`Serviço '${opts.service}' não encontrado.\n\nServiços disponíveis:\n${available}`);
|
|
4642
5069
|
}
|
|
4643
|
-
|
|
5070
|
+
await triggerDeploy(found.serviceId, found.serviceName);
|
|
5071
|
+
return;
|
|
4644
5072
|
}
|
|
4645
5073
|
if (opts.all || opts.yes || configuredServices.length === 1) {
|
|
4646
5074
|
if (configuredServices.length > 1 && !opts.yes) {
|
|
@@ -4655,25 +5083,25 @@ async function cliDeployFlow(opts) {
|
|
|
4655
5083
|
return;
|
|
4656
5084
|
}
|
|
4657
5085
|
}
|
|
4658
|
-
if (configuredServices.length === 1)
|
|
4659
|
-
else
|
|
4660
|
-
|
|
4661
|
-
console.log(chalk.bold("\nServiços disponíveis:\n"));
|
|
4662
|
-
const selectedServiceIds = await promptMultiSelect("Quais serviços deseja fazer deploy?", configuredServices.map((s) => {
|
|
4663
|
-
const relPath = relative(process.cwd(), s.path) || ".";
|
|
4664
|
-
return {
|
|
4665
|
-
label: `${s.serviceName} ${chalk.dim(`(${relPath})`)}`,
|
|
4666
|
-
value: s.serviceId
|
|
4667
|
-
};
|
|
4668
|
-
}));
|
|
4669
|
-
const selectedServices = configuredServices.filter((s) => selectedServiceIds.includes(s.serviceId));
|
|
4670
|
-
if (selectedServices.length === 0) {
|
|
4671
|
-
info("Nenhum serviço selecionado.");
|
|
4672
|
-
return;
|
|
4673
|
-
}
|
|
4674
|
-
if (selectedServices.length === 1) return await triggerDeploy(selectedServices[0].serviceId, selectedServices[0].serviceName);
|
|
4675
|
-
else return await deployServicesInParallel(await computeExtraFilesForServices(selectedServices));
|
|
5086
|
+
if (configuredServices.length === 1) await triggerDeploy(configuredServices[0].serviceId, configuredServices[0].serviceName);
|
|
5087
|
+
else await deployServicesInParallel(await computeExtraFilesForServices(configuredServices));
|
|
5088
|
+
return;
|
|
4676
5089
|
}
|
|
5090
|
+
console.log(chalk.bold("\nServiços disponíveis:\n"));
|
|
5091
|
+
const selectedServiceIds = await promptMultiSelect("Quais serviços deseja fazer deploy?", configuredServices.map((s) => {
|
|
5092
|
+
const relPath = relative(process.cwd(), s.path) || ".";
|
|
5093
|
+
return {
|
|
5094
|
+
label: `${s.serviceName} ${chalk.dim(`(${relPath})`)}`,
|
|
5095
|
+
value: s.serviceId
|
|
5096
|
+
};
|
|
5097
|
+
}));
|
|
5098
|
+
const selectedServices = configuredServices.filter((s) => selectedServiceIds.includes(s.serviceId));
|
|
5099
|
+
if (selectedServices.length === 0) {
|
|
5100
|
+
info("Nenhum serviço selecionado.");
|
|
5101
|
+
return;
|
|
5102
|
+
}
|
|
5103
|
+
if (selectedServices.length === 1) await triggerDeploy(selectedServices[0].serviceId, selectedServices[0].serviceName);
|
|
5104
|
+
else await deployServicesInParallel(await computeExtraFilesForServices(selectedServices));
|
|
4677
5105
|
}
|
|
4678
5106
|
if (!isGitRepo()) throw new Error("Este diretório não é um repositório git. Inicialize com `git init` e adicione um remote.");
|
|
4679
5107
|
info("Detectando repositório git...");
|
|
@@ -4728,7 +5156,8 @@ async function cliDeployFlow(opts) {
|
|
|
4728
5156
|
info(`Arquivo ${getConfigFileName()} criado na raiz do projeto.`);
|
|
4729
5157
|
const freshConfig = loadConfig();
|
|
4730
5158
|
if (freshConfig) await provisionDatabases(freshConfig, { yes: opts.yes ?? false });
|
|
4731
|
-
|
|
5159
|
+
await triggerDeploy(serviceId$1, void 0, detection);
|
|
5160
|
+
return;
|
|
4732
5161
|
}
|
|
4733
5162
|
if (project && project.services.length === 0) {
|
|
4734
5163
|
info(`Projeto encontrado: ${chalk.bold(project.name)}`);
|
|
@@ -4739,7 +5168,8 @@ async function cliDeployFlow(opts) {
|
|
|
4739
5168
|
});
|
|
4740
5169
|
const freshConfig = loadConfig();
|
|
4741
5170
|
if (freshConfig) await provisionDatabases(freshConfig, { yes: opts.yes ?? false });
|
|
4742
|
-
|
|
5171
|
+
await triggerDeploy(serviceId$1);
|
|
5172
|
+
return;
|
|
4743
5173
|
}
|
|
4744
5174
|
info("Projeto não encontrado. Vamos criar um novo.");
|
|
4745
5175
|
const projectName = opts.yes ? remote.repo : await prompt(`Nome do projeto: ${chalk.dim(`(${remote.repo})`)}`) || remote.repo;
|
|
@@ -4758,7 +5188,7 @@ async function cliDeployFlow(opts) {
|
|
|
4758
5188
|
});
|
|
4759
5189
|
const newConfig = loadConfig();
|
|
4760
5190
|
if (newConfig) await provisionDatabases(newConfig, { yes: opts.yes ?? false });
|
|
4761
|
-
|
|
5191
|
+
await triggerDeploy(serviceId);
|
|
4762
5192
|
}
|
|
4763
5193
|
|
|
4764
5194
|
//#endregion
|
|
@@ -5072,7 +5502,7 @@ async function pruneRemovedEntries(config, existingConfig, services, databases)
|
|
|
5072
5502
|
//#region src/index.ts
|
|
5073
5503
|
if (process.argv.includes("--mcp")) process.env.VELOZ_MCP = "true";
|
|
5074
5504
|
const cli = Cli.create("veloz", {
|
|
5075
|
-
version: "0.0.0-beta.
|
|
5505
|
+
version: "0.0.0-beta.17",
|
|
5076
5506
|
description: "CLI da plataforma Veloz — deploy rápido para o Brasil",
|
|
5077
5507
|
env: z.object({ VELOZ_ENV: z.string().optional().describe("Ambiente alvo (ex: preview, staging)") })
|
|
5078
5508
|
});
|