fix: broken lockfile in some cases

close #2919
PR #2920
This commit is contained in:
Zoltan Kochan
2020-10-11 19:47:59 +03:00
committed by GitHub
parent 005d5ad461
commit ddd98dd740
5 changed files with 114 additions and 4 deletions

View File

@@ -0,0 +1,33 @@
---
"@pnpm/resolve-dependencies": patch
"supi": patch
---
The lockfile should be correctly updated when a direct dependency that has peer dependencies has a new version specifier in `package.json`.
For instance, `jest@26` has `cascade@2` in its peer dependencies. So `pnpm install` will scope Jest to some version of cascade. This is how it will look like in `pnpm-lock.yaml`:
```yaml
dependencies:
canvas: 2.6.0
jest: 26.4.0_canvas@2.6.0
```
If the version specifier of Jest gets changed in the `package.json` to `26.5.0`, the next time `pnpm install` is executed, the lockfile should be changed to this:
```yaml
dependencies:
canvas: 2.6.0
jest: 26.5.0_canvas@2.6.0
```
Prior to this fix, after the update, Jest was not scoped with canvas, so the lockfile was incorrectly updated to the following:
```yaml
dependencies:
canvas: 2.6.0
jest: 26.5.0
```
Related issue: [#2919](https://github.com/pnpm/pnpm/issues/2919).
Related PR: [#2920](https://github.com/pnpm/pnpm/pull/2920).

View File

@@ -3,6 +3,7 @@ import './add'
import './addRecursive'
import './linkRecursive'
import './miscRecursive'
import './peerDependencies'
import './prune'
import './remove/completion'
import './remove/remove'

View File

@@ -0,0 +1,68 @@
import { add, install } from '@pnpm/plugin-commands-installation'
import prepare from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import test = require('tape')
import tempy = require('tempy')
const REGISTRY_URL = `http://localhost:${REGISTRY_MOCK_PORT}`
const DEFAULT_OPTIONS = {
argv: {
original: [],
},
bail: false,
cliOptions: {},
include: {
dependencies: true,
devDependencies: true,
optionalDependencies: true,
},
lock: true,
pnpmfile: 'pnpmfile.js',
rawConfig: { registry: REGISTRY_URL },
rawLocalConfig: { registry: REGISTRY_URL },
registries: {
default: REGISTRY_URL,
},
sort: true,
storeDir: tempy.directory(),
workspaceConcurrency: 1,
}
test('root dependency that has a peer is correctly updated after its version changes', async (t) => {
const project = prepare(t, {})
await add.handler({
...DEFAULT_OPTIONS,
dir: process.cwd(),
linkWorkspacePackages: true,
}, ['ajv@4.10.4', 'ajv-keywords@1.5.0'])
{
const lockfile = await project.readLockfile()
t.equal(lockfile.dependencies['ajv-keywords'], '1.5.0_ajv@4.10.4')
}
await project.writePackageJson({
dependencies: {
ajv: '4.10.4',
'ajv-keywords': '1.5.1',
},
})
await install.handler({
...DEFAULT_OPTIONS,
dir: process.cwd(),
linkWorkspacePackages: true,
rawLocalConfig: {
'frozen-lockfile': false,
},
})
{
const lockfile = await project.readLockfile()
t.equal(lockfile.dependencies['ajv-keywords'], '1.5.1_ajv@4.10.4')
}
t.end()
})

View File

@@ -358,7 +358,7 @@ function getDepsToResolve (
// The only reason we resolve children in case the package depends on peers
// is to get information about the existing dependencies, so that they can
// be merged with the resolved peers.
const proceedAll = options.proceed
let proceedAll = options.proceed
const allPeers = new Set<string>()
for (const wantedDependency of wantedDependencies) {
let reference = wantedDependency.alias && resolvedDependencies[wantedDependency.alias]
@@ -394,6 +394,15 @@ function getDepsToResolve (
allPeers.add(peerName)
})
}
if (!infoFromLockfile && !proceedAll) {
// In this case we don't know if the package depends on peer dependencies, so we proceed all.
proceedAll = true
for (const extendedWantedDep of extendedWantedDeps) {
if (!extendedWantedDep.proceed) {
extendedWantedDep.proceed = true
}
}
}
extendedWantedDeps.push({
infoFromLockfile,
proceed,

View File

@@ -850,7 +850,7 @@ async function toResolveImporter (
project: ImporterToUpdate
) {
const allDeps = getWantedDependencies(project.manifest)
const { linkedAliases, nonLinkedDependencies } = await partitionLinkedPackages(allDeps, {
const { nonLinkedDependencies } = await partitionLinkedPackages(allDeps, {
lockfileOnly: opts.lockfileOnly,
modulesDir: project.modulesDir,
projectDir: project.rootDir,
@@ -890,8 +890,7 @@ async function toResolveImporter (
...project,
hasRemovedDependencies: Boolean(project.removePackages?.length),
preferredVersions: opts.preferredVersions ?? (project.manifest && getPreferredVersionsFromPackage(project.manifest)) ?? {},
wantedDependencies: wantedDependencies
.filter(({ alias, updateDepth }) => updateDepth >= 0 || !linkedAliases.has(alias)),
wantedDependencies,
}
}