mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
feat: include some settings as fields in the lockfile (#6557)
ref #6312
This commit is contained in:
15
.changeset/fast-news-deliver.md
Normal file
15
.changeset/fast-news-deliver.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
"@pnpm/lockfile-types": minor
|
||||
"@pnpm/lockfile-file": minor
|
||||
"@pnpm/core": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Some settings influence the structure of the lockfile, so we cannot reuse the lockfile if those settings change. As a result, we need to store such settings in the lockfile. This way we will know with which settings the lockfile has been created.
|
||||
|
||||
A new field will now be present in the lockfile: `settings`. It will store the values of two settings: `autoInstallPeers` and `excludeLinksFromLockfile`. If someone tries to perform a `frozen-lockfile` installation and their active settings don't match the ones in the lockfile, then an error message will be thrown.
|
||||
|
||||
The lockfile format version is bumped from v6.0 to v6.1.
|
||||
|
||||
Related PR: [#6557](https://github.com/pnpm/pnpm/pull/6557)
|
||||
Related issue: [#6312](https://github.com/pnpm/pnpm/issues/6312)
|
||||
5
.changeset/itchy-moons-approve.md
Normal file
5
.changeset/itchy-moons-approve.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/lockfile-file": patch
|
||||
---
|
||||
|
||||
Convertion should work for all lockfile v6 formats, not just 6.0.
|
||||
5
.changeset/sharp-trees-pretend.md
Normal file
5
.changeset/sharp-trees-pretend.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/constants": minor
|
||||
---
|
||||
|
||||
Bump lockfile v6 version to v6.1.
|
||||
5
.changeset/short-coats-fetch.md
Normal file
5
.changeset/short-coats-fetch.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-patching": patch
|
||||
---
|
||||
|
||||
Don't run install with the `frozen-lockfile=true` setting.
|
||||
7
.changeset/tender-candles-sleep.md
Normal file
7
.changeset/tender-candles-sleep.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-rebuild": major
|
||||
"@pnpm/plugin-commands-store": major
|
||||
"@pnpm/get-context": major
|
||||
---
|
||||
|
||||
New required options added: autoInstallPeers and excludeLinksFromLockfile.
|
||||
2
__fixtures__/empty/pnpm-lock.yaml
generated
2
__fixtures__/empty/pnpm-lock.yaml
generated
@@ -1 +1 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
2
__fixtures__/local-pkg/pnpm-lock.yaml
generated
2
__fixtures__/local-pkg/pnpm-lock.yaml
generated
@@ -1 +1 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
2
__fixtures__/local-scoped-pkg/pnpm-lock.yaml
generated
2
__fixtures__/local-scoped-pkg/pnpm-lock.yaml
generated
@@ -1 +1 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
@@ -1 +1 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
2
__fixtures__/pnpm-lock.yaml
generated
2
__fixtures__/pnpm-lock.yaml
generated
@@ -1 +1 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
2
__fixtures__/tar-pkg/pnpm-lock.yaml
generated
2
__fixtures__/tar-pkg/pnpm-lock.yaml
generated
@@ -1 +1 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@ import { type Registries } from '@pnpm/types'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
|
||||
export interface StrictRebuildOptions {
|
||||
autoInstallPeers: boolean
|
||||
cacheDir: string
|
||||
childConcurrency: number
|
||||
excludeLinksFromLockfile: boolean
|
||||
extraBinPaths: string[]
|
||||
extraEnv: Record<string, string>
|
||||
lockfileDir: string
|
||||
|
||||
@@ -113,7 +113,7 @@ export function revertFromInlineSpecifiersFormat (lockfile: InlineSpecifiersLock
|
||||
|
||||
let revertedImporters = mapValues(importers, revertProjectSnapshot)
|
||||
let packages = lockfile.packages
|
||||
if (originalVersion === 6) {
|
||||
if (originalVersionStr.startsWith('6.')) {
|
||||
revertedImporters = Object.fromEntries(
|
||||
Object.entries(revertedImporters ?? {})
|
||||
.map(([importerId, pkgSnapshot]: [string, ProjectSnapshot]) => {
|
||||
@@ -150,7 +150,7 @@ export function revertFromInlineSpecifiersFormat (lockfile: InlineSpecifiersLock
|
||||
packages,
|
||||
importers: revertedImporters,
|
||||
}
|
||||
if (originalVersion === 6 && newLockfile.time) {
|
||||
if (originalVersionStr.startsWith('6.') && newLockfile.time) {
|
||||
newLockfile.time = Object.fromEntries(
|
||||
Object.entries(newLockfile.time)
|
||||
.map(([depPath, time]) => [convertLockfileV6DepPathToV5DepPath(depPath), time])
|
||||
|
||||
@@ -136,6 +136,8 @@ export function createLockfileObject (
|
||||
importerIds: string[],
|
||||
opts: {
|
||||
lockfileVersion: number | string
|
||||
autoInstallPeers: boolean
|
||||
excludeLinksFromLockfile: boolean
|
||||
}
|
||||
) {
|
||||
const importers = importerIds.reduce((acc, importerId) => {
|
||||
@@ -148,6 +150,10 @@ export function createLockfileObject (
|
||||
return {
|
||||
importers,
|
||||
lockfileVersion: opts.lockfileVersion || LOCKFILE_VERSION,
|
||||
settings: {
|
||||
autoInstallPeers: opts.autoInstallPeers,
|
||||
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,12 +33,13 @@ const ORDERED_KEYS = {
|
||||
|
||||
const ROOT_KEYS_ORDER = {
|
||||
lockfileVersion: 1,
|
||||
settings: 2,
|
||||
// only and never are conflict options.
|
||||
neverBuiltDependencies: 2,
|
||||
onlyBuiltDependencies: 2,
|
||||
overrides: 3,
|
||||
packageExtensionsChecksum: 4,
|
||||
patchedDependencies: 5,
|
||||
neverBuiltDependencies: 3,
|
||||
onlyBuiltDependencies: 3,
|
||||
overrides: 4,
|
||||
packageExtensionsChecksum: 5,
|
||||
patchedDependencies: 6,
|
||||
specifiers: 10,
|
||||
dependencies: 11,
|
||||
optionalDependencies: 12,
|
||||
|
||||
@@ -2,6 +2,11 @@ import { type DependenciesMeta, type PatchFile } from '@pnpm/types'
|
||||
|
||||
export type { PatchFile }
|
||||
|
||||
export interface LockfileSettings {
|
||||
autoInstallPeers?: boolean
|
||||
excludeLinksFromLockfile?: boolean
|
||||
}
|
||||
|
||||
export interface Lockfile {
|
||||
importers: Record<string, ProjectSnapshot>
|
||||
lockfileVersion: number | string
|
||||
@@ -12,6 +17,7 @@ export interface Lockfile {
|
||||
overrides?: Record<string, string>
|
||||
packageExtensionsChecksum?: string
|
||||
patchedDependencies?: Record<string, PatchFile>
|
||||
settings?: LockfileSettings
|
||||
}
|
||||
|
||||
export interface ProjectSnapshot {
|
||||
@@ -33,6 +39,7 @@ export interface LockfileV6 {
|
||||
overrides?: Record<string, string>
|
||||
packageExtensionsChecksum?: string
|
||||
patchedDependencies?: Record<string, PatchFile>
|
||||
settings?: LockfileSettings
|
||||
}
|
||||
|
||||
export interface ProjectSnapshotV6 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const WANTED_LOCKFILE = 'pnpm-lock.yaml'
|
||||
export const LOCKFILE_VERSION = 5.4
|
||||
export const LOCKFILE_VERSION_V6 = '6.0'
|
||||
export const LOCKFILE_VERSION_V6 = '6.1'
|
||||
|
||||
export const ENGINE_NAME = `${process.platform}-${process.arch}-node-${process.version.split('.')[0]}`
|
||||
export const LAYOUT_VERSION = 5
|
||||
|
||||
@@ -74,7 +74,13 @@ export async function handler (opts: install.InstallCommandOptions & Pick<Config
|
||||
opts.allProjectsGraph[lockfileDir].package.manifest = rootProjectManifest
|
||||
}
|
||||
|
||||
return install.handler(opts)
|
||||
return install.handler({
|
||||
...opts,
|
||||
rawLocalConfig: {
|
||||
...opts.rawLocalConfig,
|
||||
'frozen-lockfile': false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function diffFolders (folderA: string, folderB: string) {
|
||||
|
||||
@@ -532,18 +532,24 @@ describe('patch and commit in workspaces', () => {
|
||||
})
|
||||
|
||||
describe('patch with custom modules-dir and virtual-store-dir', () => {
|
||||
const customModulesDirFixture = tempDir()
|
||||
f.copy('custom-modules-dir', customModulesDirFixture)
|
||||
const cacheDir = path.resolve(customModulesDirFixture, 'cache')
|
||||
const storeDir = path.resolve(customModulesDirFixture, 'store')
|
||||
const defaultPatchOption = {
|
||||
...basePatchOption,
|
||||
cacheDir,
|
||||
dir: customModulesDirFixture,
|
||||
storeDir,
|
||||
modulesDir: 'fake_modules',
|
||||
virtualStoreDir: 'fake_modules/.fake_store',
|
||||
}
|
||||
let defaultPatchOption: patch.PatchCommandOptions
|
||||
let customModulesDirFixture: string
|
||||
let cacheDir: string
|
||||
let storeDir: string
|
||||
beforeAll(() => {
|
||||
customModulesDirFixture = tempDir()
|
||||
f.copy('custom-modules-dir', customModulesDirFixture)
|
||||
cacheDir = path.resolve(customModulesDirFixture, 'cache')
|
||||
storeDir = path.resolve(customModulesDirFixture, 'store')
|
||||
defaultPatchOption = {
|
||||
...basePatchOption,
|
||||
cacheDir,
|
||||
dir: customModulesDirFixture,
|
||||
storeDir,
|
||||
modulesDir: 'fake_modules',
|
||||
virtualStoreDir: 'fake_modules/.fake_store',
|
||||
}
|
||||
})
|
||||
|
||||
test('should work with custom modules-dir and virtual-store-dir', async () => {
|
||||
const manifest = fs.readFileSync(path.join(customModulesDirFixture, 'package.json'), 'utf8')
|
||||
|
||||
@@ -20,7 +20,7 @@ export type ListMissingPeersOptions = Partial<GetContextOptions>
|
||||
| 'useGitBranchLockfile'
|
||||
| 'workspacePackages'
|
||||
>
|
||||
& Pick<GetContextOptions, 'storeDir'>
|
||||
& Pick<GetContextOptions, 'autoInstallPeers' | 'excludeLinksFromLockfile' | 'storeDir'>
|
||||
|
||||
export async function getPeerDependencyIssues (
|
||||
projects: ProjectOptions[],
|
||||
|
||||
@@ -84,6 +84,15 @@ import { getAllUniqueSpecs, getPreferredVersionsFromLockfileAndManifests } from
|
||||
import { linkPackages } from './link'
|
||||
import { reportPeerDependencyIssues } from './reportPeerDependencyIssues'
|
||||
|
||||
class LockfileConfigMismatchError extends PnpmError {
|
||||
constructor (outdatedLockfileSettingName: string) {
|
||||
super('LOCKFILE_CONFIG_MISMATCH',
|
||||
`Cannot proceed with the frozen installation. The current "${outdatedLockfileSettingName!}" configuration doesn't match the value found in the lockfile`, {
|
||||
hint: 'Update your lockfile using "pnpm install --no-frozen-lockfile"',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const BROKEN_LOCKFILE_INTEGRITY_ERRORS = new Set([
|
||||
'ERR_PNPM_UNEXPECTED_PKG_CONTENT_IN_STORE',
|
||||
'ERR_PNPM_TARBALL_INTEGRITY',
|
||||
@@ -317,26 +326,44 @@ export async function mutateModules (
|
||||
path: path.join(opts.lockfileDir, patchFile.path),
|
||||
}), patchedDependencies)
|
||||
: undefined
|
||||
let needsFullResolution = !maybeOpts.ignorePackageManifest &&
|
||||
lockfileIsNotUpToDate(ctx.wantedLockfile, {
|
||||
const frozenLockfile = opts.frozenLockfile ||
|
||||
opts.frozenLockfileIfExists && ctx.existsWantedLockfile
|
||||
let outdatedLockfileSettings = false
|
||||
if (!opts.ignorePackageManifest) {
|
||||
const outdatedLockfileSettingName = getOutdatedLockfileSetting(ctx.wantedLockfile, {
|
||||
autoInstallPeers: opts.autoInstallPeers,
|
||||
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
||||
overrides: opts.overrides,
|
||||
neverBuiltDependencies: opts.neverBuiltDependencies,
|
||||
onlyBuiltDependencies: opts.onlyBuiltDependencies,
|
||||
packageExtensionsChecksum,
|
||||
patchedDependencies,
|
||||
}) ||
|
||||
})
|
||||
outdatedLockfileSettings = outdatedLockfileSettingName != null
|
||||
if (frozenLockfile && outdatedLockfileSettings) {
|
||||
throw new LockfileConfigMismatchError(outdatedLockfileSettingName!)
|
||||
}
|
||||
}
|
||||
let needsFullResolution = outdatedLockfileSettings ||
|
||||
opts.fixLockfile ||
|
||||
!ctx.wantedLockfile.lockfileVersion.toString().startsWith('6.') ||
|
||||
opts.forceFullResolution
|
||||
if (needsFullResolution) {
|
||||
ctx.wantedLockfile.settings = {
|
||||
autoInstallPeers: opts.autoInstallPeers,
|
||||
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
||||
}
|
||||
ctx.wantedLockfile.overrides = opts.overrides
|
||||
ctx.wantedLockfile.neverBuiltDependencies = opts.neverBuiltDependencies
|
||||
ctx.wantedLockfile.onlyBuiltDependencies = opts.onlyBuiltDependencies
|
||||
ctx.wantedLockfile.packageExtensionsChecksum = packageExtensionsChecksum
|
||||
ctx.wantedLockfile.patchedDependencies = patchedDependencies
|
||||
} else if (!frozenLockfile) {
|
||||
ctx.wantedLockfile.settings = {
|
||||
autoInstallPeers: opts.autoInstallPeers,
|
||||
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
||||
}
|
||||
}
|
||||
const frozenLockfile = opts.frozenLockfile ||
|
||||
opts.frozenLockfileIfExists && ctx.existsWantedLockfile
|
||||
if (
|
||||
!ctx.lockfileHadConflicts &&
|
||||
!opts.fixLockfile &&
|
||||
@@ -645,7 +672,7 @@ async function calcPatchHashes (patches: Record<string, string>, lockfileDir: st
|
||||
}, patches)
|
||||
}
|
||||
|
||||
function lockfileIsNotUpToDate (
|
||||
function getOutdatedLockfileSetting (
|
||||
lockfile: Lockfile,
|
||||
{
|
||||
neverBuiltDependencies,
|
||||
@@ -653,18 +680,40 @@ function lockfileIsNotUpToDate (
|
||||
overrides,
|
||||
packageExtensionsChecksum,
|
||||
patchedDependencies,
|
||||
autoInstallPeers,
|
||||
excludeLinksFromLockfile,
|
||||
}: {
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
overrides?: Record<string, string>
|
||||
packageExtensionsChecksum?: string
|
||||
patchedDependencies?: Record<string, PatchFile>
|
||||
}) {
|
||||
return !equals(lockfile.overrides ?? {}, overrides ?? {}) ||
|
||||
!equals((lockfile.neverBuiltDependencies ?? []).sort(), (neverBuiltDependencies ?? []).sort()) ||
|
||||
!equals(onlyBuiltDependencies?.sort(), lockfile.onlyBuiltDependencies) ||
|
||||
lockfile.packageExtensionsChecksum !== packageExtensionsChecksum ||
|
||||
!equals(lockfile.patchedDependencies ?? {}, patchedDependencies ?? {})
|
||||
autoInstallPeers?: boolean
|
||||
excludeLinksFromLockfile?: boolean
|
||||
}
|
||||
) {
|
||||
if (!equals(lockfile.overrides ?? {}, overrides ?? {})) {
|
||||
return 'overrides'
|
||||
}
|
||||
if (!equals((lockfile.neverBuiltDependencies ?? []).sort(), (neverBuiltDependencies ?? []).sort())) {
|
||||
return 'neverBuiltDependencies'
|
||||
}
|
||||
if (!equals(onlyBuiltDependencies?.sort(), lockfile.onlyBuiltDependencies)) {
|
||||
return 'onlyBuiltDependencies'
|
||||
}
|
||||
if (lockfile.packageExtensionsChecksum !== packageExtensionsChecksum) {
|
||||
return 'packageExtensionsChecksum'
|
||||
}
|
||||
if (!equals(lockfile.patchedDependencies ?? {}, patchedDependencies ?? {})) {
|
||||
return 'patchedDependencies'
|
||||
}
|
||||
if ((lockfile.settings?.autoInstallPeers != null && lockfile.settings.autoInstallPeers !== autoInstallPeers)) {
|
||||
return 'settings.autoInstallPeers'
|
||||
}
|
||||
if (lockfile.settings?.excludeLinksFromLockfile != null && lockfile.settings.excludeLinksFromLockfile !== excludeLinksFromLockfile) {
|
||||
return 'settings.excludeLinksFromLockfile'
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function createObjectChecksum (obj: unknown) {
|
||||
|
||||
@@ -9,7 +9,9 @@ import {
|
||||
import { type ReporterFunction } from '../types'
|
||||
|
||||
interface StrictLinkOptions {
|
||||
autoInstallPeers: boolean
|
||||
binsDir: string
|
||||
excludeLinksFromLockfile: boolean
|
||||
force: boolean
|
||||
forceSharedLockfile: boolean
|
||||
useLockfile: boolean
|
||||
|
||||
@@ -13,6 +13,10 @@ test('installing aliased dependency', async () => {
|
||||
expect(typeof project.requireModule('positive')).toBe('function')
|
||||
|
||||
expect(await project.readLockfile()).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
negative: {
|
||||
specifier: 'npm:is-negative@1.0.0',
|
||||
@@ -70,6 +74,10 @@ test('a dependency has an aliased subdependency', async () => {
|
||||
expect(project.requireModule('@pnpm.e2e/pkg-with-1-aliased-dep')().name).toEqual('@pnpm.e2e/dep-of-pkg-with-1-dep')
|
||||
|
||||
expect(await project.readLockfile()).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'@pnpm.e2e/pkg-with-1-aliased-dep': {
|
||||
specifier: '^100.0.0',
|
||||
|
||||
@@ -287,3 +287,18 @@ test('prefer-frozen-lockfile: should prefer frozen-lockfile when package has lin
|
||||
await projects['p1'].has('p2')
|
||||
await projects['p2'].has('is-negative')
|
||||
})
|
||||
|
||||
test('frozen-lockfile: installation fails if the value of auto-install-peers changes', async () => {
|
||||
prepareEmpty()
|
||||
const manifest = {
|
||||
dependencies: {
|
||||
'is-positive': '^3.0.0',
|
||||
},
|
||||
}
|
||||
|
||||
await install(manifest, await testDefaults({ autoInstallPeers: true }))
|
||||
|
||||
await expect(
|
||||
install(manifest, await testDefaults({ frozenLockfile: true, autoInstallPeers: false }))
|
||||
).rejects.toThrow('Cannot proceed with the frozen installation. The current "settings.autoInstallPeers" configuration doesn\'t match the value found in the lockfile')
|
||||
})
|
||||
|
||||
@@ -45,6 +45,10 @@ test('local file', async () => {
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'local-pkg': {
|
||||
specifier: expectedSpecs['local-pkg'],
|
||||
@@ -88,6 +92,10 @@ test('local file via link:', async () => {
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'local-pkg': {
|
||||
specifier: expectedSpecs['local-pkg'],
|
||||
@@ -116,6 +124,10 @@ test('local file with symlinked node_modules', async () => {
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'local-pkg': {
|
||||
specifier: expectedSpecs['local-pkg'],
|
||||
|
||||
@@ -94,8 +94,8 @@ test('versions are replaced with versions specified through overrides option', a
|
||||
rootDir: process.cwd(),
|
||||
}, await testDefaults({ frozenLockfile: true, overrides }))
|
||||
).rejects.toThrow(
|
||||
new PnpmError('FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE',
|
||||
'Cannot perform a frozen installation because the version of the lockfile is incompatible with this version of pnpm'
|
||||
new PnpmError('LOCKFILE_CONFIG_MISMATCH',
|
||||
'Cannot proceed with the frozen installation. The current "overrides" configuration doesn\'t match the value found in the lockfile'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -88,8 +88,8 @@ test('manifests are extended with fields specified by packageExtensions', async
|
||||
rootDir: process.cwd(),
|
||||
}, await testDefaults({ frozenLockfile: true, packageExtensions }))
|
||||
).rejects.toThrow(
|
||||
new PnpmError('FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE',
|
||||
'Cannot perform a frozen installation because the version of the lockfile is incompatible with this version of pnpm'
|
||||
new PnpmError('LOCKFILE_CONFIG_MISMATCH',
|
||||
'Cannot proceed with the frozen installation. The current "packageExtensionsChecksum" configuration doesn\'t match the value found in the lockfile'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -475,6 +475,10 @@ test('scoped module from different registry', async () => {
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'@foo/has-dep-from-same-scope': {
|
||||
specifier: '^1.0.0',
|
||||
@@ -782,6 +786,10 @@ test('packages installed via tarball URL from the default registry are normalize
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'is-positive': {
|
||||
specifier: 'https://registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
|
||||
@@ -1159,6 +1167,10 @@ test('tarball domain differs from registry domain', async () => {
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'is-positive': {
|
||||
specifier: '^3.1.0',
|
||||
@@ -1205,6 +1217,10 @@ test('tarball installed through non-standard URL endpoint from the registry doma
|
||||
const lockfile = await project.readLockfile()
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
dependencies: {
|
||||
'is-positive': {
|
||||
specifier: 'https://registry.npmjs.org/is-positive/download/is-positive-3.1.0.tgz',
|
||||
@@ -1478,7 +1494,7 @@ test('lockfile v6', async () => {
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<any>(WANTED_LOCKFILE) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
expect(lockfile.lockfileVersion).toBe('6.0')
|
||||
expect(lockfile.lockfileVersion).toBe(LOCKFILE_VERSION)
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/pkg-with-1-dep@100.0.0'])
|
||||
}
|
||||
|
||||
@@ -1486,7 +1502,7 @@ test('lockfile v6', async () => {
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<any>(WANTED_LOCKFILE) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
expect(lockfile.lockfileVersion).toBe('6.0')
|
||||
expect(lockfile.lockfileVersion).toBe(LOCKFILE_VERSION)
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/pkg-with-1-dep@100.0.0'])
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/foo@100.0.0'])
|
||||
}
|
||||
@@ -1500,7 +1516,7 @@ test('lockfile v5 is converted to lockfile v6', async () => {
|
||||
await install({ dependencies: { '@pnpm.e2e/pkg-with-1-dep': '100.0.0' } }, await testDefaults())
|
||||
|
||||
const lockfile = await readYamlFile<any>(WANTED_LOCKFILE) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
expect(lockfile.lockfileVersion).toBe('6.0')
|
||||
expect(lockfile.lockfileVersion).toBe(LOCKFILE_VERSION)
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/pkg-with-1-dep@100.0.0'])
|
||||
})
|
||||
|
||||
|
||||
@@ -317,6 +317,10 @@ test('uninstalling a dependency from package that uses shared lockfile', async (
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
importers: {
|
||||
'project-1': {},
|
||||
'project-2': {
|
||||
|
||||
@@ -71,6 +71,8 @@ interface HookOptions {
|
||||
}
|
||||
|
||||
export interface GetContextOptions {
|
||||
autoInstallPeers: boolean
|
||||
excludeLinksFromLockfile: boolean
|
||||
allProjects: Array<ProjectOptions & HookOptions>
|
||||
confirmModulesPurge?: boolean
|
||||
force: boolean
|
||||
@@ -178,6 +180,8 @@ export async function getContext (
|
||||
storeDir: opts.storeDir,
|
||||
virtualStoreDir,
|
||||
...await readLockfiles({
|
||||
autoInstallPeers: opts.autoInstallPeers,
|
||||
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
||||
force: opts.force,
|
||||
forceSharedLockfile: opts.forceSharedLockfile,
|
||||
frozenLockfile: opts.frozenLockfile === true,
|
||||
@@ -406,6 +410,8 @@ export interface PnpmSingleContext {
|
||||
export async function getContextForSingleImporter (
|
||||
manifest: ProjectManifest,
|
||||
opts: {
|
||||
autoInstallPeers: boolean
|
||||
excludeLinksFromLockfile: boolean
|
||||
force: boolean
|
||||
forceNewModules?: boolean
|
||||
forceSharedLockfile: boolean
|
||||
@@ -520,6 +526,8 @@ export async function getContextForSingleImporter (
|
||||
storeDir,
|
||||
virtualStoreDir,
|
||||
...await readLockfiles({
|
||||
autoInstallPeers: opts.autoInstallPeers,
|
||||
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
||||
force: opts.force,
|
||||
forceSharedLockfile: opts.forceSharedLockfile,
|
||||
frozenLockfile: false,
|
||||
|
||||
@@ -26,6 +26,8 @@ export interface PnpmContext {
|
||||
|
||||
export async function readLockfiles (
|
||||
opts: {
|
||||
autoInstallPeers: boolean
|
||||
excludeLinksFromLockfile: boolean
|
||||
force: boolean
|
||||
forceSharedLockfile: boolean
|
||||
frozenLockfile: boolean
|
||||
@@ -103,7 +105,11 @@ export async function readLockfiles (
|
||||
})()
|
||||
)
|
||||
const files = await Promise.all<Lockfile | null | undefined>(fileReads)
|
||||
const sopts = { lockfileVersion: wantedLockfileVersion }
|
||||
const sopts = {
|
||||
autoInstallPeers: opts.autoInstallPeers,
|
||||
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
||||
lockfileVersion: wantedLockfileVersion,
|
||||
}
|
||||
const importerIds = opts.projects.map((importer) => importer.id)
|
||||
const currentLockfile = files[1] ?? createLockfileObject(importerIds, sopts)
|
||||
for (const importerId of importerIds) {
|
||||
|
||||
@@ -5,6 +5,8 @@ import { type GetContextOptions } from '../src'
|
||||
|
||||
const DEFAULT_OPTIONS: GetContextOptions = {
|
||||
allProjects: [],
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
extraBinPaths: [],
|
||||
force: false,
|
||||
forceSharedLockfile: false,
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/deps-have-lifecycle-scripts/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/deps-have-lifecycle-scripts/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example':
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/has-glob-and-rimraf/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/has-glob-and-rimraf/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
glob:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/has-glob/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/has-glob/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
glob:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/has-incompatible-optional-subdep/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/has-incompatible-optional-subdep/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@pnpm.e2e/pkg-with-optional':
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/has-local-dep/pkg/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/has-local-dep/pkg/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
tar-pkg:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/has-local-dir-dep/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/has-local-dir-dep/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
example:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/has-nonexistent-optional-dep/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/has-nonexistent-optional-dep/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
is-positive:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/has-several-versions-of-same-pkg/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/has-several-versions-of-same-pkg/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
has-flag:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/prod-dep-is-dev-subdep/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/prod-dep-is-dev-subdep/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
is-positive:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/reinstall-peer-deps/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/reinstall-peer-deps/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
devDependencies:
|
||||
'@pnpm.e2e/abc':
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/resolved-peer-deps-in-subdeps/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/resolved-peer-deps-in-subdeps/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: false
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
pnpm-default-reporter:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/side-effects-of-subdep/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/side-effects-of-subdep/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
expire-fs:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/side-effects/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/side-effects/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example':
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/simple-shamefully-flatten/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/simple-shamefully-flatten/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: false
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@pnpm.e2e/pkg-with-peer-having-bin':
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/simple-with-more-deps/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/simple-with-more-deps/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
is-positive:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/simple-with-optional-dep/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/simple-with-optional-dep/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@pnpm.e2e/pkg-with-good-optional':
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/simple/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/simple/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
is-positive:
|
||||
|
||||
6
pkg-manager/headless/test/fixtures/with-1-dep/pnpm-lock.yaml
generated
vendored
6
pkg-manager/headless/test/fixtures/with-1-dep/pnpm-lock.yaml
generated
vendored
@@ -1,4 +1,8 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
rimraf:
|
||||
|
||||
@@ -15,7 +15,7 @@ exports[`pnpm dedupe updates old resolutions from importers block and removes ol
|
||||
},
|
||||
@@ -20,18 +20,6 @@
|
||||
},
|
||||
"lockfileVersion": "6.0",
|
||||
"lockfileVersion": "6.1",
|
||||
"packages": Object {
|
||||
- "/ajv@6.10.2": Object {
|
||||
- "dependencies": Object {
|
||||
@@ -98,7 +98,7 @@ exports[`pnpm dedupe updates old resolutions from package block 1`] = `
|
||||
|
||||
@@ -20,15 +20,6 @@
|
||||
},
|
||||
"lockfileVersion": "6.0",
|
||||
"lockfileVersion": "6.1",
|
||||
"packages": Object {
|
||||
- "/punycode@2.1.1": Object {
|
||||
- "dev": false,
|
||||
|
||||
@@ -964,6 +964,10 @@ test("shared-workspace-lockfile: don't install dependencies in projects that are
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
importers: {
|
||||
'package-1': {
|
||||
dependencies: {
|
||||
@@ -1041,6 +1045,10 @@ test('shared-workspace-lockfile: install dependencies in projects that are relat
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
autoInstallPeers: true,
|
||||
excludeLinksFromLockfile: false,
|
||||
},
|
||||
importers: {
|
||||
'.': {
|
||||
dependencies: {
|
||||
|
||||
@@ -4,6 +4,8 @@ import { type Registries } from '@pnpm/types'
|
||||
import { type ReporterFunction } from '../types'
|
||||
|
||||
export interface StrictStoreStatusOptions {
|
||||
autoInstallPeers: boolean
|
||||
excludeLinksFromLockfile: boolean
|
||||
lockfileDir: string
|
||||
dir: string
|
||||
storeDir: string
|
||||
|
||||
Reference in New Issue
Block a user