@git.zone/cli 2.19.1 → 2.19.3

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.
@@ -51,7 +51,9 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
51
51
 
52
52
  const pnpmInfo = await pmUtil.getPnpmVersionInfo();
53
53
  if (!pnpmInfo.available) {
54
- console.log("pnpm is required for gitzone tools update, but it was not found.");
54
+ console.log(
55
+ "pnpm is required for gitzone tools update, but it was not found.",
56
+ );
55
57
  return;
56
58
  }
57
59
 
@@ -59,18 +61,25 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
59
61
  console.log(" Name Current Latest Status");
60
62
  console.log(" ----------------------------------------------");
61
63
  const latestPnpm = (pnpmInfo.latestVersion || "unknown").padEnd(12);
62
- const pnpmStatus = pnpmInfo.latestVersion === null
63
- ? "? Version unknown"
64
- : pnpmInfo.needsUpdate
65
- ? "Update available"
66
- : "Up to date";
67
- console.log(` ${"pnpm".padEnd(9)}${pnpmInfo.currentVersion.padEnd(12)}${latestPnpm}${pnpmStatus}`);
64
+ const pnpmStatus =
65
+ pnpmInfo.latestVersion === null
66
+ ? "? Version unknown"
67
+ : pnpmInfo.needsUpdate
68
+ ? "Update available"
69
+ : "Up to date";
70
+ console.log(
71
+ ` ${"pnpm".padEnd(9)}${pnpmInfo.currentVersion.padEnd(12)}${latestPnpm}${pnpmStatus}`,
72
+ );
68
73
  console.log("");
69
74
 
70
75
  if (verbose) {
71
76
  console.log("Using pnpm as the supported global package manager.\n");
72
77
  }
73
78
 
79
+ const pnpmNeedsUpdate = Boolean(
80
+ pnpmInfo.latestVersion && pnpmInfo.needsUpdate,
81
+ );
82
+
74
83
  const selfUpdated = await handleSelfUpdate(pmUtil, mode);
