@boltic/cli 1.0.42 → 1.0.44-dev1.1
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/serverless.js +399 -112
- package/helper/serverless.js +239 -6
- package/package.json +2 -2
package/commands/serverless.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
parseTestArgs,
|
|
16
16
|
parsePublishArgs,
|
|
17
17
|
createServerlessFiles,
|
|
18
|
+
createGitignore,
|
|
18
19
|
loadBolticConfig,
|
|
19
20
|
parseLanguageFromConfig,
|
|
20
21
|
parseHandlerConfig,
|
|
@@ -108,7 +109,7 @@ async function handleCreate(args = []) {
|
|
|
108
109
|
|
|
109
110
|
// Step 1: Parse CLI arguments
|
|
110
111
|
const parsedArgs = parseCreateArgs(args);
|
|
111
|
-
let { name, language, directory, type } = parsedArgs;
|
|
112
|
+
let { name, language, directory, type, noGitignore } = parsedArgs;
|
|
112
113
|
|
|
113
114
|
// Step 2: Serverless Type Selection
|
|
114
115
|
if (!type) {
|
|
@@ -220,18 +221,30 @@ async function handleCreate(args = []) {
|
|
|
220
221
|
// Branch based on type
|
|
221
222
|
if (type === "git") {
|
|
222
223
|
// For git type: create empty folder with boltic.yaml only
|
|
223
|
-
await handleGitTypeCreate(
|
|
224
|
+
await handleGitTypeCreate(
|
|
225
|
+
name,
|
|
226
|
+
language,
|
|
227
|
+
version,
|
|
228
|
+
targetDir,
|
|
229
|
+
noGitignore
|
|
230
|
+
);
|
|
224
231
|
return;
|
|
225
232
|
}
|
|
226
233
|
|
|
227
234
|
if (type === "container") {
|
|
228
235
|
// For container type: ask for image and create serverless
|
|
229
|
-
await handleContainerTypeCreate(name, targetDir);
|
|
236
|
+
await handleContainerTypeCreate(name, targetDir, noGitignore);
|
|
230
237
|
return;
|
|
231
238
|
}
|
|
232
239
|
|
|
233
240
|
// For code type: create full template files and call create API
|
|
234
|
-
await handleCodeTypeCreate(
|
|
241
|
+
await handleCodeTypeCreate(
|
|
242
|
+
name,
|
|
243
|
+
language,
|
|
244
|
+
version,
|
|
245
|
+
targetDir,
|
|
246
|
+
noGitignore
|
|
247
|
+
);
|
|
235
248
|
} catch (error) {
|
|
236
249
|
if (
|
|
237
250
|
error.message &&
|
|
@@ -248,10 +261,87 @@ async function handleCreate(args = []) {
|
|
|
248
261
|
}
|
|
249
262
|
}
|
|
250
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Check if a serverless function with the given name already exists
|
|
266
|
+
* @returns {Object|null} The existing serverless object if found, null otherwise
|
|
267
|
+
*/
|
|
268
|
+
async function checkServerlessExists(name) {
|
|
269
|
+
const env = await getCurrentEnv();
|
|
270
|
+
if (!env || !env.token || !env.session) {
|
|
271
|
+
return null; // Can't check without auth, let the create call handle auth error
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const { apiUrl, token, accountId, session } = env;
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
const allServerless = await listAllServerless(
|
|
278
|
+
apiUrl,
|
|
279
|
+
token,
|
|
280
|
+
accountId,
|
|
281
|
+
session,
|
|
282
|
+
name // Use query parameter to search by name
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
if (allServerless && Array.isArray(allServerless)) {
|
|
286
|
+
// Find exact match by name (case-insensitive)
|
|
287
|
+
const existing = allServerless.find(
|
|
288
|
+
(s) => s.Name && s.Name.toLowerCase() === name.toLowerCase()
|
|
289
|
+
);
|
|
290
|
+
return existing || null;
|
|
291
|
+
}
|
|
292
|
+
} catch {
|
|
293
|
+
// If API call fails, let the create call handle it
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Display message when serverless already exists and suggest pull command
|
|
302
|
+
*/
|
|
303
|
+
function displayServerlessExistsMessage(name, existing) {
|
|
304
|
+
console.log(
|
|
305
|
+
chalk.yellow(
|
|
306
|
+
`\n⚠️ A serverless function named "${name}" already exists.`
|
|
307
|
+
)
|
|
308
|
+
);
|
|
309
|
+
console.log(chalk.dim(` ID: ${existing.ID || existing._id}`));
|
|
310
|
+
if (existing.Status) {
|
|
311
|
+
console.log(chalk.dim(` Status: ${existing.Status}`));
|
|
312
|
+
}
|
|
313
|
+
console.log();
|
|
314
|
+
console.log(chalk.cyan("To pull the existing serverless function, run:"));
|
|
315
|
+
console.log(chalk.green(` boltic serverless pull --name ${name}`));
|
|
316
|
+
console.log();
|
|
317
|
+
console.log(chalk.dim("Or use a different name:"));
|
|
318
|
+
console.log(chalk.dim(` boltic serverless create --name <new-name> ...`));
|
|
319
|
+
console.log();
|
|
320
|
+
}
|
|
321
|
+
|
|
251
322
|
/**
|
|
252
323
|
* Handle code type serverless creation - creates folder with template files and calls create API
|
|
253
324
|
*/
|
|
254
|
-
async function handleCodeTypeCreate(
|
|
325
|
+
async function handleCodeTypeCreate(
|
|
326
|
+
name,
|
|
327
|
+
language,
|
|
328
|
+
version,
|
|
329
|
+
targetDir,
|
|
330
|
+
noGitignore = false
|
|
331
|
+
) {
|
|
332
|
+
// Check if serverless with this name already exists
|
|
333
|
+
const existingServerless = await checkServerlessExists(name);
|
|
334
|
+
if (existingServerless) {
|
|
335
|
+
displayServerlessExistsMessage(name, existingServerless);
|
|
336
|
+
// Cleanup the created directory
|
|
337
|
+
try {
|
|
338
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
339
|
+
} catch {
|
|
340
|
+
// Ignore cleanup errors
|
|
341
|
+
}
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
255
345
|
const templateContext = {
|
|
256
346
|
AppSlug: name,
|
|
257
347
|
Language: `${language}/${version}`,
|
|
@@ -279,6 +369,14 @@ async function handleCodeTypeCreate(name, language, version, targetDir) {
|
|
|
279
369
|
return;
|
|
280
370
|
}
|
|
281
371
|
|
|
372
|
+
// Create .gitignore file unless --no-gitignore flag is set
|
|
373
|
+
if (!noGitignore) {
|
|
374
|
+
const gitignoreCreated = createGitignore(targetDir, language);
|
|
375
|
+
if (gitignoreCreated) {
|
|
376
|
+
console.log(chalk.dim(` Created .gitignore for ${language}`));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
282
380
|
// Get authentication credentials
|
|
283
381
|
const env = await getCurrentEnv();
|
|
284
382
|
if (!env || !env.token || !env.session) {
|
|
@@ -399,7 +497,26 @@ async function handleCodeTypeCreate(name, language, version, targetDir) {
|
|
|
399
497
|
/**
|
|
400
498
|
* Handle git type serverless creation - creates serverless on server and clones the repo
|
|
401
499
|
*/
|
|
402
|
-
async function handleGitTypeCreate(
|
|
500
|
+
async function handleGitTypeCreate(
|
|
501
|
+
name,
|
|
502
|
+
language,
|
|
503
|
+
version,
|
|
504
|
+
targetDir,
|
|
505
|
+
noGitignore = false
|
|
506
|
+
) {
|
|
507
|
+
// Check if serverless with this name already exists
|
|
508
|
+
const existingServerless = await checkServerlessExists(name);
|
|
509
|
+
if (existingServerless) {
|
|
510
|
+
displayServerlessExistsMessage(name, existingServerless);
|
|
511
|
+
// Cleanup the created directory
|
|
512
|
+
try {
|
|
513
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
514
|
+
} catch {
|
|
515
|
+
// Ignore cleanup errors
|
|
516
|
+
}
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
|
|
403
520
|
console.log(chalk.cyan("\n📁 Creating git-based serverless project..."));
|
|
404
521
|
console.log(chalk.dim(` Type: git`));
|
|
405
522
|
console.log(chalk.dim(` Language: ${language}/${version}`));
|
|
@@ -539,6 +656,14 @@ serverlessConfig:
|
|
|
539
656
|
}
|
|
540
657
|
}
|
|
541
658
|
|
|
659
|
+
// Create .gitignore file unless --no-gitignore flag is set
|
|
660
|
+
if (!noGitignore) {
|
|
661
|
+
const gitignoreCreated = createGitignore(targetDir, language);
|
|
662
|
+
if (gitignoreCreated) {
|
|
663
|
+
console.log(chalk.dim(` Created .gitignore for ${language}`));
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
542
667
|
// Display success message
|
|
543
668
|
console.log("\n" + chalk.bgGreen.black(" ✓ CREATED ") + "\n");
|
|
544
669
|
console.log(
|
|
@@ -624,7 +749,20 @@ serverlessConfig:
|
|
|
624
749
|
/**
|
|
625
750
|
* Handle container type serverless creation - creates empty folder with boltic.yaml
|
|
626
751
|
*/
|
|
627
|
-
async function handleContainerTypeCreate(name, targetDir) {
|
|
752
|
+
async function handleContainerTypeCreate(name, targetDir, noGitignore = false) {
|
|
753
|
+
// Check if serverless with this name already exists
|
|
754
|
+
const existingServerless = await checkServerlessExists(name);
|
|
755
|
+
if (existingServerless) {
|
|
756
|
+
displayServerlessExistsMessage(name, existingServerless);
|
|
757
|
+
// Cleanup the created directory
|
|
758
|
+
try {
|
|
759
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
760
|
+
} catch {
|
|
761
|
+
// Ignore cleanup errors
|
|
762
|
+
}
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
|
|
628
766
|
console.log(
|
|
629
767
|
chalk.cyan("\n🐳 Creating container-based serverless project...")
|
|
630
768
|
);
|
|
@@ -740,6 +878,14 @@ build:
|
|
|
740
878
|
return;
|
|
741
879
|
}
|
|
742
880
|
|
|
881
|
+
// Create .gitignore file unless --no-gitignore flag is set
|
|
882
|
+
if (!noGitignore) {
|
|
883
|
+
const gitignoreCreated = createGitignore(targetDir, "container");
|
|
884
|
+
if (gitignoreCreated) {
|
|
885
|
+
console.log(chalk.dim(` Created .gitignore`));
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
743
889
|
// Display success message for container type
|
|
744
890
|
console.log("\n" + chalk.bgGreen.black(" ✓ CREATED ") + "\n");
|
|
745
891
|
console.log(
|
|
@@ -784,7 +930,12 @@ async function handlePublish(args = []) {
|
|
|
784
930
|
|
|
785
931
|
// Step 1: Parse CLI arguments
|
|
786
932
|
const parsedArgs = parsePublishArgs(args);
|
|
787
|
-
const { directory } = parsedArgs;
|
|
933
|
+
const { directory, verbose } = parsedArgs;
|
|
934
|
+
|
|
935
|
+
// Enable verbose mode if requested
|
|
936
|
+
if (verbose) {
|
|
937
|
+
setVerboseMode(true);
|
|
938
|
+
}
|
|
788
939
|
|
|
789
940
|
// Validate directory exists
|
|
790
941
|
if (!fs.existsSync(directory)) {
|
|
@@ -837,10 +988,28 @@ async function handlePublish(args = []) {
|
|
|
837
988
|
let code = null;
|
|
838
989
|
if (runtime === "git") {
|
|
839
990
|
console.log(
|
|
840
|
-
chalk.
|
|
991
|
+
chalk.yellow(
|
|
992
|
+
"\n📦 Git-based serverless deploys via git push, not publish."
|
|
993
|
+
)
|
|
994
|
+
);
|
|
995
|
+
console.log(chalk.cyan("\nTo deploy your changes:\n"));
|
|
996
|
+
console.log(chalk.white(" # Stage your changes"));
|
|
997
|
+
console.log(chalk.green(" git add .\n"));
|
|
998
|
+
console.log(chalk.white(" # Commit your changes"));
|
|
999
|
+
console.log(
|
|
1000
|
+
chalk.green(' git commit -m "Update serverless function"\n')
|
|
1001
|
+
);
|
|
1002
|
+
console.log(chalk.white(" # Push to deploy"));
|
|
1003
|
+
console.log(chalk.green(" git push origin main\n"));
|
|
1004
|
+
console.log(
|
|
1005
|
+
chalk.dim(
|
|
1006
|
+
"The serverless will automatically build and deploy after push."
|
|
1007
|
+
)
|
|
841
1008
|
);
|
|
842
1009
|
console.log(
|
|
843
|
-
chalk.
|
|
1010
|
+
chalk.dim(
|
|
1011
|
+
`Monitor status with: boltic serverless status --name ${appName} --follow\n`
|
|
1012
|
+
)
|
|
844
1013
|
);
|
|
845
1014
|
return;
|
|
846
1015
|
}
|
|
@@ -1121,7 +1290,6 @@ async function handleTest(args = []) {
|
|
|
1121
1290
|
// Install Python dependencies using virtual environment
|
|
1122
1291
|
if (language === "python") {
|
|
1123
1292
|
const venvPath = path.join(directory, ".venv");
|
|
1124
|
-
const venvPython = path.join(venvPath, "bin", "python3");
|
|
1125
1293
|
const venvPip = path.join(venvPath, "bin", "pip3");
|
|
1126
1294
|
|
|
1127
1295
|
// Create virtual environment if it doesn't exist
|
|
@@ -1395,27 +1563,32 @@ async function handlePull(args) {
|
|
|
1395
1563
|
try {
|
|
1396
1564
|
// Parse command line arguments
|
|
1397
1565
|
let currentDir = process.cwd();
|
|
1398
|
-
|
|
1566
|
+
let serverlessName = null;
|
|
1399
1567
|
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1568
|
+
for (let i = 0; i < args.length; i++) {
|
|
1569
|
+
const arg = args[i];
|
|
1570
|
+
const nextArg = args[i + 1];
|
|
1571
|
+
|
|
1572
|
+
if (arg === "--path" && nextArg) {
|
|
1573
|
+
currentDir = nextArg;
|
|
1574
|
+
i++;
|
|
1575
|
+
} else if ((arg === "--name" || arg === "-n") && nextArg) {
|
|
1576
|
+
serverlessName = nextArg;
|
|
1577
|
+
i++;
|
|
1410
1578
|
}
|
|
1411
1579
|
}
|
|
1412
|
-
const { apiUrl, token, accountId, session } = await getCurrentEnv();
|
|
1413
1580
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1581
|
+
// Validate the provided path
|
|
1582
|
+
if (currentDir !== process.cwd() && !fs.existsSync(currentDir)) {
|
|
1583
|
+
console.error(
|
|
1584
|
+
chalk.red(
|
|
1585
|
+
`Error: The specified path does not exist: ${currentDir}`
|
|
1586
|
+
)
|
|
1587
|
+
);
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
const { apiUrl, token, accountId, session } = await getCurrentEnv();
|
|
1419
1592
|
|
|
1420
1593
|
const allServerless = await listAllServerless(
|
|
1421
1594
|
apiUrl,
|
|
@@ -1429,42 +1602,85 @@ async function handlePull(args) {
|
|
|
1429
1602
|
"\n❌ Failed to fetch serverless: Invalid response format"
|
|
1430
1603
|
)
|
|
1431
1604
|
);
|
|
1605
|
+
return;
|
|
1432
1606
|
}
|
|
1433
1607
|
if (allServerless.length === 0) {
|
|
1434
1608
|
console.error(chalk.red("\n❌ No serverless found."));
|
|
1435
1609
|
return;
|
|
1436
1610
|
}
|
|
1437
|
-
// Let user select an integration
|
|
1438
|
-
const choices =
|
|
1439
|
-
allServerless.map((serverless) => {
|
|
1440
|
-
const runtime = serverless.Config?.Runtime || "code";
|
|
1441
|
-
const typeIcon =
|
|
1442
|
-
runtime === "git"
|
|
1443
|
-
? "📦"
|
|
1444
|
-
: runtime === "container"
|
|
1445
|
-
? "🐳"
|
|
1446
|
-
: "📝";
|
|
1447
|
-
const language = serverless.Config?.CodeOpts?.Language;
|
|
1448
|
-
return {
|
|
1449
|
-
name: `${serverless.Config.Name}: ${typeIcon} ${runtime} | Status - ${serverless.Status}${language ? ` | language: ${language}` : ""}`,
|
|
1450
|
-
value: serverless,
|
|
1451
|
-
};
|
|
1452
|
-
}) || [];
|
|
1453
1611
|
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1612
|
+
let selectedServerless;
|
|
1613
|
+
|
|
1614
|
+
// If name is provided, find exact match
|
|
1615
|
+
if (serverlessName) {
|
|
1616
|
+
selectedServerless = allServerless.find(
|
|
1617
|
+
(s) =>
|
|
1618
|
+
s.Config?.Name?.toLowerCase() ===
|
|
1619
|
+
serverlessName.toLowerCase()
|
|
1620
|
+
);
|
|
1621
|
+
|
|
1622
|
+
if (!selectedServerless) {
|
|
1623
|
+
console.error(
|
|
1624
|
+
chalk.red(`\n❌ Serverless "${serverlessName}" not found.`)
|
|
1460
1625
|
);
|
|
1461
|
-
|
|
1462
|
-
|
|
1626
|
+
console.log(chalk.yellow("\nAvailable serverless functions:"));
|
|
1627
|
+
allServerless.slice(0, 5).forEach((s) => {
|
|
1628
|
+
console.log(chalk.dim(` - ${s.Config?.Name}`));
|
|
1629
|
+
});
|
|
1630
|
+
if (allServerless.length > 5) {
|
|
1631
|
+
console.log(
|
|
1632
|
+
chalk.dim(` ... and ${allServerless.length - 5} more`)
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
console.log(
|
|
1636
|
+
chalk.yellow("\nRun 'boltic serverless list' to see all.")
|
|
1637
|
+
);
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1463
1640
|
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1641
|
+
console.log(
|
|
1642
|
+
chalk.cyan("Selected serverless:"),
|
|
1643
|
+
selectedServerless.Config.Name
|
|
1644
|
+
);
|
|
1645
|
+
} else {
|
|
1646
|
+
// Interactive selection
|
|
1647
|
+
console.log(
|
|
1648
|
+
chalk.green(
|
|
1649
|
+
"Please select the serverless to pull from the list below:"
|
|
1650
|
+
)
|
|
1651
|
+
);
|
|
1652
|
+
|
|
1653
|
+
const choices =
|
|
1654
|
+
allServerless.map((serverless) => {
|
|
1655
|
+
const runtime = serverless.Config?.Runtime || "code";
|
|
1656
|
+
const typeIcon =
|
|
1657
|
+
runtime === "git"
|
|
1658
|
+
? "📦"
|
|
1659
|
+
: runtime === "container"
|
|
1660
|
+
? "🐳"
|
|
1661
|
+
: "📝";
|
|
1662
|
+
const language = serverless.Config?.CodeOpts?.Language;
|
|
1663
|
+
return {
|
|
1664
|
+
name: `${serverless.Config.Name}: ${typeIcon} ${runtime} | Status - ${serverless.Status}${language ? ` | language: ${language}` : ""}`,
|
|
1665
|
+
value: serverless,
|
|
1666
|
+
};
|
|
1667
|
+
}) || [];
|
|
1668
|
+
|
|
1669
|
+
selectedServerless = await search({
|
|
1670
|
+
message: "Search and select an serverless to edit:",
|
|
1671
|
+
source: async (term) => {
|
|
1672
|
+
if (!term) return choices;
|
|
1673
|
+
return choices?.filter((choice) =>
|
|
1674
|
+
choice.name.toLowerCase().includes(term.toLowerCase())
|
|
1675
|
+
);
|
|
1676
|
+
},
|
|
1677
|
+
});
|
|
1678
|
+
|
|
1679
|
+
console.log(
|
|
1680
|
+
chalk.cyan("\nSelected serverless:"),
|
|
1681
|
+
selectedServerless.Config.Name
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1468
1684
|
const pulledServerless = await pullServerless(
|
|
1469
1685
|
apiUrl,
|
|
1470
1686
|
token,
|
|
@@ -1482,12 +1698,9 @@ async function handlePull(args) {
|
|
|
1482
1698
|
}
|
|
1483
1699
|
// console.log("selectes serverless : ",pulledServerless)
|
|
1484
1700
|
|
|
1485
|
-
// Get the app name
|
|
1701
|
+
// Get the app name and type for the folder name
|
|
1486
1702
|
const appName =
|
|
1487
1703
|
pulledServerless?.Config?.Name || selectedServerless.Config?.Name;
|
|
1488
|
-
const language =
|
|
1489
|
-
pulledServerless?.Config?.CodeOpts?.Language?.split("/")[0] ||
|
|
1490
|
-
"nodejs";
|
|
1491
1704
|
const serverlessType = pulledServerless?.Config?.Runtime || "code";
|
|
1492
1705
|
|
|
1493
1706
|
// Create folder name similar to create command
|
|
@@ -1606,7 +1819,7 @@ function showHelp() {
|
|
|
1606
1819
|
"Name of the serverless function"
|
|
1607
1820
|
);
|
|
1608
1821
|
console.log(
|
|
1609
|
-
chalk.bold(" --
|
|
1822
|
+
chalk.bold(" --follow, -f".padEnd(20)) +
|
|
1610
1823
|
"Poll until status is running, failed, or degraded"
|
|
1611
1824
|
);
|
|
1612
1825
|
|
|
@@ -1656,7 +1869,7 @@ function showHelp() {
|
|
|
1656
1869
|
console.log(" boltic serverless list\n");
|
|
1657
1870
|
|
|
1658
1871
|
console.log(chalk.dim(" # Check status with polling"));
|
|
1659
|
-
console.log(" boltic serverless status -n my-function --
|
|
1872
|
+
console.log(" boltic serverless status -n my-function --follow\n");
|
|
1660
1873
|
|
|
1661
1874
|
console.log(chalk.dim(" # View builds for a serverless"));
|
|
1662
1875
|
console.log(" boltic serverless builds -n my-function\n");
|
|
@@ -1732,7 +1945,7 @@ function getStatusColor(status) {
|
|
|
1732
1945
|
}
|
|
1733
1946
|
}
|
|
1734
1947
|
|
|
1735
|
-
async function handleList(
|
|
1948
|
+
async function handleList(_args = []) {
|
|
1736
1949
|
try {
|
|
1737
1950
|
const { apiUrl, token, accountId, session } = await getCurrentEnv();
|
|
1738
1951
|
|
|
@@ -1889,7 +2102,7 @@ function displayServerlessDetails(serverless) {
|
|
|
1889
2102
|
console.log(chalk.cyan("━".repeat(60)));
|
|
1890
2103
|
console.log(
|
|
1891
2104
|
chalk.dim(
|
|
1892
|
-
"\nTip: Use 'boltic serverless status -n <name> --
|
|
2105
|
+
"\nTip: Use 'boltic serverless status -n <name> --follow' to poll for status changes."
|
|
1893
2106
|
)
|
|
1894
2107
|
);
|
|
1895
2108
|
}
|
|
@@ -1912,7 +2125,12 @@ function parseStatusArgs(args) {
|
|
|
1912
2125
|
if ((arg === "--name" || arg === "-n") && nextArg) {
|
|
1913
2126
|
parsed.name = nextArg;
|
|
1914
2127
|
i++;
|
|
1915
|
-
} else if (
|
|
2128
|
+
} else if (
|
|
2129
|
+
arg === "--follow" ||
|
|
2130
|
+
arg === "-f" ||
|
|
2131
|
+
arg === "--watch" ||
|
|
2132
|
+
arg === "-w"
|
|
2133
|
+
) {
|
|
1916
2134
|
parsed.watch = true;
|
|
1917
2135
|
} else if (arg === "--verbose" || arg === "-v") {
|
|
1918
2136
|
parsed.verbose = true;
|
|
@@ -2132,7 +2350,7 @@ async function handleStatus(args = []) {
|
|
|
2132
2350
|
lastStatus = status;
|
|
2133
2351
|
} else if (iteration % 3 === 0) {
|
|
2134
2352
|
// Show a dot every 3 iterations to indicate it's still polling
|
|
2135
|
-
process.stdout.write(chalk.dim("
|
|
2353
|
+
process.stdout.write(chalk.dim(".\n"));
|
|
2136
2354
|
}
|
|
2137
2355
|
|
|
2138
2356
|
// Check if we've reached a terminal state
|
|
@@ -2450,7 +2668,10 @@ async function handleLogs(args = []) {
|
|
|
2450
2668
|
console.log(chalk.dim("Following logs... Press Ctrl+C to stop.\n"));
|
|
2451
2669
|
}
|
|
2452
2670
|
|
|
2453
|
-
|
|
2671
|
+
// Track seen log IDs to avoid duplicates in follow mode
|
|
2672
|
+
const seenLogIds = new Set();
|
|
2673
|
+
|
|
2674
|
+
const fetchAndDisplayLogs = async (afterTimestamp = null) => {
|
|
2454
2675
|
const now = Math.floor(Date.now() / 1000);
|
|
2455
2676
|
const logsData = await getServerlessLogs(
|
|
2456
2677
|
apiUrl,
|
|
@@ -2460,24 +2681,38 @@ async function handleLogs(args = []) {
|
|
|
2460
2681
|
serverless.ID,
|
|
2461
2682
|
{
|
|
2462
2683
|
limit: lines,
|
|
2463
|
-
|
|
2464
|
-
|
|
2684
|
+
// For follow mode: fetch logs AFTER the last seen timestamp
|
|
2685
|
+
// For initial fetch: get last 24 hours
|
|
2686
|
+
timestampStart: afterTimestamp || now - 24 * 60 * 60,
|
|
2687
|
+
timestampEnd: now,
|
|
2465
2688
|
}
|
|
2466
2689
|
);
|
|
2467
2690
|
|
|
2468
2691
|
if (!logsData || !logsData.data || logsData.data.length === 0) {
|
|
2469
|
-
if (!follow) {
|
|
2692
|
+
if (!follow && !afterTimestamp) {
|
|
2470
2693
|
console.log(
|
|
2471
2694
|
chalk.yellow("No logs found for this serverless.")
|
|
2472
2695
|
);
|
|
2473
2696
|
}
|
|
2474
|
-
return
|
|
2697
|
+
return afterTimestamp;
|
|
2475
2698
|
}
|
|
2476
2699
|
|
|
2477
2700
|
const logs = logsData.data;
|
|
2478
|
-
let latestTimestamp =
|
|
2701
|
+
let latestTimestamp = afterTimestamp;
|
|
2702
|
+
|
|
2703
|
+
// Sort logs by timestamp ascending for proper display order
|
|
2704
|
+
const sortedLogs = [...logs].sort(
|
|
2705
|
+
(a, b) => (a.Timestamp || 0) - (b.Timestamp || 0)
|
|
2706
|
+
);
|
|
2707
|
+
|
|
2708
|
+
sortedLogs.forEach((log) => {
|
|
2709
|
+
// Create a unique ID for deduplication
|
|
2710
|
+
const logId = `${log.Timestamp}-${log.Log}`;
|
|
2711
|
+
if (seenLogIds.has(logId)) {
|
|
2712
|
+
return; // Skip duplicate
|
|
2713
|
+
}
|
|
2714
|
+
seenLogIds.add(logId);
|
|
2479
2715
|
|
|
2480
|
-
logs.forEach((log) => {
|
|
2481
2716
|
// Timestamp is unix epoch in seconds
|
|
2482
2717
|
const timestamp = log.Timestamp
|
|
2483
2718
|
? new Date(log.Timestamp * 1000).toLocaleTimeString()
|
|
@@ -2523,8 +2758,9 @@ async function handleLogs(args = []) {
|
|
|
2523
2758
|
let lastTimestamp = await fetchAndDisplayLogs();
|
|
2524
2759
|
|
|
2525
2760
|
if (follow) {
|
|
2761
|
+
// Poll for new logs every 2 seconds
|
|
2526
2762
|
while (true) {
|
|
2527
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
2763
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2528
2764
|
lastTimestamp = await fetchAndDisplayLogs(lastTimestamp);
|
|
2529
2765
|
}
|
|
2530
2766
|
}
|
|
@@ -2548,9 +2784,10 @@ async function handleLogs(args = []) {
|
|
|
2548
2784
|
*/
|
|
2549
2785
|
async function handleBuildLogs(args = []) {
|
|
2550
2786
|
try {
|
|
2551
|
-
// Parse args (supports --name, -n,
|
|
2787
|
+
// Parse args (supports --name, -n, --build, -b, --follow, -f)
|
|
2552
2788
|
let name = null;
|
|
2553
2789
|
let buildId = null;
|
|
2790
|
+
let follow = false;
|
|
2554
2791
|
|
|
2555
2792
|
for (let i = 0; i < args.length; i++) {
|
|
2556
2793
|
const arg = args[i];
|
|
@@ -2562,6 +2799,8 @@ async function handleBuildLogs(args = []) {
|
|
|
2562
2799
|
} else if ((arg === "--build" || arg === "-b") && nextArg) {
|
|
2563
2800
|
buildId = nextArg;
|
|
2564
2801
|
i++;
|
|
2802
|
+
} else if (arg === "--follow" || arg === "-f") {
|
|
2803
|
+
follow = true;
|
|
2565
2804
|
} else if (!arg.startsWith("-") && !name) {
|
|
2566
2805
|
// Accept positional argument as name
|
|
2567
2806
|
name = arg;
|
|
@@ -2690,50 +2929,98 @@ async function handleBuildLogs(args = []) {
|
|
|
2690
2929
|
|
|
2691
2930
|
console.log(chalk.cyan(`\n📜 Fetching build logs...\n`));
|
|
2692
2931
|
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
session,
|
|
2698
|
-
serverless.ID,
|
|
2699
|
-
buildId
|
|
2700
|
-
);
|
|
2701
|
-
|
|
2702
|
-
if (!logsData || !logsData.data) {
|
|
2703
|
-
console.log(chalk.yellow("No logs found for this build."));
|
|
2704
|
-
return;
|
|
2932
|
+
if (follow) {
|
|
2933
|
+
console.log(
|
|
2934
|
+
chalk.dim("Following build logs... Press Ctrl+C to stop.\n")
|
|
2935
|
+
);
|
|
2705
2936
|
}
|
|
2706
2937
|
|
|
2707
2938
|
console.log(chalk.cyan("━".repeat(80)));
|
|
2708
2939
|
console.log(chalk.bold("Build Logs:\n"));
|
|
2709
2940
|
|
|
2710
|
-
//
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2941
|
+
// Track displayed lines to avoid duplicates in follow mode
|
|
2942
|
+
let displayedLines = 0;
|
|
2943
|
+
|
|
2944
|
+
const fetchAndDisplayBuildLogs = async () => {
|
|
2945
|
+
const logsData = await getBuildLogs(
|
|
2946
|
+
apiUrl,
|
|
2947
|
+
token,
|
|
2948
|
+
accountId,
|
|
2949
|
+
session,
|
|
2950
|
+
serverless.ID,
|
|
2951
|
+
buildId
|
|
2952
|
+
);
|
|
2953
|
+
|
|
2954
|
+
if (!logsData || !logsData.data) {
|
|
2955
|
+
if (!follow && displayedLines === 0) {
|
|
2956
|
+
console.log(chalk.yellow("No logs found for this build."));
|
|
2724
2957
|
}
|
|
2725
|
-
|
|
2726
|
-
const timestamp = log.Timestamp
|
|
2727
|
-
? new Date(log.Timestamp * 1000).toLocaleTimeString()
|
|
2728
|
-
: "";
|
|
2729
|
-
console.log(
|
|
2730
|
-
chalk.dim(`[${timestamp}]`) +
|
|
2731
|
-
` ${log.Message || log.message}`
|
|
2732
|
-
);
|
|
2733
|
-
} else {
|
|
2734
|
-
console.log(JSON.stringify(log, null, 2));
|
|
2958
|
+
return { hasLogs: false, buildComplete: false };
|
|
2735
2959
|
}
|
|
2736
|
-
|
|
2960
|
+
|
|
2961
|
+
// Handle different log formats
|
|
2962
|
+
const logs = Array.isArray(logsData.data)
|
|
2963
|
+
? logsData.data
|
|
2964
|
+
: [logsData.data];
|
|
2965
|
+
|
|
2966
|
+
// Only display new logs (skip already displayed ones)
|
|
2967
|
+
const newLogs = logs.slice(displayedLines);
|
|
2968
|
+
|
|
2969
|
+
newLogs.forEach((log) => {
|
|
2970
|
+
if (typeof log === "string") {
|
|
2971
|
+
console.log(log);
|
|
2972
|
+
} else if (log.Log) {
|
|
2973
|
+
// Log field contains the actual log content (may include ANSI colors)
|
|
2974
|
+
// Output directly to preserve color codes
|
|
2975
|
+
process.stdout.write(log.Log);
|
|
2976
|
+
if (!log.Log.endsWith("\n")) {
|
|
2977
|
+
process.stdout.write("\n");
|
|
2978
|
+
}
|
|
2979
|
+
} else if (log.Message || log.message) {
|
|
2980
|
+
const timestamp = log.Timestamp
|
|
2981
|
+
? new Date(log.Timestamp * 1000).toLocaleTimeString()
|
|
2982
|
+
: "";
|
|
2983
|
+
console.log(
|
|
2984
|
+
chalk.dim(`[${timestamp}]`) +
|
|
2985
|
+
` ${log.Message || log.message}`
|
|
2986
|
+
);
|
|
2987
|
+
} else {
|
|
2988
|
+
console.log(JSON.stringify(log, null, 2));
|
|
2989
|
+
}
|
|
2990
|
+
});
|
|
2991
|
+
|
|
2992
|
+
displayedLines = logs.length;
|
|
2993
|
+
|
|
2994
|
+
// Check if build is complete by looking for completion indicators
|
|
2995
|
+
const lastLog = logs[logs.length - 1];
|
|
2996
|
+
const logContent =
|
|
2997
|
+
typeof lastLog === "string"
|
|
2998
|
+
? lastLog
|
|
2999
|
+
: lastLog?.Log || lastLog?.Message || "";
|
|
3000
|
+
const buildComplete =
|
|
3001
|
+
logContent.includes("Build completed") ||
|
|
3002
|
+
logContent.includes("Build failed") ||
|
|
3003
|
+
logContent.includes("successfully") ||
|
|
3004
|
+
logContent.includes("error:");
|
|
3005
|
+
|
|
3006
|
+
return { hasLogs: true, buildComplete };
|
|
3007
|
+
};
|
|
3008
|
+
|
|
3009
|
+
let result = await fetchAndDisplayBuildLogs();
|
|
3010
|
+
|
|
3011
|
+
if (follow && !result.buildComplete) {
|
|
3012
|
+
// Poll for new logs every 2 seconds until build completes
|
|
3013
|
+
while (true) {
|
|
3014
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
3015
|
+
result = await fetchAndDisplayBuildLogs();
|
|
3016
|
+
if (result.buildComplete) {
|
|
3017
|
+
console.log(
|
|
3018
|
+
chalk.dim("\n\nBuild completed. Stopping log follow.")
|
|
3019
|
+
);
|
|
3020
|
+
break;
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
2737
3024
|
|
|
2738
3025
|
console.log("\n" + chalk.cyan("━".repeat(80)));
|
|
2739
3026
|
} catch (error) {
|
package/helper/serverless.js
CHANGED
|
@@ -14,10 +14,10 @@ import ora from "ora";
|
|
|
14
14
|
// Supported languages and their versions
|
|
15
15
|
export const SUPPORTED_LANGUAGES = ["nodejs", "python", "golang", "java"];
|
|
16
16
|
export const LANGUAGE_VERSIONS = {
|
|
17
|
-
nodejs: "
|
|
17
|
+
nodejs: "24",
|
|
18
18
|
python: "3",
|
|
19
|
-
golang: "1.
|
|
20
|
-
java: "
|
|
19
|
+
golang: "1.24",
|
|
20
|
+
java: "21",
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
// Handler mapping per language
|
|
@@ -36,6 +36,233 @@ export const LANGUAGE_CHOICES = [
|
|
|
36
36
|
{ name: "Java", value: "java" },
|
|
37
37
|
];
|
|
38
38
|
|
|
39
|
+
// Language-specific .gitignore templates
|
|
40
|
+
export const GITIGNORE_TEMPLATES = {
|
|
41
|
+
nodejs: `# Dependencies
|
|
42
|
+
node_modules/
|
|
43
|
+
package-lock.json
|
|
44
|
+
yarn.lock
|
|
45
|
+
pnpm-lock.yaml
|
|
46
|
+
|
|
47
|
+
# Build output
|
|
48
|
+
dist/
|
|
49
|
+
build/
|
|
50
|
+
.next/
|
|
51
|
+
|
|
52
|
+
# Environment files
|
|
53
|
+
.env
|
|
54
|
+
.env.local
|
|
55
|
+
.env.*.local
|
|
56
|
+
|
|
57
|
+
# Logs
|
|
58
|
+
logs/
|
|
59
|
+
*.log
|
|
60
|
+
npm-debug.log*
|
|
61
|
+
yarn-debug.log*
|
|
62
|
+
yarn-error.log*
|
|
63
|
+
|
|
64
|
+
# IDE
|
|
65
|
+
.idea/
|
|
66
|
+
.vscode/
|
|
67
|
+
*.swp
|
|
68
|
+
*.swo
|
|
69
|
+
*~
|
|
70
|
+
|
|
71
|
+
# OS files
|
|
72
|
+
.DS_Store
|
|
73
|
+
Thumbs.db
|
|
74
|
+
|
|
75
|
+
# Boltic auto-generated files
|
|
76
|
+
autogen_*.js
|
|
77
|
+
`,
|
|
78
|
+
python: `# Byte-compiled / optimized / DLL files
|
|
79
|
+
__pycache__/
|
|
80
|
+
*.py[cod]
|
|
81
|
+
*$py.class
|
|
82
|
+
|
|
83
|
+
# Virtual environments
|
|
84
|
+
venv/
|
|
85
|
+
env/
|
|
86
|
+
.venv/
|
|
87
|
+
.env/
|
|
88
|
+
|
|
89
|
+
# Distribution / packaging
|
|
90
|
+
dist/
|
|
91
|
+
build/
|
|
92
|
+
*.egg-info/
|
|
93
|
+
.eggs/
|
|
94
|
+
|
|
95
|
+
# Environment files
|
|
96
|
+
.env
|
|
97
|
+
.env.local
|
|
98
|
+
.env.*.local
|
|
99
|
+
|
|
100
|
+
# Logs
|
|
101
|
+
*.log
|
|
102
|
+
|
|
103
|
+
# IDE
|
|
104
|
+
.idea/
|
|
105
|
+
.vscode/
|
|
106
|
+
*.swp
|
|
107
|
+
*.swo
|
|
108
|
+
*~
|
|
109
|
+
|
|
110
|
+
# OS files
|
|
111
|
+
.DS_Store
|
|
112
|
+
Thumbs.db
|
|
113
|
+
|
|
114
|
+
# Boltic auto-generated files
|
|
115
|
+
autogen_*.py
|
|
116
|
+
`,
|
|
117
|
+
golang: `# Binaries
|
|
118
|
+
*.exe
|
|
119
|
+
*.exe~
|
|
120
|
+
*.dll
|
|
121
|
+
*.so
|
|
122
|
+
*.dylib
|
|
123
|
+
|
|
124
|
+
# Build output
|
|
125
|
+
bin/
|
|
126
|
+
/main
|
|
127
|
+
|
|
128
|
+
# Test binary
|
|
129
|
+
*.test
|
|
130
|
+
|
|
131
|
+
# Go workspace
|
|
132
|
+
go.work
|
|
133
|
+
go.work.sum
|
|
134
|
+
|
|
135
|
+
# Vendor directory (if not committing dependencies)
|
|
136
|
+
# vendor/
|
|
137
|
+
|
|
138
|
+
# Environment files
|
|
139
|
+
.env
|
|
140
|
+
.env.local
|
|
141
|
+
.env.*.local
|
|
142
|
+
|
|
143
|
+
# Logs
|
|
144
|
+
*.log
|
|
145
|
+
|
|
146
|
+
# IDE
|
|
147
|
+
.idea/
|
|
148
|
+
.vscode/
|
|
149
|
+
*.swp
|
|
150
|
+
*.swo
|
|
151
|
+
*~
|
|
152
|
+
|
|
153
|
+
# OS files
|
|
154
|
+
.DS_Store
|
|
155
|
+
Thumbs.db
|
|
156
|
+
|
|
157
|
+
# Boltic auto-generated files
|
|
158
|
+
autogen_*.go
|
|
159
|
+
`,
|
|
160
|
+
java: `# Compiled class files
|
|
161
|
+
*.class
|
|
162
|
+
|
|
163
|
+
# Build output
|
|
164
|
+
target/
|
|
165
|
+
build/
|
|
166
|
+
out/
|
|
167
|
+
bin/
|
|
168
|
+
|
|
169
|
+
# Package files
|
|
170
|
+
*.jar
|
|
171
|
+
*.war
|
|
172
|
+
*.ear
|
|
173
|
+
|
|
174
|
+
# Maven
|
|
175
|
+
.mvn/
|
|
176
|
+
!.mvn/wrapper/maven-wrapper.jar
|
|
177
|
+
pom.xml.tag
|
|
178
|
+
pom.xml.releaseBackup
|
|
179
|
+
pom.xml.versionsBackup
|
|
180
|
+
pom.xml.next
|
|
181
|
+
|
|
182
|
+
# Gradle
|
|
183
|
+
.gradle/
|
|
184
|
+
gradle/
|
|
185
|
+
gradlew
|
|
186
|
+
gradlew.bat
|
|
187
|
+
|
|
188
|
+
# Environment files
|
|
189
|
+
.env
|
|
190
|
+
.env.local
|
|
191
|
+
.env.*.local
|
|
192
|
+
|
|
193
|
+
# Logs
|
|
194
|
+
*.log
|
|
195
|
+
|
|
196
|
+
# IDE
|
|
197
|
+
.idea/
|
|
198
|
+
.vscode/
|
|
199
|
+
*.iml
|
|
200
|
+
*.ipr
|
|
201
|
+
*.iws
|
|
202
|
+
.classpath
|
|
203
|
+
.project
|
|
204
|
+
.settings/
|
|
205
|
+
*.swp
|
|
206
|
+
*.swo
|
|
207
|
+
*~
|
|
208
|
+
|
|
209
|
+
# OS files
|
|
210
|
+
.DS_Store
|
|
211
|
+
Thumbs.db
|
|
212
|
+
|
|
213
|
+
# Boltic auto-generated files
|
|
214
|
+
AutogenIndex.java
|
|
215
|
+
`,
|
|
216
|
+
container: `# Environment files
|
|
217
|
+
.env
|
|
218
|
+
.env.local
|
|
219
|
+
.env.*.local
|
|
220
|
+
|
|
221
|
+
# Logs
|
|
222
|
+
*.log
|
|
223
|
+
|
|
224
|
+
# IDE
|
|
225
|
+
.idea/
|
|
226
|
+
.vscode/
|
|
227
|
+
*.swp
|
|
228
|
+
*.swo
|
|
229
|
+
*~
|
|
230
|
+
|
|
231
|
+
# OS files
|
|
232
|
+
.DS_Store
|
|
233
|
+
Thumbs.db
|
|
234
|
+
|
|
235
|
+
# Docker
|
|
236
|
+
.docker/
|
|
237
|
+
`,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Create a .gitignore file for the serverless project
|
|
242
|
+
* @param {string} targetDir - Directory to create .gitignore in
|
|
243
|
+
* @param {string} language - Programming language (nodejs, python, golang, java, container)
|
|
244
|
+
* @returns {boolean} - True if created successfully
|
|
245
|
+
*/
|
|
246
|
+
export function createGitignore(targetDir, language) {
|
|
247
|
+
const gitignorePath = path.join(targetDir, ".gitignore");
|
|
248
|
+
|
|
249
|
+
// Don't overwrite existing .gitignore
|
|
250
|
+
if (fs.existsSync(gitignorePath)) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const template =
|
|
255
|
+
GITIGNORE_TEMPLATES[language] || GITIGNORE_TEMPLATES.nodejs;
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
fs.writeFileSync(gitignorePath, template);
|
|
259
|
+
return true;
|
|
260
|
+
} catch {
|
|
261
|
+
// Silently fail - .gitignore is optional
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
39
266
|
/**
|
|
40
267
|
* Parse command line arguments for the create command
|
|
41
268
|
*/
|
|
@@ -45,6 +272,7 @@ export function parseCreateArgs(args) {
|
|
|
45
272
|
language: null,
|
|
46
273
|
directory: process.cwd(),
|
|
47
274
|
type: null, // code, git, or container
|
|
275
|
+
noGitignore: false, // Skip .gitignore creation
|
|
48
276
|
};
|
|
49
277
|
|
|
50
278
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -68,6 +296,8 @@ export function parseCreateArgs(args) {
|
|
|
68
296
|
}
|
|
69
297
|
parsed.type = typeValue;
|
|
70
298
|
i++;
|
|
299
|
+
} else if (arg === "--no-gitignore") {
|
|
300
|
+
parsed.noGitignore = true;
|
|
71
301
|
}
|
|
72
302
|
}
|
|
73
303
|
|
|
@@ -705,7 +935,7 @@ public class AutogenIndex {
|
|
|
705
935
|
function getGoModContent(appName) {
|
|
706
936
|
return `module ${appName}
|
|
707
937
|
|
|
708
|
-
go 1.
|
|
938
|
+
go 1.24
|
|
709
939
|
`;
|
|
710
940
|
}
|
|
711
941
|
|
|
@@ -733,7 +963,7 @@ function getJavaPomXmlContent(appName) {
|
|
|
733
963
|
<description>Boltic Serverless Function</description>
|
|
734
964
|
|
|
735
965
|
<properties>
|
|
736
|
-
<java.version>
|
|
966
|
+
<java.version>21</java.version>
|
|
737
967
|
</properties>
|
|
738
968
|
|
|
739
969
|
<dependencies>
|
|
@@ -1071,6 +1301,7 @@ export function displayTestStartupMessage(port) {
|
|
|
1071
1301
|
export function parsePublishArgs(args) {
|
|
1072
1302
|
const parsed = {
|
|
1073
1303
|
directory: process.cwd(),
|
|
1304
|
+
verbose: false,
|
|
1074
1305
|
};
|
|
1075
1306
|
|
|
1076
1307
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -1080,6 +1311,8 @@ export function parsePublishArgs(args) {
|
|
|
1080
1311
|
if ((arg === "--directory" || arg === "-d") && nextArg) {
|
|
1081
1312
|
parsed.directory = path.resolve(nextArg);
|
|
1082
1313
|
i++;
|
|
1314
|
+
} else if (arg === "--verbose" || arg === "-v") {
|
|
1315
|
+
parsed.verbose = true;
|
|
1083
1316
|
} else if (!arg.startsWith("-") && !parsed._dirSet) {
|
|
1084
1317
|
// Accept positional argument as directory (e.g., `boltic serverless publish ./my-project`)
|
|
1085
1318
|
parsed.directory = path.resolve(arg);
|
|
@@ -1207,7 +1440,7 @@ export function displayPublishSuccessMessage(name, response) {
|
|
|
1207
1440
|
export function getPulledBolticYamlContent(serverlessData) {
|
|
1208
1441
|
const config = serverlessData.Config;
|
|
1209
1442
|
const runtime = config.Runtime || "code";
|
|
1210
|
-
const language = config.CodeOpts?.Language || "nodejs/
|
|
1443
|
+
const language = config.CodeOpts?.Language || "nodejs/24";
|
|
1211
1444
|
const handler =
|
|
1212
1445
|
HANDLER_MAPPING[language.split("/")[0]] || "handler.handler";
|
|
1213
1446
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boltic/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.44-dev1.1",
|
|
4
4
|
"description": "Professional CLI for interacting with the Boltic platform — create, manage, and publish integrations, serverless functions, workflows, MCPs, and more with enterprise-grade features and a seamless developer experience",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -136,4 +136,4 @@
|
|
|
136
136
|
"x64",
|
|
137
137
|
"arm64"
|
|
138
138
|
]
|
|
139
|
-
}
|
|
139
|
+
}
|