fix(tools): handle pnpm 11 global migrations
This commit is contained in:
+226
-46
@@ -51,7 +51,9 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
|
||||
const pnpmInfo = await pmUtil.getPnpmVersionInfo();
|
||||
if (!pnpmInfo.available) {
|
||||
console.log("pnpm is required for gitzone tools update, but it was not found.");
|
||||
console.log(
|
||||
"pnpm is required for gitzone tools update, but it was not found.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -59,18 +61,25 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
console.log(" Name Current Latest Status");
|
||||
console.log(" ----------------------------------------------");
|
||||
const latestPnpm = (pnpmInfo.latestVersion || "unknown").padEnd(12);
|
||||
const pnpmStatus = pnpmInfo.latestVersion === null
|
||||
? "? Version unknown"
|
||||
: pnpmInfo.needsUpdate
|
||||
? "Update available"
|
||||
: "Up to date";
|
||||
console.log(` ${"pnpm".padEnd(9)}${pnpmInfo.currentVersion.padEnd(12)}${latestPnpm}${pnpmStatus}`);
|
||||
const pnpmStatus =
|
||||
pnpmInfo.latestVersion === null
|
||||
? "? Version unknown"
|
||||
: pnpmInfo.needsUpdate
|
||||
? "Update available"
|
||||
: "Up to date";
|
||||
console.log(
|
||||
` ${"pnpm".padEnd(9)}${pnpmInfo.currentVersion.padEnd(12)}${latestPnpm}${pnpmStatus}`,
|
||||
);
|
||||
console.log("");
|
||||
|
||||
if (verbose) {
|
||||
console.log("Using pnpm as the supported global package manager.\n");
|
||||
}
|
||||
|
||||
const pnpmNeedsUpdate = Boolean(
|
||||
pnpmInfo.latestVersion && pnpmInfo.needsUpdate,
|
||||
);
|
||||
|
||||
const selfUpdated = await handleSelfUpdate(pmUtil, mode);
|
||||
if (selfUpdated) {
|
||||
return;
|
||||
@@ -78,39 +87,79 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
|
||||
const installedPackages = await pmUtil.getInstalledPackages();
|
||||
const packageInfos = await getPackageUpdateInfos(pmUtil, installedPackages);
|
||||
const legacyRoots = await pmUtil.getLegacyGlobalRoots();
|
||||
const legacyCleanupNeeded = legacyRoots.length > 0;
|
||||
|
||||
if (packageInfos.length === 0) {
|
||||
console.log("No managed @git.zone packages found installed globally.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Installed @git.zone packages:\n");
|
||||
console.log(" Package Current Latest Status");
|
||||
console.log(" ------------------------------------------------------------");
|
||||
for (const packageInfo of packageInfos) {
|
||||
const status = packageInfo.latestVersion === "unknown"
|
||||
? "? Version unknown"
|
||||
: packageInfo.needsUpdate
|
||||
? "Update available"
|
||||
: "Up to date";
|
||||
} else {
|
||||
console.log("Installed @git.zone packages:\n");
|
||||
console.log(
|
||||
` ${packageInfo.name.padEnd(28)}${packageInfo.currentVersion.padEnd(12)}${packageInfo.latestVersion.padEnd(12)}${status}`,
|
||||
" Package Current Latest Status",
|
||||
);
|
||||
console.log(
|
||||
" ------------------------------------------------------------",
|
||||
);
|
||||
for (const packageInfo of packageInfos) {
|
||||
console.log(
|
||||
` ${packageInfo.name.padEnd(28)}${packageInfo.currentVersion.padEnd(12)}${packageInfo.latestVersion.padEnd(12)}${getPackageStatus(packageInfo)}`,
|
||||
);
|
||||
}
|
||||
console.log("");
|
||||
|
||||
await printMissingPackages(pmUtil, installedPackages);
|
||||
}
|
||||
console.log("");
|
||||
|
||||
await printMissingPackages(pmUtil, installedPackages);
|
||||
const packagesToUpdate = packageInfos.filter(
|
||||
(packageInfo) => packageInfo.needsUpdate || packageInfo.needsMigration,
|
||||
);
|
||||
const packagesToMigrate = packageInfos.filter(
|
||||
(packageInfo) => packageInfo.needsMigration,
|
||||
);
|
||||
|
||||
const packagesToUpdate = packageInfos.filter((packageInfo) => packageInfo.needsUpdate);
|
||||
if (packagesToUpdate.length === 0) {
|
||||
if (packagesToMigrate.length > 0) {
|
||||
console.log(
|
||||
`Detected ${packagesToMigrate.length} package(s) in legacy pnpm global roots.`,
|
||||
);
|
||||
if (verbose) {
|
||||
for (const packageInfo of packagesToMigrate) {
|
||||
console.log(
|
||||
` ${packageInfo.name} -> ${packageInfo.globalDir || "unknown"}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
console.log("");
|
||||
} else if (legacyCleanupNeeded) {
|
||||
console.log(
|
||||
`Detected ${legacyRoots.length} legacy pnpm global root(s) for cleanup.`,
|
||||
);
|
||||
if (verbose) {
|
||||
for (const legacyRoot of legacyRoots) {
|
||||
console.log(` ${legacyRoot.globalDir}`);
|
||||
}
|
||||
}
|
||||
console.log("");
|
||||
}
|
||||
|
||||
if (
|
||||
packagesToUpdate.length === 0 &&
|
||||
!pnpmNeedsUpdate &&
|
||||
!legacyCleanupNeeded
|
||||
) {
|
||||
console.log("All managed packages are up to date.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Found ${packagesToUpdate.length} package(s) with available updates.\n`);
|
||||
const actionCount =
|
||||
packagesToUpdate.length +
|
||||
(pnpmNeedsUpdate ? 1 : 0) +
|
||||
(legacyCleanupNeeded ? 1 : 0);
|
||||
console.log(`Found ${actionCount} update action(s).\n`);
|
||||
|
||||
if (!mode.yes && !mode.interactive) {
|
||||
console.log("Run gitzone tools update -y to update without prompts.");
|
||||
console.log(
|
||||
"Run gitzone tools update -y to update, migrate, and cleanup without prompts.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,7 +169,7 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
const answer = await interactInstance.askQuestion({
|
||||
type: "confirm",
|
||||
name: "confirmUpdate",
|
||||
message: "Do you want to update these packages?",
|
||||
message: "Do you want to update, migrate, and cleanup these tools?",
|
||||
default: true,
|
||||
});
|
||||
shouldUpdate = answer.value === true;
|
||||
@@ -131,7 +180,35 @@ async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await installPackages(pmUtil, packagesToUpdate.map((packageInfo) => packageInfo.name), "updated");
|
||||
if (pnpmNeedsUpdate && pnpmInfo.latestVersion) {
|
||||
console.log(`Updating pnpm to ${pnpmInfo.latestVersion}...`);
|
||||
const success = await pmUtil.updatePnpm(pnpmInfo.latestVersion);
|
||||
console.log(
|
||||
success
|
||||
? "pnpm updated successfully.\n"
|
||||
: "pnpm update failed. Continuing with package updates.\n",
|
||||
);
|
||||
}
|
||||
|
||||
const installResult =
|
||||
packagesToUpdate.length > 0
|
||||
? await installPackages(
|
||||
pmUtil,
|
||||
packagesToUpdate.map((packageInfo) => ({
|
||||
name: packageInfo.name,
|
||||
version:
|
||||
packageInfo.latestVersion !== "unknown"
|
||||
? packageInfo.latestVersion
|
||||
: undefined,
|
||||
})),
|
||||
"updated",
|
||||
)
|
||||
: { successCount: 0, failCount: 0 };
|
||||
|
||||
if (packagesToUpdate.length > 0 || legacyCleanupNeeded) {
|
||||
await syncCurrentGlobalShims(pmUtil);
|
||||
await cleanupLegacyInstalls(pmUtil);
|
||||
}
|
||||
}
|
||||
|
||||
async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
@@ -142,7 +219,9 @@ async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
|
||||
const pnpmAvailable = await pmUtil.detectPnpm();
|
||||
if (!pnpmAvailable) {
|
||||
console.log("pnpm is required for gitzone tools install, but it was not found.");
|
||||
console.log(
|
||||
"pnpm is required for gitzone tools install, but it was not found.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -151,8 +230,12 @@ async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
}
|
||||
|
||||
const installedPackages = await pmUtil.getInstalledPackages();
|
||||
const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
|
||||
const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
|
||||
const installedNames = new Set(
|
||||
installedPackages.map((packageInfo) => packageInfo.name),
|
||||
);
|
||||
const missingPackages = GITZONE_PACKAGES.filter(
|
||||
(packageName) => !installedNames.has(packageName),
|
||||
);
|
||||
|
||||
if (missingPackages.length === 0) {
|
||||
console.log("All managed @git.zone packages are already installed.");
|
||||
@@ -163,7 +246,9 @@ async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
|
||||
|
||||
if (!mode.yes && !mode.interactive) {
|
||||
await printPackageListWithLatest(pmUtil, missingPackages);
|
||||
console.log("Run gitzone tools install -y to install all missing packages without prompts.");
|
||||
console.log(
|
||||
"Run gitzone tools install -y to install all missing packages without prompts.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -210,7 +295,9 @@ async function handleSelfUpdate(
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(` @git.zone/cli ${currentVersion} -> ${latestVersion} Update available\n`);
|
||||
console.log(
|
||||
` @git.zone/cli ${currentVersion} -> ${latestVersion} Update available\n`,
|
||||
);
|
||||
|
||||
if (!mode.yes && !mode.interactive) {
|
||||
console.log("Run gitzone tools update -y to update gitzone first.");
|
||||
@@ -236,11 +323,15 @@ async function handleSelfUpdate(
|
||||
|
||||
const success = await pmUtil.installLatest("@git.zone/cli");
|
||||
if (!success) {
|
||||
console.log("\ngitzone self-update failed. Continuing with the current version.\n");
|
||||
console.log(
|
||||
"\ngitzone self-update failed. Continuing with the current version.\n",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log("\ngitzone has been updated. Re-run gitzone tools update to check remaining packages.");
|
||||
console.log(
|
||||
"\ngitzone has been updated. Re-run gitzone tools update to check remaining packages.",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -261,17 +352,39 @@ async function getPackageUpdateInfos(
|
||||
needsUpdate: latestVersion
|
||||
? pmUtil.isNewerVersion(installedPackage.version, latestVersion)
|
||||
: false,
|
||||
needsMigration: installedPackage.legacy === true,
|
||||
globalDir: installedPackage.globalDir,
|
||||
});
|
||||
}
|
||||
return packageInfos;
|
||||
}
|
||||
|
||||
function getPackageStatus(packageInfo: IPackageUpdateInfo): string {
|
||||
if (packageInfo.latestVersion === "unknown") {
|
||||
return "? Version unknown";
|
||||
}
|
||||
if (packageInfo.needsUpdate && packageInfo.needsMigration) {
|
||||
return "Update + migrate";
|
||||
}
|
||||
if (packageInfo.needsUpdate) {
|
||||
return "Update available";
|
||||
}
|
||||
if (packageInfo.needsMigration) {
|
||||
return "Migrate global root";
|
||||
}
|
||||
return "Up to date";
|
||||
}
|
||||
|
||||
async function printMissingPackages(
|
||||
pmUtil: PackageManagerUtil,
|
||||
installedPackages: IInstalledPackage[],
|
||||
): Promise<void> {
|
||||
const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
|
||||
const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
|
||||
const installedNames = new Set(
|
||||
installedPackages.map((packageInfo) => packageInfo.name),
|
||||
);
|
||||
const missingPackages = GITZONE_PACKAGES.filter(
|
||||
(packageName) => !installedNames.has(packageName),
|
||||
);
|
||||
if (missingPackages.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -296,14 +409,18 @@ async function printPackageListWithLatest(
|
||||
|
||||
async function installPackages(
|
||||
pmUtil: PackageManagerUtil,
|
||||
packageNames: string[],
|
||||
packageSpecs: Array<string | { name: string; version?: string }>,
|
||||
action: "installed" | "updated",
|
||||
): Promise<void> {
|
||||
): Promise<{ successCount: number; failCount: number }> {
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
for (const packageName of packageNames) {
|
||||
const success = await pmUtil.installLatest(packageName);
|
||||
for (const packageSpec of packageSpecs) {
|
||||
const packageName =
|
||||
typeof packageSpec === "string" ? packageSpec : packageSpec.name;
|
||||
const packageVersion =
|
||||
typeof packageSpec === "string" ? undefined : packageSpec.version;
|
||||
const success = await pmUtil.installLatest(packageName, packageVersion);
|
||||
if (success) {
|
||||
console.log(` ${packageName} ${action} successfully`);
|
||||
successCount++;
|
||||
@@ -319,6 +436,56 @@ async function installPackages(
|
||||
} else {
|
||||
console.log(`${successCount} package(s) ${action}, ${failCount} failed.`);
|
||||
}
|
||||
|
||||
return { successCount, failCount };
|
||||
}
|
||||
|
||||
async function cleanupLegacyInstalls(
|
||||
pmUtil: PackageManagerUtil,
|
||||
): Promise<void> {
|
||||
const cleanupResults = await pmUtil.cleanupLegacyGlobalRoots();
|
||||
if (cleanupResults.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Legacy pnpm global roots:\n");
|
||||
for (const cleanupResult of cleanupResults) {
|
||||
if (cleanupResult.deleted) {
|
||||
console.log(` ${cleanupResult.globalDir} deleted`);
|
||||
} else {
|
||||
console.log(
|
||||
` ${cleanupResult.globalDir} kept (${cleanupResult.reason || "unknown reason"})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
console.log("");
|
||||
}
|
||||
|
||||
async function syncCurrentGlobalShims(
|
||||
pmUtil: PackageManagerUtil,
|
||||
): Promise<void> {
|
||||
const shimResults = await pmUtil.syncCurrentGlobalShims();
|
||||
const changedResults = shimResults.filter(
|
||||
(shimResult) => shimResult.action !== "skipped",
|
||||
);
|
||||
const skippedResults = shimResults.filter(
|
||||
(shimResult) => shimResult.action === "skipped",
|
||||
);
|
||||
|
||||
if (changedResults.length === 0 && skippedResults.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Command shims:\n");
|
||||
for (const shimResult of changedResults) {
|
||||
console.log(` ${shimResult.name} ${shimResult.action}`);
|
||||
}
|
||||
for (const shimResult of skippedResults) {
|
||||
console.log(
|
||||
` ${shimResult.name} skipped (${shimResult.reason || "unknown reason"})`,
|
||||
);
|
||||
}
|
||||
console.log("");
|
||||
}
|
||||
|
||||
export function showHelp(mode?: ICliMode): void {
|
||||
@@ -327,12 +494,21 @@ export function showHelp(mode?: ICliMode): void {
|
||||
name: "gitzone tools",
|
||||
usage: "gitzone tools <command> [options]",
|
||||
commands: [
|
||||
{ name: "update", description: "Check and update globally installed @git.zone packages" },
|
||||
{ name: "install", description: "Install missing managed @git.zone packages" },
|
||||
{
|
||||
name: "update",
|
||||
description: "Check and update globally installed @git.zone packages",
|
||||
},
|
||||
{
|
||||
name: "install",
|
||||
description: "Install missing managed @git.zone packages",
|
||||
},
|
||||
],
|
||||
flags: [
|
||||
{ flag: "-y, --yes", description: "Run without confirmation prompts" },
|
||||
{ flag: "-v, --verbose", description: "Show package manager diagnostics" },
|
||||
{
|
||||
flag: "-v, --verbose",
|
||||
description: "Show package manager diagnostics",
|
||||
},
|
||||
],
|
||||
packageManager: "pnpm",
|
||||
managedPackages: GITZONE_PACKAGES,
|
||||
@@ -344,8 +520,12 @@ export function showHelp(mode?: ICliMode): void {
|
||||
console.log("Usage: gitzone tools <command> [options]");
|
||||
console.log("");
|
||||
console.log("Commands:");
|
||||
console.log(" update Check and update globally installed @git.zone packages");
|
||||
console.log(" install Install missing managed @git.zone packages");
|
||||
console.log(
|
||||
" update Check and update globally installed @git.zone packages",
|
||||
);
|
||||
console.log(
|
||||
" install Install missing managed @git.zone packages",
|
||||
);
|
||||
console.log("");
|
||||
console.log("Options:");
|
||||
console.log(" -y, --yes Run without confirmation prompts");
|
||||
|
||||
Reference in New Issue
Block a user