fix: fail incompatible lockfile in frozen CI mode (#10978)

* fix(lockfile): fail incompatible lockfile in frozen CI

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: zubeyralmaho <zubeyralmaho@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
zybo
2026-03-17 03:47:13 +03:00
committed by GitHub
parent 672e58c285
commit 5d130c3aed
3 changed files with 54 additions and 4 deletions

View File

@@ -0,0 +1,6 @@
---
'@pnpm/get-context': patch
pnpm: patch
---
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled, while preserving non-frozen CI fallback behavior.

View File

@@ -53,10 +53,11 @@ export async function readLockfiles (
lockfileHadConflicts: boolean
}> {
const wantedLockfileVersion = LOCKFILE_VERSION
// ignore `pnpm-lock.yaml` on CI servers
// a latest pnpm should not break all the builds
// On CI, avoid breaking builds due to incompatible lockfiles by default.
// Ignore incompatible lockfiles only for non-frozen CI installs or when `force` is set;
// in frozen-lockfile mode, incompatible lockfiles should still fail.
const lockfileOpts = {
ignoreIncompatible: opts.force || opts.ci === true,
ignoreIncompatible: opts.force || (opts.ci === true && !opts.frozenLockfile),
wantedVersions: [LOCKFILE_VERSION],
useGitBranchLockfile: opts.useGitBranchLockfile,
mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,

View File

@@ -1,10 +1,13 @@
/// <reference path="../../../__typings__/index.d.ts"/>
import { promises as fs } from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { arrayOfWorkspacePackagesToMap, getContext } from '@pnpm/get-context'
import type { ProjectRootDir } from '@pnpm/types'
import type { ProjectId, ProjectRootDir } from '@pnpm/types'
import type { GetContextOptions } from '../src/index.js'
import { readLockfiles } from '../src/readLockfiles.js'
const DEFAULT_OPTIONS: GetContextOptions = {
allProjects: [],
@@ -58,3 +61,43 @@ test('arrayOfWorkspacePackagesToMap() treats private packages with no version as
])],
]))
})
test('readLockfiles() throws on incompatible lockfile in CI when frozenLockfile is true', async () => {
const lockfileDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pnpm-get-context-'))
await fs.writeFile(path.join(lockfileDir, 'pnpm-lock.yaml'), 'lockfileVersion: 1.0\nimporters:\n .:\n specifiers: {}\n')
await expect(readLockfiles({
autoInstallPeers: true,
excludeLinksFromLockfile: false,
peersSuffixMaxLength: 1000,
ci: true,
force: false,
frozenLockfile: true,
projects: [{ id: '.' as ProjectId, rootDir: lockfileDir as ProjectRootDir }],
lockfileDir,
registry: 'https://registry.npmjs.org/',
useLockfile: true,
internalPnpmDir: path.join(lockfileDir, 'node_modules', '.pnpm'),
})).rejects.toMatchObject({ code: 'ERR_PNPM_LOCKFILE_BREAKING_CHANGE' })
})
test('readLockfiles() ignores incompatible lockfile in CI when frozenLockfile is false', async () => {
const lockfileDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pnpm-get-context-'))
await fs.writeFile(path.join(lockfileDir, 'pnpm-lock.yaml'), 'lockfileVersion: 1.0\nimporters:\n .:\n specifiers: {}\n')
const context = await readLockfiles({
autoInstallPeers: true,
excludeLinksFromLockfile: false,
peersSuffixMaxLength: 1000,
ci: true,
force: false,
frozenLockfile: false,
projects: [{ id: '.' as ProjectId, rootDir: lockfileDir as ProjectRootDir }],
lockfileDir,
registry: 'https://registry.npmjs.org/',
useLockfile: true,
internalPnpmDir: path.join(lockfileDir, 'node_modules', '.pnpm'),
})
expect(context.existsWantedLockfile).toBe(false)
})