75
84
  if (selfUpdated) {
76
85
  return;
@@ -78,39 +87,79 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
78
87
 
79
88
  const installedPackages = await pmUtil.getInstalledPackages();
80
89
  const packageInfos = await getPackageUpdateInfos(pmUtil, installedPackages);
90
+ const legacyRoots = await pmUtil.getLegacyGlobalRoots();
91
+ const legacyCleanupNeeded = legacyRoots.length > 0;
81
92
 
82
93
  if (packageInfos.length === 0) {
83
94
  console.log("No managed @git.zone packages found installed globally.");
84
- return;
95
+ } else {
96
+ console.log("Installed @git.zone packages:\n");
97
+ console.log(
98
+ " Package Current Latest Status",
99
+ );
100
+ console.log(
101
+ " ------------------------------------------------------------",
102
+ );
103
+ for (const packageInfo of packageInfos) {
104
+ console.log(
105
+ ` ${packageInfo.name.padEnd(28)}${packageInfo.currentVersion.padEnd(12)}${packageInfo.latestVersion.padEnd(12)}${getPackageStatus(packageInfo)}`,
106
+ );
107
+ }
108
+ console.log("");
109
+
110
+ await printMissingPackages(pmUtil, installedPackages);
85
111
  }
86
112
 
87
- console.log("Installed @git.zone packages:\n");
88
- console.log(" Package Current Latest Status");
89
- console.log(" ------------------------------------------------------------");
90
- for (const packageInfo of packageInfos) {
91
- const status = packageInfo.latestVersion === "unknown"
92
- ? "? Version unknown"
93
- : packageInfo.needsUpdate
94
- ? "Update available"
95
- : "Up to date";
113
+ const packagesToUpdate = packageInfos.filter(
114
+ (packageInfo) => packageInfo.needsUpdate || packageInfo.needsMigration,
115
+ );
116
+ const packagesToMigrate = packageInfos.filter(
117
+ (packageInfo) => packageInfo.needsMigration,
118
+ );
119
+
120
+ if (packagesToMigrate.length > 0) {
96
121
  console.log(
97
- ` ${packageInfo.name.padEnd(28)}${packageInfo.currentVersion.padEnd(12)}${packageInfo.latestVersion.padEnd(12)}${status}`,
122
+ `Detected ${packagesToMigrate.length} package(s) in legacy pnpm global roots.`,
98
123
  );
124
+ if (verbose) {
125
+ for (const packageInfo of packagesToMigrate) {
126
+ console.log(
127
+ ` ${packageInfo.name} -> ${packageInfo.globalDir || "unknown"}`,
128
+ );
129
+ }
130
+ }
131
+ console.log("");
132
+ } else if (legacyCleanupNeeded) {
133
+ console.log(
134
+ `Detected ${legacyRoots.length} legacy pnpm global root(s) for cleanup.`,
135
+ );
136
+ if (verbose) {
137
+ for (const legacyRoot of legacyRoots) {
138
+ console.log(` ${legacyRoot.globalDir}`);
139
+ }
140
+ }
141
+ console.log("");
99
142
  }
100
- console.log("");
101
143
 
102
- await printMissingPackages(pmUtil, installedPackages);
103
-
104
- const packagesToUpdate = packageInfos.filter((packageInfo) => packageInfo.needsUpdate);
105
- if (packagesToUpdate.length === 0) {
144
+ if (
145
+ packagesToUpdate.length === 0 &&
146
+ !pnpmNeedsUpdate &&
147
+ !legacyCleanupNeeded
148
+ ) {
106
149
  console.log("All managed packages are up to date.");
107
150
  return;
108
151
  }
109
152
 
110
- console.log(`Found ${packagesToUpdate.length} package(s) with available updates.\n`);
153
+ const actionCount =
154
+ packagesToUpdate.length +
155
+ (pnpmNeedsUpdate ? 1 : 0) +
156
+ (legacyCleanupNeeded ? 1 : 0);
157
+ console.log(`Found ${actionCount} update action(s).\n`);
111
158
 
112
159
  if (!mode.yes && !mode.interactive) {
113
- console.log("Run gitzone tools update -y to update without prompts.");
160
+ console.log(
161
+ "Run gitzone tools update -y to update, migrate, and cleanup without prompts.",
162
+ );
114
163
  return;
115
164
  }
116
165
 
@@ -120,7 +169,7 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
120
169
  const answer = await interactInstance.askQuestion({
121
170
  type: "confirm",
122
171
  name: "confirmUpdate",
123
- message: "Do you want to update these packages?",
172
+ message: "Do you want to update, migrate, and cleanup these tools?",
124
173
  default: true,
125
174
  });
126
175
  shouldUpdate = answer.value === true;
@@ -131,7 +180,35 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
131
180
  return;
132
181
  }
133
182
 
134
- await installPackages(pmUtil, packagesToUpdate.map((packageInfo) => packageInfo.name), "updated");
183
+ if (pnpmNeedsUpdate && pnpmInfo.latestVersion) {
184
+ console.log(`Updating pnpm to ${pnpmInfo.latestVersion}...`);
185
+ const success = await pmUtil.updatePnpm(pnpmInfo.latestVersion);
186
+ console.log(
187
+ success
188
+ ? "pnpm updated successfully.\n"
189
+ : "pnpm update failed. Continuing with package updates.\n",
190
+ );
191
+ }
192
+
193
+ const installResult =
194
+ packagesToUpdate.length > 0
195
+ ? await installPackages(
196
+ pmUtil,
197
+ packagesToUpdate.map((packageInfo) => ({
198
+ name: packageInfo.name,
199
+ version:
200
+ packageInfo.latestVersion !== "unknown"
201
+ ? packageInfo.latestVersion
202
+ : undefined,
203
+ })),
204
+ "updated",
205
+ )
206
+ : { successCount: 0, failCount: 0 };
207
+
208
+ if (packagesToUpdate.length > 0 || legacyCleanupNeeded) {
209
+ await syncCurrentGlobalShims(pmUtil);
210
+ await cleanupLegacyInstalls(pmUtil);
211
+ }
135
212
  }
136
213
 
137
214
  async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
@@ -142,7 +219,9 @@ async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
142
219
 
143
220
  const pnpmAvailable = await pmUtil.detectPnpm();
144
221
  if (!pnpmAvailable) {
145
- console.log("pnpm is required for gitzone tools install, but it was not found.");
222
+ console.log(
223
+ "pnpm is required for gitzone tools install, but it was not found.",
224
+ );
146
225
  return;
147
226
  }
148
227
 
@@ -151,8 +230,12 @@ async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
151
230
  }
152
231
 
153
232
  const installedPackages = await pmUtil.getInstalledPackages();
154
- const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
155
- const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
233
+ const installedNames = new Set(
234
+ installedPackages.map((packageInfo) => packageInfo.name),
235
+ );
236
+ const missingPackages = GITZONE_PACKAGES.filter(
237
+ (packageName) => !installedNames.has(packageName),
238
+ );
156
239
 
