@cbnventures/nova 0.15.4 → 0.16.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.
Files changed (65) hide show
  1. package/build/package.json +1 -1
  2. package/build/src/cli/generate/github/workflows.d.ts +6 -1
  3. package/build/src/cli/generate/github/workflows.d.ts.map +1 -1
  4. package/build/src/cli/generate/github/workflows.js +244 -6
  5. package/build/src/cli/generate/github/workflows.js.map +1 -1
  6. package/build/src/cli/utility/initialize.d.ts.map +1 -1
  7. package/build/src/cli/utility/initialize.js +228 -4
  8. package/build/src/cli/utility/initialize.js.map +1 -1
  9. package/build/src/lib/nova-config.d.ts.map +1 -1
  10. package/build/src/lib/nova-config.js +33 -0
  11. package/build/src/lib/nova-config.js.map +1 -1
  12. package/build/src/lib/regex.d.ts +4 -0
  13. package/build/src/lib/regex.d.ts.map +1 -1
  14. package/build/src/lib/regex.js +4 -0
  15. package/build/src/lib/regex.js.map +1 -1
  16. package/build/src/lib/workflow-templates.d.ts.map +1 -1
  17. package/build/src/lib/workflow-templates.js +176 -113
  18. package/build/src/lib/workflow-templates.js.map +1 -1
  19. package/build/src/types/cli/generate/github/workflows.d.ts +178 -0
  20. package/build/src/types/cli/utility/initialize.d.ts +216 -0
  21. package/build/src/types/lib/nova-config.d.ts +24 -0
  22. package/build/src/types/lib/workflow-templates.d.ts +53 -0
  23. package/build/src/types/shared.d.ts +103 -1
  24. package/build/src/types/tests/cli/generate/github/workflows-helpers.test.d.ts +54 -0
  25. package/build/src/types/tests/cli/generate/github/workflows.test.d.ts +12 -2
  26. package/build/src/types/tests/lib/workflow-templates.test.d.ts +10 -70
  27. package/build/templates/generators/github/workflows/check-sponsor-gated-issues/base.yml +6 -10
  28. package/build/templates/generators/github/workflows/check-sponsor-gated-issues/triggers/issue-comment.yml +5 -0
  29. package/build/templates/generators/github/workflows/check-sponsor-gated-issues/triggers/issues.yml +5 -0
  30. package/build/templates/generators/github/workflows/lock-inactive-issues/triggers/schedule-daily.yml +5 -0
  31. package/build/templates/generators/github/workflows/lock-inactive-issues/triggers/schedule-monthly.yml +5 -0
  32. package/build/templates/generators/github/workflows/{publish-to-cloudflare-pages-docusaurus → publish}/base.yml +8 -17
  33. package/build/templates/generators/github/workflows/publish/targets/aws-amplify-nextjs.yml +32 -0
  34. package/build/templates/generators/github/workflows/publish/targets/cloudflare-pages-docusaurus.yml +25 -0
  35. package/build/templates/generators/github/workflows/publish/targets/docker-hub.yml +47 -0
  36. package/build/templates/generators/github/workflows/publish/targets/ghcr.yml +47 -0
  37. package/build/templates/generators/github/workflows/publish/targets/github-packages.yml +84 -0
  38. package/build/templates/generators/github/workflows/publish/targets/github-pages-docusaurus.yml +43 -0
  39. package/build/templates/generators/github/workflows/publish/targets/npm.yml +60 -0
  40. package/build/templates/generators/github/workflows/publish/targets/vercel-nextjs.yml +45 -0
  41. package/build/templates/generators/github/workflows/{publish-to-npm → publish}/triggers/release.yml +1 -1
  42. package/build/templates/generators/github/workflows/{publish-to-npm → publish}/triggers/workflow-run-any.yml +1 -1
  43. package/build/templates/generators/github/workflows/{publish-to-npm → publish}/triggers/workflow-run-failure.yml +1 -1
  44. package/build/templates/generators/github/workflows/{publish-to-npm → publish}/triggers/workflow-run-success.yml +1 -1
  45. package/package.json +1 -1
  46. package/build/templates/generators/github/workflows/publish-to-aws-amplify-nextjs/base.yml +0 -54
  47. package/build/templates/generators/github/workflows/publish-to-aws-amplify-nextjs/triggers/push.yml +0 -5
  48. package/build/templates/generators/github/workflows/publish-to-aws-amplify-nextjs/triggers/release.yml +0 -5
  49. package/build/templates/generators/github/workflows/publish-to-cloudflare-pages-docusaurus/triggers/push.yml +0 -5
  50. package/build/templates/generators/github/workflows/publish-to-cloudflare-pages-docusaurus/triggers/release.yml +0 -5
  51. package/build/templates/generators/github/workflows/publish-to-docker-hub/base.yml +0 -59
  52. package/build/templates/generators/github/workflows/publish-to-docker-hub/triggers/release.yml +0 -5
  53. package/build/templates/generators/github/workflows/publish-to-docker-hub/triggers/workflow-run-any.yml +0 -7
  54. package/build/templates/generators/github/workflows/publish-to-docker-hub/triggers/workflow-run-failure.yml +0 -8
  55. package/build/templates/generators/github/workflows/publish-to-docker-hub/triggers/workflow-run-success.yml +0 -8
  56. package/build/templates/generators/github/workflows/publish-to-github-packages/base.yml +0 -120
  57. package/build/templates/generators/github/workflows/publish-to-github-packages/triggers/release.yml +0 -5
  58. package/build/templates/generators/github/workflows/publish-to-github-packages/triggers/workflow-run-any.yml +0 -7
  59. package/build/templates/generators/github/workflows/publish-to-github-packages/triggers/workflow-run-failure.yml +0 -8
  60. package/build/templates/generators/github/workflows/publish-to-github-packages/triggers/workflow-run-success.yml +0 -8
  61. package/build/templates/generators/github/workflows/publish-to-github-pages-docusaurus/base.yml +0 -79
  62. package/build/templates/generators/github/workflows/publish-to-github-pages-docusaurus/triggers/push.yml +0 -5
  63. package/build/templates/generators/github/workflows/publish-to-github-pages-docusaurus/triggers/release.yml +0 -5
  64. package/build/templates/generators/github/workflows/publish-to-npm/base.yml +0 -97
  65. /package/build/templates/generators/github/workflows/lock-inactive-issues/triggers/{schedule.yml → schedule-weekly.yml} +0 -0
