@wpmoo/toolkit 0.9.16 → 0.9.18

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/cli.js CHANGED
@@ -280,8 +280,8 @@ async function showStartup(argv, skipUpdateCheck, details) {
280
280
  }
281
281
  console.log();
282
282
  }
283
- async function selectCockpitCommandFromMenu(serviceStatus) {
284
- const selection = await selectCockpitTopLevelMenu({ serviceStatus });
283
+ async function selectCockpitCommandFromMenu(serviceStatus, moduleCount) {
284
+ const selection = await selectCockpitTopLevelMenu({ serviceStatus, moduleCount });
285
285
  if (selection.kind === 'exit') {
286
286
  return 'exit';
287
287
  }
@@ -856,7 +856,7 @@ async function removeModuleOptionsFromPrompts(showIntro = true, cancelAction = '
856
856
  message: menuPromptMessage('Delete module files too?', cancelAction),
857
857
  active: 'Y',
858
858
  inactive: 'n',
859
- initialValue: false,
859
+ initialValue: cancelAction === 'back',
860
860
  });
861
861
  handleCancel(deleteFiles, cancelAction);
862
862
  return {
@@ -1234,7 +1234,7 @@ async function runSelectedModuleAction(action, module, cwd) {
1234
1234
  message: menuPromptMessage('Delete module files too?', 'back'),
1235
1235
  active: 'Y',
1236
1236
  inactive: 'n',
1237
- initialValue: false,
1237
+ initialValue: true,
1238
1238
  });
1239
1239
  handleCancel(deleteFiles, 'back');
1240
1240
  const removeCommand = cockpitCommands.find((entry) => entry.id === 'remove-module');
@@ -1453,7 +1453,7 @@ export async function runCli(cliArgv = process.argv.slice(2), cwd = process.cwd(
1453
1453
  };
1454
1454
  while (true) {
1455
1455
  try {
1456
- const command = await selectCockpitCommandFromMenu(serviceStatus);
1456
+ const command = await selectCockpitCommandFromMenu(serviceStatus, status.kind === 'environment' ? status.moduleCandidateCount : undefined);
1457
1457
  if (command === 'exit') {
1458
1458
  return;
1459
1459
  }
@@ -20,6 +20,7 @@ const topLevelCategoryOrder = [
20
20
  ];
21
21
  const topLevelCommands = topLevelCategoryOrder.flatMap((category) => cockpitCommands.filter((command) => command.category === category && command.id !== 'exit'));
22
22
  const topLevelCommandLabelWidth = Math.max(...topLevelCommands.map((command) => command.label.length));
23
+ const moduleDependentCommandIds = new Set(['list-modules', 'install', 'update', 'test', 'lint', 'pot', 'remove-module']);
23
24
  function rgb(red, green, blue, value) {
24
25
  return `\u001B[38;2;${red};${green};${blue}m${value}\u001B[39m`;
25
26
  }
@@ -32,7 +33,7 @@ function categoryHeading(category) {
32
33
  function commandName(command) {
33
34
  return `${rgb(226, 184, 96, ` ${command.label.padEnd(topLevelCommandLabelWidth)}`)}${dim(` ${command.description}`)}`;
34
35
  }
35
- function disabledReason(command, serviceStatus) {
36
+ function serviceDisabledReason(command, serviceStatus) {
36
37
  if (command.category !== 'services' || !serviceStatus)
37
38
  return undefined;
38
39
  if (serviceStatus.kind === 'docker-not-running')
@@ -44,31 +45,54 @@ function disabledReason(command, serviceStatus) {
44
45
  }
45
46
  return undefined;
46
47
  }
47
- function disabledMenuReason(serviceStatus) {
48
+ function moduleDisabledReason(command, moduleCount) {
49
+ return moduleCount === 0 && moduleDependentCommandIds.has(command.id) ? 'No modules found.' : undefined;
50
+ }
51
+ function disabledReason(command, serviceStatus, moduleCount) {
52
+ return serviceDisabledReason(command, serviceStatus) ?? moduleDisabledReason(command, moduleCount);
53
+ }
54
+ function disabledMenuReasons(serviceStatus, moduleCount) {
55
+ const reasons = [];
48
56
  if (serviceStatus?.kind === 'docker-not-running')
49
- return 'Docker not running.';
57
+ reasons.push('Docker not running.');
50
58
  if (serviceStatus?.kind === 'running')
51
- return 'Already running.';
59
+ reasons.push('Already running.');
52
60
  if (serviceStatus?.kind === 'stopped')
53
- return 'Services stopped.';
54
- return undefined;
61
+ reasons.push('Services stopped.');
62
+ if (moduleCount === 0)
63
+ reasons.push('No modules found.');
64
+ return reasons;
65
+ }
66
+ function disabledError(serviceStatus, moduleCount) {
67
+ const reasons = disabledMenuReasons(serviceStatus, moduleCount);
68
+ if (reasons.length === 0) {
69
+ return undefined;
70
+ }
71
+ return [
72
+ 'This option is disabled and cannot be selected.',
73
+ ...reasons.map((reason) => `Reason: ${reason}`),
74
+ ].join('\n');
75
+ }
76
+ function moduleChoiceDisabledValue(reason) {
77
+ if (!reason) {
78
+ return undefined;
79
+ }
80
+ return reason === 'No modules found.' ? reason : true;
55
81
  }
56
- function disabledError(serviceStatus) {
57
- const reason = disabledMenuReason(serviceStatus);
58
- return reason ? `This option is disabled and cannot be selected.\nReason: ${reason}` : undefined;
82
+ function commandDisabledValue(command, serviceStatus, moduleCount) {
83
+ return moduleChoiceDisabledValue(disabledReason(command, serviceStatus, moduleCount));
59
84
  }
60
- function categoryChoices(category, index, serviceStatus) {
85
+ function categoryChoices(category, index, serviceStatus, moduleCount) {
61
86
  const choices = [
62
87
  promptSeparator(categoryHeading(category)),
63
88
  ...topLevelCommands
64
89
  .filter((command) => command.category === category)
65
90
  .map((command) => {
66
- const reason = disabledReason(command, serviceStatus);
67
91
  return {
68
92
  value: command,
69
93
  name: commandName(command),
70
94
  short: command.label,
71
- disabled: reason ? true : undefined,
95
+ disabled: commandDisabledValue(command, serviceStatus, moduleCount),
72
96
  };
73
97
  }),
74
98
  ];
@@ -101,8 +125,8 @@ function menuDeps(deps = {}) {
101
125
  function isCockpitCommand(value) {
102
126
  return typeof value === 'object' && value !== null && 'id' in value && 'slashAlias' in value;
103
127
  }
104
- function topLevelChoices(serviceStatus) {
105
- return topLevelCategoryOrder.flatMap((category, index) => categoryChoices(category, index, serviceStatus));
128
+ function topLevelChoices(serviceStatus, moduleCount) {
129
+ return topLevelCategoryOrder.flatMap((category, index) => categoryChoices(category, index, serviceStatus, moduleCount));
106
130
  }
107
131
  function defaultCommand(serviceStatus) {
108
132
  if (serviceStatus?.kind === 'running') {
@@ -115,7 +139,7 @@ function defaultCommand(serviceStatus) {
115
139
  }
116
140
  export async function selectCockpitTopLevelMenu(options = {}) {
117
141
  const deps = menuDeps(options);
118
- const choices = topLevelChoices(options.serviceStatus);
142
+ const choices = topLevelChoices(options.serviceStatus, options.moduleCount);
119
143
  const cancelAction = 'back';
120
144
  const selected = await deps.select({
121
145
  message: '',
@@ -124,7 +148,7 @@ export async function selectCockpitTopLevelMenu(options = {}) {
124
148
  pageSize: topLevelPageSize(choices.length),
125
149
  loop: false,
126
150
  hideMessage: true,
127
- disabledError: disabledError(options.serviceStatus),
151
+ disabledError: disabledError(options.serviceStatus, options.moduleCount),
128
152
  navigationWarning: options.navigationWarning,
129
153
  escapeBehavior: 'ignore',
130
154
  });
@@ -355,7 +355,7 @@ async function assertModuleCleanBeforeDelete(target, sourceType, repoPath, modul
355
355
  const repoRoot = sourceRepoPath(target, sourceType, repoPath);
356
356
  try {
357
357
  const result = await git.run(repoRoot, ['status', '--short', '--', moduleName]);
358
- if (result.stdout.trim()) {
358
+ if (result.stdout.trim() && (await moduleHasCommittedFiles(repoRoot, moduleName, git))) {
359
359
  throw new Error(`Refusing to delete module ${moduleName} because it has dirty git changes in source repo ${repoPath}.`);
360
360
  }
361
361
  }
@@ -365,6 +365,15 @@ async function assertModuleCleanBeforeDelete(target, sourceType, repoPath, modul
365
365
  }
366
366
  }
367
367
  }
368
+ async function moduleHasCommittedFiles(repoRoot, moduleName, git) {
369
+ try {
370
+ const result = await git.run(repoRoot, ['ls-tree', '-r', '--name-only', 'HEAD', '--', moduleName]);
371
+ return Boolean(result.stdout.trim());
372
+ }
373
+ catch {
374
+ return false;
375
+ }
376
+ }
368
377
  export async function addModuleToSourceRepo(options, git = realGit) {
369
378
  const repoPath = validateRepoPath(options.repoPath);
370
379
  const moduleName = validateModuleName(options.moduleName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpmoo/toolkit",
3
- "version": "0.9.16",
3
+ "version": "0.9.18",
4
4
  "description": "WPMoo Toolkit for development, staging, and production lifecycle workflows.",
5
5
  "type": "module",
6
6
  "repository": {