From 976d3b5b51847de5b44087077632c8bed34f1e64 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:23:23 +0800 Subject: [PATCH 01/11] feat: start clean --- rush-plugins/rush-migrate-subspace-plugin/command-line.json | 6 ++++++ .../rush-migrate-subspace-plugin/src/interactMenu.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/rush-plugins/rush-migrate-subspace-plugin/command-line.json b/rush-plugins/rush-migrate-subspace-plugin/command-line.json index c6681b2..d785f49 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/command-line.json +++ b/rush-plugins/rush-migrate-subspace-plugin/command-line.json @@ -28,6 +28,12 @@ "longName": "--debug", "description": "Provide debug logs", "associatedCommands": ["migrate-subspace"] + }, + { + "parameterKind": "flag", + "longName": "--clean", + "description": "Merge and clean multiple common versions together", + "associatedCommands": ["migrate-subspace"] } ] } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts b/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts index c2fad17..efe6a72 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts @@ -1,3 +1,4 @@ +import { cleanSubspace } from './cleanSubspace'; import { migrateProject } from './migrateProject'; import { chooseCommandPrompt } from './prompts/command'; import Console from './providers/console'; @@ -21,6 +22,11 @@ export const interactMenu = async (): Promise => { await syncVersions(); Console.newLine(); break; + + case 'clean': + await cleanSubspace(); + Console.newLine(); + break; } } while (!exitApplication); From dfc541529418155687c4b307075e0e62da3c7557 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:06:55 +0800 Subject: [PATCH 02/11] feat: support clean subspace --- .../src/cleanSubspace.ts | 263 +++++++++++++++++- .../src/functions/syncProjectDependencies.ts | 10 +- .../src/prompts/command.ts | 1 + .../src/prompts/dependency.ts | 12 +- .../src/prompts/subspace.ts | 47 ++++ .../src/utilities/project.ts | 26 ++ .../src/utilities/subspace.ts | 58 ---- 7 files changed, 339 insertions(+), 78 deletions(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts index a847bf5..91a702d 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts @@ -1,14 +1,244 @@ -import { chooseSubspacePrompt } from './prompts/subspace'; +import { + chooseSubspacePrompt, + scanForUnusedDependencyVersionsPrompt, + scanForDuplicatedDependenciesPrompt, + scanForSubsetDependencyVersionsPrompt, + scanForAllDependenciesPrompt +} from './prompts/subspace'; import Console from './providers/console'; import { getRootPath } from './utilities/path'; import { Colorize } from '@rushstack/terminal'; import { - cleanSubspaceCommonVersions, getRushSubspaceCommonVersionsFilePath, - isSubspaceSupported + getSubspaceDependencies, + isSubspaceSupported, + loadRushSubspaceCommonVersions, + queryProjectsFromSubspace } from './utilities/subspace'; import { getRushSubspacesConfigurationJsonPath, querySubspaces } from './utilities/repository'; import { RushConstants } from '@rushstack/rush-sdk'; +import { chooseDependencyPrompt, confirmNextDependencyPrompt } from './prompts/dependency'; +import { IPackageJson, JsonFile } from '@rushstack/node-core-library'; +import { sortVersions, subsetVersion } from './utilities/dependency'; +import { + getProjectPackageFilePath, + loadProjectPackageJson, + updateProjectDependency +} from './utilities/project'; +import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; + +const removeSubsetDependency = async ( + subspaceName: string, + dependencyName: string, + versionsMap: Map, + rootPath: string = getRootPath() +): Promise => { + const versions: string[] = Array.from(versionsMap.keys()); + const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName, rootPath); + const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = loadRushSubspaceCommonVersions( + subspaceName, + rootPath + ); + + const validVersions: string[] = sortVersions(versions); + + let targetIndex: number = 0; + while (targetIndex < validVersions.length) { + const newVersion: string = validVersions[targetIndex]; + const toCompareVersions: string[] = validVersions.slice(targetIndex + 1); + + const toDeleteIndex: number = toCompareVersions.findIndex((toCompareVersion) => + subsetVersion(toCompareVersion, newVersion) + ); + + if (toDeleteIndex > -1) { + // Delete subset version + + const [deletedVersion] = validVersions.splice(targetIndex + 1 + toDeleteIndex, 1); + versionsMap.get(deletedVersion)?.forEach((projectName) => { + if (updateProjectDependency(projectName, dependencyName, newVersion, rootPath)) { + Console.debug( + `Updated project ${Colorize.bold(projectName)} for dependency ${Colorize.bold( + dependencyName + )} ${Colorize.bold(deletedVersion)} => ${Colorize.bold(newVersion)}!` + ); + } + }); + } else { + // Go to next version + targetIndex += 1; + } + } + + const removedAlternativeVersionsCount: number = versions.length - validVersions.length; + if (removedAlternativeVersionsCount > 0) { + // Update subspace common versions + if (validVersions.length > 0) { + subspaceCommonVersionsJson.allowedAlternativeVersions![dependencyName] = validVersions; + } else { + delete subspaceCommonVersionsJson.allowedAlternativeVersions![dependencyName]; + } + + JsonFile.save(subspaceCommonVersionsJson, subspaceCommonVersionsPath); + } + + return removedAlternativeVersionsCount; +}; + +const removeDuplicatedDependencies = (subspaceName: string, rootPath: string = getRootPath()): void => { + Console.log(`Removing duplicated dependencies for subspace ${Colorize.bold(subspaceName)}...`); + + const projects: IRushConfigurationProjectJson[] = queryProjectsFromSubspace(subspaceName, rootPath); + let countRemoved: number = 0; + projects.forEach((project) => { + const projectPackageFilePath: string = getProjectPackageFilePath(project.projectFolder, rootPath); + const projectPackageJson: IPackageJson = loadProjectPackageJson(project.projectFolder, rootPath); + + const dependencies: string[] = Object.keys(projectPackageJson.dependencies || {}); + const devDependencies: string[] = Object.keys(projectPackageJson.devDependencies || {}); + + devDependencies.forEach((devDependency) => { + if (dependencies.includes(devDependency)) { + countRemoved += 1; + Console.debug( + `Removed ${Colorize.bold(devDependency)} from project ${Colorize.bold(project.packageName)}` + ); + delete projectPackageJson.devDependencies![devDependency]; + } + }); + + JsonFile.save(projectPackageJson, projectPackageFilePath); + }); + + if (countRemoved > 0) { + Console.success( + `Removed ${Colorize.bold(`${countRemoved}`)} duplicated dependencies from subspace ${Colorize.bold( + subspaceName + )}!` + ); + } else { + Console.success(`No duplicated dependencies found for subspace ${Colorize.bold(subspaceName)}!`); + } +}; + +const removeUnusedAlternativeVersions = ( + subspaceName: string, + subspaceDependencies: Map> +): void => { + Console.log(`Removing unused alternative versions for subspace ${Colorize.bold(subspaceName)}...`); + + const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName); + const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = + loadRushSubspaceCommonVersions(subspaceName); + + if (!subspaceCommonVersionsJson.allowedAlternativeVersions) { + return; + } + + let countRemoved: number = 0; + + for (const [dependency, alternativeVersions] of Object.entries( + subspaceCommonVersionsJson.allowedAlternativeVersions + )) { + const subspaceDependency: Map | undefined = subspaceDependencies.get(dependency); + const newAlternativeVersions: string[] = + subspaceDependency && subspaceDependency.size > 1 + ? alternativeVersions.filter((version) => subspaceDependency.has(version)) + : []; + + const removedAlternativeVersionsCount: number = + alternativeVersions.length - newAlternativeVersions.length; + if (removedAlternativeVersionsCount > 0) { + countRemoved += removedAlternativeVersionsCount; + Console.debug( + `Moving from [${Colorize.bold(alternativeVersions.join(','))}] to [${Colorize.bold( + newAlternativeVersions.join(',') + )}] for dependency ${Colorize.bold(dependency)}` + ); + } + + if (newAlternativeVersions.length === 0) { + delete subspaceCommonVersionsJson.allowedAlternativeVersions[dependency]; + continue; + } + + subspaceCommonVersionsJson.allowedAlternativeVersions = { + ...subspaceCommonVersionsJson.allowedAlternativeVersions, + [dependency]: newAlternativeVersions + }; + } + + if (countRemoved > 0) { + JsonFile.save(subspaceCommonVersionsJson, subspaceCommonVersionsPath); + Console.success( + `Removed ${Colorize.bold(`${countRemoved}`)} unused alternative versions from subspace ${Colorize.bold( + subspaceName + )}!` + ); + } else { + Console.success(`No unused alternative versions found for subspace ${Colorize.bold(subspaceName)}!`); + } +}; + +const removeSubsetDependencyVersions = async ( + subspaceName: string, + subspaceDependencies: Map> +): Promise => { + const multipleVersionDependencies: string[] = Array.from(subspaceDependencies.keys()).filter( + (dependency) => subspaceDependencies.get(dependency)!.size > 1 + ); + + if (multipleVersionDependencies.length === 0) { + Console.success( + `The subspace ${Colorize.bold(subspaceName)} doesn't contain alternative versions! Exiting...` + ); + return; + } + + if (await scanForAllDependenciesPrompt()) { + Console.log(`Removing subset versions for subspace ${Colorize.bold(subspaceName)}...`); + await Promise.all( + Array.from(subspaceDependencies.entries()).map(([dependency, versionsMap]) => + removeSubsetDependency(subspaceName, dependency, versionsMap) + ) + ).then((countPerDependency) => { + const count: number = countPerDependency.reduce((a, b) => a + b, 0); + if (count > 0) { + Console.success(`Removed ${Colorize.bold(`${count}`)} subset alternative versions!`); + } else { + Console.success(`No alternative versions have been removed!`); + } + }); + + return; + } + + do { + const selectedDependency: string = await chooseDependencyPrompt(multipleVersionDependencies); + + Console.log(`Removing subset versions for dependency ${Colorize.bold(selectedDependency)}...`); + const count: number = await removeSubsetDependency( + subspaceName, + selectedDependency, + subspaceDependencies.get(selectedDependency) as Map + ); + + if (count > 0) { + Console.success( + `Removed ${Colorize.bold(`${count}`)} subset alternative versions for dependency ${Colorize.bold( + selectedDependency + )}!` + ); + } else { + Console.success( + `No alternative versions have been removed for dependency ${Colorize.bold(selectedDependency)}!` + ); + } + + const index: number = multipleVersionDependencies.indexOf(selectedDependency); + multipleVersionDependencies.splice(index, 1); + } while (multipleVersionDependencies.length > 0 && (await confirmNextDependencyPrompt())); +}; export const cleanSubspace = async (): Promise => { Console.debug('Executing clean subspace command...'); @@ -26,15 +256,24 @@ export const cleanSubspace = async (): Promise => { } const targetSubspace: string = await chooseSubspacePrompt(targetSubspaces); - Console.title(`🛁 Cleaning subspace ${Colorize.underline(targetSubspace)} common versions...`); + Console.title(`🛁 Cleaning subspace ${Colorize.underline(targetSubspace)} alternative versions...`); - if (cleanSubspaceCommonVersions(targetSubspace)) { - Console.success( - `${Colorize.bold( - getRushSubspaceCommonVersionsFilePath(targetSubspace) - )} has been successfully refactored!` - ); - } else { - Console.success(`The subspace ${Colorize.bold(targetSubspace)} doesn't require cleaning! Exiting...`); + let subspaceDependencies: Map> = getSubspaceDependencies(targetSubspace); + if (await scanForDuplicatedDependenciesPrompt()) { + removeDuplicatedDependencies(targetSubspace); + subspaceDependencies = getSubspaceDependencies(targetSubspace); + } + + if (await scanForSubsetDependencyVersionsPrompt()) { + await removeSubsetDependencyVersions(targetSubspace, subspaceDependencies); + subspaceDependencies = getSubspaceDependencies(targetSubspace); + } + + if (await scanForUnusedDependencyVersionsPrompt()) { + removeUnusedAlternativeVersions(targetSubspace, subspaceDependencies); } + + Console.warn( + `Please run "rush update --subspace ${targetSubspace}" to update the subspace shrinkwrap file.` + ); }; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts index 2d92909..a4ba899 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts @@ -179,11 +179,17 @@ export const syncProjectMismatchedDependencies = async (projectName: string): Pr break; case 'fix': do { - const selectedDependency: string = await chooseDependencyPrompt(mismatchedDependencies); + const selectedDependency: string = await chooseDependencyPrompt( + mismatchedDependencies, + ` (${Colorize.bold(`${mismatchedDependencies.length}`)} mismatched dependencies)` + ); if (await syncDependencyVersion(selectedDependency, projectName)) { mismatchedDependencies = fetchProjectMismatches(projectName); } - } while (mismatchedDependencies.length > 0 && (await confirmNextDependencyPrompt(projectName))); + } while ( + mismatchedDependencies.length > 0 && + (await confirmNextDependencyPrompt(` (Current project: ${Colorize.bold(projectName)})`)) + ); break; case 'skip': diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/command.ts b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/command.ts index 4c1f6c5..ee43e74 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/command.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/command.ts @@ -9,6 +9,7 @@ export const chooseCommandPrompt = async (): Promise => { choices: [ { name: 'Move a project to a new subspace', value: 'move' }, { name: 'Scan & fix version mismatches', value: 'sync' }, + { name: 'Clean common subspace versions', value: 'clean' }, { name: 'Exit application', value: 'exit' } ] } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/dependency.ts b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/dependency.ts index 98703c0..457283e 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/dependency.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/dependency.ts @@ -2,11 +2,11 @@ import { Colorize } from '@rushstack/terminal'; import inquirer from 'inquirer'; import { sortVersions } from '../utilities/dependency'; -export const confirmNextDependencyPrompt = async (projectName: string): Promise => { +export const confirmNextDependencyPrompt = async (suffix?: string): Promise => { const { confirmNext } = await inquirer.prompt([ { - message: `Do you want to fix another dependency?`, - suffix: ` (Current project: ${Colorize.bold(projectName)})`, + message: `Do you want to choose another dependency?`, + suffix, type: 'confirm', name: 'confirmNext', default: true @@ -79,13 +79,13 @@ export const enterVersionPrompt = async (dependencyName: string): Promise => { +export const chooseDependencyPrompt = async (dependencies: string[], suffix?: string): Promise => { const { dependencyInput } = await inquirer.prompt([ { type: 'list', name: 'dependencyInput', - message: `Please enter the dependency you wish to fix the mismatch.`, - suffix: ` (${Colorize.bold(`${dependencies.length}`)} mismatched dependencies)`, + message: `Please select the dependency name (Type to filter).`, + suffix, choices: dependencies.sort().map((name) => ({ name, value: name })) } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts index f590844..27819b2 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts @@ -56,3 +56,50 @@ export const chooseCreateOrSelectSubspacePrompt = async (subspaces: string[]): P return subspaceSelection; }; + +export const scanForUnusedDependencyVersionsPrompt = async (): Promise => { + const { removeUnused } = await inquirer.prompt([ + { + message: 'Do you want to remove unused alternative versions from the subspace?', + name: 'removeUnused', + type: 'confirm' + } + ]); + + return removeUnused; +}; + +export const scanForDuplicatedDependenciesPrompt = async (): Promise => { + const { scanForDuplicated } = await inquirer.prompt([ + { + message: 'Do you want to scan for duplicated dependencies in the subspace?', + name: 'scanForDuplicated', + type: 'confirm' + } + ]); + + return scanForDuplicated; +}; + +export const scanForSubsetDependencyVersionsPrompt = async (): Promise => { + const { scanForSubset } = await inquirer.prompt([ + { + message: 'Do you want to scan for subset dependency versions in the subspace?', + name: 'scanForSubset', + type: 'confirm' + } + ]); + return scanForSubset; +}; + +export const scanForAllDependenciesPrompt = async (): Promise => { + const { executeForAll } = await inquirer.prompt([ + { + message: `Do you want to scan for all dependencies?`, + type: 'confirm', + name: 'executeForAll' + } + ]); + + return executeForAll; +}; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts index 42d7bc2..886cafa 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts @@ -98,3 +98,29 @@ export const getProjectMismatchedDependencies = (projectName: string): string[] return Array.from(projectMismatches.keys()); }; + +export const updateProjectDependency = ( + projectName: string, + dependencyName: string, + newVersion: string, + rootPath: string = getRootPath() +): boolean => { + const project: IRushConfigurationProjectJson | undefined = queryProject(projectName, rootPath); + if (!project) { + return false; + } + + const projectPackageFilePath: string = getProjectPackageFilePath(project.projectFolder, rootPath); + const projectPackageJson: IPackageJson = loadProjectPackageJson(project.projectFolder, rootPath); + + if (projectPackageJson.dependencies![dependencyName]) { + projectPackageJson.dependencies![dependencyName] = newVersion; + } + + if (projectPackageJson.devDependencies![dependencyName]) { + projectPackageJson.devDependencies![dependencyName] = newVersion; + } + + JsonFile.save(projectPackageJson, projectPackageFilePath); + return true; +}; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts index 860f965..39bb7b0 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts @@ -15,7 +15,6 @@ import { VersionMismatchFinder } from '@rushstack/rush-sdk/lib/logic/versionMism import { VersionMismatchFinderEntity } from '@rushstack/rush-sdk/lib/logic/versionMismatch/VersionMismatchFinderEntity'; import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; import { getProjectDependencies } from './project'; -import { sortVersions, subsetVersion } from './dependency'; export const queryProjectsFromSubspace = ( targetSubspaceName: string, @@ -160,60 +159,3 @@ export const getSubspaceDependencies = ( return subspaceDependencies; }; - -const reduceSubspaceDependencyVersions = (versions: string[]): string[] => { - const validVersions: string[] = sortVersions(versions); - - let targetIndex: number = 0; - while (targetIndex < validVersions.length) { - const targetVersion: string = validVersions[targetIndex]; - const toCompareVersions: string[] = validVersions.slice(targetIndex + 1); - - const toDeleteIndex: number = toCompareVersions.findIndex((toCompareVersion) => - subsetVersion(toCompareVersion, targetVersion) - ); - - if (toDeleteIndex > -1) { - validVersions.splice(targetIndex + 1 + toDeleteIndex, 1); - } else { - targetIndex += 1; - } - } - - return validVersions; -}; - -export const cleanSubspaceCommonVersions = ( - subspaceName: string, - rootPath: string = getRootPath() -): boolean => { - let hasChanged: boolean = false; - const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName, rootPath); - const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = loadRushSubspaceCommonVersions( - subspaceName, - rootPath - ); - - subspaceCommonVersionsJson.allowedAlternativeVersions = - subspaceCommonVersionsJson.allowedAlternativeVersions || {}; - for (const [dependency, versions] of Object.entries( - subspaceCommonVersionsJson.allowedAlternativeVersions - )) { - // Remove duplicates & unnecessary versions - const validVersions: string[] = reduceSubspaceDependencyVersions(versions); - if (validVersions.length === 0) { - delete subspaceCommonVersionsJson.allowedAlternativeVersions[dependency]; - } else { - subspaceCommonVersionsJson.allowedAlternativeVersions[dependency] = validVersions; - } - - hasChanged = hasChanged || validVersions.length !== versions.length; - } - - if (hasChanged) { - JsonFile.save(subspaceCommonVersionsJson, subspaceCommonVersionsPath); - return true; - } - - return false; -}; From 92df3f82277d38081335530f308db56714a3add7 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:07:44 +0800 Subject: [PATCH 03/11] feat: support clean subspace (II) --- .../src/cleanSubspace.ts | 31 +++++++++---------- .../rush-migrate-subspace-plugin/src/cli.ts | 8 +++-- .../src/prompts/subspace.ts | 10 +++--- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts index 91a702d..8e49377 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts @@ -2,7 +2,7 @@ import { chooseSubspacePrompt, scanForUnusedDependencyVersionsPrompt, scanForDuplicatedDependenciesPrompt, - scanForSubsetDependencyVersionsPrompt, + scanForSupersetDependencyVersionsPrompt, scanForAllDependenciesPrompt } from './prompts/subspace'; import Console from './providers/console'; @@ -27,7 +27,7 @@ import { } from './utilities/project'; import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; -const removeSubsetDependency = async ( +const removeSupersetDependency = async ( subspaceName: string, dependencyName: string, versionsMap: Map, @@ -47,14 +47,13 @@ const removeSubsetDependency = async ( const newVersion: string = validVersions[targetIndex]; const toCompareVersions: string[] = validVersions.slice(targetIndex + 1); - const toDeleteIndex: number = toCompareVersions.findIndex((toCompareVersion) => + const foundSubsetIndex: number = toCompareVersions.findIndex((toCompareVersion) => subsetVersion(toCompareVersion, newVersion) ); - if (toDeleteIndex > -1) { - // Delete subset version - - const [deletedVersion] = validVersions.splice(targetIndex + 1 + toDeleteIndex, 1); + if (foundSubsetIndex > -1) { + // Delete superset version + const [deletedVersion] = validVersions.splice(targetIndex, 1); versionsMap.get(deletedVersion)?.forEach((projectName) => { if (updateProjectDependency(projectName, dependencyName, newVersion, rootPath)) { Console.debug( @@ -180,7 +179,7 @@ const removeUnusedAlternativeVersions = ( } }; -const removeSubsetDependencyVersions = async ( +const removeSupersetDependencyVersions = async ( subspaceName: string, subspaceDependencies: Map> ): Promise => { @@ -196,15 +195,15 @@ const removeSubsetDependencyVersions = async ( } if (await scanForAllDependenciesPrompt()) { - Console.log(`Removing subset versions for subspace ${Colorize.bold(subspaceName)}...`); + Console.log(`Removing superset versions for subspace ${Colorize.bold(subspaceName)}...`); await Promise.all( Array.from(subspaceDependencies.entries()).map(([dependency, versionsMap]) => - removeSubsetDependency(subspaceName, dependency, versionsMap) + removeSupersetDependency(subspaceName, dependency, versionsMap) ) ).then((countPerDependency) => { const count: number = countPerDependency.reduce((a, b) => a + b, 0); if (count > 0) { - Console.success(`Removed ${Colorize.bold(`${count}`)} subset alternative versions!`); + Console.success(`Removed ${Colorize.bold(`${count}`)} superset alternative versions!`); } else { Console.success(`No alternative versions have been removed!`); } @@ -216,8 +215,8 @@ const removeSubsetDependencyVersions = async ( do { const selectedDependency: string = await chooseDependencyPrompt(multipleVersionDependencies); - Console.log(`Removing subset versions for dependency ${Colorize.bold(selectedDependency)}...`); - const count: number = await removeSubsetDependency( + Console.log(`Removing superset versions for dependency ${Colorize.bold(selectedDependency)}...`); + const count: number = await removeSupersetDependency( subspaceName, selectedDependency, subspaceDependencies.get(selectedDependency) as Map @@ -225,7 +224,7 @@ const removeSubsetDependencyVersions = async ( if (count > 0) { Console.success( - `Removed ${Colorize.bold(`${count}`)} subset alternative versions for dependency ${Colorize.bold( + `Removed ${Colorize.bold(`${count}`)} superset alternative versions for dependency ${Colorize.bold( selectedDependency )}!` ); @@ -264,8 +263,8 @@ export const cleanSubspace = async (): Promise => { subspaceDependencies = getSubspaceDependencies(targetSubspace); } - if (await scanForSubsetDependencyVersionsPrompt()) { - await removeSubsetDependencyVersions(targetSubspace, subspaceDependencies); + if (await scanForSupersetDependencyVersionsPrompt()) { + await removeSupersetDependencyVersions(targetSubspace, subspaceDependencies); subspaceDependencies = getSubspaceDependencies(targetSubspace); } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts index 7c3574f..e3fc559 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts @@ -5,6 +5,7 @@ import { syncVersions } from './syncVersions'; import { migrateProject } from './migrateProject'; import Console from './providers/console'; import { interactMenu } from './interactMenu'; +import { cleanSubspace } from './cleanSubspace'; inquirer.registerPrompt('search-list', inquirerSearchList); @@ -13,9 +14,10 @@ const program: Command = new Command(); program .option('--sync', 'to sync the versions in a subspace') .option('--move', 'to move projects to a new subspace') + .option('--clean', 'to reduce subspace alternative versions') .option('--debug', 'to provide debug logs') - .description('Example: rush migrate-subspace [--move] [--sync] [--debug]') - .action(async ({ sync, debug, move }) => { + .description('Example: rush migrate-subspace [--move] [--sync] [--debug] [--clean]') + .action(async ({ sync, debug, move, clean }) => { Console.enableDebug(debug); Console.title('🚀 Welcome to the Rush Migrate Subspace Plugin!'); Console.newLine(); @@ -24,6 +26,8 @@ program await syncVersions(); } else if (move) { await migrateProject(); + } else if (clean) { + await cleanSubspace(); } else { await interactMenu(); } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts index 27819b2..3bc4ee1 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts @@ -81,15 +81,15 @@ export const scanForDuplicatedDependenciesPrompt = async (): Promise => return scanForDuplicated; }; -export const scanForSubsetDependencyVersionsPrompt = async (): Promise => { - const { scanForSubset } = await inquirer.prompt([ +export const scanForSupersetDependencyVersionsPrompt = async (): Promise => { + const { scanForSuperset } = await inquirer.prompt([ { - message: 'Do you want to scan for subset dependency versions in the subspace?', - name: 'scanForSubset', + message: 'Do you want to scan for superset dependency versions in the subspace?', + name: 'scanForSuperset', type: 'confirm' } ]); - return scanForSubset; + return scanForSuperset; }; export const scanForAllDependenciesPrompt = async (): Promise => { From e4afdb336efad153a6039e8e8b7c4b3a7c05cb55 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:10:37 +0800 Subject: [PATCH 04/11] feat: support clean subspace (III) --- .../src/cleanSubspace.ts | 15 +++++++++------ .../src/constants/versions.ts | 4 ++++ .../src/utilities/dependency.ts | 9 ++++----- 3 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 rush-plugins/rush-migrate-subspace-plugin/src/constants/versions.ts diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts index 8e49377..830fc48 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts @@ -19,13 +19,14 @@ import { getRushSubspacesConfigurationJsonPath, querySubspaces } from './utiliti import { RushConstants } from '@rushstack/rush-sdk'; import { chooseDependencyPrompt, confirmNextDependencyPrompt } from './prompts/dependency'; import { IPackageJson, JsonFile } from '@rushstack/node-core-library'; -import { sortVersions, subsetVersion } from './utilities/dependency'; +import { rSortVersions, subsetVersion } from './utilities/dependency'; import { getProjectPackageFilePath, loadProjectPackageJson, updateProjectDependency } from './utilities/project'; import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; +import { RESERVED_VERSIONS } from './constants/versions'; const removeSupersetDependency = async ( subspaceName: string, @@ -40,20 +41,22 @@ const removeSupersetDependency = async ( rootPath ); - const validVersions: string[] = sortVersions(versions); + const validVersions: string[] = rSortVersions(versions).filter( + (version) => !RESERVED_VERSIONS.includes(version) + ); let targetIndex: number = 0; while (targetIndex < validVersions.length) { const newVersion: string = validVersions[targetIndex]; const toCompareVersions: string[] = validVersions.slice(targetIndex + 1); - const foundSubsetIndex: number = toCompareVersions.findIndex((toCompareVersion) => - subsetVersion(toCompareVersion, newVersion) + const toDeleteIndex: number = toCompareVersions.findIndex( + (toCompareVersion) => newVersion !== toCompareVersion && subsetVersion(newVersion, toCompareVersion) ); - if (foundSubsetIndex > -1) { + if (toDeleteIndex > -1) { // Delete superset version - const [deletedVersion] = validVersions.splice(targetIndex, 1); + const [deletedVersion] = validVersions.splice(targetIndex + toDeleteIndex + 1, 1); versionsMap.get(deletedVersion)?.forEach((projectName) => { if (updateProjectDependency(projectName, dependencyName, newVersion, rootPath)) { Console.debug( diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/constants/versions.ts b/rush-plugins/rush-migrate-subspace-plugin/src/constants/versions.ts new file mode 100644 index 0000000..dee0bb6 --- /dev/null +++ b/rush-plugins/rush-migrate-subspace-plugin/src/constants/versions.ts @@ -0,0 +1,4 @@ +export const LATEST_VERSION: string = 'latest'; +export const LOCAL_VERSION: string = 'workspace:*'; + +export const RESERVED_VERSIONS: string[] = [LATEST_VERSION, LOCAL_VERSION]; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts index b56793c..46ff979 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts @@ -1,9 +1,8 @@ import { compare, eq, intersects, minVersion, satisfies, subset, valid, validRange } from 'semver'; +import { RESERVED_VERSIONS } from '../constants/versions'; export const subsetVersion = (version1: string, version2: string): boolean => { - if (version1 === version2) { - return true; - } else if (['latest', 'workspace:*'].includes(version2)) { + if (RESERVED_VERSIONS.includes(version2)) { return true; } else if ((!valid(version1) && !validRange(version1)) || (!valid(version2) && !validRange(version2))) { return false; @@ -26,10 +25,10 @@ export const sortVersions = (versions: string[]): string[] => { if (v1 === v2) { // e.g. 1.0.0 , 1.0.0 return 0; - } else if (['latest', 'workspace:*'].includes(v1)) { + } else if (RESERVED_VERSIONS.includes(v1)) { // e.g. workspace:*, 1.0.0 return 1; - } else if (['latest', 'workspace:*'].includes(v2)) { + } else if (RESERVED_VERSIONS.includes(v2)) { // e.g. 1.0.0, workspace:* return -1; } else if (!valid(v1) && !validRange(v1)) { From aeaa91460ccfa351f2aa844be86967233706be56 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:18:11 +0800 Subject: [PATCH 05/11] feat: support clean subspace (IV) --- .../src/cleanSubspace.ts | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts index 830fc48..b6ddec1 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts @@ -41,42 +41,39 @@ const removeSupersetDependency = async ( rootPath ); - const validVersions: string[] = rSortVersions(versions).filter( - (version) => !RESERVED_VERSIONS.includes(version) - ); - - let targetIndex: number = 0; - while (targetIndex < validVersions.length) { - const newVersion: string = validVersions[targetIndex]; - const toCompareVersions: string[] = validVersions.slice(targetIndex + 1); - - const toDeleteIndex: number = toCompareVersions.findIndex( - (toCompareVersion) => newVersion !== toCompareVersion && subsetVersion(newVersion, toCompareVersion) - ); - - if (toDeleteIndex > -1) { - // Delete superset version - const [deletedVersion] = validVersions.splice(targetIndex + toDeleteIndex + 1, 1); - versionsMap.get(deletedVersion)?.forEach((projectName) => { - if (updateProjectDependency(projectName, dependencyName, newVersion, rootPath)) { - Console.debug( - `Updated project ${Colorize.bold(projectName)} for dependency ${Colorize.bold( - dependencyName - )} ${Colorize.bold(deletedVersion)} => ${Colorize.bold(newVersion)}!` - ); - } - }); + const newValidVersions: string[] = rSortVersions(versions).reduce((prevVersions, currVersion) => { + const newVersions: string[] = [...prevVersions]; + if (newVersions.includes(currVersion)) { + // do nothing. + } else if (RESERVED_VERSIONS.includes(currVersion)) { + newVersions.push(currVersion); } else { - // Go to next version - targetIndex += 1; + // Find and replace versions with subset versions + const newSubsetVersion: string | undefined = newVersions.find((newVersion) => + subsetVersion(newVersion, currVersion) + ); + if (newSubsetVersion) { + // Update projects with new subset version + versionsMap.get(currVersion)?.forEach((projectName) => { + if (updateProjectDependency(projectName, dependencyName, newSubsetVersion, rootPath)) { + Console.debug( + `Updated project ${Colorize.bold(projectName)} for dependency ${Colorize.bold( + dependencyName + )} ${Colorize.bold(currVersion)} => ${Colorize.bold(newSubsetVersion)}!` + ); + } + }); + } } - } - const removedAlternativeVersionsCount: number = versions.length - validVersions.length; + return newVersions; + }, []); + + const removedAlternativeVersionsCount: number = versions.length - newValidVersions.length; if (removedAlternativeVersionsCount > 0) { // Update subspace common versions - if (validVersions.length > 0) { - subspaceCommonVersionsJson.allowedAlternativeVersions![dependencyName] = validVersions; + if (newValidVersions.length > 0) { + subspaceCommonVersionsJson.allowedAlternativeVersions![dependencyName] = newValidVersions; } else { delete subspaceCommonVersionsJson.allowedAlternativeVersions![dependencyName]; } From d06f2ccec821f249920e6f537c830d1253270488 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:14:14 +0800 Subject: [PATCH 06/11] fix: remove superset --- .../src/cleanSubspace.ts | 36 +++++++++---------- .../rush-migrate-subspace-plugin/src/cli.ts | 6 +++- .../src/prompts/subspace.ts | 4 +-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts index b6ddec1..3882ecc 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts @@ -44,26 +44,26 @@ const removeSupersetDependency = async ( const newValidVersions: string[] = rSortVersions(versions).reduce((prevVersions, currVersion) => { const newVersions: string[] = [...prevVersions]; if (newVersions.includes(currVersion)) { - // do nothing. - } else if (RESERVED_VERSIONS.includes(currVersion)) { + return newVersions; + } + + const newSubsetVersion: string | undefined = newVersions.find((newVersion) => + subsetVersion(newVersion, currVersion) + ); + + if (RESERVED_VERSIONS.includes(currVersion) || !newSubsetVersion) { newVersions.push(currVersion); } else { - // Find and replace versions with subset versions - const newSubsetVersion: string | undefined = newVersions.find((newVersion) => - subsetVersion(newVersion, currVersion) - ); - if (newSubsetVersion) { - // Update projects with new subset version - versionsMap.get(currVersion)?.forEach((projectName) => { - if (updateProjectDependency(projectName, dependencyName, newSubsetVersion, rootPath)) { - Console.debug( - `Updated project ${Colorize.bold(projectName)} for dependency ${Colorize.bold( - dependencyName - )} ${Colorize.bold(currVersion)} => ${Colorize.bold(newSubsetVersion)}!` - ); - } - }); - } + // Update projects with new subset version + versionsMap.get(currVersion)?.forEach((projectName) => { + if (updateProjectDependency(projectName, dependencyName, newSubsetVersion, rootPath)) { + Console.debug( + `Updated project ${Colorize.bold(projectName)} for dependency ${Colorize.bold( + dependencyName + )} ${Colorize.bold(currVersion)} => ${Colorize.bold(newSubsetVersion)}!` + ); + } + }); } return newVersions; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts index e3fc559..5e5a687 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts @@ -1,5 +1,7 @@ import { Command } from 'commander'; import inquirer from 'inquirer'; +import path from 'path'; +import { IPackageJson, JsonFile } from '@rushstack/node-core-library'; import inquirerSearchList from 'inquirer-search-list'; import { syncVersions } from './syncVersions'; import { migrateProject } from './migrateProject'; @@ -18,8 +20,10 @@ program .option('--debug', 'to provide debug logs') .description('Example: rush migrate-subspace [--move] [--sync] [--debug] [--clean]') .action(async ({ sync, debug, move, clean }) => { + const packageJson: IPackageJson = JsonFile.load(`${path.resolve(__dirname, '../package.json')}`); + Console.enableDebug(debug); - Console.title('🚀 Welcome to the Rush Migrate Subspace Plugin!'); + Console.title(`🚀 Welcome to the Rush Migrate Subspace Plugin! Version: ${packageJson.version}`); Console.newLine(); if (sync) { diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts index 3bc4ee1..6b34e43 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts @@ -72,7 +72,7 @@ export const scanForUnusedDependencyVersionsPrompt = async (): Promise export const scanForDuplicatedDependenciesPrompt = async (): Promise => { const { scanForDuplicated } = await inquirer.prompt([ { - message: 'Do you want to scan for duplicated dependencies in the subspace?', + message: 'Do you want to remove duplicated dependencies in the subspace?', name: 'scanForDuplicated', type: 'confirm' } @@ -84,7 +84,7 @@ export const scanForDuplicatedDependenciesPrompt = async (): Promise => export const scanForSupersetDependencyVersionsPrompt = async (): Promise => { const { scanForSuperset } = await inquirer.prompt([ { - message: 'Do you want to scan for superset dependency versions in the subspace?', + message: 'Do you want to remove superset dependency versions in the subspace (EXPERIMENTAL)?', name: 'scanForSuperset', type: 'confirm' } From 77cbc443b0c29db247191d1c664ba4f8e69b1167 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:18:27 +0800 Subject: [PATCH 07/11] feat: add changelog --- ...ogomes-support-clean-subspace_2024-12-20-04-18.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/rush-migrate-subspace-plugin/pedrogomes-support-clean-subspace_2024-12-20-04-18.json diff --git a/common/changes/rush-migrate-subspace-plugin/pedrogomes-support-clean-subspace_2024-12-20-04-18.json b/common/changes/rush-migrate-subspace-plugin/pedrogomes-support-clean-subspace_2024-12-20-04-18.json new file mode 100644 index 0000000..6628831 --- /dev/null +++ b/common/changes/rush-migrate-subspace-plugin/pedrogomes-support-clean-subspace_2024-12-20-04-18.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "rush-migrate-subspace-plugin", + "comment": "Provides a parameter to automatically remove similar dependency versions, including duplicates and unused", + "type": "minor" + } + ], + "packageName": "rush-migrate-subspace-plugin" +} \ No newline at end of file From 219e04af2e6dba306fd97c541782508fa7d4a0fb Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:29:58 +0800 Subject: [PATCH 08/11] Update rush-plugins/rush-migrate-subspace-plugin/src/cli.ts Co-authored-by: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> --- rush-plugins/rush-migrate-subspace-plugin/src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts index 5e5a687..4824f68 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts @@ -23,7 +23,7 @@ program const packageJson: IPackageJson = JsonFile.load(`${path.resolve(__dirname, '../package.json')}`); Console.enableDebug(debug); - Console.title(`🚀 Welcome to the Rush Migrate Subspace Plugin! Version: ${packageJson.version}`); + Console.title(`🚀 Rush Migrate Subspace Plugin - version ${packageJson.version}`); Console.newLine(); if (sync) { From 2ce224272e9f3efdf35dc275ff0bff0bf5b31c6c Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:33:42 +0800 Subject: [PATCH 09/11] Update rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts Co-authored-by: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> --- .../rush-migrate-subspace-plugin/src/prompts/subspace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts index 6b34e43..bfd34cf 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/prompts/subspace.ts @@ -84,7 +84,7 @@ export const scanForDuplicatedDependenciesPrompt = async (): Promise => export const scanForSupersetDependencyVersionsPrompt = async (): Promise => { const { scanForSuperset } = await inquirer.prompt([ { - message: 'Do you want to remove superset dependency versions in the subspace (EXPERIMENTAL)?', + message: '(EXPERIMENTAL) Do you want to remove superset dependency versions from the subspace?', name: 'scanForSuperset', type: 'confirm' } From 38d22be9d985dbcb0b56d66dd2023d990f46d920 Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:35:01 +0800 Subject: [PATCH 10/11] chore: improve mr after review --- .../src/cleanSubspace.ts | 132 ++++++++++-------- .../src/functions/addProjectToSubspace.ts | 33 +++-- .../src/functions/createSubspace.ts | 12 +- .../src/functions/generateReport.ts | 7 +- .../src/functions/initSubspaces.ts | 13 +- .../src/functions/syncProjectDependencies.ts | 57 +++++--- .../src/functions/updateEdenProject.ts | 10 +- .../src/functions/updateProjectDependency.ts | 7 +- .../src/functions/updateRushConfiguration.ts | 15 +- .../src/functions/updateSubspace.ts | 36 +++-- .../src/migrateProject.ts | 34 +++-- .../src/syncVersions.ts | 19 +-- .../src/utilities/dependency.ts | 6 +- .../src/utilities/project.ts | 37 ++--- .../src/utilities/repository.ts | 18 +-- .../src/utilities/subspace.ts | 38 ++--- 16 files changed, 253 insertions(+), 221 deletions(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts index 3882ecc..6f8af6b 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts @@ -19,7 +19,7 @@ import { getRushSubspacesConfigurationJsonPath, querySubspaces } from './utiliti import { RushConstants } from '@rushstack/rush-sdk'; import { chooseDependencyPrompt, confirmNextDependencyPrompt } from './prompts/dependency'; import { IPackageJson, JsonFile } from '@rushstack/node-core-library'; -import { rSortVersions, subsetVersion } from './utilities/dependency'; +import { reverseSortVersions, subsetVersion } from './utilities/dependency'; import { getProjectPackageFilePath, loadProjectPackageJson, @@ -28,12 +28,12 @@ import { import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; import { RESERVED_VERSIONS } from './constants/versions'; -const removeSupersetDependency = async ( +const removeSupersetDependency = ( subspaceName: string, dependencyName: string, versionsMap: Map, - rootPath: string = getRootPath() -): Promise => { + rootPath: string +): number => { const versions: string[] = Array.from(versionsMap.keys()); const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName, rootPath); const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = loadRushSubspaceCommonVersions( @@ -41,33 +41,36 @@ const removeSupersetDependency = async ( rootPath ); - const newValidVersions: string[] = rSortVersions(versions).reduce((prevVersions, currVersion) => { - const newVersions: string[] = [...prevVersions]; - if (newVersions.includes(currVersion)) { - return newVersions; - } + const newValidVersions: string[] = reverseSortVersions(versions).reduce( + (prevVersions, currVersion) => { + const newVersions: string[] = [...prevVersions]; + if (newVersions.includes(currVersion)) { + return newVersions; + } - const newSubsetVersion: string | undefined = newVersions.find((newVersion) => - subsetVersion(newVersion, currVersion) - ); + const newSubsetVersion: string | undefined = newVersions.find((newVersion) => + subsetVersion(newVersion, currVersion) + ); - if (RESERVED_VERSIONS.includes(currVersion) || !newSubsetVersion) { - newVersions.push(currVersion); - } else { - // Update projects with new subset version - versionsMap.get(currVersion)?.forEach((projectName) => { - if (updateProjectDependency(projectName, dependencyName, newSubsetVersion, rootPath)) { - Console.debug( - `Updated project ${Colorize.bold(projectName)} for dependency ${Colorize.bold( - dependencyName - )} ${Colorize.bold(currVersion)} => ${Colorize.bold(newSubsetVersion)}!` - ); + if (RESERVED_VERSIONS.includes(currVersion) || !newSubsetVersion) { + newVersions.push(currVersion); + } else { + // Update projects with new subset version + for (const projectName of versionsMap.get(currVersion) || []) { + if (updateProjectDependency(projectName, dependencyName, newSubsetVersion, rootPath)) { + Console.debug( + `Updated project ${Colorize.bold(projectName)} for dependency ${Colorize.bold( + dependencyName + )} ${Colorize.bold(currVersion)} => ${Colorize.bold(newSubsetVersion)}!` + ); + } } - }); - } + } - return newVersions; - }, []); + return newVersions; + }, + [] + ); const removedAlternativeVersionsCount: number = versions.length - newValidVersions.length; if (removedAlternativeVersionsCount > 0) { @@ -84,19 +87,20 @@ const removeSupersetDependency = async ( return removedAlternativeVersionsCount; }; -const removeDuplicatedDependencies = (subspaceName: string, rootPath: string = getRootPath()): void => { +const removeDuplicatedDependencies = (subspaceName: string, rootPath: string): void => { Console.log(`Removing duplicated dependencies for subspace ${Colorize.bold(subspaceName)}...`); const projects: IRushConfigurationProjectJson[] = queryProjectsFromSubspace(subspaceName, rootPath); let countRemoved: number = 0; - projects.forEach((project) => { + + for (const project of projects) { const projectPackageFilePath: string = getProjectPackageFilePath(project.projectFolder, rootPath); const projectPackageJson: IPackageJson = loadProjectPackageJson(project.projectFolder, rootPath); const dependencies: string[] = Object.keys(projectPackageJson.dependencies || {}); const devDependencies: string[] = Object.keys(projectPackageJson.devDependencies || {}); - devDependencies.forEach((devDependency) => { + for (const devDependency of devDependencies) { if (dependencies.includes(devDependency)) { countRemoved += 1; Console.debug( @@ -104,10 +108,10 @@ const removeDuplicatedDependencies = (subspaceName: string, rootPath: string = g ); delete projectPackageJson.devDependencies![devDependency]; } - }); + } JsonFile.save(projectPackageJson, projectPackageFilePath); - }); + } if (countRemoved > 0) { Console.success( @@ -122,13 +126,16 @@ const removeDuplicatedDependencies = (subspaceName: string, rootPath: string = g const removeUnusedAlternativeVersions = ( subspaceName: string, - subspaceDependencies: Map> + subspaceDependencies: Map>, + rootPath: string ): void => { Console.log(`Removing unused alternative versions for subspace ${Colorize.bold(subspaceName)}...`); - const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName); - const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = - loadRushSubspaceCommonVersions(subspaceName); + const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName, rootPath); + const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = loadRushSubspaceCommonVersions( + subspaceName, + rootPath + ); if (!subspaceCommonVersionsJson.allowedAlternativeVersions) { return; @@ -181,7 +188,8 @@ const removeUnusedAlternativeVersions = ( const removeSupersetDependencyVersions = async ( subspaceName: string, - subspaceDependencies: Map> + subspaceDependencies: Map>, + rootPath: string ): Promise => { const multipleVersionDependencies: string[] = Array.from(subspaceDependencies.keys()).filter( (dependency) => subspaceDependencies.get(dependency)!.size > 1 @@ -196,18 +204,16 @@ const removeSupersetDependencyVersions = async ( if (await scanForAllDependenciesPrompt()) { Console.log(`Removing superset versions for subspace ${Colorize.bold(subspaceName)}...`); - await Promise.all( - Array.from(subspaceDependencies.entries()).map(([dependency, versionsMap]) => - removeSupersetDependency(subspaceName, dependency, versionsMap) - ) - ).then((countPerDependency) => { - const count: number = countPerDependency.reduce((a, b) => a + b, 0); - if (count > 0) { - Console.success(`Removed ${Colorize.bold(`${count}`)} superset alternative versions!`); - } else { - Console.success(`No alternative versions have been removed!`); - } - }); + const countPerDependency: number[] = Array.from(subspaceDependencies.entries()).map( + ([dependency, versionsMap]) => removeSupersetDependency(subspaceName, dependency, versionsMap, rootPath) + ); + + const count: number = countPerDependency.reduce((a, b) => a + b, 0); + if (count > 0) { + Console.success(`Removed ${Colorize.bold(`${count}`)} superset alternative versions!`); + } else { + Console.success(`No alternative versions have been removed!`); + } return; } @@ -219,7 +225,8 @@ const removeSupersetDependencyVersions = async ( const count: number = await removeSupersetDependency( subspaceName, selectedDependency, - subspaceDependencies.get(selectedDependency) as Map + subspaceDependencies.get(selectedDependency) as Map, + rootPath ); if (count > 0) { @@ -239,16 +246,16 @@ const removeSupersetDependencyVersions = async ( } while (multipleVersionDependencies.length > 0 && (await confirmNextDependencyPrompt())); }; -export const cleanSubspace = async (): Promise => { +export const cleanSubspace = async (targetMonorepoPath: string = getRootPath()): Promise => { Console.debug('Executing clean subspace command...'); - const targetSubspaces: string[] = querySubspaces(); - if (!isSubspaceSupported()) { + const targetSubspaces: string[] = querySubspaces(targetMonorepoPath); + if (!isSubspaceSupported(targetMonorepoPath)) { Console.error( `The monorepo ${Colorize.bold( - getRootPath() + targetMonorepoPath )} doesn't support subspaces! Make sure you have ${Colorize.bold( - getRushSubspacesConfigurationJsonPath() + getRushSubspacesConfigurationJsonPath(targetMonorepoPath) )} with the ${Colorize.bold(RushConstants.defaultSubspaceName)} subspace. Exiting...` ); return; @@ -257,19 +264,22 @@ export const cleanSubspace = async (): Promise => { const targetSubspace: string = await chooseSubspacePrompt(targetSubspaces); Console.title(`🛁 Cleaning subspace ${Colorize.underline(targetSubspace)} alternative versions...`); - let subspaceDependencies: Map> = getSubspaceDependencies(targetSubspace); + let subspaceDependencies: Map> = getSubspaceDependencies( + targetSubspace, + targetMonorepoPath + ); if (await scanForDuplicatedDependenciesPrompt()) { - removeDuplicatedDependencies(targetSubspace); - subspaceDependencies = getSubspaceDependencies(targetSubspace); + removeDuplicatedDependencies(targetSubspace, targetMonorepoPath); + subspaceDependencies = getSubspaceDependencies(targetSubspace, targetMonorepoPath); } if (await scanForSupersetDependencyVersionsPrompt()) { - await removeSupersetDependencyVersions(targetSubspace, subspaceDependencies); - subspaceDependencies = getSubspaceDependencies(targetSubspace); + await removeSupersetDependencyVersions(targetSubspace, subspaceDependencies, targetMonorepoPath); + subspaceDependencies = getSubspaceDependencies(targetSubspace, targetMonorepoPath); } if (await scanForUnusedDependencyVersionsPrompt()) { - removeUnusedAlternativeVersions(targetSubspace, subspaceDependencies); + removeUnusedAlternativeVersions(targetSubspace, subspaceDependencies, targetMonorepoPath); } Console.warn( diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/addProjectToSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/addProjectToSubspace.ts index f074e6c..d2594aa 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/addProjectToSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/addProjectToSubspace.ts @@ -5,7 +5,6 @@ import Console from '../providers/console'; import { Colorize } from '@rushstack/terminal'; import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; import { enterNewProjectLocationPrompt, moveProjectPrompt } from '../prompts/project'; -import { getRootPath } from '../utilities/path'; import { RushConstants } from '@rushstack/rush-sdk'; import { addProjectToRushConfiguration } from './updateRushConfiguration'; import { @@ -20,7 +19,7 @@ import path from 'path'; const refreshSubspace = (subspaceName: string, rootPath: string): void => { const subspacesConfig: ISubspacesConfigurationJson = loadRushSubspacesConfiguration(rootPath); const newSubspaces: string[] = [...subspacesConfig.subspaceNames]; - if (queryProjectsFromSubspace(subspaceName).length === 0) { + if (queryProjectsFromSubspace(subspaceName, rootPath).length === 0) { newSubspaces.splice(newSubspaces.indexOf(subspaceName), 1); } @@ -31,11 +30,10 @@ const refreshSubspace = (subspaceName: string, rootPath: string): void => { const moveProjectToSubspaceFolder = async ( sourceProjectFolderPath: string, - targetSubspace: string + targetSubspace: string, + rootPath: string ): Promise => { - const targetSubspaceFolderPath: string = `${getRootPath()}/${ - RushNameConstants.SubspacesFolderName - }/${targetSubspace}`; + const targetSubspaceFolderPath: string = `${rootPath}/${RushNameConstants.SubspacesFolderName}/${targetSubspace}`; const targetProjectFolderPath: string = await enterNewProjectLocationPrompt( sourceProjectFolderPath, @@ -71,7 +69,8 @@ const moveProjectToSubspaceFolder = async ( export const addProjectToSubspace = async ( sourceProject: IRushConfigurationProjectJson, targetSubspace: string, - sourceMonorepoPath: string + sourceMonorepoPath: string, + targetMonorepoPath: string ): Promise => { Console.debug( `Adding project ${Colorize.bold(sourceProject.packageName)} to subspace ${Colorize.bold( @@ -79,16 +78,24 @@ export const addProjectToSubspace = async ( )}...` ); - let targetProjectFolderPath: string | undefined = `${getRootPath()}/${sourceProject.projectFolder}`; - if (isExternalMonorepo(sourceMonorepoPath) || (await moveProjectPrompt())) { + let targetProjectFolderPath: string | undefined = `${targetMonorepoPath}/${sourceProject.projectFolder}`; + if (isExternalMonorepo(sourceMonorepoPath, targetMonorepoPath) || (await moveProjectPrompt())) { const sourceProjectFolderPath: string = `${sourceMonorepoPath}/${sourceProject.projectFolder}`; - targetProjectFolderPath = await moveProjectToSubspaceFolder(sourceProjectFolderPath, targetSubspace); + targetProjectFolderPath = await moveProjectToSubspaceFolder( + sourceProjectFolderPath, + targetSubspace, + targetMonorepoPath + ); if (!targetProjectFolderPath) { return; } - if (FileSystem.exists(`${getRootPath()}/${RushNameConstants.EdenMonorepoFileName}`)) { - await updateEdenProject(sourceProject, path.relative(sourceMonorepoPath, targetProjectFolderPath)); + if (FileSystem.exists(`${targetMonorepoPath}/${RushNameConstants.EdenMonorepoFileName}`)) { + await updateEdenProject( + sourceProject, + path.relative(sourceMonorepoPath, targetProjectFolderPath), + targetMonorepoPath + ); } } @@ -103,7 +110,7 @@ export const addProjectToSubspace = async ( FileSystem.deleteFolder(targetLegacySubspaceFolderPath); } - addProjectToRushConfiguration(sourceProject, targetSubspace, targetProjectFolderPath); + addProjectToRushConfiguration(sourceProject, targetSubspace, targetProjectFolderPath, targetMonorepoPath); if (sourceProject.subspaceName) { refreshSubspace(sourceProject.subspaceName, sourceMonorepoPath); } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/createSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/createSubspace.ts index 6913e61..2b90b97 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/createSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/createSubspace.ts @@ -8,9 +8,9 @@ import { import { ISubspacesConfigurationJson } from '@rushstack/rush-sdk/lib/api/SubspacesConfiguration'; import { getRushSubspaceConfigurationFolderPath } from '../utilities/subspace'; -export const createSubspace = async (subspaceName: string): Promise => { +export const createSubspace = async (subspaceName: string, rootPath: string): Promise => { Console.debug(`Creating subspace ${Colorize.bold(subspaceName)}...`); - const subspaceConfigFolder: string = getRushSubspaceConfigurationFolderPath(subspaceName); + const subspaceConfigFolder: string = getRushSubspaceConfigurationFolderPath(subspaceName, rootPath); FileSystem.ensureFolder(subspaceConfigFolder); const files: string[] = ['.npmrc', 'common-versions.json', 'repo-state.json']; @@ -23,17 +23,19 @@ export const createSubspace = async (subspaceName: string): Promise => { } } - const subspacesConfigJson: ISubspacesConfigurationJson = loadRushSubspacesConfiguration(); + const subspacesConfigJson: ISubspacesConfigurationJson = loadRushSubspacesConfiguration(rootPath); if (!subspacesConfigJson.subspaceNames.includes(subspaceName)) { Console.debug( - `Updating ${getRushSubspacesConfigurationJsonPath()} by adding ${Colorize.bold(subspaceName)}...` + `Updating ${getRushSubspacesConfigurationJsonPath(rootPath)} by adding ${Colorize.bold( + subspaceName + )}...` ); const newSubspacesConfigJson: ISubspacesConfigurationJson = { ...subspacesConfigJson, subspaceNames: [...subspacesConfigJson.subspaceNames, subspaceName] }; - JsonFile.save(newSubspacesConfigJson, getRushSubspacesConfigurationJsonPath(), { + JsonFile.save(newSubspacesConfigJson, getRushSubspacesConfigurationJsonPath(rootPath), { updateExistingFile: true }); } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/generateReport.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/generateReport.ts index 483b4d2..a5f194f 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/generateReport.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/generateReport.ts @@ -5,16 +5,15 @@ import { Colorize } from '@rushstack/terminal'; import { RushNameConstants } from '../constants/paths'; import { getProjectMismatches } from '../utilities/project'; import { VersionMismatchFinderEntity } from '@rushstack/rush-sdk/lib/logic/versionMismatch/VersionMismatchFinderEntity'; -import { getRootPath } from '../utilities/path'; import { sortVersions } from '../utilities/dependency'; -export const generateReport = async (projectName: string): Promise => { +export const generateReport = async (projectName: string, rootPath: string): Promise => { Console.debug(`Generating mismatches report for the project ${Colorize.bold(projectName)}...`); const projectMismatches: ReadonlyMap< string, ReadonlyMap - > = getProjectMismatches(projectName); + > = getProjectMismatches(projectName, rootPath); if (projectMismatches.size === 0) { Console.success(`No mismatches found for the project ${Colorize.bold(projectName)}.`); return; @@ -39,7 +38,7 @@ export const generateReport = async (projectName: string): Promise => { } } - const reportFilePath: string = `${getRootPath()}/${projectName}_${RushNameConstants.AnalysisFileName}`; + const reportFilePath: string = `${rootPath}/${projectName}_${RushNameConstants.AnalysisFileName}`; const jsonFilePath: string = await enterReportFileLocationPrompt(reportFilePath); JsonFile.save(output, jsonFilePath, { prettyFormatting: true }); Console.success(`Saved report file to ${Colorize.bold(jsonFilePath)}.`); diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/initSubspaces.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/initSubspaces.ts index 1bd67e6..d46c674 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/initSubspaces.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/initSubspaces.ts @@ -5,12 +5,11 @@ import { RushConstants } from '@rushstack/rush-sdk'; import { getRushSubspacesConfigurationJsonPath } from '../utilities/repository'; import { getRushSubspaceConfigurationFolderPath } from '../utilities/subspace'; import { Colorize } from '@rushstack/terminal'; -import { getRootPath } from '../utilities/path'; -export const initSubspaces = async (): Promise => { - Console.debug(`Starting subspaces feature on ${Colorize.bold(getRootPath())}...`); +export const initSubspaces = async (rootPath: string): Promise => { + Console.debug(`Starting subspaces feature on ${Colorize.bold(rootPath)}...`); - const subspacesConfigurationJsonPath: string = getRushSubspacesConfigurationJsonPath(); + const subspacesConfigurationJsonPath: string = getRushSubspacesConfigurationJsonPath(rootPath); if (!FileSystem.exists(subspacesConfigurationJsonPath)) { FileSystem.copyFile({ sourcePath: FileSystem.getRealPath(`${__dirname}/../templates/subspaces.json`), @@ -20,7 +19,9 @@ export const initSubspaces = async (): Promise => { Console.success(`${Colorize.bold(subspacesConfigurationJsonPath)} file created successfully!`); } - if (!FileSystem.exists(getRushSubspaceConfigurationFolderPath(RushConstants.defaultSubspaceName))) { - await createSubspace(RushConstants.defaultSubspaceName); + if ( + !FileSystem.exists(getRushSubspaceConfigurationFolderPath(RushConstants.defaultSubspaceName, rootPath)) + ) { + await createSubspace(RushConstants.defaultSubspaceName, rootPath); } }; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts index a4ba899..dd715eb 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/syncProjectDependencies.ts @@ -23,11 +23,14 @@ import { generateReport } from './generateReport'; const addVersionToCommonVersionConfiguration = ( subspaceName: string, dependencyName: string, - selectedVersion: string + selectedVersion: string, + rootPath: string ): void => { - const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName); - const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = - loadRushSubspaceCommonVersions(subspaceName); + const subspaceCommonVersionsPath: string = getRushSubspaceCommonVersionsFilePath(subspaceName, rootPath); + const subspaceCommonVersionsJson: RushSubspaceCommonVersionsJson = loadRushSubspaceCommonVersions( + subspaceName, + rootPath + ); Console.debug( `Adding ${Colorize.bold(selectedVersion)} to allowedAlternativeVersions of ${Colorize.bold( @@ -49,16 +52,19 @@ const addVersionToCommonVersionConfiguration = ( const syncDependencyVersion = async ( dependencyToUpdate: string, - projectToUpdate: string + projectToUpdate: string, + rootPath: string ): Promise => { const dependencyName: string = dependencyToUpdate.replace(' (cyclic)', ''); - const project: IRushConfigurationProjectJson | undefined = queryProject(projectToUpdate); + const project: IRushConfigurationProjectJson | undefined = queryProject(projectToUpdate, rootPath); if (!project || !project.subspaceName) { return false; } - const projectDependencies: IPackageJsonDependencyTable | undefined = - getProjectDependencies(projectToUpdate); + const projectDependencies: IPackageJsonDependencyTable | undefined = getProjectDependencies( + projectToUpdate, + rootPath + ); const currentVersion: string | undefined = projectDependencies?.[dependencyName]; if (!currentVersion) { Console.error( @@ -69,12 +75,16 @@ const syncDependencyVersion = async ( return false; } - const subspaceCommonVersionsJson: JsonObject = loadRushSubspaceCommonVersions(project.subspaceName); + const subspaceCommonVersionsJson: JsonObject = loadRushSubspaceCommonVersions( + project.subspaceName, + rootPath + ); const subspaceAlternativeVersions: string[] = subspaceCommonVersionsJson.allowedAlternativeVersions[dependencyName] || []; const subspaceDependencies: Map> = getSubspaceDependencies( - project.subspaceName + project.subspaceName, + rootPath ); const subspaceVersionsMap: Map = subspaceDependencies.get(dependencyName) as Map< @@ -118,22 +128,22 @@ const syncDependencyVersion = async ( return false; } else if (versionToSync === 'manual') { const newVersion: string = (await enterVersionPrompt(dependencyName)).trim(); - addVersionToCommonVersionConfiguration(project.subspaceName, dependencyName, newVersion); - await updateProjectDependency(projectToUpdate, dependencyName, newVersion); + addVersionToCommonVersionConfiguration(project.subspaceName, dependencyName, newVersion, rootPath); + await updateProjectDependency(projectToUpdate, dependencyName, newVersion, rootPath); } else if (versionToSync === 'alternative') { - addVersionToCommonVersionConfiguration(project.subspaceName, dependencyName, currentVersion); + addVersionToCommonVersionConfiguration(project.subspaceName, dependencyName, currentVersion, rootPath); } else { - await updateProjectDependency(projectToUpdate, dependencyName, versionToSync); + await updateProjectDependency(projectToUpdate, dependencyName, versionToSync, rootPath); } return true; }; -const fetchProjectMismatches = (projectName: string): string[] => { +const fetchProjectMismatches = (projectName: string, rootPath: string): string[] => { const projectMismatches: ReadonlyMap< string, ReadonlyMap - > = getProjectMismatches(projectName); + > = getProjectMismatches(projectName, rootPath); const mismatchedDependencies: string[] = Array.from(projectMismatches.keys()); if (mismatchedDependencies.length === 0) { @@ -157,16 +167,19 @@ const fetchProjectMismatches = (projectName: string): string[] => { return mismatchedDependencies; }; -export const syncProjectMismatchedDependencies = async (projectName: string): Promise => { +export const syncProjectMismatchedDependencies = async ( + projectName: string, + rootPath: string +): Promise => { Console.title(`🔄 Syncing version mismatches for project ${Colorize.bold(projectName)}...`); - let mismatchedDependencies: string[] = fetchProjectMismatches(projectName); + let mismatchedDependencies: string[] = fetchProjectMismatches(projectName, rootPath); if (mismatchedDependencies.length === 0) { Console.success(`No mismatches found in the project ${Colorize.bold(projectName)}!`); return true; } - const project: IRushConfigurationProjectJson | undefined = queryProject(projectName); + const project: IRushConfigurationProjectJson | undefined = queryProject(projectName, rootPath); if (!project || !project.subspaceName) { Console.error(`Project ${Colorize.bold(projectName)} is not part of a subspace!`); return true; @@ -175,7 +188,7 @@ export const syncProjectMismatchedDependencies = async (projectName: string): Pr const nextCommand: string = await chooseSyncCommandPrompt(project.packageName); switch (nextCommand) { case 'report': - await generateReport(project.packageName); + await generateReport(project.packageName, rootPath); break; case 'fix': do { @@ -183,8 +196,8 @@ export const syncProjectMismatchedDependencies = async (projectName: string): Pr mismatchedDependencies, ` (${Colorize.bold(`${mismatchedDependencies.length}`)} mismatched dependencies)` ); - if (await syncDependencyVersion(selectedDependency, projectName)) { - mismatchedDependencies = fetchProjectMismatches(projectName); + if (await syncDependencyVersion(selectedDependency, projectName, rootPath)) { + mismatchedDependencies = fetchProjectMismatches(projectName, rootPath); } } while ( mismatchedDependencies.length > 0 && diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateEdenProject.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateEdenProject.ts index a768bb7..a1df07c 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateEdenProject.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateEdenProject.ts @@ -3,15 +3,15 @@ import { RushNameConstants } from '../constants/paths'; import Console from '../providers/console'; import { Colorize } from '@rushstack/terminal'; import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; -import { getRootPath } from '../utilities/path'; export async function updateEdenProject( sourceProject: IRushConfigurationProjectJson, - targetProjectFolderPath: string + targetProjectFolderPath: string, + rootPath: string ): Promise { - Console.debug(`Update monorepo eden configuration on ${Colorize.bold(getRootPath())}...`); + Console.debug(`Update monorepo eden configuration on ${Colorize.bold(rootPath)}...`); - const edenPipelineFilePath: string = `${getRootPath()}/${RushNameConstants.EdenPipelineFileName}`; + const edenPipelineFilePath: string = `${rootPath}/${RushNameConstants.EdenPipelineFileName}`; const edenPipelineJson: JsonObject = JsonFile.load(edenPipelineFilePath); for (const entry of Object.values(edenPipelineJson.scene.scm)) { if (entry.pipelinePath?.includes(sourceProject.projectFolder)) { @@ -30,7 +30,7 @@ export async function updateEdenProject( } } - const edenMonorepoFilePath: string = `${getRootPath()}/${RushNameConstants.EdenMonorepoFileName}`; + const edenMonorepoFilePath: string = `${rootPath}/${RushNameConstants.EdenMonorepoFileName}`; const edenMonorepoJson: JsonObject = JsonFile.load(edenMonorepoFilePath); const edenProject: JsonObject = edenMonorepoJson.packages.find( ({ name }: JsonObject) => name === sourceProject.packageName diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateProjectDependency.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateProjectDependency.ts index 8b705fc..443f584 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateProjectDependency.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateProjectDependency.ts @@ -7,15 +7,16 @@ import Console from '../providers/console'; export const updateProjectDependency = async ( projectName: string, dependencyName: string, - newVersion: string + newVersion: string, + rootPath: string ): Promise => { - const project: IRushConfigurationProjectJson | undefined = queryProject(projectName); + const project: IRushConfigurationProjectJson | undefined = queryProject(projectName, rootPath); if (!project) { Console.error(`Could not load find the project ${Colorize.bold(projectName)}.`); return false; } - const pkgJsonPath: string = getProjectPackageFilePath(project.projectFolder); + const pkgJsonPath: string = getProjectPackageFilePath(project.projectFolder, rootPath); if (!FileSystem.exists(pkgJsonPath)) { Console.error(`Could not load ${Colorize.bold(pkgJsonPath)}.`); return false; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateRushConfiguration.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateRushConfiguration.ts index 8edee35..98ba840 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateRushConfiguration.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateRushConfiguration.ts @@ -1,5 +1,4 @@ import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; -import { getRootPath } from '../utilities/path'; import { IRushConfigurationJson } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; import { loadRushConfiguration } from '../utilities/repository'; import Console from '../providers/console'; @@ -10,10 +9,10 @@ import path from 'path'; export const removeProjectFromRushConfiguration = ( project: IRushConfigurationProjectJson, - monoRepoRootPath: string = getRootPath() + rootPath: string ): void => { - const rushConfigFile: string = `${monoRepoRootPath}/${RushConstants.rushJsonFilename}`; - const rushConfig: IRushConfigurationJson = loadRushConfiguration(monoRepoRootPath); + const rushConfigFile: string = `${rootPath}/${RushConstants.rushJsonFilename}`; + const rushConfig: IRushConfigurationJson = loadRushConfiguration(rootPath); const projectIndex: number = rushConfig.projects.findIndex( ({ packageName }) => packageName === project.packageName ); @@ -47,17 +46,17 @@ export const addProjectToRushConfiguration = ( sourceProject: IRushConfigurationProjectJson, targetSubspace: string, targetProjectFolderPath: string, - monoRepoRootPath: string = getRootPath() + rootPath: string ): void => { - const rushConfigFile: string = `${monoRepoRootPath}/${RushConstants.rushJsonFilename}`; - const rushConfig: IRushConfigurationJson = loadRushConfiguration(monoRepoRootPath); + const rushConfigFile: string = `${rootPath}/${RushConstants.rushJsonFilename}`; + const rushConfig: IRushConfigurationJson = loadRushConfiguration(rootPath); const projectIndex: number = rushConfig.projects.findIndex( ({ packageName }) => packageName === sourceProject.packageName ); let newTargetProject: IRushConfigurationProjectJson = { subspaceName: targetSubspace, packageName: sourceProject.packageName, - projectFolder: path.relative(monoRepoRootPath, targetProjectFolderPath), + projectFolder: path.relative(rootPath, targetProjectFolderPath), decoupledLocalDependencies: [] }; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateSubspace.ts index d879c43..338ab10 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/functions/updateSubspace.ts @@ -12,10 +12,14 @@ import { const mergeSubspaceCommonVersionsFiles = ( targetSubspaceName: string, - sourceSubspaceFolderPath: string + sourceSubspaceFolderPath: string, + rootPath: string ): void => { const sourceCommonVersionsFilePath: string = `${sourceSubspaceFolderPath}/${RushConstants.commonVersionsFilename}`; - const targetCommonVersionsFilePath: string = getRushSubspaceCommonVersionsFilePath(targetSubspaceName); + const targetCommonVersionsFilePath: string = getRushSubspaceCommonVersionsFilePath( + targetSubspaceName, + rootPath + ); const sourceCommonVersions: RushSubspaceCommonVersionsJson = JsonFile.load(sourceCommonVersionsFilePath); if (FileSystem.exists(targetCommonVersionsFilePath)) { @@ -97,15 +101,20 @@ const copySubspaceRepoStateFile = ( }; */ -const mergeSubspacePnpmFiles = (targetSubspaceName: string, sourceSubspaceFolderPath: string): void => { +const mergeSubspacePnpmFiles = ( + targetSubspaceName: string, + sourceSubspaceFolderPath: string, + rootPath: string +): void => { const sourcePnpmFilePath: string = `${sourceSubspaceFolderPath}/${RushNameConstants.PnpmSubspaceFileName}`; - const targetPnpmFilePath: string = getRushSubspacePnpmFilePath(targetSubspaceName); + const targetPnpmFilePath: string = getRushSubspacePnpmFilePath(targetSubspaceName, rootPath); if (FileSystem.exists(sourcePnpmFilePath)) { if (FileSystem.exists(targetPnpmFilePath)) { const tempPnpmSubspaceFileName: string = `.pnpmfile-subspace-temp_${new Date().getTime()}.cjs`; const targetPnpmTempFilePath: string = `${getRushSubspaceConfigurationFolderPath( - targetSubspaceName + targetSubspaceName, + rootPath )}/${tempPnpmSubspaceFileName}`; Console.debug( `Duplicating temporary ${Colorize.bold(sourcePnpmFilePath)} into ${Colorize.bold( @@ -139,9 +148,13 @@ const mergeSubspacePnpmFiles = (targetSubspaceName: string, sourceSubspaceFolder } }; -const copySubspaceNpmRcFile = (targetSubspaceName: string, sourceSubspaceFolderPath: string): void => { +const copySubspaceNpmRcFile = ( + targetSubspaceName: string, + sourceSubspaceFolderPath: string, + rootPath: string +): void => { const sourceNpmRcFilePath: string = `${sourceSubspaceFolderPath}/${RushNameConstants.NpmRcFileName}`; - const targetNpmRcFilePath: string = getRushSubspaceNpmRcFilePath(targetSubspaceName); + const targetNpmRcFilePath: string = getRushSubspaceNpmRcFilePath(targetSubspaceName, rootPath); if (FileSystem.exists(sourceNpmRcFilePath)) { Console.debug( @@ -156,10 +169,11 @@ const copySubspaceNpmRcFile = (targetSubspaceName: string, sourceSubspaceFolderP export const updateSubspace = async ( targetSubspaceName: string, - sourceSubspaceConfigurationFolderPath: string + sourceSubspaceConfigurationFolderPath: string, + rootPath: string ): Promise => { - copySubspaceNpmRcFile(targetSubspaceName, sourceSubspaceConfigurationFolderPath); - mergeSubspaceCommonVersionsFiles(targetSubspaceName, sourceSubspaceConfigurationFolderPath); + copySubspaceNpmRcFile(targetSubspaceName, sourceSubspaceConfigurationFolderPath, rootPath); + mergeSubspaceCommonVersionsFiles(targetSubspaceName, sourceSubspaceConfigurationFolderPath, rootPath); // copySubspaceRepoStateFile(sourceSubspaceConfigurationFolderPath, targetSubspaceConfigurationFolderPath); - mergeSubspacePnpmFiles(targetSubspaceName, sourceSubspaceConfigurationFolderPath); + mergeSubspacePnpmFiles(targetSubspaceName, sourceSubspaceConfigurationFolderPath, rootPath); }; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts b/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts index 4c39fa6..93060ce 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts @@ -16,36 +16,36 @@ import { import { RushConstants } from '@rushstack/rush-sdk'; import { syncProjectMismatchedDependencies } from './functions/syncProjectDependencies'; -export const migrateProject = async (): Promise => { +export const migrateProject = async (targetMonorepoPath: string = getRootPath()): Promise => { Console.debug('Executing project migration command...'); - Console.title(`🔍 Analyzing if monorepo ${Colorize.underline(getRootPath())} supports subspaces...`); + Console.title(`🔍 Analyzing if monorepo ${Colorize.underline(targetMonorepoPath)} supports subspaces...`); /** * WARN: Disabling auto subspace initialization for now. * if (!isSubspaceSupported()) { * Console.warn( - * `The monorepo ${Colorize.bold(getRootPath())} doesn't contain subspaces. Initializing subspaces...` + * `The monorepo ${Colorize.bold(rootPath)} doesn't contain subspaces. Initializing subspaces...` *); * await initSubspaces(); * } */ - const targetSubspaces: string[] = querySubspaces(); - if (!isSubspaceSupported() || targetSubspaces.length === 0) { + const targetSubspaces: string[] = querySubspaces(targetMonorepoPath); + if (!isSubspaceSupported(targetMonorepoPath) || targetSubspaces.length === 0) { Console.error( `The monorepo ${Colorize.bold( - getRootPath() + targetMonorepoPath )} doesn't support subspaces! Make sure you have ${Colorize.bold( - getRushSubspacesConfigurationJsonPath() + getRushSubspacesConfigurationJsonPath(targetMonorepoPath) )} with the ${Colorize.bold(RushConstants.defaultSubspaceName)} subspace. Exiting...` ); return; } - Console.success(`Monorepo ${Colorize.bold(getRootPath())} fully supports subspaces!`); + Console.success(`Monorepo ${Colorize.bold(targetMonorepoPath)} fully supports subspaces!`); - Console.title(`🔍 Finding projects to migrate to ${Colorize.bold(getRootPath())}...`); + Console.title(`🔍 Finding projects to migrate to ${Colorize.bold(targetMonorepoPath)}...`); /** * WARN: Disabling different repository selection for now. @@ -76,7 +76,10 @@ export const migrateProject = async (): Promise => { // Loop until user asks to quit do { const sourceProjects: IRushConfigurationProjectJson[] = queryProjects(sourceMonorepoPath); - const sourceAvailableProjects: IRushConfigurationProjectJson[] = isExternalMonorepo(sourceMonorepoPath) + const sourceAvailableProjects: IRushConfigurationProjectJson[] = isExternalMonorepo( + sourceMonorepoPath, + targetMonorepoPath + ) ? sourceProjects : sourceProjects.filter(({ subspaceName }) => subspaceName !== targetSubspace); @@ -108,11 +111,16 @@ export const migrateProject = async (): Promise => { sourceProjectToMigrate.projectFolder ); - await updateSubspace(targetSubspace, sourceSubspaceConfigurationFolderPath); + await updateSubspace(targetSubspace, sourceSubspaceConfigurationFolderPath, targetMonorepoPath); } - await addProjectToSubspace(sourceProjectToMigrate, targetSubspace, sourceMonorepoPath); - await syncProjectMismatchedDependencies(sourceProjectToMigrate.packageName); + await addProjectToSubspace( + sourceProjectToMigrate, + targetSubspace, + sourceMonorepoPath, + targetMonorepoPath + ); + await syncProjectMismatchedDependencies(sourceProjectToMigrate.packageName, targetMonorepoPath); } while (await confirmNextProjectToAddPrompt(targetSubspace)); Console.warn( diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts b/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts index ab6c46e..2ad191c 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts @@ -8,12 +8,12 @@ import { getSubspaceMismatches } from './utilities/subspace'; import { chooseProjectPrompt, confirmNextProjectToSyncPrompt } from './prompts/project'; import { syncProjectMismatchedDependencies } from './functions/syncProjectDependencies'; -const fetchSubspaceMismatchedProjects = (subspaceName: string): string[] => { +const fetchSubspaceMismatchedProjects = (subspaceName: string, rootPath: string): string[] => { const mismatchedProjects: string[] = []; const subspaceMismatches: ReadonlyMap< string, ReadonlyMap - > = getSubspaceMismatches(subspaceName); + > = getSubspaceMismatches(subspaceName, rootPath); for (const [, versions] of subspaceMismatches) { for (const [, entities] of versions) { @@ -32,19 +32,22 @@ const fetchSubspaceMismatchedProjects = (subspaceName: string): string[] => { return mismatchedProjects; }; -export const syncVersions = async (): Promise => { +export const syncVersions = async (targetMonorepoPath: string = getRootPath()): Promise => { Console.debug('Synching project version...'); - const sourceSubspaces: string[] = querySubspaces(); + const sourceSubspaces: string[] = querySubspaces(targetMonorepoPath); if (sourceSubspaces.length === 0) { - Console.error(`No subspaces found in the monorepo ${Colorize.bold(getRootPath())}! Exiting...`); + Console.error(`No subspaces found in the monorepo ${Colorize.bold(targetMonorepoPath)}! Exiting...`); return; } const selectedSubspaceName: string = await chooseSubspacePrompt(sourceSubspaces); Console.title(`🔄 Syncing version mismatches for subspace ${Colorize.bold(selectedSubspaceName)}...`); - let mismatchedProjects: string[] = fetchSubspaceMismatchedProjects(selectedSubspaceName); + let mismatchedProjects: string[] = fetchSubspaceMismatchedProjects( + selectedSubspaceName, + targetMonorepoPath + ); if (mismatchedProjects.length === 0) { Console.success(`No mismatches found in the subspace ${Colorize.bold(selectedSubspaceName)}! Exiting...`); return; @@ -52,11 +55,11 @@ export const syncVersions = async (): Promise => { do { const selectedProjectName: string = await chooseProjectPrompt(mismatchedProjects); - if (!(await syncProjectMismatchedDependencies(selectedProjectName))) { + if (!(await syncProjectMismatchedDependencies(selectedProjectName, targetMonorepoPath))) { return; } - mismatchedProjects = fetchSubspaceMismatchedProjects(selectedSubspaceName); + mismatchedProjects = fetchSubspaceMismatchedProjects(selectedSubspaceName, targetMonorepoPath); } while (mismatchedProjects.length > 0 && (await confirmNextProjectToSyncPrompt(selectedSubspaceName))); if (mismatchedProjects.length === 0) { diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts index 46ff979..577341c 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/dependency.ts @@ -71,13 +71,13 @@ export const sortVersions = (versions: string[]): string[] => { return newVersions; }; -export const rSortVersions = (versions: string[]): string[] => { +export const reverseSortVersions = (versions: string[]): string[] => { return sortVersions(versions).reverse(); }; export const getClosestVersion = (targetVersion: string, versions: string[]): string | undefined => { - const rSortedVersions: string[] = rSortVersions(versions); - return rSortedVersions.find((version) => intersectsVersion(targetVersion, version)); + const reverseSortedVersions: string[] = reverseSortVersions(versions); + return reverseSortedVersions.find((version) => intersectsVersion(targetVersion, version)); }; export const getRecommendedVersion = (targetVersion: string, versions: string[]): string | undefined => { diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts index 886cafa..da10fe7 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/project.ts @@ -1,41 +1,32 @@ import { IRushConfigurationJson } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; import { IRushConfigurationProjectJson } from '@rushstack/rush-sdk/lib/api/RushConfigurationProject'; -import { getRootPath } from './path'; import { loadRushConfiguration } from './repository'; import { getSubspaceMismatches } from './subspace'; import { VersionMismatchFinderEntity } from '@rushstack/rush-sdk/lib/logic/versionMismatch/VersionMismatchFinderEntity'; import { RushNameConstants } from '../constants/paths'; import { IPackageJson, IPackageJsonDependencyTable, JsonFile } from '@rushstack/node-core-library'; -export const getProjectPackageFilePath = ( - projectFolder: string, - rootPath: string = getRootPath() -): string => { +export const getProjectPackageFilePath = (projectFolder: string, rootPath: string): string => { return `${rootPath}/${projectFolder}/${RushNameConstants.PackageName}`; }; -export const loadProjectPackageJson = ( - projectFolder: string, - rootPath: string = getRootPath() -): IPackageJson => { +export const loadProjectPackageJson = (projectFolder: string, rootPath: string): IPackageJson => { return JsonFile.load(getProjectPackageFilePath(projectFolder, rootPath)); }; -export const queryProjects = (rootPath: string = getRootPath()): IRushConfigurationProjectJson[] => { +export const queryProjects = (rootPath: string): IRushConfigurationProjectJson[] => { const rushJson: IRushConfigurationJson = loadRushConfiguration(rootPath); return rushJson.projects; }; -export const queryProjectsWithoutSubspace = ( - rootPath: string = getRootPath() -): IRushConfigurationProjectJson[] => { +export const queryProjectsWithoutSubspace = (rootPath: string): IRushConfigurationProjectJson[] => { const projects: IRushConfigurationProjectJson[] = queryProjects(rootPath); return projects.filter(({ subspaceName }) => !subspaceName); }; export const queryProject = ( projectName: string, - rootPath: string = getRootPath() + rootPath: string ): IRushConfigurationProjectJson | undefined => { const projects: IRushConfigurationProjectJson[] = queryProjects(rootPath); return projects.find(({ packageName }) => packageName === projectName); @@ -43,7 +34,7 @@ export const queryProject = ( export const getProjectMismatches = ( projectName: string, - rootPath: string = getRootPath() + rootPath: string ): ReadonlyMap> => { const project: IRushConfigurationProjectJson | undefined = queryProject(projectName, rootPath); if (!project || !project.subspaceName) { @@ -76,7 +67,7 @@ export const getProjectMismatches = ( export const getProjectDependencies = ( projectName: string, - rootPath: string = getRootPath() + rootPath: string ): IPackageJsonDependencyTable | undefined => { const project: IRushConfigurationProjectJson | undefined = queryProject(projectName, rootPath); if (!project || !project.subspaceName) { @@ -90,11 +81,11 @@ export const getProjectDependencies = ( }; }; -export const getProjectMismatchedDependencies = (projectName: string): string[] => { +export const getProjectMismatchedDependencies = (projectName: string, rootPath: string): string[] => { const projectMismatches: ReadonlyMap< string, ReadonlyMap - > = getProjectMismatches(projectName); + > = getProjectMismatches(projectName, rootPath); return Array.from(projectMismatches.keys()); }; @@ -103,7 +94,7 @@ export const updateProjectDependency = ( projectName: string, dependencyName: string, newVersion: string, - rootPath: string = getRootPath() + rootPath: string ): boolean => { const project: IRushConfigurationProjectJson | undefined = queryProject(projectName, rootPath); if (!project) { @@ -113,12 +104,12 @@ export const updateProjectDependency = ( const projectPackageFilePath: string = getProjectPackageFilePath(project.projectFolder, rootPath); const projectPackageJson: IPackageJson = loadProjectPackageJson(project.projectFolder, rootPath); - if (projectPackageJson.dependencies![dependencyName]) { - projectPackageJson.dependencies![dependencyName] = newVersion; + if (projectPackageJson.dependencies?.[dependencyName]) { + projectPackageJson.dependencies[dependencyName] = newVersion; } - if (projectPackageJson.devDependencies![dependencyName]) { - projectPackageJson.devDependencies![dependencyName] = newVersion; + if (projectPackageJson.devDependencies?.[dependencyName]) { + projectPackageJson.devDependencies[dependencyName] = newVersion; } JsonFile.save(projectPackageJson, projectPackageFilePath); diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/repository.ts b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/repository.ts index 428222d..7dee644 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/repository.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/repository.ts @@ -1,33 +1,27 @@ import { JsonFile } from '@rushstack/node-core-library'; -import { getRootPath } from './path'; import { IRushConfigurationJson } from '@rushstack/rush-sdk/lib/api/RushConfiguration'; import { RushPathConstants } from '../constants/paths'; import { ISubspacesConfigurationJson } from '@rushstack/rush-sdk/lib/api/SubspacesConfiguration'; import { RushConstants } from '@rushstack/rush-sdk'; -export const getRushConfigurationJsonPath = (rootPath: string = getRootPath()): string => +export const getRushConfigurationJsonPath = (rootPath: string): string => `${rootPath}/${RushConstants.rushJsonFilename}`; -export const getRushSubspacesConfigurationJsonPath = (rootPath: string = getRootPath()): string => +export const getRushSubspacesConfigurationJsonPath = (rootPath: string): string => `${rootPath}/${RushPathConstants.SubspacesConfigurationFilePath}`; -export const loadRushConfiguration = (rootPath: string = getRootPath()): IRushConfigurationJson => { +export const loadRushConfiguration = (rootPath: string): IRushConfigurationJson => { return JsonFile.load(getRushConfigurationJsonPath(rootPath)); }; -export const loadRushSubspacesConfiguration = ( - rootPath: string = getRootPath() -): ISubspacesConfigurationJson => { +export const loadRushSubspacesConfiguration = (rootPath: string): ISubspacesConfigurationJson => { return JsonFile.load(getRushSubspacesConfigurationJsonPath(rootPath)); }; -export const querySubspaces = (rootPath: string = getRootPath()): string[] => { +export const querySubspaces = (rootPath: string): string[] => { const subspaceJson: ISubspacesConfigurationJson = loadRushSubspacesConfiguration(rootPath); return subspaceJson.subspaceNames; }; -export const isExternalMonorepo = ( - sourceRootPath: string, - targetRootPath: string = getRootPath() -): boolean => { +export const isExternalMonorepo = (sourceRootPath: string, targetRootPath: string): boolean => { return sourceRootPath !== targetRootPath; }; diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts index 39bb7b0..4d615ad 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/utilities/subspace.ts @@ -1,7 +1,6 @@ import { FileSystem, IPackageJsonDependencyTable, JsonFile } from '@rushstack/node-core-library'; import { RushNameConstants, RushPathConstants } from '../constants/paths'; import { ISubspacesConfigurationJson } from '@rushstack/rush-sdk/lib/api/SubspacesConfiguration'; -import { getRootPath } from './path'; import { getRushConfigurationJsonPath, getRushSubspacesConfigurationJsonPath, @@ -18,7 +17,7 @@ import { getProjectDependencies } from './project'; export const queryProjectsFromSubspace = ( targetSubspaceName: string, - rootPath: string = getRootPath() + rootPath: string ): IRushConfigurationProjectJson[] => { const rushConfig: IRushConfigurationJson = loadRushConfiguration(rootPath); return rushConfig.projects.filter(({ subspaceName }) => subspaceName === targetSubspaceName); @@ -27,14 +26,14 @@ export const queryProjectsFromSubspace = ( const getRushLegacySubspaceConfigurationFolderPath = ( subspaceName: string, projectFolderPath: string, - rootPath: string = getRootPath() + rootPath: string ): string => { return `${rootPath}/${projectFolderPath}/subspace/${subspaceName}`; }; export const getRushSubspaceConfigurationFolderPath = ( subspaceName: string, - rootPath: string = getRootPath(), + rootPath: string, projectFolderPath?: string ): string => { if (projectFolderPath) { @@ -52,10 +51,7 @@ export const getRushSubspaceConfigurationFolderPath = ( return `${rootPath}/${RushPathConstants.SubspacesConfigurationFolderPath}/${subspaceName}`; }; -export const getRushSubspaceCommonVersionsFilePath = ( - subspaceName: string, - rootPath: string = getRootPath() -): string => { +export const getRushSubspaceCommonVersionsFilePath = (subspaceName: string, rootPath: string): string => { return `${getRushSubspaceConfigurationFolderPath(subspaceName, rootPath)}/${ RushConstants.commonVersionsFilename }`; @@ -63,15 +59,12 @@ export const getRushSubspaceCommonVersionsFilePath = ( export const loadRushSubspaceCommonVersions = ( subspaceName: string, - rootPath: string = getRootPath() + rootPath: string ): RushSubspaceCommonVersionsJson => { return JsonFile.load(getRushSubspaceCommonVersionsFilePath(subspaceName, rootPath)); }; -export const getRushSubspacePnpmFilePath = ( - subspaceName: string, - rootPath: string = getRootPath() -): string => { +export const getRushSubspacePnpmFilePath = (subspaceName: string, rootPath: string): string => { return `${getRushSubspaceConfigurationFolderPath(subspaceName, rootPath)}/${ RushNameConstants.PnpmSubspaceFileName }`; @@ -79,15 +72,12 @@ export const getRushSubspacePnpmFilePath = ( export const loadRushSubspacePnpm = ( subspaceName: string, - rootPath: string = getRootPath() + rootPath: string ): RushSubspaceCommonVersionsJson => { return JsonFile.load(getRushSubspacePnpmFilePath(subspaceName, rootPath)); }; -export const getRushSubspaceNpmRcFilePath = ( - subspaceName: string, - rootPath: string = getRootPath() -): string => { +export const getRushSubspaceNpmRcFilePath = (subspaceName: string, rootPath: string): string => { return `${getRushSubspaceConfigurationFolderPath(subspaceName, rootPath)}/${ RushNameConstants.NpmRcFileName }`; @@ -95,31 +85,31 @@ export const getRushSubspaceNpmRcFilePath = ( export const loadRushSubspaceNpmRc = ( subspaceName: string, - rootPath: string = getRootPath() + rootPath: string ): RushSubspaceCommonVersionsJson => { return JsonFile.load(getRushSubspaceNpmRcFilePath(subspaceName, rootPath)); }; -export const isSubspaceSupported = (rootPath: string = getRootPath()): boolean => { +export const isSubspaceSupported = (rootPath: string): boolean => { if ( FileSystem.exists(getRushSubspacesConfigurationJsonPath(rootPath)) && FileSystem.exists(getRushSubspaceConfigurationFolderPath(RushConstants.defaultSubspaceName, rootPath)) ) { - const subspacesConfig: ISubspacesConfigurationJson = loadRushSubspacesConfiguration(); + const subspacesConfig: ISubspacesConfigurationJson = loadRushSubspacesConfiguration(rootPath); return subspacesConfig.subspacesEnabled; } return false; }; -export const subspaceExists = (subspaceName: string, rootPath: string = getRootPath()): boolean => { +export const subspaceExists = (subspaceName: string, rootPath: string): boolean => { const subspaces: string[] = querySubspaces(rootPath); return !!subspaces.find((name) => name === subspaceName); }; export const getSubspaceMismatches = ( subspaceName: string, - rootPath: string = getRootPath() + rootPath: string ): ReadonlyMap> => { const rushConfig: RushConfiguration = RushConfiguration.loadFromConfigurationFile( getRushConfigurationJsonPath(rootPath) @@ -135,7 +125,7 @@ export const getSubspaceMismatches = ( export const getSubspaceDependencies = ( subspaceName: string, - rootPath: string = getRootPath() + rootPath: string ): Map> => { const subspaceProjects: IRushConfigurationProjectJson[] = queryProjectsFromSubspace(subspaceName, rootPath); const subspaceDependencies: Map> = new Map>(); From b372387cc01b0061970acd2fffca3de47d712b4a Mon Sep 17 00:00:00 2001 From: Pedro Gomes <37028775+pedro-gomes-92@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:18:45 +0800 Subject: [PATCH 11/11] chore: improve mr after review (II) --- .../src/cleanSubspace.ts | 25 ++++++++----------- .../rush-migrate-subspace-plugin/src/cli.ts | 12 ++++++--- .../src/interactMenu.ts | 8 +++--- .../src/migrateProject.ts | 8 +++--- .../src/syncVersions.ts | 16 +++++------- 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts index 6f8af6b..e329eb4 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cleanSubspace.ts @@ -6,7 +6,6 @@ import { scanForAllDependenciesPrompt } from './prompts/subspace'; import Console from './providers/console'; -import { getRootPath } from './utilities/path'; import { Colorize } from '@rushstack/terminal'; import { getRushSubspaceCommonVersionsFilePath, @@ -246,16 +245,14 @@ const removeSupersetDependencyVersions = async ( } while (multipleVersionDependencies.length > 0 && (await confirmNextDependencyPrompt())); }; -export const cleanSubspace = async (targetMonorepoPath: string = getRootPath()): Promise => { +export const cleanSubspace = async (rootPath: string): Promise => { Console.debug('Executing clean subspace command...'); - const targetSubspaces: string[] = querySubspaces(targetMonorepoPath); - if (!isSubspaceSupported(targetMonorepoPath)) { + const targetSubspaces: string[] = querySubspaces(rootPath); + if (!isSubspaceSupported(rootPath)) { Console.error( - `The monorepo ${Colorize.bold( - targetMonorepoPath - )} doesn't support subspaces! Make sure you have ${Colorize.bold( - getRushSubspacesConfigurationJsonPath(targetMonorepoPath) + `The monorepo ${Colorize.bold(rootPath)} doesn't support subspaces! Make sure you have ${Colorize.bold( + getRushSubspacesConfigurationJsonPath(rootPath) )} with the ${Colorize.bold(RushConstants.defaultSubspaceName)} subspace. Exiting...` ); return; @@ -266,20 +263,20 @@ export const cleanSubspace = async (targetMonorepoPath: string = getRootPath()): let subspaceDependencies: Map> = getSubspaceDependencies( targetSubspace, - targetMonorepoPath + rootPath ); if (await scanForDuplicatedDependenciesPrompt()) { - removeDuplicatedDependencies(targetSubspace, targetMonorepoPath); - subspaceDependencies = getSubspaceDependencies(targetSubspace, targetMonorepoPath); + removeDuplicatedDependencies(targetSubspace, rootPath); + subspaceDependencies = getSubspaceDependencies(targetSubspace, rootPath); } if (await scanForSupersetDependencyVersionsPrompt()) { - await removeSupersetDependencyVersions(targetSubspace, subspaceDependencies, targetMonorepoPath); - subspaceDependencies = getSubspaceDependencies(targetSubspace, targetMonorepoPath); + await removeSupersetDependencyVersions(targetSubspace, subspaceDependencies, rootPath); + subspaceDependencies = getSubspaceDependencies(targetSubspace, rootPath); } if (await scanForUnusedDependencyVersionsPrompt()) { - removeUnusedAlternativeVersions(targetSubspace, subspaceDependencies, targetMonorepoPath); + removeUnusedAlternativeVersions(targetSubspace, subspaceDependencies, rootPath); } Console.warn( diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts index 4824f68..31e1f8d 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/cli.ts @@ -8,6 +8,7 @@ import { migrateProject } from './migrateProject'; import Console from './providers/console'; import { interactMenu } from './interactMenu'; import { cleanSubspace } from './cleanSubspace'; +import { getRootPath } from './utilities/path'; inquirer.registerPrompt('search-list', inquirerSearchList); @@ -26,14 +27,17 @@ program Console.title(`🚀 Rush Migrate Subspace Plugin - version ${packageJson.version}`); Console.newLine(); + const sourceMonorepoPath: string = getRootPath(); + const targetMonorepoPath: string = getRootPath(); + if (sync) { - await syncVersions(); + await syncVersions(targetMonorepoPath); } else if (move) { - await migrateProject(); + await migrateProject(sourceMonorepoPath, targetMonorepoPath); } else if (clean) { - await cleanSubspace(); + await cleanSubspace(targetMonorepoPath); } else { - await interactMenu(); + await interactMenu(sourceMonorepoPath, targetMonorepoPath); } }); diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts b/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts index efe6a72..89d301a 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/interactMenu.ts @@ -4,7 +4,7 @@ import { chooseCommandPrompt } from './prompts/command'; import Console from './providers/console'; import { syncVersions } from './syncVersions'; -export const interactMenu = async (): Promise => { +export const interactMenu = async (sourceMonorepoPath: string, targetMonorepoPath: string): Promise => { let exitApplication: boolean = false; do { const nextCommand: string = await chooseCommandPrompt(); @@ -14,17 +14,17 @@ export const interactMenu = async (): Promise => { break; case 'move': - await migrateProject(); + await migrateProject(sourceMonorepoPath, targetMonorepoPath); Console.newLine(); break; case 'sync': - await syncVersions(); + await syncVersions(targetMonorepoPath); Console.newLine(); break; case 'clean': - await cleanSubspace(); + await cleanSubspace(targetMonorepoPath); Console.newLine(); break; } diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts b/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts index 93060ce..d0bf9b1 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/migrateProject.ts @@ -2,7 +2,6 @@ import { chooseSubspacePrompt } from './prompts/subspace'; import { addProjectToSubspace } from './functions/addProjectToSubspace'; import { chooseProjectPrompt, confirmNextProjectToAddPrompt } from './prompts/project'; import Console from './providers/console'; -import { getRootPath } from './utilities/path'; import { Colorize } from '@rushstack/terminal'; import { updateSubspace } from './functions/updateSubspace'; import { getRushSubspaceConfigurationFolderPath, isSubspaceSupported } from './utilities/subspace'; @@ -16,7 +15,10 @@ import { import { RushConstants } from '@rushstack/rush-sdk'; import { syncProjectMismatchedDependencies } from './functions/syncProjectDependencies'; -export const migrateProject = async (targetMonorepoPath: string = getRootPath()): Promise => { +export const migrateProject = async ( + sourceMonorepoPath: string, + targetMonorepoPath: string +): Promise => { Console.debug('Executing project migration command...'); Console.title(`🔍 Analyzing if monorepo ${Colorize.underline(targetMonorepoPath)} supports subspaces...`); @@ -55,8 +57,6 @@ export const migrateProject = async (targetMonorepoPath: string = getRootPath()) * ); */ - const sourceMonorepoPath: string = getRootPath(); - /** * WARN: Disabling creating new subspaces for now. * const subspaceSelectionType: string = await chooseCreateOrSelectSubspacePrompt(targetSubspaces); diff --git a/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts b/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts index 2ad191c..f831a3c 100644 --- a/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts +++ b/rush-plugins/rush-migrate-subspace-plugin/src/syncVersions.ts @@ -3,7 +3,6 @@ import { VersionMismatchFinderEntity } from '@rushstack/rush-sdk/lib/logic/versi import Console from './providers/console'; import { Colorize } from '@rushstack/terminal'; import { querySubspaces } from './utilities/repository'; -import { getRootPath } from './utilities/path'; import { getSubspaceMismatches } from './utilities/subspace'; import { chooseProjectPrompt, confirmNextProjectToSyncPrompt } from './prompts/project'; import { syncProjectMismatchedDependencies } from './functions/syncProjectDependencies'; @@ -32,22 +31,19 @@ const fetchSubspaceMismatchedProjects = (subspaceName: string, rootPath: string) return mismatchedProjects; }; -export const syncVersions = async (targetMonorepoPath: string = getRootPath()): Promise => { +export const syncVersions = async (rootPath: string): Promise => { Console.debug('Synching project version...'); - const sourceSubspaces: string[] = querySubspaces(targetMonorepoPath); + const sourceSubspaces: string[] = querySubspaces(rootPath); if (sourceSubspaces.length === 0) { - Console.error(`No subspaces found in the monorepo ${Colorize.bold(targetMonorepoPath)}! Exiting...`); + Console.error(`No subspaces found in the monorepo ${Colorize.bold(rootPath)}! Exiting...`); return; } const selectedSubspaceName: string = await chooseSubspacePrompt(sourceSubspaces); Console.title(`🔄 Syncing version mismatches for subspace ${Colorize.bold(selectedSubspaceName)}...`); - let mismatchedProjects: string[] = fetchSubspaceMismatchedProjects( - selectedSubspaceName, - targetMonorepoPath - ); + let mismatchedProjects: string[] = fetchSubspaceMismatchedProjects(selectedSubspaceName, rootPath); if (mismatchedProjects.length === 0) { Console.success(`No mismatches found in the subspace ${Colorize.bold(selectedSubspaceName)}! Exiting...`); return; @@ -55,11 +51,11 @@ export const syncVersions = async (targetMonorepoPath: string = getRootPath()): do { const selectedProjectName: string = await chooseProjectPrompt(mismatchedProjects); - if (!(await syncProjectMismatchedDependencies(selectedProjectName, targetMonorepoPath))) { + if (!(await syncProjectMismatchedDependencies(selectedProjectName, rootPath))) { return; } - mismatchedProjects = fetchSubspaceMismatchedProjects(selectedSubspaceName, targetMonorepoPath); + mismatchedProjects = fetchSubspaceMismatchedProjects(selectedSubspaceName, rootPath); } while (mismatchedProjects.length > 0 && (await confirmNextProjectToSyncPrompt(selectedSubspaceName))); if (mismatchedProjects.length === 0) {