157
240
  if (missingPackages.length === 0) {
158
241
  console.log("All managed @git.zone packages are already installed.");
@@ -163,7 +246,9 @@ async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
163
246
 
164
247
  if (!mode.yes && !mode.interactive) {
165
248
  await printPackageListWithLatest(pmUtil, missingPackages);
166
- console.log("Run gitzone tools install -y to install all missing packages without prompts.");
249
+ console.log(
250
+ "Run gitzone tools install -y to install all missing packages without prompts.",
251
+ );
167
252
  return;
168
253
  }
169
254
 
@@ -210,7 +295,9 @@ async function handleSelfUpdate(
210
295
  return false;
211
296
  }
212
297
 
213
- console.log(` @git.zone/cli ${currentVersion} -> ${latestVersion} Update available\n`);
298
+ console.log(
299
+ ` @git.zone/cli ${currentVersion} -> ${latestVersion} Update available\n`,
300
+ );
214
301
 
215
302
  if (!mode.yes && !mode.interactive) {
216
303
  console.log("Run gitzone tools update -y to update gitzone first.");
@@ -236,11 +323,15 @@ async function handleSelfUpdate(
236
323
 
237
324
  const success = await pmUtil.installLatest("@git.zone/cli");
238
325
  if (!success) {
239
- console.log("\ngitzone self-update failed. Continuing with the current version.\n");
326
+ console.log(
327
+ "\ngitzone self-update failed. Continuing with the current version.\n",
328
+ );
240
329
  return false;
241
330
  }
242
331
 
243
- console.log("\ngitzone has been updated. Re-run gitzone tools update to check remaining packages.");
332
+ console.log(
333
+ "\ngitzone has been updated. Re-run gitzone tools update to check remaining packages.",
334
+ );
244
335
  return true;
245
336
  }
246
337
 
@@ -261,17 +352,39 @@ async function getPackageUpdateInfos(
261
352
  needsUpdate: latestVersion
262
353
  ? pmUtil.isNewerVersion(installedPackage.version, latestVersion)
263
354
  : false,
355
+ needsMigration: installedPackage.legacy === true,
356
+ globalDir: installedPackage.globalDir,
264
357
  });
265
358
  }
266
359
  return packageInfos;
267
360
  }
268
361
 
