From 705f950a0572428b59053dfc3fadedc3d7bf7b1b Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Sat, 28 Oct 2023 18:08:21 +0800 Subject: [PATCH 1/5] feat(update): pnpm update support update corepack config --- packages/types/src/package.ts | 1 + .../src/update/getUpdateChoices.ts | 5 +- .../src/update/index.ts | 30 ++++++- .../test/update/getUpdateChoices.test.ts | 40 ++++++++-- .../test/update/interactive.ts | 80 +++++++++++++++++++ reviewing/outdated/src/outdated.ts | 21 ++++- .../plugin-commands-outdated/src/outdated.ts | 2 +- .../plugin-commands-outdated/src/recursive.ts | 6 +- 8 files changed, 168 insertions(+), 17 deletions(-) diff --git a/packages/types/src/package.ts b/packages/types/src/package.ts index 52c00acd28c..2a84f29e2bf 100644 --- a/packages/types/src/package.ts +++ b/packages/types/src/package.ts @@ -107,6 +107,7 @@ export interface BaseManifest { author?: string license?: string exports?: Record + packageManager?: string } export type DependencyManifest = BaseManifest & Required> diff --git a/pkg-manager/plugin-commands-installation/src/update/getUpdateChoices.ts b/pkg-manager/plugin-commands-installation/src/update/getUpdateChoices.ts index 61113eb1732..d9a01ede5f8 100644 --- a/pkg-manager/plugin-commands-installation/src/update/getUpdateChoices.ts +++ b/pkg-manager/plugin-commands-installation/src/update/getUpdateChoices.ts @@ -8,6 +8,7 @@ import isEmpty from 'ramda/src/isEmpty' export interface ChoiceRow { name: string value: string + path?: string disabled?: boolean } @@ -75,8 +76,8 @@ export function getUpdateChoices (outdatedPkgsOfProjects: OutdatedPackage[], wor } }) - // To filter out selected "dependencies" or "devDependencies" in the final output, - // we rename it here to "[dependencies]" or "[devDependencies]", + // To filter out selected "dependencies", "devDependencies" and "packageManager" in the final output, + // we rename it here to "[dependencies]", "[devDependencies]" and "[packageManager]" // which will be filtered out in the format function of the prompt. finalChoices.push({ name: `[${depGroup}]`, choices, message: depGroup }) diff --git a/pkg-manager/plugin-commands-installation/src/update/index.ts b/pkg-manager/plugin-commands-installation/src/update/index.ts index d541d6158bc..3bff702386f 100644 --- a/pkg-manager/plugin-commands-installation/src/update/index.ts +++ b/pkg-manager/plugin-commands-installation/src/update/index.ts @@ -210,7 +210,7 @@ async function interactiveUpdate ( } return 'All of your dependencies are already up to date inside the specified ranges. Use the --latest option to update the ranges in package.json' } - const { updateDependencies } = await prompt({ + let { updateDependencies } = await prompt({ choices, footer: '\nEnter to start updating. Ctrl-c to cancel.', indicator (state: any, choice: any) { // eslint-disable-line @typescript-eslint/no-explicit-any @@ -230,7 +230,7 @@ async function interactiveUpdate ( if (Array.isArray(this.selected)) { return this.selected - // The custom format function is used to filter out "[dependencies]" or "[devDependencies]" from the output. + // The custom format function is used to filter out "[dependencies]" or "[devDependencies]" or "[packageManager]" from the output. // https://github.com/enquirer/enquirer/blob/master/lib/prompts/select.js#L98 .filter((choice: ChoiceRow) => !/^\[.+\]$/.test(choice.name)) .map((choice: ChoiceRow) => this.styles.primary(choice.name)).join(', ') @@ -267,6 +267,16 @@ async function interactiveUpdate ( }, } as any) as any // eslint-disable-line @typescript-eslint/no-explicit-any + updateDependencies = (updateDependencies as ChoiceRow[]).filter(dep => !(dep.path && dep.path.startsWith('[packageManager]'))) + const packageManagerManifest = outdatedPkgsOfProjects[0].filter(pkg => pkg.belongsTo === 'packageManager') + + if (opts.save !== false && packageManagerManifest.length) { + await updateProjectCorepackConfig({ + ...opts, + updatedVersion: packageManagerManifest[0].wanted, + updatedPackage: packageManagerManifest[0].packageName, + }) + } const updatePkgNames = pluck('value', updateDependencies as ChoiceRow[]) return update(updatePkgNames, opts) } @@ -309,3 +319,19 @@ function makeIncludeDependenciesFromCLI (opts: { optionalDependencies: opts.optional === true || (opts.production !== true && opts.dev !== true), } } + +async function updateProjectCorepackConfig (opts: { + updatedVersion: string + updatedPackage: string +} & UpdateCommandOptions) { + if (!opts.allProjects) { + return + } + const { updatedPackage, updatedVersion } = opts + + return Promise.all(opts.allProjects.map((project) => { + const updatedManifest = project.manifest + updatedManifest.packageManager = `${updatedPackage}@${updatedVersion}` + return project.writeProjectManifest(updatedManifest) + })) +} \ No newline at end of file diff --git a/pkg-manager/plugin-commands-installation/test/update/getUpdateChoices.test.ts b/pkg-manager/plugin-commands-installation/test/update/getUpdateChoices.test.ts index bdabc343c0c..d28a8a5a7a9 100644 --- a/pkg-manager/plugin-commands-installation/test/update/getUpdateChoices.test.ts +++ b/pkg-manager/plugin-commands-installation/test/update/getUpdateChoices.test.ts @@ -6,7 +6,7 @@ test('getUpdateChoices()', () => { getUpdateChoices([ { alias: 'foo', - belongsTo: 'dependencies' as const, + belongsTo: 'dependencies', current: '1.0.0', latestManifest: { name: 'foo', @@ -18,7 +18,7 @@ test('getUpdateChoices()', () => { }, { alias: 'foo', - belongsTo: 'devDependencies' as const, + belongsTo: 'devDependencies', current: '1.0.0', latestManifest: { name: 'foo', @@ -32,7 +32,7 @@ test('getUpdateChoices()', () => { }, { alias: 'qar', - belongsTo: 'devDependencies' as const, + belongsTo: 'devDependencies', current: '1.0.0', latestManifest: { name: 'qar', @@ -43,7 +43,7 @@ test('getUpdateChoices()', () => { }, { alias: 'zoo', - belongsTo: 'devDependencies' as const, + belongsTo: 'devDependencies', current: '1.1.0', latestManifest: { name: 'zoo', @@ -54,7 +54,7 @@ test('getUpdateChoices()', () => { }, { alias: 'qaz', - belongsTo: 'optionalDependencies' as const, + belongsTo: 'optionalDependencies', current: '1.0.1', latestManifest: { name: 'qaz', @@ -65,7 +65,7 @@ test('getUpdateChoices()', () => { }, { alias: 'qaz', - belongsTo: 'devDependencies' as const, + belongsTo: 'devDependencies', current: '1.0.1', latestManifest: { name: 'qaz', @@ -74,6 +74,17 @@ test('getUpdateChoices()', () => { packageName: 'foo', wanted: '1.0.1', }, + { + alias: 'pnpm', + belongsTo: 'packageManager', + current: '7.9.1', + latestManifest: { + name: 'pnpm', + version: '7.9.2', + }, + packageName: 'pnpm', + wanted: '7.9.1', + }, ], false)) .toStrictEqual([ { @@ -137,5 +148,22 @@ test('getUpdateChoices()', () => { }, ], }, + { + name: '[packageManager]', + message: 'packageManager', + choices: [ + { + name: 'Package Current Target URL ', + disabled: true, + hint: '', + value: '', + }, + { + message: chalk`pnpm 7.9.1 ❯ 7.9.{greenBright.bold 2} `, + name: 'pnpm', + value: 'pnpm', + }, + ], + }, ]) }) diff --git a/pkg-manager/plugin-commands-installation/test/update/interactive.ts b/pkg-manager/plugin-commands-installation/test/update/interactive.ts index 972117b141e..25be3b6eb7a 100644 --- a/pkg-manager/plugin-commands-installation/test/update/interactive.ts +++ b/pkg-manager/plugin-commands-installation/test/update/interactive.ts @@ -354,3 +354,83 @@ test('interactively update should ignore dependencies from the ignoreDependencie expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy() } }) + +test('interactively update should update corepack config', async () => { + prepare({ + name: 'project-1', + packageManager: 'pnpm@8.7.0', + }) + + const storeDir = path.resolve('pnpm-store') + + await add.handler( + { + ...DEFAULT_OPTIONS, + cacheDir: path.resolve('cache'), + dir: process.cwd(), + linkWorkspacePackages: true, + save: false, + storeDir, + }, + ['pnpm@8.9.2'] + ) + + prompt.mockResolvedValue({ + updateDependencies: [ + { + value: 'pnpm', + name: chalk`pnpm 8.7.0 ❯ 8.9.2 https://pnpm.io/ `, + }, + ], + }) + + prompt.mockClear() + await update.handler({ + ...DEFAULT_OPTIONS, + cacheDir: path.resolve('cache'), + dir: process.cwd(), + interactive: true, + linkWorkspacePackages: true, + storeDir, + }) + + const promptStr = JSON.stringify(prompt.mock.calls[0][0].choices[0]) + const latestVersionIndex = promptStr.indexOf('❯') + const latestVersion = promptStr.substring( + latestVersionIndex + 2, + latestVersionIndex + 7 + ) + const promptChoices = JSON.parse(promptStr.replace(latestVersion, '8.9.0')) + + expect(promptChoices).toMatchInlineSnapshot(` + { + "choices": [ + { + "disabled": true, + "hint": "", + "name": "Package Current Target URL ", + "value": "", + }, + { + "message": "pnpm 8.7.0 ❯ 8.9.0 ", + "name": "pnpm", + "value": "pnpm", + }, + ], + "message": "packageManager", + "name": "[packageManager]", + } + `) + expect(prompt).toBeCalledWith( + expect.objectContaining({ + footer: '\nEnter to start updating. Ctrl-c to cancel.', + message: + 'Choose which packages to update ' + + `(Press ${chalk.cyan('')} to select, ` + + `${chalk.cyan('')} to toggle all, ` + + `${chalk.cyan('')} to invert selection)`, + name: 'updateDependencies', + type: 'multiselect', + }) + ) +}) diff --git a/reviewing/outdated/src/outdated.ts b/reviewing/outdated/src/outdated.ts index f65d7028f3a..f962bcace12 100644 --- a/reviewing/outdated/src/outdated.ts +++ b/reviewing/outdated/src/outdated.ts @@ -27,7 +27,7 @@ export type GetLatestManifestFunction = (packageName: string, rangeOrTag: string export interface OutdatedPackage { alias: string - belongsTo: DependenciesField + belongsTo: DependenciesField | 'packageManager' current?: string // not defined means the package is not installed latestManifest?: PackageManifest packageName: string @@ -50,7 +50,7 @@ export async function outdated ( wantedLockfile: Lockfile | null } ): Promise { - if (packageHasNoDeps(opts.manifest)) return [] + if (packageHasNoDeps(opts.manifest) && !opts.manifest.packageManager) return [] if (opts.wantedLockfile == null) { throw new PnpmError('OUTDATED_NO_LOCKFILE', `No lockfile in directory "${opts.lockfileDir}". Run \`pnpm install\` to generate one.`) } @@ -59,6 +59,22 @@ export async function outdated ( const currentLockfile = opts.currentLockfile ?? { importers: { [importerId]: {} } } const outdated: OutdatedPackage[] = [] + if (typeof opts.manifest?.packageManager === 'string' && opts.manifest?.packageManager.startsWith('pnpm@')) { + const [pkgManager, pkgManagerVersion] = opts.manifest.packageManager.split('@') + const latestPkgManifest = await opts.getLatestManifest(pkgManager, 'latest') + + if (latestPkgManifest !== null && semver.lt(pkgManagerVersion, latestPkgManifest.version)) { + outdated.push({ + alias: pkgManager, + belongsTo: 'packageManager', + current: pkgManagerVersion, + packageName: pkgManager, + latestManifest: latestPkgManifest, + wanted: latestPkgManifest.version, + workspace: opts.manifest.name, + }) + } + } const ignoreDependenciesMatcher = opts.ignoreDependencies?.length ? createMatcher(opts.ignoreDependencies) : undefined @@ -154,7 +170,6 @@ export async function outdated ( packageName, wanted, workspace: opts.manifest.name, - }) } }) diff --git a/reviewing/plugin-commands-outdated/src/outdated.ts b/reviewing/plugin-commands-outdated/src/outdated.ts index 20a93a6f580..b86ebaf32e9 100644 --- a/reviewing/plugin-commands-outdated/src/outdated.ts +++ b/reviewing/plugin-commands-outdated/src/outdated.ts @@ -283,7 +283,7 @@ function renderOutdatedJSON (outdatedPackages: readonly OutdatedPackage[], opts: latest: outdatedPkg.latestManifest?.version, wanted: outdatedPkg.wanted, isDeprecated: Boolean(outdatedPkg.latestManifest?.deprecated), - dependencyType: outdatedPkg.belongsTo, + dependencyType: outdatedPkg.belongsTo as DependenciesField, } if (opts.long) { acc[outdatedPkg.packageName].latestManifest = outdatedPkg.latestManifest diff --git a/reviewing/plugin-commands-outdated/src/recursive.ts b/reviewing/plugin-commands-outdated/src/recursive.ts index 6a1792b6469..279bc255acf 100644 --- a/reviewing/plugin-commands-outdated/src/recursive.ts +++ b/reviewing/plugin-commands-outdated/src/recursive.ts @@ -34,11 +34,11 @@ const DEP_PRIORITY: Record = { const COMPARATORS = [ ...DEFAULT_COMPARATORS, (o1: OutdatedInWorkspace, o2: OutdatedInWorkspace) => - DEP_PRIORITY[o1.belongsTo] - DEP_PRIORITY[o2.belongsTo], + DEP_PRIORITY[o1.belongsTo as DependenciesField] - DEP_PRIORITY[o2.belongsTo as DependenciesField], ] interface OutdatedInWorkspace extends OutdatedPackage { - belongsTo: DependenciesField + belongsTo: DependenciesField | 'packageManager' current?: string dependentPkgs: Array<{ location: string, manifest: ProjectManifest }> latest?: string @@ -188,7 +188,7 @@ function renderOutdatedJSON ( latest: outdatedPkg.latestManifest?.version, wanted: outdatedPkg.wanted, isDeprecated: Boolean(outdatedPkg.latestManifest?.deprecated), - dependencyType: outdatedPkg.belongsTo, + dependencyType: outdatedPkg.belongsTo as DependenciesField, dependentPackages: outdatedPkg.dependentPkgs.map(({ manifest, location }) => ({ name: manifest.name!, location })), } if (opts.long) { From f968f10e14350899acce3b3f4d8e73096ea4b334 Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Sun, 29 Oct 2023 10:25:54 +0800 Subject: [PATCH 2/5] chore: update test --- .../test/update/interactive.ts | 200 +++++++++--------- 1 file changed, 99 insertions(+), 101 deletions(-) diff --git a/pkg-manager/plugin-commands-installation/test/update/interactive.ts b/pkg-manager/plugin-commands-installation/test/update/interactive.ts index 25be3b6eb7a..4923129ce46 100644 --- a/pkg-manager/plugin-commands-installation/test/update/interactive.ts +++ b/pkg-manager/plugin-commands-installation/test/update/interactive.ts @@ -1,19 +1,19 @@ -import path from 'path' -import { readProjects } from '@pnpm/filter-workspace-packages' -import { type Lockfile } from '@pnpm/lockfile-types' -import { add, install, update } from '@pnpm/plugin-commands-installation' -import { prepare, preparePackages } from '@pnpm/prepare' -import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock' -import readYamlFile from 'read-yaml-file' -import chalk from 'chalk' -import * as enquirer from 'enquirer' - -jest.mock('enquirer', () => ({ prompt: jest.fn() })) +import path from 'path'; +import { readProjects } from '@pnpm/filter-workspace-packages'; +import { type Lockfile } from '@pnpm/lockfile-types'; +import { add, install, update } from '@pnpm/plugin-commands-installation'; +import { prepare, preparePackages } from '@pnpm/prepare'; +import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'; +import readYamlFile from 'read-yaml-file'; +import chalk from 'chalk'; +import * as enquirer from 'enquirer'; + +jest.mock('enquirer', () => ({ prompt: jest.fn() })); // eslint-disable-next-line -const prompt = enquirer.prompt as any +const prompt = enquirer.prompt as any; -const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}` +const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}`; const DEFAULT_OPTIONS = { argv: { @@ -41,7 +41,7 @@ const DEFAULT_OPTIONS = { sort: true, userConfig: {}, workspaceConcurrency: 1, -} +}; test('interactively update', async () => { const project = prepare({ @@ -53,16 +53,16 @@ test('interactively update', async () => { // has many versions that satisfy ^3.0.0 micromatch: '^3.0.0', }, - }) + }); - const storeDir = path.resolve('pnpm-store') + const storeDir = path.resolve('pnpm-store'); const headerChoice = { name: 'Package Current Target URL ', disabled: true, hint: '', value: '', - } + }; await add.handler( { @@ -73,8 +73,8 @@ test('interactively update', async () => { save: false, storeDir, }, - ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'] - ) + ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'], + ); prompt.mockResolvedValue({ updateDependencies: [ @@ -83,9 +83,9 @@ test('interactively update', async () => { name: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} https://pnpm.io/ `, }, ], - }) + }); - prompt.mockClear() + prompt.mockClear(); // t.comment('update to compatible versions') await update.handler({ ...DEFAULT_OPTIONS, @@ -94,7 +94,7 @@ test('interactively update', async () => { interactive: true, linkWorkspacePackages: true, storeDir, - }) + }); expect(prompt.mock.calls[0][0].choices).toStrictEqual([ { @@ -114,7 +114,7 @@ test('interactively update', async () => { name: '[dependencies]', message: 'dependencies', }, - ]) + ]); expect(prompt).toBeCalledWith( expect.objectContaining({ footer: '\nEnter to start updating. Ctrl-c to cancel.', @@ -125,19 +125,19 @@ test('interactively update', async () => { `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }) - ) + }), + ); { - const lockfile = await project.readLockfile() + const lockfile = await project.readLockfile(); - expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy() - expect(lockfile.packages['/is-negative@1.0.1']).toBeTruthy() - expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy() + expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy(); + expect(lockfile.packages['/is-negative@1.0.1']).toBeTruthy(); + expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy(); } // t.comment('update to latest versions') - prompt.mockClear() + prompt.mockClear(); await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -146,7 +146,7 @@ test('interactively update', async () => { latest: true, linkWorkspacePackages: true, storeDir, - }) + }); expect(prompt.mock.calls[0][0].choices).toStrictEqual([ { @@ -171,7 +171,7 @@ test('interactively update', async () => { name: '[dependencies]', message: 'dependencies', }, - ]) + ]); expect(prompt).toBeCalledWith( expect.objectContaining({ footer: '\nEnter to start updating. Ctrl-c to cancel.', @@ -182,17 +182,17 @@ test('interactively update', async () => { `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }) - ) + }), + ); { - const lockfile = await project.readLockfile() + const lockfile = await project.readLockfile(); - expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy() - expect(lockfile.packages['/is-negative@2.1.0']).toBeTruthy() - expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy() + expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy(); + expect(lockfile.packages['/is-negative@2.1.0']).toBeTruthy(); + expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy(); } -}) +}); test('interactive update of dev dependencies only', async () => { preparePackages([ @@ -210,8 +210,8 @@ test('interactive update of dev dependencies only', async () => { 'is-negative': '^1.0.0', }, }, - ]) - const storeDir = path.resolve('store') + ]); + const storeDir = path.resolve('store'); prompt.mockResolvedValue({ updateDependencies: [ @@ -220,12 +220,12 @@ test('interactive update of dev dependencies only', async () => { name: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} https://pnpm.io/ `, }, ], - }) + }); const { allProjects, selectedProjectsGraph } = await readProjects( process.cwd(), - [] - ) + [], + ); await install.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -237,7 +237,7 @@ test('interactive update of dev dependencies only', async () => { selectedProjectsGraph, storeDir, workspaceDir: process.cwd(), - }) + }); await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -256,15 +256,15 @@ test('interactive update of dev dependencies only', async () => { selectedProjectsGraph, storeDir, workspaceDir: process.cwd(), - }) + }); - const lockfile = await readYamlFile('pnpm-lock.yaml') + const lockfile = await readYamlFile('pnpm-lock.yaml'); expect(Object.keys(lockfile.packages ?? {})).toStrictEqual([ '/is-negative@1.0.1', '/is-negative@2.1.0', - ]) -}) + ]); +}); test('interactively update should ignore dependencies from the ignoreDependencies field', async () => { const project = prepare({ @@ -281,9 +281,9 @@ test('interactively update should ignore dependencies from the ignoreDependencie ignoreDependencies: ['is-negative'], }, }, - }) + }); - const storeDir = path.resolve('pnpm-store') + const storeDir = path.resolve('pnpm-store'); await add.handler( { @@ -294,14 +294,14 @@ test('interactively update should ignore dependencies from the ignoreDependencie save: false, storeDir, }, - ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'] - ) + ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'], + ); prompt.mockResolvedValue({ updateDependencies: [{ value: 'micromatch', name: 'anything' }], - }) + }); - prompt.mockClear() + prompt.mockClear(); await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -309,29 +309,27 @@ test('interactively update should ignore dependencies from the ignoreDependencie interactive: true, linkWorkspacePackages: true, storeDir, - }) + }); - expect(prompt.mock.calls[0][0].choices).toStrictEqual( - [ - { - choices: [ - { - disabled: true, - hint: '', - name: 'Package Current Target URL ', - value: '', - }, - { - message: chalk`micromatch 3.0.0 ❯ 3.{yellowBright.bold 1.10} `, - value: 'micromatch', - name: 'micromatch', - }, - ], - name: '[dependencies]', - message: 'dependencies', - }, - ] - ) + expect(prompt.mock.calls[0][0].choices).toStrictEqual([ + { + choices: [ + { + disabled: true, + hint: '', + name: 'Package Current Target URL ', + value: '', + }, + { + message: chalk`micromatch 3.0.0 ❯ 3.{yellowBright.bold 1.10} `, + value: 'micromatch', + name: 'micromatch', + }, + ], + name: '[dependencies]', + message: 'dependencies', + }, + ]); expect(prompt).toBeCalledWith( expect.objectContaining({ @@ -343,25 +341,25 @@ test('interactively update should ignore dependencies from the ignoreDependencie `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }) - ) + }), + ); { - const lockfile = await project.readLockfile() + const lockfile = await project.readLockfile(); - expect(lockfile.packages['/micromatch@3.1.10']).toBeTruthy() - expect(lockfile.packages['/is-negative@1.0.0']).toBeTruthy() - expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy() + expect(lockfile.packages['/micromatch@3.1.10']).toBeTruthy(); + expect(lockfile.packages['/is-negative@1.0.0']).toBeTruthy(); + expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy(); } -}) +}); test('interactively update should update corepack config', async () => { prepare({ name: 'project-1', packageManager: 'pnpm@8.7.0', - }) + }); - const storeDir = path.resolve('pnpm-store') + const storeDir = path.resolve('pnpm-store'); await add.handler( { @@ -372,8 +370,8 @@ test('interactively update should update corepack config', async () => { save: false, storeDir, }, - ['pnpm@8.9.2'] - ) + ['pnpm@8.9.2'], + ); prompt.mockResolvedValue({ updateDependencies: [ @@ -382,9 +380,9 @@ test('interactively update should update corepack config', async () => { name: chalk`pnpm 8.7.0 ❯ 8.9.2 https://pnpm.io/ `, }, ], - }) + }); - prompt.mockClear() + prompt.mockClear(); await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -392,15 +390,15 @@ test('interactively update should update corepack config', async () => { interactive: true, linkWorkspacePackages: true, storeDir, - }) + }); - const promptStr = JSON.stringify(prompt.mock.calls[0][0].choices[0]) - const latestVersionIndex = promptStr.indexOf('❯') + const promptStr = JSON.stringify(prompt.mock.calls[0][0].choices[0]); + const latestVersionIndex = promptStr.indexOf('❯'); const latestVersion = promptStr.substring( latestVersionIndex + 2, - latestVersionIndex + 7 - ) - const promptChoices = JSON.parse(promptStr.replace(latestVersion, '8.9.0')) + latestVersionIndex + 10, + ); + const promptChoices = JSON.parse(promptStr.replace(latestVersion, '8.9.0')); expect(promptChoices).toMatchInlineSnapshot(` { @@ -412,7 +410,7 @@ test('interactively update should update corepack config', async () => { "value": "", }, { - "message": "pnpm 8.7.0 ❯ 8.9.0 ", + "message": "pnpm 8.7.0 ❯ 8.9.0 ", "name": "pnpm", "value": "pnpm", }, @@ -420,7 +418,7 @@ test('interactively update should update corepack config', async () => { "message": "packageManager", "name": "[packageManager]", } - `) + `); expect(prompt).toBeCalledWith( expect.objectContaining({ footer: '\nEnter to start updating. Ctrl-c to cancel.', @@ -431,6 +429,6 @@ test('interactively update should update corepack config', async () => { `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }) - ) -}) + }), + ); +}); From 605f98cf4ee27e40e16895d56da44966e4143b40 Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Sun, 29 Oct 2023 10:27:50 +0800 Subject: [PATCH 3/5] fix: lint --- .../test/update/interactive.ts | 158 +++++++++--------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/pkg-manager/plugin-commands-installation/test/update/interactive.ts b/pkg-manager/plugin-commands-installation/test/update/interactive.ts index 4923129ce46..ca0d27a3347 100644 --- a/pkg-manager/plugin-commands-installation/test/update/interactive.ts +++ b/pkg-manager/plugin-commands-installation/test/update/interactive.ts @@ -1,19 +1,19 @@ -import path from 'path'; -import { readProjects } from '@pnpm/filter-workspace-packages'; -import { type Lockfile } from '@pnpm/lockfile-types'; -import { add, install, update } from '@pnpm/plugin-commands-installation'; -import { prepare, preparePackages } from '@pnpm/prepare'; -import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'; -import readYamlFile from 'read-yaml-file'; -import chalk from 'chalk'; -import * as enquirer from 'enquirer'; - -jest.mock('enquirer', () => ({ prompt: jest.fn() })); +import path from 'path' +import { readProjects } from '@pnpm/filter-workspace-packages' +import { type Lockfile } from '@pnpm/lockfile-types' +import { add, install, update } from '@pnpm/plugin-commands-installation' +import { prepare, preparePackages } from '@pnpm/prepare' +import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock' +import readYamlFile from 'read-yaml-file' +import chalk from 'chalk' +import * as enquirer from 'enquirer' + +jest.mock('enquirer', () => ({ prompt: jest.fn() })) // eslint-disable-next-line const prompt = enquirer.prompt as any; -const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}`; +const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}` const DEFAULT_OPTIONS = { argv: { @@ -41,7 +41,7 @@ const DEFAULT_OPTIONS = { sort: true, userConfig: {}, workspaceConcurrency: 1, -}; +} test('interactively update', async () => { const project = prepare({ @@ -53,16 +53,16 @@ test('interactively update', async () => { // has many versions that satisfy ^3.0.0 micromatch: '^3.0.0', }, - }); + }) - const storeDir = path.resolve('pnpm-store'); + const storeDir = path.resolve('pnpm-store') const headerChoice = { name: 'Package Current Target URL ', disabled: true, hint: '', value: '', - }; + } await add.handler( { @@ -73,8 +73,8 @@ test('interactively update', async () => { save: false, storeDir, }, - ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'], - ); + ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'] + ) prompt.mockResolvedValue({ updateDependencies: [ @@ -83,9 +83,9 @@ test('interactively update', async () => { name: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} https://pnpm.io/ `, }, ], - }); + }) - prompt.mockClear(); + prompt.mockClear() // t.comment('update to compatible versions') await update.handler({ ...DEFAULT_OPTIONS, @@ -94,7 +94,7 @@ test('interactively update', async () => { interactive: true, linkWorkspacePackages: true, storeDir, - }); + }) expect(prompt.mock.calls[0][0].choices).toStrictEqual([ { @@ -114,7 +114,7 @@ test('interactively update', async () => { name: '[dependencies]', message: 'dependencies', }, - ]); + ]) expect(prompt).toBeCalledWith( expect.objectContaining({ footer: '\nEnter to start updating. Ctrl-c to cancel.', @@ -125,19 +125,19 @@ test('interactively update', async () => { `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }), - ); + }) + ) { - const lockfile = await project.readLockfile(); + const lockfile = await project.readLockfile() - expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy(); - expect(lockfile.packages['/is-negative@1.0.1']).toBeTruthy(); - expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy(); + expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy() + expect(lockfile.packages['/is-negative@1.0.1']).toBeTruthy() + expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy() } // t.comment('update to latest versions') - prompt.mockClear(); + prompt.mockClear() await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -146,7 +146,7 @@ test('interactively update', async () => { latest: true, linkWorkspacePackages: true, storeDir, - }); + }) expect(prompt.mock.calls[0][0].choices).toStrictEqual([ { @@ -171,7 +171,7 @@ test('interactively update', async () => { name: '[dependencies]', message: 'dependencies', }, - ]); + ]) expect(prompt).toBeCalledWith( expect.objectContaining({ footer: '\nEnter to start updating. Ctrl-c to cancel.', @@ -182,17 +182,17 @@ test('interactively update', async () => { `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }), - ); + }) + ) { - const lockfile = await project.readLockfile(); + const lockfile = await project.readLockfile() - expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy(); - expect(lockfile.packages['/is-negative@2.1.0']).toBeTruthy(); - expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy(); + expect(lockfile.packages['/micromatch@3.0.0']).toBeTruthy() + expect(lockfile.packages['/is-negative@2.1.0']).toBeTruthy() + expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy() } -}); +}) test('interactive update of dev dependencies only', async () => { preparePackages([ @@ -210,8 +210,8 @@ test('interactive update of dev dependencies only', async () => { 'is-negative': '^1.0.0', }, }, - ]); - const storeDir = path.resolve('store'); + ]) + const storeDir = path.resolve('store') prompt.mockResolvedValue({ updateDependencies: [ @@ -220,12 +220,12 @@ test('interactive update of dev dependencies only', async () => { name: chalk`is-negative 1.0.0 ❯ 1.0.{greenBright.bold 1} https://pnpm.io/ `, }, ], - }); + }) const { allProjects, selectedProjectsGraph } = await readProjects( process.cwd(), - [], - ); + [] + ) await install.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -237,7 +237,7 @@ test('interactive update of dev dependencies only', async () => { selectedProjectsGraph, storeDir, workspaceDir: process.cwd(), - }); + }) await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -256,15 +256,15 @@ test('interactive update of dev dependencies only', async () => { selectedProjectsGraph, storeDir, workspaceDir: process.cwd(), - }); + }) - const lockfile = await readYamlFile('pnpm-lock.yaml'); + const lockfile = await readYamlFile('pnpm-lock.yaml') expect(Object.keys(lockfile.packages ?? {})).toStrictEqual([ '/is-negative@1.0.1', '/is-negative@2.1.0', - ]); -}); + ]) +}) test('interactively update should ignore dependencies from the ignoreDependencies field', async () => { const project = prepare({ @@ -281,9 +281,9 @@ test('interactively update should ignore dependencies from the ignoreDependencie ignoreDependencies: ['is-negative'], }, }, - }); + }) - const storeDir = path.resolve('pnpm-store'); + const storeDir = path.resolve('pnpm-store') await add.handler( { @@ -294,14 +294,14 @@ test('interactively update should ignore dependencies from the ignoreDependencie save: false, storeDir, }, - ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'], - ); + ['is-negative@1.0.0', 'is-positive@2.0.0', 'micromatch@3.0.0'] + ) prompt.mockResolvedValue({ updateDependencies: [{ value: 'micromatch', name: 'anything' }], - }); + }) - prompt.mockClear(); + prompt.mockClear() await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -309,7 +309,7 @@ test('interactively update should ignore dependencies from the ignoreDependencie interactive: true, linkWorkspacePackages: true, storeDir, - }); + }) expect(prompt.mock.calls[0][0].choices).toStrictEqual([ { @@ -329,7 +329,7 @@ test('interactively update should ignore dependencies from the ignoreDependencie name: '[dependencies]', message: 'dependencies', }, - ]); + ]) expect(prompt).toBeCalledWith( expect.objectContaining({ @@ -341,25 +341,25 @@ test('interactively update should ignore dependencies from the ignoreDependencie `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }), - ); + }) + ) { - const lockfile = await project.readLockfile(); + const lockfile = await project.readLockfile() - expect(lockfile.packages['/micromatch@3.1.10']).toBeTruthy(); - expect(lockfile.packages['/is-negative@1.0.0']).toBeTruthy(); - expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy(); + expect(lockfile.packages['/micromatch@3.1.10']).toBeTruthy() + expect(lockfile.packages['/is-negative@1.0.0']).toBeTruthy() + expect(lockfile.packages['/is-positive@2.0.0']).toBeTruthy() } -}); +}) test('interactively update should update corepack config', async () => { prepare({ name: 'project-1', packageManager: 'pnpm@8.7.0', - }); + }) - const storeDir = path.resolve('pnpm-store'); + const storeDir = path.resolve('pnpm-store') await add.handler( { @@ -370,8 +370,8 @@ test('interactively update should update corepack config', async () => { save: false, storeDir, }, - ['pnpm@8.9.2'], - ); + ['pnpm@8.9.2'] + ) prompt.mockResolvedValue({ updateDependencies: [ @@ -380,9 +380,9 @@ test('interactively update should update corepack config', async () => { name: chalk`pnpm 8.7.0 ❯ 8.9.2 https://pnpm.io/ `, }, ], - }); + }) - prompt.mockClear(); + prompt.mockClear() await update.handler({ ...DEFAULT_OPTIONS, cacheDir: path.resolve('cache'), @@ -390,15 +390,15 @@ test('interactively update should update corepack config', async () => { interactive: true, linkWorkspacePackages: true, storeDir, - }); + }) - const promptStr = JSON.stringify(prompt.mock.calls[0][0].choices[0]); - const latestVersionIndex = promptStr.indexOf('❯'); + const promptStr = JSON.stringify(prompt.mock.calls[0][0].choices[0]) + const latestVersionIndex = promptStr.indexOf('❯') const latestVersion = promptStr.substring( latestVersionIndex + 2, - latestVersionIndex + 10, - ); - const promptChoices = JSON.parse(promptStr.replace(latestVersion, '8.9.0')); + latestVersionIndex + 10 + ) + const promptChoices = JSON.parse(promptStr.replace(latestVersion, '8.9.0')) expect(promptChoices).toMatchInlineSnapshot(` { @@ -418,7 +418,7 @@ test('interactively update should update corepack config', async () => { "message": "packageManager", "name": "[packageManager]", } - `); + `) expect(prompt).toBeCalledWith( expect.objectContaining({ footer: '\nEnter to start updating. Ctrl-c to cancel.', @@ -429,6 +429,6 @@ test('interactively update should update corepack config', async () => { `${chalk.cyan('')} to invert selection)`, name: 'updateDependencies', type: 'multiselect', - }), - ); -}); + }) + ) +}) From 545a1c8fcc3eff0073bf58ab24431fcfe2597e78 Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Sun, 29 Oct 2023 10:30:38 +0800 Subject: [PATCH 4/5] chore: lint fix --- .../plugin-commands-installation/test/update/interactive.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg-manager/plugin-commands-installation/test/update/interactive.ts b/pkg-manager/plugin-commands-installation/test/update/interactive.ts index ca0d27a3347..b125d021f1f 100644 --- a/pkg-manager/plugin-commands-installation/test/update/interactive.ts +++ b/pkg-manager/plugin-commands-installation/test/update/interactive.ts @@ -10,8 +10,7 @@ import * as enquirer from 'enquirer' jest.mock('enquirer', () => ({ prompt: jest.fn() })) -// eslint-disable-next-line -const prompt = enquirer.prompt as any; +const prompt = enquirer.prompt as any // eslint-disable-line const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}` From 4c9b69f4d4eb3cc503d151da1ec66949c431b261 Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Sun, 29 Oct 2023 10:58:13 +0800 Subject: [PATCH 5/5] chore: add changeset --- .changeset/three-llamas-cheer.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/three-llamas-cheer.md diff --git a/.changeset/three-llamas-cheer.md b/.changeset/three-llamas-cheer.md new file mode 100644 index 00000000000..f77499d67a7 --- /dev/null +++ b/.changeset/three-llamas-cheer.md @@ -0,0 +1,7 @@ +--- +'@pnpm/plugin-commands-installation': patch +'@pnpm/outdated': patch +'@pnpm/plugin-commands-outdated': patch +--- + +feat: support corepack update for pnpm update --interactive