fix(prune): should work in a workspace (#4691)

close #4647
This commit is contained in:
Zoltan Kochan
2022-05-07 04:10:05 +03:00
committed by GitHub
parent bf6839a556
commit 0075fcd234
10 changed files with 74 additions and 29 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-installation": patch
"pnpm": patch
---
`pnpm prune` works in a workspace [#4647](https://github.com/pnpm/pnpm/pull/4691).

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-installation": patch
"pnpm": patch
---
`pnpm prune` does not remove hoisted dependencies.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/modules-cleaner": patch
---
Do not remove hoisted dependencies, when pruneDirectDependencies is set to `true`.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/core": minor
---
The `install()` function accepts the `pruneDirectDependencies` option.

View File

@@ -119,6 +119,7 @@ export async function install (
manifest: ProjectManifest,
opts: InstallOptions & {
preferredVersions?: PreferredVersions
pruneDirectDependencies?: boolean
}
) {
const projects = await mutateModules(
@@ -127,6 +128,7 @@ export async function install (
buildIndex: 0,
manifest,
mutation: 'install',
pruneDirectDependencies: opts.pruneDirectDependencies,
rootDir: opts.dir ?? process.cwd(),
},
],

View File

@@ -74,10 +74,11 @@ export default async function prune (
...difference(currentPkgs, wantedPkgs).map(([depName]) => depName),
])
if (pruneDirectDependencies) {
const publiclyHoistedDeps = getPubliclyHoistedDependencies(opts.hoistedDependencies)
if (allCurrentPackages.size > 0) {
const newPkgsSet = new Set<string>(wantedPkgs.map(([depName]) => depName))
for (const currentPackage of Array.from(allCurrentPackages)) {
if (!newPkgsSet.has(currentPackage)) {
if (!newPkgsSet.has(currentPackage) && !publiclyHoistedDeps.has(currentPackage)) {
depsToRemove.add(currentPackage)
}
}
@@ -245,3 +246,15 @@ function getPkgsDepPathsOwnedOnlyByImporters (
const packagesOfSelectedOnly = pickAll(difference(Object.keys(selected.packages!), Object.keys(other.packages!)), selected.packages!) as PackageSnapshots
return getPkgsDepPaths(registries, packagesOfSelectedOnly, skipped)
}
function getPubliclyHoistedDependencies (hoistedDependencies: HoistedDependencies): Set<string> {
const publiclyHoistedDeps = new Set<string>()
for (const hoistedAliases of Object.values(hoistedDependencies)) {
for (const [alias, hoistType] of Object.entries(hoistedAliases)) {
if (hoistType === 'public') {
publiclyHoistedDeps.add(alias)
}
}
}
return publiclyHoistedDeps
}

View File

@@ -274,9 +274,11 @@ export type InstallCommandOptions = Pick<Config,
}
fixLockfile?: boolean
useBetaCli?: boolean
pruneDirectDependencies?: boolean
pruneStore?: boolean
recursive?: boolean
workspace?: boolean
} & Partial<Pick<Config, 'pnpmHomeDir' | 'preferWorkspacePackages'>>
} & Partial<Pick<Config, 'modulesCacheMaxAge' | 'pnpmHomeDir' | 'preferWorkspacePackages'>>
export async function handler (
opts: InstallCommandOptions

View File

@@ -1,11 +1,9 @@
import { docsUrl, readProjectManifestOnly } from '@pnpm/cli-utils'
import { docsUrl } from '@pnpm/cli-utils'
import { UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
import { Config, types as allTypes } from '@pnpm/config'
import { createOrConnectStoreController, CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
import { InstallOptions, mutateModules } from '@pnpm/core'
import { types as allTypes } from '@pnpm/config'
import pick from 'ramda/src/pick'
import renderHelp from 'render-help'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
import * as install from './install'
export const rcOptionsTypes = cliOptionsTypes
@@ -45,29 +43,12 @@ export function help () {
}
export async function handler (
opts: Pick<Config, 'dev' | 'engineStrict' | 'optional' | 'production' | 'rootProjectManifest'> & CreateStoreControllerOptions
opts: install.InstallCommandOptions
) {
const store = await createOrConnectStoreController(opts)
const manifest = await readProjectManifestOnly(process.cwd(), opts)
return mutateModules([
{
buildIndex: 0,
manifest,
mutation: 'install',
pruneDirectDependencies: true,
rootDir: process.cwd(),
},
], {
return install.handler({
...opts,
...getOptionsFromRootManifest(opts.rootProjectManifest ?? {}),
include: {
dependencies: opts.production !== false,
devDependencies: opts.dev !== false,
optionalDependencies: opts.optional !== false,
},
modulesCacheMaxAge: 0,
pruneDirectDependencies: true,
pruneStore: true,
storeController: store.ctrl,
storeDir: store.dir,
} as InstallOptions)
})
}

View File

@@ -80,6 +80,7 @@ type RecursiveOptions = CreateStoreControllerOptions & Pick<Config,
useBetaCli?: boolean
selectedProjectsGraph: ProjectsGraph
preferredVersions?: PreferredVersions
pruneDirectDependencies?: boolean
} & Partial<
Pick<Config,
| 'sort'
@@ -258,6 +259,7 @@ export default async function recursive (
manifest,
modulesDir,
mutation,
pruneDirectDependencies: opts.pruneDirectDependencies,
rootDir,
} as MutatedProject)
}

View File

@@ -1,5 +1,5 @@
import path from 'path'
import { install, link, prune } from '@pnpm/plugin-commands-installation'
import { add, install, link, prune } from '@pnpm/plugin-commands-installation'
import prepare from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import fixtures from '@pnpm/test-fixtures'
@@ -20,6 +20,7 @@ const DEFAULT_OPTIONS = {
optionalDependencies: true,
},
lock: true,
linkWorkspacePackages: true,
pnpmfile: '.pnpmfile.cjs',
pnpmHomeDir: '',
rawConfig: { registry: REGISTRY_URL },
@@ -56,6 +57,28 @@ test('prune removes external link that is not in package.json', async () => {
await project.hasNot('local-pkg')
})
test('prune keeps hoisted dependencies', async () => {
const project = prepare(undefined)
const storeDir = path.resolve('store')
const cacheDir = path.resolve('cache')
await add.handler({
...DEFAULT_OPTIONS,
cacheDir,
dir: process.cwd(),
storeDir,
}, ['pkg-with-1-dep@100.0.0'])
await prune.handler({
...DEFAULT_OPTIONS,
cacheDir,
dir: process.cwd(),
storeDir,
})
await project.hasNot('dep-of-pkg-with-1-dep')
})
test('prune removes dev dependencies', async () => {
const project = prepare({
dependencies: { 'is-positive': '1.0.0' },