@glash/cli 0.2.12 → 0.2.14
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/commands/deploy.mjs +74 -1
- package/lib/version.mjs +1 -1
- package/lib/zip.mjs +79 -74
- package/package.json +4 -4
package/commands/deploy.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { join, basename } from 'node:path';
|
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
8
|
import { openAsBlob } from 'node:fs';
|
|
9
9
|
import { access, readFile, rm, stat } from 'node:fs/promises';
|
|
10
|
+
import { stdout } from 'node:process';
|
|
10
11
|
|
|
11
12
|
function currentCommit() {
|
|
12
13
|
try {
|
|
@@ -179,6 +180,9 @@ export async function deploy({ flags }) {
|
|
|
179
180
|
const start = Date.now();
|
|
180
181
|
let pollDelayMs = 5000;
|
|
181
182
|
let lastProgressAt = Date.now();
|
|
183
|
+
let currentPhase = 'queued';
|
|
184
|
+
const indicator = createDeployIndicator({ start, getPhase: () => currentPhase });
|
|
185
|
+
indicator.start();
|
|
182
186
|
while (Date.now() - start < 15 * 60 * 1000) {
|
|
183
187
|
let pipe;
|
|
184
188
|
try {
|
|
@@ -203,24 +207,30 @@ export async function deploy({ flags }) {
|
|
|
203
207
|
const key = `${ev.id ?? ev.createdAt}:${ev.step}:${ev.status}`;
|
|
204
208
|
if (seen.has(key)) continue;
|
|
205
209
|
seen.add(key);
|
|
210
|
+
indicator.clear();
|
|
206
211
|
const tag = stepBadge(ev.status);
|
|
207
212
|
info(` ${tag} ${color.dim(ev.step.padEnd(8))} ${ev.message ?? ''}`);
|
|
208
213
|
lastProgressAt = Date.now();
|
|
214
|
+
currentPhase = phaseFromEvent(ev);
|
|
209
215
|
}
|
|
210
216
|
|
|
211
217
|
const status = pipe.deployStatus ?? pipe.buildStatus ?? '';
|
|
212
218
|
if (status && status !== lastStatus) lastStatus = status;
|
|
213
219
|
if (['ready', 'live', 'success'].includes(status)) {
|
|
220
|
+
indicator.stop();
|
|
214
221
|
const url = pipe.hostings?.[0]?.domains?.[0]?.domain;
|
|
215
222
|
ok(`Live${url ? ` → ${color.cyan(`https://${url.replace(/^https?:\/\//, '')}`)}` : ''}`);
|
|
216
223
|
return;
|
|
217
224
|
}
|
|
218
225
|
if (['error', 'failed'].includes(status)) {
|
|
226
|
+
indicator.stop();
|
|
219
227
|
return fail(`Deployment failed (${status}). Run \`glash logs ${dep.id}\` for details.`);
|
|
220
228
|
}
|
|
229
|
+
currentPhase = phaseFromPipeline(pipe, currentPhase);
|
|
221
230
|
pollDelayMs = nextPollDelay(pipe);
|
|
222
|
-
await
|
|
231
|
+
await indicator.wait(pollDelayMs);
|
|
223
232
|
}
|
|
233
|
+
indicator.stop();
|
|
224
234
|
warn('Timed out waiting for deployment. Check `glash status <id>`.');
|
|
225
235
|
}
|
|
226
236
|
|
|
@@ -300,4 +310,67 @@ function nextPollDelay(pipe) {
|
|
|
300
310
|
return 5000;
|
|
301
311
|
}
|
|
302
312
|
|
|
313
|
+
function phaseFromEvent(ev) {
|
|
314
|
+
if (ev.step === 'detect') return 'detecting';
|
|
315
|
+
if (ev.step === 'host') return 'assigning host';
|
|
316
|
+
if (ev.step === 'package') return ev.status === 'queued' ? 'queued' : 'packaging';
|
|
317
|
+
if (ev.step === 'build') return 'building';
|
|
318
|
+
if (ev.step === 'deploy') return ev.status === 'ready' ? 'finalizing' : 'deploying';
|
|
319
|
+
if (ev.step === 'route' || ev.step === 'edge' || ev.step === 'ssl') return 'routing';
|
|
320
|
+
if (ev.step === 'runtime') return 'checking runtime';
|
|
321
|
+
return ev.step || 'deploying';
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function phaseFromPipeline(pipe, fallback) {
|
|
325
|
+
const status = pipe.deployStatus ?? pipe.buildStatus ?? '';
|
|
326
|
+
if (status === 'queued') return 'queued';
|
|
327
|
+
if (status === 'building') return 'building';
|
|
328
|
+
if (status === 'rolling-out') return 'deploying';
|
|
329
|
+
const last = [...(pipe.events ?? [])].reverse().find(Boolean);
|
|
330
|
+
return last ? phaseFromEvent(last) : fallback;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function createDeployIndicator({ start, getPhase }) {
|
|
334
|
+
const interactive = Boolean(stdout.isTTY);
|
|
335
|
+
let frame = 0;
|
|
336
|
+
let timer;
|
|
337
|
+
let plainLast = 0;
|
|
338
|
+
const frames = ['.', '..', '...'];
|
|
339
|
+
|
|
340
|
+
function message() {
|
|
341
|
+
const elapsed = Math.floor((Date.now() - start) / 1000);
|
|
342
|
+
const dots = frames[frame++ % frames.length].padEnd(3, ' ');
|
|
343
|
+
return ` ${color.cyan('•')} ${color.dim('deploy'.padEnd(8))} ${getPhase()}${dots} ${color.dim(`${elapsed}s elapsed`)}`;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function render() {
|
|
347
|
+
if (!interactive) {
|
|
348
|
+
if (Date.now() - plainLast > 30_000) {
|
|
349
|
+
plainLast = Date.now();
|
|
350
|
+
info(message().trimEnd());
|
|
351
|
+
}
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
stdout.write(`\r\x1b[2K${message()}`);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
start() {
|
|
359
|
+
render();
|
|
360
|
+
timer = setInterval(render, 1000);
|
|
361
|
+
},
|
|
362
|
+
clear() {
|
|
363
|
+
if (interactive) stdout.write('\r\x1b[2K');
|
|
364
|
+
},
|
|
365
|
+
stop() {
|
|
366
|
+
if (timer) clearInterval(timer);
|
|
367
|
+
timer = undefined;
|
|
368
|
+
if (interactive) stdout.write('\r\x1b[2K');
|
|
369
|
+
},
|
|
370
|
+
wait(ms) {
|
|
371
|
+
return sleep(ms);
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
303
376
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
package/lib/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.2.
|
|
1
|
+
export const VERSION = '0.2.14';
|
package/lib/zip.mjs
CHANGED
|
@@ -1,86 +1,91 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import yazl from 'yazl';
|
|
2
3
|
import { createWriteStream } from 'node:fs';
|
|
3
4
|
import { join, relative } from 'node:path';
|
|
4
5
|
import fs from 'fs-extra';
|
|
5
6
|
|
|
6
7
|
export async function zipDirectory(sourceDir, outPath, { ignore = [] } = {}) {
|
|
8
|
+
// Default ignores
|
|
9
|
+
const defaultIgnore = [
|
|
10
|
+
'node_modules/**',
|
|
11
|
+
'**/node_modules/**',
|
|
12
|
+
'.git/**',
|
|
13
|
+
'**/.git/**',
|
|
14
|
+
'.next/**',
|
|
15
|
+
'**/.next/**',
|
|
16
|
+
'.next*/**',
|
|
17
|
+
'**/.next*/**',
|
|
18
|
+
'.nuxt/**',
|
|
19
|
+
'**/.nuxt/**',
|
|
20
|
+
'.nuxt*/**',
|
|
21
|
+
'**/.nuxt*/**',
|
|
22
|
+
'.output/**',
|
|
23
|
+
'**/.output/**',
|
|
24
|
+
'.svelte-kit/**',
|
|
25
|
+
'**/.svelte-kit/**',
|
|
26
|
+
'.wrangler/**',
|
|
27
|
+
'**/.wrangler/**',
|
|
28
|
+
'.netlify/**',
|
|
29
|
+
'**/.netlify/**',
|
|
30
|
+
'dist/**',
|
|
31
|
+
'**/dist/**',
|
|
32
|
+
'build/**',
|
|
33
|
+
'**/build/**',
|
|
34
|
+
'out/**',
|
|
35
|
+
'**/out/**',
|
|
36
|
+
'coverage/**',
|
|
37
|
+
'**/coverage/**',
|
|
38
|
+
'.turbo/**',
|
|
39
|
+
'**/.turbo/**',
|
|
40
|
+
'.cache/**',
|
|
41
|
+
'**/.cache/**',
|
|
42
|
+
'.parcel-cache/**',
|
|
43
|
+
'**/.parcel-cache/**',
|
|
44
|
+
'.vite/**',
|
|
45
|
+
'**/.vite/**',
|
|
46
|
+
'.glash/**',
|
|
47
|
+
'**/.glash/**',
|
|
48
|
+
'*.log',
|
|
49
|
+
'**/*.log',
|
|
50
|
+
'npm-debug.log*',
|
|
51
|
+
'**/npm-debug.log*',
|
|
52
|
+
'yarn-debug.log*',
|
|
53
|
+
'**/yarn-debug.log*',
|
|
54
|
+
'yarn-error.log*',
|
|
55
|
+
'**/yarn-error.log*',
|
|
56
|
+
'.env',
|
|
57
|
+
'**/.env',
|
|
58
|
+
'.env.local',
|
|
59
|
+
'**/.env.local',
|
|
60
|
+
'.env.production',
|
|
61
|
+
'**/.env.production',
|
|
62
|
+
'.env.development',
|
|
63
|
+
'**/.env.development',
|
|
64
|
+
];
|
|
65
|
+
const allIgnore = [...new Set([...defaultIgnore, ...loadIgnorePatterns(sourceDir), ...ignore])];
|
|
66
|
+
const files = await fg('**/*', {
|
|
67
|
+
cwd: sourceDir,
|
|
68
|
+
ignore: allIgnore,
|
|
69
|
+
dot: true,
|
|
70
|
+
onlyFiles: true,
|
|
71
|
+
followSymbolicLinks: false,
|
|
72
|
+
});
|
|
73
|
+
|
|
7
74
|
return new Promise((resolve, reject) => {
|
|
75
|
+
const zip = new yazl.ZipFile();
|
|
8
76
|
const output = createWriteStream(outPath);
|
|
9
|
-
|
|
10
|
-
const level = Number.isInteger(rawLevel) && rawLevel >= 0 && rawLevel <= 9 ? rawLevel : 1;
|
|
11
|
-
const archive = archiver('zip', { zlib: { level } });
|
|
12
|
-
|
|
13
|
-
output.on('close', () => resolve(archive.pointer()));
|
|
14
|
-
archive.on('error', (err) => reject(err));
|
|
77
|
+
let bytes = 0;
|
|
15
78
|
|
|
16
|
-
|
|
79
|
+
output.on('close', () => resolve(bytes));
|
|
80
|
+
output.on('error', reject);
|
|
81
|
+
zip.outputStream.on('data', (chunk) => { bytes += chunk.length; });
|
|
82
|
+
zip.outputStream.on('error', reject);
|
|
83
|
+
zip.outputStream.pipe(output);
|
|
17
84
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
'.git/**',
|
|
23
|
-
'**/.git/**',
|
|
24
|
-
'.next/**',
|
|
25
|
-
'**/.next/**',
|
|
26
|
-
'.next*/**',
|
|
27
|
-
'**/.next*/**',
|
|
28
|
-
'.nuxt/**',
|
|
29
|
-
'**/.nuxt/**',
|
|
30
|
-
'.nuxt*/**',
|
|
31
|
-
'**/.nuxt*/**',
|
|
32
|
-
'.output/**',
|
|
33
|
-
'**/.output/**',
|
|
34
|
-
'.svelte-kit/**',
|
|
35
|
-
'**/.svelte-kit/**',
|
|
36
|
-
'.wrangler/**',
|
|
37
|
-
'**/.wrangler/**',
|
|
38
|
-
'.netlify/**',
|
|
39
|
-
'**/.netlify/**',
|
|
40
|
-
'dist/**',
|
|
41
|
-
'**/dist/**',
|
|
42
|
-
'build/**',
|
|
43
|
-
'**/build/**',
|
|
44
|
-
'out/**',
|
|
45
|
-
'**/out/**',
|
|
46
|
-
'coverage/**',
|
|
47
|
-
'**/coverage/**',
|
|
48
|
-
'.turbo/**',
|
|
49
|
-
'**/.turbo/**',
|
|
50
|
-
'.cache/**',
|
|
51
|
-
'**/.cache/**',
|
|
52
|
-
'.parcel-cache/**',
|
|
53
|
-
'**/.parcel-cache/**',
|
|
54
|
-
'.vite/**',
|
|
55
|
-
'**/.vite/**',
|
|
56
|
-
'.glash/**',
|
|
57
|
-
'**/.glash/**',
|
|
58
|
-
'*.log',
|
|
59
|
-
'**/*.log',
|
|
60
|
-
'npm-debug.log*',
|
|
61
|
-
'**/npm-debug.log*',
|
|
62
|
-
'yarn-debug.log*',
|
|
63
|
-
'**/yarn-debug.log*',
|
|
64
|
-
'yarn-error.log*',
|
|
65
|
-
'**/yarn-error.log*',
|
|
66
|
-
'.env',
|
|
67
|
-
'**/.env',
|
|
68
|
-
'.env.local',
|
|
69
|
-
'**/.env.local',
|
|
70
|
-
'.env.production',
|
|
71
|
-
'**/.env.production',
|
|
72
|
-
'.env.development',
|
|
73
|
-
'**/.env.development',
|
|
74
|
-
];
|
|
75
|
-
const allIgnore = [...new Set([...defaultIgnore, ...loadIgnorePatterns(sourceDir), ...ignore])];
|
|
76
|
-
|
|
77
|
-
archive.glob('**/*', {
|
|
78
|
-
cwd: sourceDir,
|
|
79
|
-
ignore: allIgnore,
|
|
80
|
-
dot: true,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
archive.finalize();
|
|
85
|
+
for (const file of files) {
|
|
86
|
+
zip.addFile(join(sourceDir, file), file);
|
|
87
|
+
}
|
|
88
|
+
zip.end();
|
|
84
89
|
});
|
|
85
90
|
}
|
|
86
91
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glash/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "glashDB command-line interface — deploy projects, pull source + env, manage env vars.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://glashdb.com",
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
"database"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"archiver": "^7.0.1",
|
|
34
33
|
"chalk": "^5.3.0",
|
|
35
34
|
"commander": "^12.1.0",
|
|
36
35
|
"dotenv": "^16.4.5",
|
|
36
|
+
"fast-glob": "^3.3.3",
|
|
37
37
|
"fs-extra": "^11.2.0",
|
|
38
|
-
"node-fetch": "^3.3.2",
|
|
39
38
|
"open": "^10.1.0",
|
|
40
|
-
"ora": "^8.0.1"
|
|
39
|
+
"ora": "^8.0.1",
|
|
40
|
+
"yazl": "^3.3.1"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|