@@ -1122,7 +1122,7 @@ export class CliUtilityInitialize {
1122
1122
  return 'back';
1123
1123
  }
1124
1124
  if (menuOutputResult.action['kind'] === 'add') {
1125
- const result = await CliUtilityInitialize.promptWorkflowsForm(undefined, 'create', workflows);
1125
+ const result = await CliUtilityInitialize.promptWorkflowsForm(undefined, 'create', workflows, config);
1126
1126
  if (result['action'] === 'back') {
1127
1127
  continue;
1128
1128
  }
@@ -1142,7 +1142,7 @@ export class CliUtilityInitialize {
1142
1142
  continue;
1143
1143
  }
1144
1144
  const workflowToEdit = workflows[workflowIndex];
1145
- const workflowResult = await CliUtilityInitialize.promptWorkflowsForm(workflowToEdit, 'update', workflows);
1145
+ const workflowResult = await CliUtilityInitialize.promptWorkflowsForm(workflowToEdit, 'update', workflows, config);
1146
1146
  if (workflowResult['action'] === 'back') {
1147
1147
  continue;
1148
1148
  }
@@ -1189,11 +1189,13 @@ export class CliUtilityInitialize {
1189
1189
  }
1190
1190
  }
1191
1191
  }
1192
- static async promptWorkflowsForm(workflow, mode, workflows) {
1192
+ static async promptWorkflowsForm(workflow, mode, workflows, config) {
1193
1193
  const existingTemplate = (workflow !== undefined && typeof workflow['template'] === 'string') ? workflow['template'] : '';
1194
1194
  const existingSuffix = (workflow !== undefined && typeof workflow['suffix'] === 'string') ? workflow['suffix'] : '';
1195
1195
  const existingTriggers = (workflow !== undefined && Array.isArray(workflow['triggers']) === true) ? workflow['triggers'] : [];
1196
1196
  const existingDependsOn = (workflow !== undefined && Array.isArray(workflow['depends-on']) === true) ? workflow['depends-on'] : [];
1197
+ const existingTargets = (workflow !== undefined && Array.isArray(workflow['targets']) === true) ? workflow['targets'] : [];
1198
+ const existingScopes = (workflow !== undefined && Array.isArray(workflow['scopes']) === true) ? workflow['scopes'] : [];
1197
1199
  const templateChoices = libWorkflowTemplatesMetadata.map((entry) => ({
1198
1200
  title: entry['name'],
1199
1201
  description: entry['description'],
@@ -1278,6 +1280,18 @@ export class CliUtilityInitialize {
1278
1280
  }
1279
1281
  const triggersOutputResult = triggersOutput['result'];
1280
1282
  selectedTriggers = (Array.isArray(triggersOutputResult.triggers) === true) ? triggersOutputResult.triggers : [];
1283
+ const scheduleVariants = selectedTriggers.filter((trigger) => trigger.startsWith('schedule-'));
1284
+ if (scheduleVariants.length > 1) {
1285
+ Logger.customize({
1286
+ name: 'CliUtilityInitialize.promptWorkflowsForm',
1287
+ purpose: 'validation',
1288
+ padTop: 1,
1289
+ padBottom: 1,
1290
+ }).error(`Only one ${chalk.cyan('schedule-*')} trigger may be selected. Please try again.`);
1291
+ return {
1292
+ action: 'back',
1293
+ };
1294
+ }
1281
1295
  }
1282
1296
  let selectedDependsOn = undefined;
1283
1297
  if (selectedTriggers.some((trigger) => trigger.startsWith('workflow-run')) === true) {
@@ -1310,9 +1324,213 @@ export class CliUtilityInitialize {
1310
1324
  }
1311
1325
  }
1312
1326
  const matchedMetadata = libWorkflowTemplatesMetadata.find((entry) => entry['name'] === selectedTemplate);
1327
+ const workspaceKeys = Object.keys(config['workspaces'] ?? {});
1328
+ const selectedTargets = [...existingTargets];
1329
+ if (matchedMetadata !== undefined && matchedMetadata['supportsTargets'] === true) {
1330
+ const targetsMetadata = matchedMetadata['targets'] ?? {};
1331
+ const availableTargetTypes = Object.keys(targetsMetadata);
1332
+ while (true) {
1333
+ const targetMenuChoices = [];
1334
+ for (let i = 0; i < selectedTargets.length; i += 1) {
1335
+ const currentTarget = selectedTargets[i];
1336
+ if (currentTarget === undefined) {
1337
+ continue;
1338
+ }
1339
+ const currentTargetType = currentTarget['type'];
1340
+ const currentTargetWorkingDir = currentTarget['workingDir'];
1341
+ targetMenuChoices.push({
1342
+ title: `${chalk.yellow.bold('[EDIT]')} ${currentTargetType} → ${currentTargetWorkingDir}`,
1343
+ value: {
1344
+ kind: 'edit',
1345
+ index: i,
1346
+ },
1347
+ });
1348
+ targetMenuChoices.push({
1349
+ title: `${chalk.red.bold('[REMOVE]')} ${currentTargetType} → ${currentTargetWorkingDir}`,
1350
+ value: {
1351
+ kind: 'remove',
1352
+ index: i,
1353
+ },
1354
+ });
1355
+ }
1356
+ targetMenuChoices.push({
1357
+ title: 'Add target',
1358
+ value: {
1359
+ kind: 'add',
1360
+ },
1361
+ });
1362
+ targetMenuChoices.push({
1363
+ title: 'Done',
1364
+ value: {
1365
+ kind: 'done',
1366
+ },
1367
+ });
1368
+ const targetMenuOutput = await CliUtilityInitialize.promptWithCancel({
1369
+ type: 'select',
1370
+ name: 'targetAction',
1371
+ message: (selectedTargets.length > 0) ? 'Select a target to manage.' : 'No targets added yet. Choose an option.',
1372
+ choices: targetMenuChoices,
1373
+ });
1374
+ if (targetMenuOutput['cancelled'] === true) {
1375
+ return {
1376
+ action: 'back',
1377
+ };
1378
+ }
1379
+ const targetMenuOutputResult = targetMenuOutput['result'];
1380
+ const targetMenuAction = targetMenuOutputResult.targetAction;
1381
+ if (targetMenuAction['kind'] === 'done') {
1382
+ break;
1383
+ }
1384
+ if (targetMenuAction['kind'] === 'remove') {
1385
+ const targetToRemoveIndex = targetMenuAction['index'];
1386
+ if (targetToRemoveIndex >= 0 && targetToRemoveIndex < selectedTargets.length) {
1387
+ selectedTargets.splice(targetToRemoveIndex, 1);
1388
+ }
1389
+ continue;
1390
+ }
1391
+ if (targetMenuAction['kind'] === 'add' || targetMenuAction['kind'] === 'edit') {
1392
+ const targetEditIndex = (targetMenuAction['kind'] === 'edit') ? targetMenuAction['index'] : -1;
1393
+ const targetToEdit = (targetEditIndex >= 0) ? selectedTargets[targetEditIndex] : undefined;
1394
+ const targetTypeInitial = (targetToEdit !== undefined) ? availableTargetTypes.indexOf(targetToEdit['type']) : 0;
1395
+ const targetTypeChoices = availableTargetTypes.map((availableTargetType) => ({
1396
+ title: availableTargetType,
1397
+ value: availableTargetType,
1398
+ }));
1399
+ const targetTypeOutput = await CliUtilityInitialize.promptWithCancel({
1400
+ type: 'select',
1401
+ name: 'targetType',
1402
+ message: 'Select a target type.',
1403
+ choices: targetTypeChoices,
1404
+ initial: (targetTypeInitial >= 0) ? targetTypeInitial : 0,
1405
+ });
1406
+ if (targetTypeOutput['cancelled'] === true) {
1407
+ continue;
1408
+ }
1409
+ const targetTypeOutputResult = targetTypeOutput['result'];
1410
+ const selectedTargetType = targetTypeOutputResult.targetType;
1411
+ const targetWorkingDirInitial = (targetToEdit !== undefined) ? workspaceKeys.indexOf(targetToEdit['workingDir']) : 0;
1412
+ const targetWorkingDirChoices = workspaceKeys.map((workspaceKey) => ({
1413
+ title: workspaceKey,
1414
+ value: workspaceKey,
1415
+ }));
1416
+ const targetWorkingDirOutput = await CliUtilityInitialize.promptWithCancel({
1417
+ type: 'select',
1418
+ name: 'targetWorkingDir',
1419
+ message: 'Select a working directory.',
1420
+ choices: targetWorkingDirChoices,
1421
+ initial: (targetWorkingDirInitial >= 0) ? targetWorkingDirInitial : 0,
1422
+ });
1423
+ if (targetWorkingDirOutput['cancelled'] === true) {
1424
+ continue;
1425
+ }
1426
+ const targetWorkingDirOutputResult = targetWorkingDirOutput['result'];
1427
+ const selectedTargetWorkingDir = targetWorkingDirOutputResult.targetWorkingDir;
1428
+ const targetIsDuplicate = selectedTargets.some((selectedTarget, selectedTargetIndex) => {
1429
+ if (selectedTargetIndex === targetEditIndex) {
1430
+ return false;
1431
+ }
1432
+ return selectedTarget['type'] === selectedTargetType && selectedTarget['workingDir'] === selectedTargetWorkingDir;
1433
+ });
1434
+ if (targetIsDuplicate === true) {
1435
+ Logger.customize({
1436
+ name: 'CliUtilityInitialize.promptWorkflowsForm',
1437
+ purpose: 'validation',
1438
+ padTop: 1,
1439
+ padBottom: 1,
1440
+ }).error(`Target ${chalk.cyan(`${selectedTargetType} → ${selectedTargetWorkingDir}`)} already exists.`);
1441
+ continue;
1442
+ }
1443
+ let selectedTargetNeeds = undefined;
1444
+ const targetToEditExistingNeeds = (targetToEdit !== undefined && Array.isArray(targetToEdit['needs']) === true) ? targetToEdit['needs'] : [];
1445
+ const targetNeedsChoices = selectedTargets
1446
+ .filter((candidate, candidateIndex) => {
1447
+ return candidate['type'] === selectedTargetType
1448
+ && candidateIndex !== targetEditIndex
1449
+ && candidate['workingDir'] !== selectedTargetWorkingDir;
1450
+ })
1451
+ .map((candidate) => ({
1452
+ title: candidate['workingDir'],
1453
+ value: candidate['workingDir'],
1454
+ selected: targetToEditExistingNeeds.includes(candidate['workingDir']),
1455
+ }));
1456
+ if (targetNeedsChoices.length > 0) {
1457
+ const targetNeedsOutput = await CliUtilityInitialize.promptWithCancel({
1458
+ type: 'multiselect',
1459
+ name: 'targetNeeds',
1460
+ message: 'Select targets this must wait for before publishing (optional).',
1461
+ choices: targetNeedsChoices,
1462
+ });
1463
+ if (targetNeedsOutput['cancelled'] === true) {
1464
+ continue;
1465
+ }
1466
+ const targetNeedsOutputResult = targetNeedsOutput['result'];
1467
+ selectedTargetNeeds = (Array.isArray(targetNeedsOutputResult.targetNeeds) === true && targetNeedsOutputResult.targetNeeds.length > 0) ? targetNeedsOutputResult.targetNeeds : undefined;
1468
+ }
1469
+ const newTarget = {
1470
+ type: selectedTargetType,
1471
+ workingDir: selectedTargetWorkingDir,
1472
+ };
1473
+ if (selectedTargetNeeds !== undefined) {
1474
+ Reflect.set(newTarget, 'needs', selectedTargetNeeds);
1475
+ }
1476
+ if (targetEditIndex >= 0) {
1477
+ Reflect.set(selectedTargets, targetEditIndex, newTarget);
1478
+ }
1479
+ else {
1480
+ selectedTargets.push(newTarget);
1481
+ }
1482
+ continue;
1483
+ }
1484
+ }
1485
+ }
1486
+ let selectedScopes = [];
1487
+ if (matchedMetadata !== undefined && matchedMetadata['supportsScopes'] === true) {
1488
+ const lockedPaths = new Set(selectedTargets.map((selectedTarget) => selectedTarget['workingDir']));
1489
+ const extraWorkspaceKeys = workspaceKeys.filter((workspaceKey) => lockedPaths.has(workspaceKey) === false);
1490
+ selectedScopes = [...lockedPaths];
1491
+ if (extraWorkspaceKeys.length > 0) {
1492
+ const scopeChoices = extraWorkspaceKeys.map((workspaceKey) => ({
1493
+ title: workspaceKey,
1494
+ value: workspaceKey,
1495
+ selected: existingScopes.includes(workspaceKey),
1496
+ }));
1497
+ const scopesOutput = await CliUtilityInitialize.promptWithCancel({
1498
+ type: 'multiselect',
1499
+ name: 'scopes',
1500
+ message: 'Select any EXTRA workspaces to check and build for this workflow.',
1501
+ choices: scopeChoices,
1502
+ });
1503
+ if (scopesOutput['cancelled'] === true) {
1504
+ return {
1505
+ action: 'back',
1506
+ };
1507
+ }
1508
+ const scopesOutputResult = scopesOutput['result'];
1509
+ const extraScopes = (Array.isArray(scopesOutputResult.scopes) === true) ? scopesOutputResult.scopes : [];
1510
+ for (const extraScope of extraScopes) {
1511
+ if (selectedScopes.includes(extraScope) === false) {
1512
+ selectedScopes.push(extraScope);
1513
+ }
1514
+ }
1515
+ }
1516
+ }
1313
1517
  const settings = {};
1314
1518
  if (matchedMetadata !== undefined) {
1315
- const variableEntries = Object.entries(matchedMetadata['variables']);
1519
+ const mergedVariables = { ...matchedMetadata['variables'] };
1520
+ for (const selectedTarget of selectedTargets) {
1521
+ const targetType = selectedTarget['type'];
1522
+ const targetMetadata = matchedMetadata['targets'] ?? {};
1523
+ const targetVariables = (targetMetadata[targetType] !== undefined) ? targetMetadata[targetType]['variables'] : {};
1524
+ const targetVarEntries = Object.entries(targetVariables);
1525
+ for (const entry of targetVarEntries) {
1526
+ const targetVarKey = entry[0];
1527
+ const targetVarValue = entry[1];
1528
+ if (mergedVariables[targetVarKey] === undefined) {
1529
+ Reflect.set(mergedVariables, targetVarKey, targetVarValue);
1530
+ }
1531
+ }
1532
+ }
1533
+ const variableEntries = Object.entries(mergedVariables);
1316
1534
  for (const variableEntry of variableEntries) {
1317
1535
  const variableName = variableEntry[0];
1318
1536
  const variableConfig = variableEntry[1];
@@ -1370,6 +1588,12 @@ export class CliUtilityInitialize {
1370
1588
  if (selectedDependsOn !== undefined) {
1371
1589
  Reflect.set(resolvedWorkflow, 'depends-on', selectedDependsOn);
1372
1590
  }
1591
+ if (selectedTargets.length > 0) {
1592
+ Reflect.set(resolvedWorkflow, 'targets', selectedTargets);
1593
+ }
1594
+ if (selectedScopes.length > 0) {
1595
+ Reflect.set(resolvedWorkflow, 'scopes', selectedScopes);
1596
+ }
1373
1597
  if (Object.keys(settings).length > 0) {
1374
1598
  resolvedWorkflow.settings = settings;
1375
1599
  }