rushdeploy 1.0.6 → 1.0.7
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/bin/index.js +152 -31
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -92,8 +92,8 @@ const ui = {
|
|
|
92
92
|
},
|
|
93
93
|
|
|
94
94
|
box(fields, options = {}) {
|
|
95
|
-
const fieldPairs = Array.isArray(fields)
|
|
96
|
-
? fields
|
|
95
|
+
const fieldPairs = Array.isArray(fields)
|
|
96
|
+
? fields
|
|
97
97
|
: Object.entries(fields).map(([label, value]) => ({ label, value }));
|
|
98
98
|
|
|
99
99
|
const labelWidth = 14;
|
|
@@ -110,7 +110,7 @@ const ui = {
|
|
|
110
110
|
const innerWidth = Math.max(options.minWidth || 66, leftIndent + labelWidth + gap + maxValLen + rightMargin);
|
|
111
111
|
|
|
112
112
|
const topBorder = `┌${'─'.repeat(innerWidth)}┐`;
|
|
113
|
-
const emptyRow
|
|
113
|
+
const emptyRow = `│${' '.repeat(innerWidth)}│`;
|
|
114
114
|
const bottomBorder = `└${'─'.repeat(innerWidth)}┘`;
|
|
115
115
|
|
|
116
116
|
console.log(`\n${colors.gray}${topBorder}${colors.reset}`);
|
|
@@ -255,7 +255,7 @@ function makeRequest(apiPath, method = 'GET', data = null) {
|
|
|
255
255
|
} else if (jsonResponse && jsonResponse.detail) {
|
|
256
256
|
errorMsg = typeof jsonResponse.detail === 'object' ? jsonResponse.detail.message : jsonResponse.detail;
|
|
257
257
|
}
|
|
258
|
-
|
|
258
|
+
|
|
259
259
|
if (res.statusCode === 401) {
|
|
260
260
|
ui.stepError(`Unauthorized (401). Your token may have expired or been revoked.`);
|
|
261
261
|
console.log(` Please log in again using: ${colors.green}rushdeploy login <token>${colors.reset}`);
|
|
@@ -345,16 +345,16 @@ function extractRepoName(url) {
|
|
|
345
345
|
async function cmdLogin(token, serverArg) {
|
|
346
346
|
const server = serverArg || getServerUrl();
|
|
347
347
|
ui.stepInfo(`Connecting to ${colors.brightWhite}${server}${colors.reset}...`);
|
|
348
|
-
|
|
348
|
+
|
|
349
349
|
saveConfig(server, token);
|
|
350
|
-
|
|
350
|
+
|
|
351
351
|
try {
|
|
352
352
|
ui.stepInfo(`Validating authentication token...`);
|
|
353
353
|
const res = await makeRequest('/auth/me');
|
|
354
354
|
if (res.success) {
|
|
355
355
|
const user = res.user;
|
|
356
356
|
ui.step(`Authentication successful!`);
|
|
357
|
-
|
|
357
|
+
|
|
358
358
|
ui.box([
|
|
359
359
|
{ label: 'Account', value: `${colors.bold}${user.name}${colors.reset} (${colors.gray}${user.email}${colors.reset})` },
|
|
360
360
|
{ label: 'Role', value: user.role.toUpperCase() },
|
|
@@ -421,7 +421,7 @@ async function cmdPlans() {
|
|
|
421
421
|
function drawCards(cards, cardsPerRow = 2) {
|
|
422
422
|
const cardWidth = 34;
|
|
423
423
|
const rows = [];
|
|
424
|
-
|
|
424
|
+
|
|
425
425
|
for (let i = 0; i < cards.length; i += cardsPerRow) {
|
|
426
426
|
rows.push(cards.slice(i, i + cardsPerRow));
|
|
427
427
|
}
|
|
@@ -440,19 +440,19 @@ function drawCards(cards, cardsPerRow = 2) {
|
|
|
440
440
|
|
|
441
441
|
const label = card.label || '';
|
|
442
442
|
let value = card.value !== undefined ? String(card.value) : '';
|
|
443
|
-
|
|
443
|
+
|
|
444
444
|
let valColor = colors.bold;
|
|
445
445
|
if (card.status === 'online') valColor = colors.green + colors.bold;
|
|
446
446
|
else if (card.status === 'offline') valColor = colors.red + colors.bold;
|
|
447
447
|
else if (card.status === 'warn') valColor = colors.yellow + colors.bold;
|
|
448
|
-
|
|
448
|
+
|
|
449
449
|
const valStr = `${valColor}${value}${colors.reset}`;
|
|
450
450
|
const rawVal = stripAnsi(value);
|
|
451
|
-
|
|
451
|
+
|
|
452
452
|
const textLen = label.length + rawVal.length;
|
|
453
453
|
const padLen = cardWidth - 6 - textLen;
|
|
454
454
|
const pad = ' '.repeat(Math.max(1, padLen));
|
|
455
|
-
|
|
455
|
+
|
|
456
456
|
labelValLine += space + `${colors.gray}│${colors.reset} ${colors.brightCyan}${label}${colors.reset}${pad}${valStr} ${colors.gray}│${colors.reset}`;
|
|
457
457
|
sepLine += space + colors.gray + '├' + '─'.repeat(cardWidth - 2) + '┤' + colors.reset;
|
|
458
458
|
|
|
@@ -460,7 +460,7 @@ function drawCards(cards, cardsPerRow = 2) {
|
|
|
460
460
|
const rawHint = stripAnsi(hint);
|
|
461
461
|
const hintPadLen = cardWidth - 6 - rawHint.length;
|
|
462
462
|
const hintPad = ' '.repeat(Math.max(0, hintPadLen));
|
|
463
|
-
|
|
463
|
+
|
|
464
464
|
hintLine += space + `${colors.gray}│${colors.reset} ${colors.gray}${hint}${colors.reset}${hintPad} ${colors.gray}│${colors.reset}`;
|
|
465
465
|
bottomBorder += space + colors.gray + '└' + '─'.repeat(cardWidth - 2) + '┘' + colors.reset;
|
|
466
466
|
});
|
|
@@ -499,7 +499,7 @@ async function cmdStatus() {
|
|
|
499
499
|
const byStatus = stats.projects_by_status || {};
|
|
500
500
|
const celery = stats.celery || {};
|
|
501
501
|
const workerOnline = (celery.workers ?? 0) > 0;
|
|
502
|
-
|
|
502
|
+
|
|
503
503
|
const activeBuildingProjects = (byStatus.building || byStatus.BUILDING || 0) + (byStatus.pending || byStatus.PENDING || 0);
|
|
504
504
|
const activeTasksCount = (celery.active && celery.active > 0) ? celery.active : activeBuildingProjects;
|
|
505
505
|
const pendingInQueue = stats.redis_queue_len ?? celery.queued ?? 0;
|
|
@@ -517,23 +517,23 @@ async function cmdStatus() {
|
|
|
517
517
|
const adminCards = [
|
|
518
518
|
{ label: 'Users', value: stats.users ?? 0, hint: 'Total registered users' },
|
|
519
519
|
{ label: 'Databases', value: stats.databases ?? 0, hint: 'Total workspace databases' },
|
|
520
|
-
{
|
|
521
|
-
label: 'Projects',
|
|
522
|
-
value: stats.projects ?? 0,
|
|
523
|
-
hint: `${colors.green}${runCount} run${colors.reset} · ${colors.yellow}${buildCount} build${colors.reset} · ${colors.red}${failCount} fail${colors.reset}`
|
|
520
|
+
{
|
|
521
|
+
label: 'Projects',
|
|
522
|
+
value: stats.projects ?? 0,
|
|
523
|
+
hint: `${colors.green}${runCount} run${colors.reset} · ${colors.yellow}${buildCount} build${colors.reset} · ${colors.red}${failCount} fail${colors.reset}`
|
|
524
524
|
},
|
|
525
|
-
{
|
|
526
|
-
label: 'App Containers',
|
|
527
|
-
value: stats.running_containers ?? 0,
|
|
525
|
+
{
|
|
526
|
+
label: 'App Containers',
|
|
527
|
+
value: stats.running_containers ?? 0,
|
|
528
528
|
status: stats.docker_available ? 'online' : 'offline',
|
|
529
529
|
hint: stats.docker_available ? 'Active running containers' : 'Engine offline'
|
|
530
530
|
},
|
|
531
531
|
{ label: 'CPU Usage', value: cpuVal, hint: 'Host CPU load' },
|
|
532
532
|
{ label: 'RAM Usage', value: ramVal, hint: 'Host memory allocation' },
|
|
533
533
|
{ label: 'Disk Usage', value: diskVal, hint: 'Host storage capacity' },
|
|
534
|
-
{
|
|
535
|
-
label: 'Task Queue',
|
|
536
|
-
value: workerOnline ? 'Online' : 'Offline',
|
|
534
|
+
{
|
|
535
|
+
label: 'Task Queue',
|
|
536
|
+
value: workerOnline ? 'Online' : 'Offline',
|
|
537
537
|
status: workerOnline ? 'online' : 'offline',
|
|
538
538
|
hint: `${activeTasksCount} active · ${pendingInQueue} pending`
|
|
539
539
|
}
|
|
@@ -773,28 +773,80 @@ async function cmdDeploy(type, args) {
|
|
|
773
773
|
]);
|
|
774
774
|
}
|
|
775
775
|
|
|
776
|
+
} else if (type === 'n8n') {
|
|
777
|
+
const name = args[0];
|
|
778
|
+
if (!name) {
|
|
779
|
+
ui.stepError(`Please specify the n8n project name.`);
|
|
780
|
+
console.log(` Usage: ${colors.green}rushdeploy deploy n8n <name> [--key <encryption_key>] [--auth-user <user>] [--auth-pass <pass>]${colors.reset}`);
|
|
781
|
+
process.exit(1);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
let encryptionKey = null;
|
|
785
|
+
const keyIdx = args.indexOf('--key');
|
|
786
|
+
if (keyIdx !== -1 && args[keyIdx + 1]) encryptionKey = args[keyIdx + 1];
|
|
787
|
+
|
|
788
|
+
let basicAuthActive = false;
|
|
789
|
+
let basicAuthUser = 'admin';
|
|
790
|
+
let basicAuthPass = null;
|
|
791
|
+
|
|
792
|
+
const authUserIdx = args.indexOf('--auth-user');
|
|
793
|
+
if (authUserIdx !== -1 && args[authUserIdx + 1]) {
|
|
794
|
+
basicAuthActive = true;
|
|
795
|
+
basicAuthUser = args[authUserIdx + 1];
|
|
796
|
+
}
|
|
797
|
+
const authPassIdx = args.indexOf('--auth-pass');
|
|
798
|
+
if (authPassIdx !== -1 && args[authPassIdx + 1]) {
|
|
799
|
+
basicAuthActive = true;
|
|
800
|
+
basicAuthPass = args[authPassIdx + 1];
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
ui.step(`Preparing n8n autonomous workflow environment for ${name}`);
|
|
804
|
+
ui.step(`Configuring persistent volume storage and container security`);
|
|
805
|
+
ui.step(`Queueing 1-click n8n instance deployment`);
|
|
806
|
+
|
|
807
|
+
const res = await makeRequest('/projects/n8n', 'POST', {
|
|
808
|
+
name,
|
|
809
|
+
encryption_key: encryptionKey,
|
|
810
|
+
basic_auth_active: basicAuthActive,
|
|
811
|
+
basic_auth_user: basicAuthUser,
|
|
812
|
+
basic_auth_password: basicAuthPass
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
if (res.success) {
|
|
816
|
+
ui.step(`n8n deployment queued successfully!`);
|
|
817
|
+
ui.box([
|
|
818
|
+
{ label: 'Site Name', value: colors.bold + name + colors.reset },
|
|
819
|
+
{ label: 'State', value: ui.badge('QUEUED') },
|
|
820
|
+
{ label: 'Project ID', value: String(res.project_id) },
|
|
821
|
+
{ label: 'Deployment ID', value: String(res.deployment_id) },
|
|
822
|
+
{ label: 'Public URL', value: colors.brightCyan + colors.bold + res.url + colors.reset }
|
|
823
|
+
]);
|
|
824
|
+
}
|
|
825
|
+
|
|
776
826
|
} else {
|
|
777
|
-
ui.stepError(`Invalid deployment source type. Must be 'git', 'repo', or '
|
|
827
|
+
ui.stepError(`Invalid deployment source type. Must be 'git', 'repo', 'wordpress', or 'n8n'.`);
|
|
778
828
|
console.log(`\nUsage:`);
|
|
779
829
|
console.log(` rushdeploy deploy git <repo_url> [options]`);
|
|
780
830
|
console.log(` rushdeploy deploy repo <owner/repo> [options]`);
|
|
781
831
|
console.log(` rushdeploy deploy wordpress <name> --email <email> [options]`);
|
|
832
|
+
console.log(` rushdeploy deploy n8n <name> [options]`);
|
|
782
833
|
process.exit(1);
|
|
783
834
|
}
|
|
784
835
|
}
|
|
785
836
|
|
|
837
|
+
|
|
786
838
|
async function resolveProjectId(idOrSlug) {
|
|
787
839
|
if (/^\d+$/.test(idOrSlug)) {
|
|
788
840
|
return parseInt(idOrSlug, 10);
|
|
789
841
|
}
|
|
790
|
-
|
|
842
|
+
|
|
791
843
|
const res = await makeRequest('/projects/');
|
|
792
844
|
const projects = res.projects || [];
|
|
793
845
|
const matched = projects.find(p => p.slug === idOrSlug || p.name.toLowerCase() === idOrSlug.toLowerCase());
|
|
794
846
|
if (matched) {
|
|
795
847
|
return matched.id;
|
|
796
848
|
}
|
|
797
|
-
|
|
849
|
+
|
|
798
850
|
ui.stepError(`No project found matching name or slug "${idOrSlug}".`);
|
|
799
851
|
process.exit(1);
|
|
800
852
|
}
|
|
@@ -864,7 +916,7 @@ async function cmdProject(idOrSlug, subcommand, subArgs) {
|
|
|
864
916
|
const stats = statsRes.stats;
|
|
865
917
|
|
|
866
918
|
ui.stepInfo(`Resource metrics for Project ${id}`);
|
|
867
|
-
|
|
919
|
+
|
|
868
920
|
const fields = [
|
|
869
921
|
{ label: 'Current Status', value: ui.badge(info.status) }
|
|
870
922
|
];
|
|
@@ -1145,7 +1197,7 @@ async function cmdWorkspace() {
|
|
|
1145
1197
|
|
|
1146
1198
|
function printHelp() {
|
|
1147
1199
|
console.log(`
|
|
1148
|
-
${colors.bold}${colors.brightWhite}RushDeploy CLI${colors.reset} ${colors.gray}v1.0.
|
|
1200
|
+
${colors.bold}${colors.brightWhite}RushDeploy CLI${colors.reset} ${colors.gray}v1.0.7${colors.reset} - Modern PaaS Command Line Interface
|
|
1149
1201
|
|
|
1150
1202
|
${colors.bold}USAGE:${colors.reset}
|
|
1151
1203
|
${colors.brightCyan}rushdeploy${colors.reset} <command> [arguments] [options]
|
|
@@ -1199,6 +1251,11 @@ async function main() {
|
|
|
1199
1251
|
process.exit(0);
|
|
1200
1252
|
}
|
|
1201
1253
|
|
|
1254
|
+
if (command === 'version' || command === '-v' || command === '--version') {
|
|
1255
|
+
console.log(`${colors.bold}${colors.brightWhite}RushDeploy CLI${colors.reset} ${colors.gray}v1.0.7${colors.reset}`);
|
|
1256
|
+
process.exit(0);
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1202
1259
|
switch (command) {
|
|
1203
1260
|
case 'login': {
|
|
1204
1261
|
const token = args[1];
|
|
@@ -1207,13 +1264,13 @@ async function main() {
|
|
|
1207
1264
|
console.log(` Usage: ${colors.green}rushdeploy login <token> [--server <url>]${colors.reset}`);
|
|
1208
1265
|
process.exit(1);
|
|
1209
1266
|
}
|
|
1210
|
-
|
|
1267
|
+
|
|
1211
1268
|
let server = null;
|
|
1212
1269
|
const serverIndex = args.indexOf('--server');
|
|
1213
1270
|
if (serverIndex !== -1 && args[serverIndex + 1]) {
|
|
1214
1271
|
server = args[serverIndex + 1];
|
|
1215
1272
|
}
|
|
1216
|
-
|
|
1273
|
+
|
|
1217
1274
|
await cmdLogin(token, server);
|
|
1218
1275
|
break;
|
|
1219
1276
|
}
|
|
@@ -1230,6 +1287,7 @@ async function main() {
|
|
|
1230
1287
|
await cmdStatus();
|
|
1231
1288
|
break;
|
|
1232
1289
|
case 'projects':
|
|
1290
|
+
case 'ls':
|
|
1233
1291
|
await cmdProjects();
|
|
1234
1292
|
break;
|
|
1235
1293
|
case 'repos':
|
|
@@ -1241,6 +1299,68 @@ async function main() {
|
|
|
1241
1299
|
await cmdDeploy(type, deployArgs);
|
|
1242
1300
|
break;
|
|
1243
1301
|
}
|
|
1302
|
+
case 'open':
|
|
1303
|
+
case 'visit': {
|
|
1304
|
+
const target = args[1];
|
|
1305
|
+
if (!target) {
|
|
1306
|
+
ui.stepError(`Usage: rushdeploy open <slug|id>`);
|
|
1307
|
+
process.exit(1);
|
|
1308
|
+
}
|
|
1309
|
+
await cmdProject(target, 'visit', []);
|
|
1310
|
+
break;
|
|
1311
|
+
}
|
|
1312
|
+
case 'logs': {
|
|
1313
|
+
const target = args[1];
|
|
1314
|
+
if (!target) {
|
|
1315
|
+
ui.stepError(`Usage: rushdeploy logs <slug|id> [--lines <N>]`);
|
|
1316
|
+
process.exit(1);
|
|
1317
|
+
}
|
|
1318
|
+
await cmdProject(target, 'logs', args.slice(2));
|
|
1319
|
+
break;
|
|
1320
|
+
}
|
|
1321
|
+
case 'start': {
|
|
1322
|
+
const target = args[1];
|
|
1323
|
+
if (!target) {
|
|
1324
|
+
ui.stepError(`Usage: rushdeploy start <slug|id>`);
|
|
1325
|
+
process.exit(1);
|
|
1326
|
+
}
|
|
1327
|
+
await cmdProject(target, 'start', []);
|
|
1328
|
+
break;
|
|
1329
|
+
}
|
|
1330
|
+
case 'stop': {
|
|
1331
|
+
const target = args[1];
|
|
1332
|
+
if (!target) {
|
|
1333
|
+
ui.stepError(`Usage: rushdeploy stop <slug|id>`);
|
|
1334
|
+
process.exit(1);
|
|
1335
|
+
}
|
|
1336
|
+
await cmdProject(target, 'stop', []);
|
|
1337
|
+
break;
|
|
1338
|
+
}
|
|
1339
|
+
case 'restart':
|
|
1340
|
+
case 'redeploy': {
|
|
1341
|
+
const target = args[1];
|
|
1342
|
+
if (!target) {
|
|
1343
|
+
ui.stepError(`Usage: rushdeploy restart <slug|id>`);
|
|
1344
|
+
process.exit(1);
|
|
1345
|
+
}
|
|
1346
|
+
await cmdProject(target, 'redeploy', []);
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
case 'delete':
|
|
1350
|
+
case 'remove': {
|
|
1351
|
+
const target = args[1];
|
|
1352
|
+
if (!target) {
|
|
1353
|
+
ui.stepError(`Usage: rushdeploy delete <slug|id>`);
|
|
1354
|
+
process.exit(1);
|
|
1355
|
+
}
|
|
1356
|
+
const id = await resolveProjectId(target);
|
|
1357
|
+
ui.stepInfo(`Deleting project ${id}...`);
|
|
1358
|
+
const res = await makeRequest(`/projects/${id}`, 'DELETE');
|
|
1359
|
+
if (res.success) {
|
|
1360
|
+
ui.step(`Project deleted successfully.`);
|
|
1361
|
+
}
|
|
1362
|
+
break;
|
|
1363
|
+
}
|
|
1244
1364
|
case 'project': {
|
|
1245
1365
|
const idOrSlug = args[1];
|
|
1246
1366
|
if (!idOrSlug) {
|
|
@@ -1263,6 +1383,7 @@ async function main() {
|
|
|
1263
1383
|
}
|
|
1264
1384
|
}
|
|
1265
1385
|
|
|
1386
|
+
|
|
1266
1387
|
main().catch(err => {
|
|
1267
1388
|
ui.stepError(`Fatal Error: ${err.message}`);
|
|
1268
1389
|
process.exit(1);
|