mirror of
https://github.com/pnpm/pnpm.git
synced 2026-07-26 07:27:20 -04:00
fix(headless): postinstall script should run after root deps are linked (#4026)
close #4018
This commit is contained in:
6
.changeset/real-badgers-mate.md
Normal file
6
.changeset/real-badgers-mate.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/headless": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
The postinstall scripts of dependencies should be executed after the root dependencies of the project are symlinked [#4018](https://github.com/pnpm/pnpm/issues/4018).
|
||||
@@ -35,7 +35,7 @@
|
||||
"@commitlint/prompt-cli": "^15.0.0",
|
||||
"@pnpm/eslint-config": "workspace:*",
|
||||
"@pnpm/meta-updater": "0.0.6",
|
||||
"@pnpm/registry-mock": "^2.9.0",
|
||||
"@pnpm/registry-mock": "^2.10.0",
|
||||
"@pnpm/tsconfig": "workspace:*",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/node": "^14.17.32",
|
||||
|
||||
@@ -511,3 +511,42 @@ test('lifecycle scripts have access to package\'s own binary by binary name', as
|
||||
|
||||
await project.isExecutable('.pnpm/runs-own-bin@1.0.0/node_modules/runs-own-bin/node_modules/.bin/runs-own-bin')
|
||||
})
|
||||
|
||||
test('lifecycle scripts run after linking root dependencies', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
const manifest = {
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
'postinstall-requires-is-positive': '1.0.0',
|
||||
},
|
||||
}
|
||||
|
||||
await mutateModules(
|
||||
[
|
||||
{
|
||||
buildIndex: 0,
|
||||
manifest,
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd(),
|
||||
},
|
||||
],
|
||||
await testDefaults({ fastUnpack: false })
|
||||
)
|
||||
|
||||
await rimraf('node_modules')
|
||||
|
||||
await mutateModules(
|
||||
[
|
||||
{
|
||||
buildIndex: 0,
|
||||
manifest,
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd(),
|
||||
},
|
||||
],
|
||||
await testDefaults({ fastUnpack: false, frozenLockfile: true })
|
||||
)
|
||||
|
||||
// if there was no exception, the test passed
|
||||
})
|
||||
|
||||
@@ -259,6 +259,7 @@ export default async (opts: HeadlessOptions) => {
|
||||
})
|
||||
}
|
||||
|
||||
let newHoistedDependencies!: HoistedDependencies
|
||||
if (opts.enableModulesDir !== false) {
|
||||
await Promise.all(depNodes.map(async (depNode) => fs.mkdir(depNode.modules, { recursive: true })))
|
||||
await Promise.all([
|
||||
@@ -280,7 +281,6 @@ export default async (opts: HeadlessOptions) => {
|
||||
stage: 'importing_done',
|
||||
})
|
||||
|
||||
let newHoistedDependencies!: HoistedDependencies
|
||||
if (opts.ignorePackageManifest !== true && (opts.hoistPattern != null || opts.publicHoistPattern != null)) {
|
||||
// It is important to keep the skipped packages in the lockfile which will be saved as the "current lockfile".
|
||||
// pnpm is comparing the current lockfile to the wanted one and they should much.
|
||||
@@ -304,84 +304,11 @@ export default async (opts: HeadlessOptions) => {
|
||||
newHoistedDependencies = {}
|
||||
}
|
||||
|
||||
if (opts.ignoreScripts) {
|
||||
for (const { id, manifest } of opts.projects) {
|
||||
if (opts.ignoreScripts && ((manifest?.scripts) != null) &&
|
||||
(manifest.scripts.preinstall ?? manifest.scripts.prepublish ??
|
||||
manifest.scripts.install ??
|
||||
manifest.scripts.postinstall ??
|
||||
manifest.scripts.prepare)
|
||||
) {
|
||||
opts.pendingBuilds.push(id)
|
||||
}
|
||||
}
|
||||
// we can use concat here because we always only append new packages, which are guaranteed to not be there by definition
|
||||
opts.pendingBuilds = opts.pendingBuilds
|
||||
.concat(
|
||||
depNodes
|
||||
.filter(({ requiresBuild }) => requiresBuild)
|
||||
.map(({ depPath }) => depPath)
|
||||
)
|
||||
} else {
|
||||
const directNodes = new Set<string>()
|
||||
for (const id of importerIds) {
|
||||
Object
|
||||
.values(directDependenciesByImporterId[id])
|
||||
.filter((loc) => graph[loc])
|
||||
.forEach((loc) => {
|
||||
directNodes.add(loc)
|
||||
})
|
||||
}
|
||||
const extraBinPaths = [...opts.extraBinPaths ?? []]
|
||||
if (opts.hoistPattern != null) {
|
||||
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
|
||||
}
|
||||
let extraEnv: Record<string, string> | undefined
|
||||
if (opts.enablePnp) {
|
||||
extraEnv = makeNodeRequireOption(path.join(opts.lockfileDir, '.pnp.cjs'))
|
||||
}
|
||||
await buildModules(graph, Array.from(directNodes), {
|
||||
childConcurrency: opts.childConcurrency,
|
||||
extraBinPaths,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
extraEnv,
|
||||
lockfileDir,
|
||||
optional: opts.include.optionalDependencies,
|
||||
rawConfig: opts.rawConfig,
|
||||
rootModulesDir: virtualStoreDir,
|
||||
scriptsPrependNodePath: opts.scriptsPrependNodePath,
|
||||
scriptShell: opts.scriptShell,
|
||||
shellEmulator: opts.shellEmulator,
|
||||
sideEffectsCacheWrite: opts.sideEffectsCacheWrite,
|
||||
storeController: opts.storeController,
|
||||
unsafePerm: opts.unsafePerm,
|
||||
userAgent: opts.userAgent,
|
||||
})
|
||||
}
|
||||
|
||||
await writeModulesYaml(rootModulesDir, {
|
||||
hoistedDependencies: newHoistedDependencies,
|
||||
hoistPattern: opts.hoistPattern,
|
||||
included: opts.include,
|
||||
layoutVersion: LAYOUT_VERSION,
|
||||
packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`,
|
||||
pendingBuilds: opts.pendingBuilds,
|
||||
publicHoistPattern: opts.publicHoistPattern,
|
||||
prunedAt: opts.pruneVirtualStore === true || opts.prunedAt == null
|
||||
? new Date().toUTCString()
|
||||
: opts.prunedAt,
|
||||
registries: opts.registries,
|
||||
skipped: Array.from(skipped),
|
||||
storeDir: opts.storeDir,
|
||||
virtualStoreDir,
|
||||
})
|
||||
|
||||
await linkAllBins(graph, { extendNodePath: opts.extendNodePath, optional: opts.include.optionalDependencies, warn })
|
||||
|
||||
if ((currentLockfile != null) && !equals(importerIds.sort(), Object.keys(filteredLockfile.importers).sort())) {
|
||||
Object.assign(filteredLockfile.packages, currentLockfile.packages)
|
||||
}
|
||||
await writeCurrentLockfile(virtualStoreDir, filteredLockfile)
|
||||
|
||||
/** Skip linking and due to no project manifest */
|
||||
if (!opts.ignorePackageManifest) {
|
||||
@@ -405,7 +332,67 @@ export default async (opts: HeadlessOptions) => {
|
||||
updated: manifest,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.ignoreScripts) {
|
||||
for (const { id, manifest } of opts.projects) {
|
||||
if (opts.ignoreScripts && ((manifest?.scripts) != null) &&
|
||||
(manifest.scripts.preinstall ?? manifest.scripts.prepublish ??
|
||||
manifest.scripts.install ??
|
||||
manifest.scripts.postinstall ??
|
||||
manifest.scripts.prepare)
|
||||
) {
|
||||
opts.pendingBuilds.push(id)
|
||||
}
|
||||
}
|
||||
// we can use concat here because we always only append new packages, which are guaranteed to not be there by definition
|
||||
opts.pendingBuilds = opts.pendingBuilds
|
||||
.concat(
|
||||
depNodes
|
||||
.filter(({ requiresBuild }) => requiresBuild)
|
||||
.map(({ depPath }) => depPath)
|
||||
)
|
||||
} else {
|
||||
const directNodes = new Set<string>()
|
||||
for (const id of importerIds) {
|
||||
Object
|
||||
.values(directDependenciesByImporterId[id])
|
||||
.filter((loc) => graph[loc])
|
||||
.forEach((loc) => {
|
||||
directNodes.add(loc)
|
||||
})
|
||||
}
|
||||
const extraBinPaths = [...opts.extraBinPaths ?? []]
|
||||
if (opts.hoistPattern != null) {
|
||||
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
|
||||
}
|
||||
let extraEnv: Record<string, string> | undefined
|
||||
if (opts.enablePnp) {
|
||||
extraEnv = makeNodeRequireOption(path.join(opts.lockfileDir, '.pnp.cjs'))
|
||||
}
|
||||
await buildModules(graph, Array.from(directNodes), {
|
||||
childConcurrency: opts.childConcurrency,
|
||||
extraBinPaths,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
extraEnv,
|
||||
lockfileDir,
|
||||
optional: opts.include.optionalDependencies,
|
||||
rawConfig: opts.rawConfig,
|
||||
rootModulesDir: virtualStoreDir,
|
||||
scriptsPrependNodePath: opts.scriptsPrependNodePath,
|
||||
scriptShell: opts.scriptShell,
|
||||
shellEmulator: opts.shellEmulator,
|
||||
sideEffectsCacheWrite: opts.sideEffectsCacheWrite,
|
||||
storeController: opts.storeController,
|
||||
unsafePerm: opts.unsafePerm,
|
||||
userAgent: opts.userAgent,
|
||||
})
|
||||
}
|
||||
|
||||
if (opts.enableModulesDir !== false) {
|
||||
/** Skip linking and due to no project manifest */
|
||||
if (!opts.ignorePackageManifest) {
|
||||
await Promise.all(opts.projects.map(async (project) => {
|
||||
if (opts.publicHoistPattern?.length && path.relative(opts.lockfileDir, project.rootDir) === '') {
|
||||
await linkBinsOfImporter(project, { extendNodePath: opts.extendNodePath })
|
||||
@@ -427,7 +414,25 @@ export default async (opts: HeadlessOptions) => {
|
||||
}
|
||||
}))
|
||||
}
|
||||
await writeModulesYaml(rootModulesDir, {
|
||||
hoistedDependencies: newHoistedDependencies,
|
||||
hoistPattern: opts.hoistPattern,
|
||||
included: opts.include,
|
||||
layoutVersion: LAYOUT_VERSION,
|
||||
packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`,
|
||||
pendingBuilds: opts.pendingBuilds,
|
||||
publicHoistPattern: opts.publicHoistPattern,
|
||||
prunedAt: opts.pruneVirtualStore === true || opts.prunedAt == null
|
||||
? new Date().toUTCString()
|
||||
: opts.prunedAt,
|
||||
registries: opts.registries,
|
||||
skipped: Array.from(skipped),
|
||||
storeDir: opts.storeDir,
|
||||
virtualStoreDir,
|
||||
})
|
||||
await writeCurrentLockfile(virtualStoreDir, filteredLockfile)
|
||||
}
|
||||
|
||||
// waiting till package requests are finished
|
||||
await Promise.all(depNodes.map(({ finishing }) => finishing))
|
||||
|
||||
|
||||
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
@@ -40,7 +40,7 @@ importers:
|
||||
'@commitlint/prompt-cli': ^15.0.0
|
||||
'@pnpm/eslint-config': workspace:*
|
||||
'@pnpm/meta-updater': 0.0.6
|
||||
'@pnpm/registry-mock': ^2.9.0
|
||||
'@pnpm/registry-mock': ^2.10.0
|
||||
'@pnpm/tsconfig': workspace:*
|
||||
'@types/jest': ^26.0.24
|
||||
'@types/node': ^14.17.32
|
||||
@@ -71,7 +71,7 @@ importers:
|
||||
'@commitlint/prompt-cli': 15.0.0
|
||||
'@pnpm/eslint-config': link:utils/eslint-config
|
||||
'@pnpm/meta-updater': 0.0.6
|
||||
'@pnpm/registry-mock': 2.9.0
|
||||
'@pnpm/registry-mock': 2.10.0
|
||||
'@pnpm/tsconfig': link:utils/tsconfig
|
||||
'@types/jest': 26.0.24
|
||||
'@types/node': 14.17.34
|
||||
@@ -4645,15 +4645,15 @@ packages:
|
||||
load-json-file: 6.2.0
|
||||
dev: true
|
||||
|
||||
/@pnpm/cli-utils/0.6.31_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-SrCdFnD5dbyyAzqm5hnOY2S/6/+zxs7nkuVQWYdhNWiAmwxlVy5ip9ZYlwMzhUHVnlTXtOwelrJm7GlaVFu84g==}
|
||||
/@pnpm/cli-utils/0.6.32_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-zHX4ozJeuEWWH/i9/nekXxpKduXJ9buRNEppR9X3A4Ir/a4je4Feyjf9gPXwa/ZB5dbOerweQYlK0SB5nQuUKg==}
|
||||
engines: {node: '>=12.17'}
|
||||
peerDependencies:
|
||||
'@pnpm/logger': ^4.0.0
|
||||
dependencies:
|
||||
'@pnpm/cli-meta': 2.0.0
|
||||
'@pnpm/config': 13.4.2_@pnpm+logger@4.0.0
|
||||
'@pnpm/default-reporter': 8.3.6_@pnpm+logger@4.0.0
|
||||
'@pnpm/config': 13.5.0_@pnpm+logger@4.0.0
|
||||
'@pnpm/default-reporter': 8.3.7_@pnpm+logger@4.0.0
|
||||
'@pnpm/error': 2.0.0
|
||||
'@pnpm/logger': 4.0.0
|
||||
'@pnpm/manifest-utils': 2.1.2_@pnpm+logger@4.0.0
|
||||
@@ -4670,8 +4670,8 @@ packages:
|
||||
chalk: 4.1.2
|
||||
dev: false
|
||||
|
||||
/@pnpm/config/13.4.2_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-SO1EwqIJFE3DdeihtNAPlqodxR0hRZ/XY++qc8wJKdnbHlX4nuLT7eaQ2t60l66EVSA05yaYzMjUwahPdYFVUA==}
|
||||
/@pnpm/config/13.5.0_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-CGcTb8hQtAAhCQ22MFiJ5lx/B67ZYnE9Xo+n1jDCJBy2z9YRqzXv7YpKd8ez2HsHkqEB1mehheD1pN5vxuaPJg==}
|
||||
engines: {node: '>=12.17'}
|
||||
dependencies:
|
||||
'@pnpm/constants': 5.0.0
|
||||
@@ -4705,11 +4705,11 @@ packages:
|
||||
'@pnpm/types': 7.6.0
|
||||
dev: true
|
||||
|
||||
/@pnpm/default-reporter/8.3.6_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-dq0vb3Brv+MxvcH8TSBLVaasgS3XvJPL+ORD/nPvinDnmiSiT+qGn/OIwO0Ib6lpIzvWXv93+OPPuQ9Jnpb/vA==}
|
||||
/@pnpm/default-reporter/8.3.7_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-J1B+Q77AvAW81e3x6nNBZEbVudeEbaUrILtf9UJQLVJy+wU2nUHaF0uWVK++B/0utx262DRt0DieDeQMJaZ60Q==}
|
||||
engines: {node: '>=12.17'}
|
||||
dependencies:
|
||||
'@pnpm/config': 13.4.2_@pnpm+logger@4.0.0
|
||||
'@pnpm/config': 13.5.0_@pnpm+logger@4.0.0
|
||||
'@pnpm/core-loggers': 6.0.6_@pnpm+logger@4.0.0
|
||||
'@pnpm/error': 2.0.0
|
||||
'@pnpm/types': 7.6.0
|
||||
@@ -4752,11 +4752,11 @@ packages:
|
||||
find-up: 5.0.0
|
||||
dev: true
|
||||
|
||||
/@pnpm/find-workspace-packages/3.1.23_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-22z6tgybQ9I/UA9FNPJ1S3wtYa36RxF2xpjfqZNv3l7Q9P651duhevP7uUWyUYeQ0xT8259D+PpdOTHQhSpcpQ==}
|
||||
/@pnpm/find-workspace-packages/3.1.24_@pnpm+logger@4.0.0:
|
||||
resolution: {integrity: sha512-Ik8FsWp3sXGQHGQPGqM9MAr3WEoaIZXIec/k58/F9RHqmaTfKmP60B444grpS8xGVeNXyYkKqKCvsf7Wr/tHag==}
|
||||
engines: {node: '>=12.17'}
|
||||
dependencies:
|
||||
'@pnpm/cli-utils': 0.6.31_@pnpm+logger@4.0.0
|
||||
'@pnpm/cli-utils': 0.6.32_@pnpm+logger@4.0.0
|
||||
'@pnpm/constants': 5.0.0
|
||||
'@pnpm/types': 7.6.0
|
||||
find-packages: 8.0.7
|
||||
@@ -4812,7 +4812,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@pnpm/find-workspace-dir': 3.0.1
|
||||
'@pnpm/find-workspace-packages': 3.1.23_@pnpm+logger@4.0.0
|
||||
'@pnpm/find-workspace-packages': 3.1.24_@pnpm+logger@4.0.0
|
||||
'@pnpm/logger': 4.0.0
|
||||
'@pnpm/types': 7.6.0
|
||||
load-json-file: 6.2.0
|
||||
@@ -4893,8 +4893,8 @@ packages:
|
||||
strip-bom: 4.0.0
|
||||
dev: true
|
||||
|
||||
/@pnpm/registry-mock/2.9.0:
|
||||
resolution: {integrity: sha512-o3jkMVvyZ/kGZXVQ4f+8ENH2p2A/AIH4kAz0d4ULxtCeXS5ujRIqCfwaBYIU2NfJrZP8lSMYsLBat1egXJV+GA==}
|
||||
/@pnpm/registry-mock/2.10.0:
|
||||
resolution: {integrity: sha512-96frA3W36rjd6BRIjKmkXKTLIlpZFogvkbKnYp68+K2RWBoqDQd789ZZbJvz6Tz3fNWYcKpz6lUI4Bm3S+jtwA==}
|
||||
engines: {node: '>=10.13'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user