362
+ function getPackageStatus(packageInfo: IPackageUpdateInfo): string {
363
+ if (packageInfo.latestVersion === "unknown") {
364
+ return "? Version unknown";
365
+ }
366
+ if (packageInfo.needsUpdate && packageInfo.needsMigration) {
367
+ return "Update + migrate";
368
+ }
369
+ if (packageInfo.needsUpdate) {
370
+ return "Update available";
371
+ }
372
+ if (packageInfo.needsMigration) {
373
+ return "Migrate global root";
374
+ }
375
+ return "Up to date";
376
+ }
377
+
269
378
  async function printMissingPackages(
270
379
  pmUtil: PackageManagerUtil,
271
380
  installedPackages: IInstalledPackage[],
272
381
  ): Promise<void> {
273
- const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
274
- const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
382
+ const installedNames = new Set(
383
+ installedPackages.map((packageInfo) => packageInfo.name),
384
+ );
385
+ const missingPackages = GITZONE_PACKAGES.filter(
386
+ (packageName) => !installedNames.has(packageName),
387
+ );
275
388
  if (missingPackages.length === 0) {
276
389
  return;
277
390
  }
@@ -296,14 +409,18 @@ async function printPackageListWithLatest(
296
409
 
297
410
  async function installPackages(
298
411
  pmUtil: PackageManagerUtil,
299
- packageNames: string[],
412
+ packageSpecs: Array<string | { name: string; version?: string }>,
300
413
  action: "installed" | "updated",
301
- ): Promise<void> {
414
+ ): Promise<{ successCount: number; failCount: number }> {
302
415
  let successCount = 0;
303
416
  let failCount = 0;
304
417
 
305
- for (const packageName of packageNames) {
306
- const success = await pmUtil.installLatest(packageName);
418
+ for (const packageSpec of packageSpecs) {
419
+ const packageName =
420
+ typeof packageSpec === "string" ? packageSpec : packageSpec.name;
421
+ const packageVersion =
422
+ typeof packageSpec === "string" ? undefined : packageSpec.version;
423
+ const success = await pmUtil.installLatest(packageName, packageVersion);
307
424
  if (success) {
308
425
  console.log(` ${packageName} ${action} successfully`);
309
426
  successCount++;
@@ -319,6 +436,56 @@ async function installPackages(
319
436
  } else {
320
437
  console.log(`${successCount} package(s) ${action}, ${failCount} failed.`);
321
438
  }
439
+
440
+ return { successCount, failCount };
441
+ }
442
+
443
+ async function cleanupLegacyInstalls(
444
+ pmUtil: PackageManagerUtil,
445
+ ): Promise<void> {
446
+ const cleanupResults = await pmUtil.cleanupLegacyGlobalRoots();
447
+ if (cleanupResults.length === 0) {
448
+ return;
449
+ }
450
+
451
+ console.log("Legacy pnpm global roots:\n");
452
+ for (const cleanupResult of cleanupResults) {
453
+ if (cleanupResult.deleted) {
454
+ console.log(` ${cleanupResult.globalDir} deleted`);
455
+ } else {
456
+ console.log(
457
+ ` ${cleanupResult.globalDir} kept (${cleanupResult.reason || "unknown reason"})`,
458
+ );
459
+ }
460
+ }
461
+ console.log("");
462
+ }
463
+
464
+ async function syncCurrentGlobalShims(
465
+ pmUtil: PackageManagerUtil,
466
+ ): Promise<void> {
467
+ const shimResults = await pmUtil.syncCurrentGlobalShims();
468
+ const changedResults = shimResults.filter(
469
+ (shimResult) => shimResult.action !== "skipped",
470
+ );
471
+ const skippedResults = shimResults.filter(
472
+ (shimResult) => shimResult.action === "skipped",
473
+ );
474
+
475
+ if (changedResults.length === 0 && skippedResults.length === 0) {
476
+ return;
477
+ }
478
+
479
+ console.log("Command shims:\n");
480
+ for (const shimResult of changedResults) {
481
+ console.log(` ${shimResult.name} ${shimResult.action}`);
482
+ }
483
+ for (const shimResult of skippedResults) {
484
+ console.log(
485
+ ` ${shimResult.name} skipped (${shimResult.reason || "unknown reason"})`,
486
+ );
487
+ }
488
+ console.log("");
322
489
  }
323
490
 
324
491
  export function showHelp(mode?: ICliMode): void {
@@ -327,12 +494,21 @@ export function showHelp(mode?: ICliMode): void {
327
494
  name: "gitzone tools",
328
495
  usage: "gitzone tools <command> [options]",
329
496
  commands: [
330
- { name: "update", description: "Check and update globally installed @git.zone packages" },
331
- { name: "install", description: "Install missing managed @git.zone packages" },
497
+ {
498
+ name: "update",
499
+ description: "Check and update globally installed @git.zone packages",
500
+ },
501
+ {
502
+ name: "install",
503
+ description: "Install missing managed @git.zone packages",
504
+ },
332
505
  ],
333
506
  flags: [
334
507
  { flag: "-y, --yes", description: "Run without confirmation prompts" },
335
- { flag: "-v, --verbose", description: "Show package manager diagnostics" },
508
+ {
509
+ flag: "-v, --verbose",
510
+ description: "Show package manager diagnostics",
511
+ },
336
512
  ],
337
513
  packageManager: "pnpm",
338
514
  managedPackages: GITZONE_PACKAGES,
@@ -344,8 +520,12 @@ export function showHelp(mode?: ICliMode): void {
344
520
  console.log("Usage: gitzone tools <command> [options]");
345
521
  console.log("");
346
522
  console.log("Commands:");
347
- console.log(" update Check and update globally installed @git.zone packages");
348
- console.log(" install Install missing managed @git.zone packages");
523
+ console.log(
524
+ " update Check and update globally installed @git.zone packages",
525
+ );
526
+ console.log(
527
+ " install Install missing managed @git.zone packages",
528
+ );
349
529
  console.log("");
350
530
  console.log("Options:");
351
531
  console.log(" -y, --yes Run without confirmation prompts");
package/ts/plugins.ts CHANGED
@@ -2,6 +2,7 @@ import * as smartlog from '@push.rocks/smartlog';
2
2
  import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
3
3
  import * as smartconfig from '@push.rocks/smartconfig';
4
4
  import * as path from 'path';
5
+ import * as fs from 'node:fs/promises';
5
6
  import * as projectinfo from '@push.rocks/projectinfo';
6
7
  import * as smartcli from '@push.rocks/smartcli';
7
8
  import * as smartpath from '@push.rocks/smartpath';
@@ -22,6 +23,7 @@ export {
22
23
  smartlogDestinationLocal,
23
24
  smartconfig,
24
25
  path,
26
+ fs,
25
27
  projectinfo,
26
28
  smartcli,
27
29
  smartpath,