mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-27 00:58:11 -05:00
fix: honor never/only-built-dependencies in workspace setup (#7141)
close #7135 close #5407 --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
8
.changeset/modern-crabs-smile.md
Normal file
8
.changeset/modern-crabs-smile.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": patch
|
||||
"@pnpm/plugin-commands-rebuild": patch
|
||||
"@pnpm/core": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Use `neverBuiltDependencies` and `onlyBuiltDependencies` from the root `package.json` of the workspace, when `shared-workspace-lockfile` is set to `false` [#7141](https://github.com/pnpm/pnpm/pull/7141).
|
||||
@@ -45,6 +45,7 @@
|
||||
"write-yaml-file": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pnpm/builder.policy": "1.0.0",
|
||||
"@pnpm/calc-dep-state": "workspace:*",
|
||||
"@pnpm/cli-utils": "workspace:*",
|
||||
"@pnpm/common-cli-options-help": "workspace:*",
|
||||
|
||||
@@ -45,6 +45,8 @@ export interface StrictRebuildOptions {
|
||||
pending: boolean
|
||||
shamefullyHoist: boolean
|
||||
deployAllFiles: boolean
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
}
|
||||
|
||||
export type RebuildOptions = Partial<StrictRebuildOptions> &
|
||||
|
||||
@@ -25,6 +25,7 @@ import { logger, streamParser } from '@pnpm/logger'
|
||||
import { writeModulesManifest } from '@pnpm/modules-yaml'
|
||||
import { createOrConnectStoreController } from '@pnpm/store-connection-manager'
|
||||
import { type ProjectManifest } from '@pnpm/types'
|
||||
import { createAllowBuildFunction } from '@pnpm/builder.policy'
|
||||
import * as dp from '@pnpm/dependency-path'
|
||||
import { hardLinkDir } from '@pnpm/fs.hard-link-dir'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
@@ -282,6 +283,9 @@ async function _rebuild (
|
||||
const warn = (message: string) => {
|
||||
logger.info({ message, prefix: opts.dir })
|
||||
}
|
||||
|
||||
const allowBuild = createAllowBuildFunction(opts) ?? (() => true)
|
||||
|
||||
const groups = chunks.map((chunk) => chunk.filter((depPath) => ctx.pkgsToRebuild.has(depPath) && !ctx.skipped.has(depPath)).map((depPath) =>
|
||||
async () => {
|
||||
const pkgSnapshot = pkgSnapshots[depPath]
|
||||
@@ -318,7 +322,8 @@ async function _rebuild (
|
||||
return
|
||||
}
|
||||
}
|
||||
const hasSideEffects = await runPostinstallHooks({
|
||||
|
||||
const hasSideEffects = allowBuild(pkgInfo.name) && await runPostinstallHooks({
|
||||
depPath,
|
||||
extraBinPaths,
|
||||
extraEnv: opts.extraEnv,
|
||||
|
||||
@@ -94,6 +94,8 @@ export async function handler (
|
||||
reporter?: (logObj: LogBase) => void
|
||||
pending: boolean
|
||||
skipIfHasSideEffectsCache?: boolean
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
},
|
||||
params: string[]
|
||||
) {
|
||||
|
||||
@@ -375,3 +375,44 @@ test(`rebuild should not fail on incomplete ${WANTED_LOCKFILE}`, async () => {
|
||||
storeDir,
|
||||
}, [])
|
||||
})
|
||||
|
||||
test('never build neverBuiltDependencies', async () => {
|
||||
const project = prepare()
|
||||
const cacheDir = path.resolve('cache')
|
||||
const storeDir = path.resolve('store')
|
||||
|
||||
await execa('node', [
|
||||
pnpmBin,
|
||||
'add',
|
||||
'@pnpm.e2e/install-script-example@1.0.0',
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0',
|
||||
`--registry=${REGISTRY}`,
|
||||
`--store-dir=${storeDir}`,
|
||||
`--cache-dir=${cacheDir}`,
|
||||
])
|
||||
|
||||
const modulesManifest = await project.readModulesManifest()
|
||||
await rebuild.handler(
|
||||
{
|
||||
...DEFAULT_OPTS,
|
||||
neverBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
cacheDir,
|
||||
dir: process.cwd(),
|
||||
pending: false,
|
||||
registries: modulesManifest!.registries!,
|
||||
storeDir,
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
expect(
|
||||
await exists(
|
||||
'node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-prepare.js'
|
||||
)
|
||||
).toBeFalsy()
|
||||
expect(
|
||||
await exists(
|
||||
'node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
@@ -222,3 +222,191 @@ test.skip('rebuild multiple packages in correct order', async () => {
|
||||
expect(outputs1).toStrictEqual(['project-1', 'project-2'])
|
||||
expect(outputs2).toStrictEqual(['project-1', 'project-3'])
|
||||
})
|
||||
|
||||
test('never build neverBuiltDependencies', async () => {
|
||||
const projects = preparePackages([
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
|
||||
dependencies: {
|
||||
'@pnpm.e2e/install-script-example': '*',
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': '*',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '1.0.0',
|
||||
|
||||
dependencies: {
|
||||
'@pnpm.e2e/install-script-example': '*',
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': '*',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const { allProjects, selectedProjectsGraph } = await readProjects(
|
||||
process.cwd(),
|
||||
[]
|
||||
)
|
||||
await execa(
|
||||
'node',
|
||||
[
|
||||
pnpmBin,
|
||||
'install',
|
||||
'-r',
|
||||
`--registry=${REGISTRY}`,
|
||||
`--store-dir=${path.resolve(DEFAULT_OPTS.storeDir)}`,
|
||||
`--cache-dir=${path.resolve(DEFAULT_OPTS.cacheDir)}`,
|
||||
'--ignore-scripts',
|
||||
'--reporter=append-only',
|
||||
],
|
||||
{ stdout: 'inherit' }
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
|
||||
const modulesManifest = await projects['project-1'].readModulesManifest()
|
||||
await rebuild.handler(
|
||||
{
|
||||
...DEFAULT_OPTS,
|
||||
neverBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
registries: modulesManifest!.registries!,
|
||||
selectedProjectsGraph,
|
||||
workspaceDir: process.cwd(),
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
await projects['project-1'].has(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-2'].has(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
})
|
||||
|
||||
test('only build onlyBuiltDependencies', async () => {
|
||||
const projects = preparePackages([
|
||||
{
|
||||
name: 'project-1',
|
||||
version: '1.0.0',
|
||||
|
||||
dependencies: {
|
||||
'@pnpm.e2e/install-script-example': '*',
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': '*',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'project-2',
|
||||
version: '1.0.0',
|
||||
|
||||
dependencies: {
|
||||
'@pnpm.e2e/install-script-example': '*',
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': '*',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const { allProjects, selectedProjectsGraph } = await readProjects(
|
||||
process.cwd(),
|
||||
[]
|
||||
)
|
||||
await execa(
|
||||
'node',
|
||||
[
|
||||
pnpmBin,
|
||||
'install',
|
||||
'-r',
|
||||
`--registry=${REGISTRY}`,
|
||||
`--store-dir=${path.resolve(DEFAULT_OPTS.storeDir)}`,
|
||||
`--cache-dir=${path.resolve(DEFAULT_OPTS.cacheDir)}`,
|
||||
'--ignore-scripts',
|
||||
'--reporter=append-only',
|
||||
],
|
||||
{ stdout: 'inherit' }
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
|
||||
const modulesManifest = await projects['project-1'].readModulesManifest()
|
||||
await rebuild.handler(
|
||||
{
|
||||
...DEFAULT_OPTS,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
registries: modulesManifest!.registries!,
|
||||
selectedProjectsGraph,
|
||||
workspaceDir: process.cwd(),
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
await projects['project-1'].hasNot(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-2'].hasNot(
|
||||
'@pnpm.e2e/install-script-example/generated-by-install.js'
|
||||
)
|
||||
await projects['project-1'].has(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-1'].has(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
await projects['project-2'].has(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
await projects['project-2'].has(
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js'
|
||||
)
|
||||
})
|
||||
@@ -17,6 +17,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@pnpm/build-modules": "workspace:*",
|
||||
"@pnpm/builder.policy": "1.0.0",
|
||||
"@pnpm/calc-dep-state": "workspace:*",
|
||||
"@pnpm/constants": "workspace:*",
|
||||
"@pnpm/core-loggers": "workspace:*",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import crypto from 'crypto'
|
||||
import path from 'path'
|
||||
import { buildModules, type DepsStateCache, linkBinsOfDependencies } from '@pnpm/build-modules'
|
||||
import { createAllowBuildFunction } from '@pnpm/builder.policy'
|
||||
import {
|
||||
LAYOUT_VERSION,
|
||||
LOCKFILE_VERSION,
|
||||
@@ -1364,22 +1365,6 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
}
|
||||
}
|
||||
|
||||
function createAllowBuildFunction (
|
||||
opts: {
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
}
|
||||
): undefined | ((pkgName: string) => boolean) {
|
||||
if (opts.neverBuiltDependencies != null && opts.neverBuiltDependencies.length > 0) {
|
||||
const neverBuiltDependencies = new Set(opts.neverBuiltDependencies)
|
||||
return (pkgName) => !neverBuiltDependencies.has(pkgName)
|
||||
} else if (opts.onlyBuiltDependencies != null) {
|
||||
const onlyBuiltDependencies = new Set(opts.onlyBuiltDependencies)
|
||||
return (pkgName) => onlyBuiltDependencies.has(pkgName)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
const installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
try {
|
||||
if (opts.nodeLinker === 'hoisted' && !opts.lockfileOnly) {
|
||||
|
||||
@@ -100,6 +100,7 @@ export type ImportCommandOptions = Pick<Config,
|
||||
| 'ignoreWorkspaceCycles'
|
||||
| 'disallowWorkspaceCycles'
|
||||
| 'sharedWorkspaceLockfile'
|
||||
| 'rootProjectManifest'
|
||||
> & CreateStoreControllerOptions & Omit<InstallOptions, 'storeController' | 'lockfileOnly' | 'preferredVersions'>
|
||||
|
||||
export async function handler (
|
||||
@@ -170,7 +171,7 @@ export async function handler (
|
||||
const manifest = await readProjectManifestOnly(opts.dir)
|
||||
const installOpts = {
|
||||
...opts,
|
||||
...getOptionsFromRootManifest(manifest),
|
||||
...getOptionsFromRootManifest({ ...opts.rootProjectManifest, ...manifest }),
|
||||
lockfileOnly: true,
|
||||
preferredVersions,
|
||||
storeController: store.ctrl,
|
||||
|
||||
@@ -58,6 +58,7 @@ export type InstallDepsOptions = Pick<Config,
|
||||
| 'production'
|
||||
| 'rawLocalConfig'
|
||||
| 'registries'
|
||||
| 'rootProjectManifest'
|
||||
| 'save'
|
||||
| 'saveDev'
|
||||
| 'saveExact'
|
||||
@@ -187,6 +188,7 @@ when running add/update with the --workspace option')
|
||||
params,
|
||||
{
|
||||
...opts,
|
||||
...getOptionsFromRootManifest(opts.rootProjectManifest ?? {}),
|
||||
forceHoistPattern,
|
||||
forcePublicHoistPattern,
|
||||
allProjectsGraph,
|
||||
@@ -219,7 +221,7 @@ when running add/update with the --workspace option')
|
||||
const store = await createOrConnectStoreController(opts)
|
||||
const installOpts: Omit<MutateModulesOptions, 'allProjects'> = {
|
||||
...opts,
|
||||
...getOptionsFromRootManifest(manifest),
|
||||
...getOptionsFromRootManifest({ ...opts.rootProjectManifest, ...manifest }),
|
||||
forceHoistPattern,
|
||||
forcePublicHoistPattern,
|
||||
// In case installation is done in a multi-package repository
|
||||
|
||||
@@ -58,6 +58,7 @@ type RecursiveOptions = CreateStoreControllerOptions & Pick<Config,
|
||||
| 'pnpmfile'
|
||||
| 'rawLocalConfig'
|
||||
| 'registries'
|
||||
| 'rootProjectManifest'
|
||||
| 'save'
|
||||
| 'saveDev'
|
||||
| 'saveExact'
|
||||
@@ -363,7 +364,7 @@ export async function recursive (
|
||||
{
|
||||
...installOpts,
|
||||
...localConfig,
|
||||
...getOptionsFromRootManifest(manifest),
|
||||
...getOptionsFromRootManifest({ ...opts.rootProjectManifest, ...manifest }),
|
||||
bin: path.join(rootDir, 'node_modules', '.bin'),
|
||||
dir: rootDir,
|
||||
hooks,
|
||||
@@ -412,6 +413,7 @@ export async function recursive (
|
||||
) {
|
||||
await rebuild.handler({
|
||||
...opts,
|
||||
...getOptionsFromRootManifest(opts.rootProjectManifest ?? {}),
|
||||
pending: opts.pending === true,
|
||||
skipIfHasSideEffectsCache: true,
|
||||
}, [])
|
||||
|
||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@@ -1158,6 +1158,9 @@ importers:
|
||||
|
||||
exec/plugin-commands-rebuild:
|
||||
dependencies:
|
||||
'@pnpm/builder.policy':
|
||||
specifier: 1.0.0
|
||||
version: 1.0.0
|
||||
'@pnpm/calc-dep-state':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/calc-dep-state
|
||||
@@ -2862,6 +2865,9 @@ importers:
|
||||
'@pnpm/build-modules':
|
||||
specifier: workspace:*
|
||||
version: link:../../exec/build-modules
|
||||
'@pnpm/builder.policy':
|
||||
specifier: 1.0.0
|
||||
version: 1.0.0
|
||||
'@pnpm/calc-dep-state':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/calc-dep-state
|
||||
@@ -7733,6 +7739,11 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@pnpm/builder.policy@1.0.0:
|
||||
resolution: {integrity: sha512-0BhTu6nZ5DzIjJzuTJWOVbd1cN+0wu8k1aXXSawT+/i9Biq/3vuzqnxiTSt5e7IStZ01n59GTMvCoZ/VRAYQiA==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
dev: false
|
||||
|
||||
/@pnpm/byline@1.0.0:
|
||||
resolution: {integrity: sha512-61tmh+k7hnKK6b2XbF4GvxmiaF3l2a+xQlZyeoOGBs7mXU3Ie8iCAeAnM0+r70KiqTrgWvBCjMeM+W3JarJqaQ==}
|
||||
engines: {node: '>=12.17'}
|
||||
|
||||
Reference in New Issue
Block a user