Skip to content

Commit a53ef4d

Browse files
authored
fix: don't print that lockfile is up to date when it is not (pnpm#6574)
close pnpm#6544
1 parent 78e8392 commit a53ef4d

File tree

14 files changed

+67
-62
lines changed

14 files changed

+67
-62
lines changed

.changeset/curly-starfishes-end.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@pnpm/headless": major
3+
"@pnpm/core": patch
4+
"pnpm": patch
5+
---
6+
7+
Don't print "Lockfile is up-to-date" message before finishing all the lockfile checks [#6544](https://github.com/pnpm/pnpm/issues/6544).

.changeset/metal-turkeys-know.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@pnpm/get-context": major
3+
---
4+
5+
New property returned: `existsNonEmptyWantedLockfile`.
6+
The `existsWantedLockfile` now means only that a file existed.

hooks/types/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export interface PreResolutionHookContext {
55
wantedLockfile: Lockfile
66
currentLockfile: Lockfile
77
existsCurrentLockfile: boolean
8-
existsWantedLockfile: boolean
8+
existsNonEmptyWantedLockfile: boolean
99
lockfileDir: string
1010
storeDir: string
1111
registries: Registries

lockfile/lockfile-file/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ if the lockfile file format is not compatible with the current library.
2828

2929
Reads the lockfile file from `<virtualStoreDir>/lock.yaml`.
3030

31-
### `existsWantedLockfile(pkgPath) => Promise<Boolean>`
31+
### `existsNonEmptyWantedLockfile(pkgPath) => Promise<Boolean>`
3232

3333
Returns `true` if a `pnpm-lock.yaml` exists in the root of the package.
3434

lockfile/lockfile-file/src/existsWantedLockfile.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import fs from 'fs'
22
import path from 'path'
33
import { getWantedLockfileName } from './lockfileName'
44

5-
interface ExistsWantedLockfileOptions {
5+
interface existsNonEmptyWantedLockfileOptions {
66
useGitBranchLockfile?: boolean
77
mergeGitBranchLockfiles?: boolean
88
}
99

10-
export async function existsWantedLockfile (pkgPath: string, opts: ExistsWantedLockfileOptions = {
10+
export async function existsNonEmptyWantedLockfile (pkgPath: string, opts: existsNonEmptyWantedLockfileOptions = {
1111
useGitBranchLockfile: false,
1212
mergeGitBranchLockfiles: false,
1313
}) {

lockfile/lockfile-file/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export {
44
writeCurrentLockfile,
55
writeWantedLockfile,
66
} from './write'
7-
export { existsWantedLockfile } from './existsWantedLockfile'
7+
export { existsNonEmptyWantedLockfile } from './existsWantedLockfile'
88
export { getLockfileImporterId } from './getLockfileImporterId'
99
export * from '@pnpm/lockfile-types'
1010
export * from './read'

lockfile/lockfile-file/test/read.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import path from 'path'
22
import { getCurrentBranch } from '@pnpm/git-utils'
33
import {
4-
existsWantedLockfile,
4+
existsNonEmptyWantedLockfile,
55
readCurrentLockfile,
66
readWantedLockfile,
77
writeCurrentLockfile,
@@ -154,9 +154,9 @@ test('writeCurrentLockfile()', async () => {
154154
expect(await readCurrentLockfile(projectPath, { ignoreIncompatible: false })).toEqual(wantedLockfile)
155155
})
156156

157-
test('existsWantedLockfile()', async () => {
157+
test('existsNonEmptyWantedLockfile()', async () => {
158158
const projectPath = tempy.directory()
159-
expect(await existsWantedLockfile(projectPath)).toBe(false)
159+
expect(await existsNonEmptyWantedLockfile(projectPath)).toBe(false)
160160
await writeWantedLockfile(projectPath, {
161161
importers: {
162162
'.': {
@@ -192,7 +192,7 @@ test('existsWantedLockfile()', async () => {
192192
},
193193
},
194194
})
195-
expect(await existsWantedLockfile(projectPath)).toBe(true)
195+
expect(await existsNonEmptyWantedLockfile(projectPath)).toBe(true)
196196
})
197197

198198
test('readWantedLockfile() when useGitBranchLockfile', async () => {

pkg-manager/core/src/install/index.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
type PatchFile,
3333
} from '@pnpm/lockfile-file'
3434
import { writePnpFile } from '@pnpm/lockfile-to-pnp'
35-
import { extendProjectsWithTargetDirs } from '@pnpm/lockfile-utils'
35+
import { extendProjectsWithTargetDirs, satisfiesPackageManifest } from '@pnpm/lockfile-utils'
3636
import { logger, globalInfo, streamParser } from '@pnpm/logger'
3737
import { getAllDependenciesFromManifest } from '@pnpm/manifest-utils'
3838
import { writeModulesManifest } from '@pnpm/modules-yaml'
@@ -251,7 +251,7 @@ export async function mutateModules (
251251
currentLockfile: ctx.currentLockfile,
252252
wantedLockfile: ctx.wantedLockfile,
253253
existsCurrentLockfile: ctx.existsCurrentLockfile,
254-
existsWantedLockfile: ctx.existsWantedLockfile,
254+
existsNonEmptyWantedLockfile: ctx.existsNonEmptyWantedLockfile,
255255
lockfileDir: ctx.lockfileDir,
256256
storeDir: ctx.storeDir,
257257
registries: ctx.registries,
@@ -327,7 +327,7 @@ export async function mutateModules (
327327
}), patchedDependencies)
328328
: undefined
329329
const frozenLockfile = opts.frozenLockfile ||
330-
opts.frozenLockfileIfExists && ctx.existsWantedLockfile
330+
opts.frozenLockfileIfExists && ctx.existsNonEmptyWantedLockfile
331331
let outdatedLockfileSettings = false
332332
if (!opts.ignorePackageManifest) {
333333
const outdatedLockfileSettingName = getOutdatedLockfileSetting(ctx.wantedLockfile, {
@@ -375,7 +375,7 @@ export async function mutateModules (
375375
!needsFullResolution &&
376376
opts.preferFrozenLockfile &&
377377
(!opts.pruneLockfileImporters || Object.keys(ctx.wantedLockfile.importers).length === Object.keys(ctx.projects).length) &&
378-
ctx.existsWantedLockfile &&
378+
ctx.existsNonEmptyWantedLockfile &&
379379
(
380380
ctx.wantedLockfile.lockfileVersion === LOCKFILE_VERSION ||
381381
ctx.wantedLockfile.lockfileVersion === LOCKFILE_VERSION_V6
@@ -401,14 +401,39 @@ Note that in CI environments, this setting is enabled by default.`,
401401
}
402402
)
403403
}
404+
if (!opts.ignorePackageManifest) {
405+
const _satisfiesPackageManifest = satisfiesPackageManifest.bind(null, {
406+
autoInstallPeers: opts.autoInstallPeers,
407+
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
408+
})
409+
for (const { id, manifest, rootDir } of Object.values(ctx.projects)) {
410+
const { satisfies, detailedReason } = _satisfiesPackageManifest(ctx.wantedLockfile.importers[id], manifest)
411+
if (!satisfies) {
412+
if (!ctx.existsWantedLockfile) {
413+
throw new PnpmError('NO_LOCKFILE',
414+
`Cannot install with "frozen-lockfile" because ${WANTED_LOCKFILE} is present`, {
415+
hint: 'Note that in CI environments this setting is true by default. If you still need to run install in such cases, use "pnpm install --no-frozen-lockfile"',
416+
})
417+
}
418+
throw new PnpmError('OUTDATED_LOCKFILE',
419+
`Cannot install with "frozen-lockfile" because ${WANTED_LOCKFILE} is not up to date with ` +
420+
path.relative(opts.lockfileDir, path.join(rootDir, 'package.json')), {
421+
hint: `Note that in CI environments this setting is true by default. If you still need to run install in such cases, use "pnpm install --no-frozen-lockfile"
422+
423+
Failure reason:
424+
${detailedReason ?? ''}`,
425+
})
426+
}
427+
}
428+
}
404429
if (opts.lockfileOnly) {
405430
// The lockfile will only be changed if the workspace will have new projects with no dependencies.
406431
await writeWantedLockfile(ctx.lockfileDir, ctx.wantedLockfile)
407432
return {
408433
updatedProjects: projects.map((mutatedProject) => ctx.projects[mutatedProject.rootDir]),
409434
}
410435
}
411-
if (!ctx.existsWantedLockfile) {
436+
if (!ctx.existsNonEmptyWantedLockfile) {
412437
if (Object.values(ctx.projects).some((project) => pkgHasDependencies(project.manifest))) {
413438
throw new Error(`Headless installation requires a ${WANTED_LOCKFILE} file`)
414439
}
@@ -463,7 +488,7 @@ Note that in CI environments, this setting is enabled by default.`,
463488
error.code !== 'ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY' &&
464489
!BROKEN_LOCKFILE_INTEGRITY_ERRORS.has(error.code)
465490
) ||
466-
(!ctx.existsWantedLockfile && !ctx.existsCurrentLockfile)
491+
(!ctx.existsNonEmptyWantedLockfile && !ctx.existsCurrentLockfile)
467492
) throw error
468493
if (BROKEN_LOCKFILE_INTEGRITY_ERRORS.has(error.code)) {
469494
needsFullResolution = true
@@ -641,12 +666,12 @@ Note that in CI environments, this setting is enabled by default.`,
641666
// Unfortunately, the private lockfile may differ from the public one.
642667
// A user might run named installations on a project that has a pnpm-lock.yaml file before running a noop install
643668
const makePartialCurrentLockfile = !installsOnly && (
644-
ctx.existsWantedLockfile && !ctx.existsCurrentLockfile ||
669+
ctx.existsNonEmptyWantedLockfile && !ctx.existsCurrentLockfile ||
645670
!ctx.currentLockfileIsUpToDate
646671
)
647672
const result = await installInContext(projectsToInstall, ctx, {
648673
...opts,
649-
currentLockfileIsUpToDate: !ctx.existsWantedLockfile || ctx.currentLockfileIsUpToDate,
674+
currentLockfileIsUpToDate: !ctx.existsNonEmptyWantedLockfile || ctx.currentLockfileIsUpToDate,
650675
makePartialCurrentLockfile,
651676
needsFullResolution,
652677
pruneVirtualStore,
@@ -1377,7 +1402,7 @@ const installInContext: InstallFunction = async (projects, ctx, opts) => {
13771402
} catch (error: any) { // eslint-disable-line
13781403
if (
13791404
!BROKEN_LOCKFILE_INTEGRITY_ERRORS.has(error.code) ||
1380-
(!ctx.existsWantedLockfile && !ctx.existsCurrentLockfile)
1405+
(!ctx.existsNonEmptyWantedLockfile && !ctx.existsCurrentLockfile)
13811406
) throw error
13821407
opts.needsFullResolution = true
13831408
// Ideally, we would not update but currently there is no other way to redownload the integrity of the package

pkg-manager/core/test/install/frozenLockfile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ test(`frozen-lockfile: should fail if no ${WANTED_LOCKFILE} is present`, async (
124124
'is-positive': '^3.0.0',
125125
},
126126
}, await testDefaults({ frozenLockfile: true }))
127-
).rejects.toThrow(`Headless installation requires a ${WANTED_LOCKFILE} file`)
127+
).rejects.toThrow(`Cannot install with "frozen-lockfile" because ${WANTED_LOCKFILE} is present`)
128128
})
129129

130130
test(`prefer-frozen-lockfile: should prefer headless installation when ${WANTED_LOCKFILE} satisfies package.json`, async () => {

pkg-manager/get-context/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface PnpmContext {
3434
currentLockfileIsUpToDate: boolean
3535
existsCurrentLockfile: boolean
3636
existsWantedLockfile: boolean
37+
existsNonEmptyWantedLockfile: boolean
3738
extraBinPaths: string[]
3839
extraNodePaths: string[]
3940
lockfileHadConflicts: boolean
@@ -383,6 +384,7 @@ export interface PnpmSingleContext {
383384
currentLockfileIsUpToDate: boolean
384385
existsCurrentLockfile: boolean
385386
existsWantedLockfile: boolean
387+
existsNonEmptyWantedLockfile: boolean
386388
extraBinPaths: string[]
387389
extraNodePaths: string[]
388390
lockfileHadConflicts: boolean

0 commit comments

Comments
 (0)