mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-27 18:46:18 -04:00
feat!: deprecate old settings that were replaced by allowBuilds (#10382)
This commit is contained in:
5
.changeset/deploy-preserve-allow-builds.md
Normal file
5
.changeset/deploy-preserve-allow-builds.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-deploy": minor
|
||||
---
|
||||
|
||||
Preserve `allowBuilds` settings when deploying a project. The `allowBuilds` configuration is now written to `pnpm-workspace.yaml` in the deploy directory.
|
||||
6
.changeset/global-install-allow-builds.md
Normal file
6
.changeset/global-install-allow-builds.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/config": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Support reading `allowBuilds` from `pnpm-workspace.yaml` in the global package directory for global installs.
|
||||
30
.changeset/remove-deprecated-build-settings.md
Normal file
30
.changeset/remove-deprecated-build-settings.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
"pnpm": major
|
||||
---
|
||||
|
||||
Remove deprecated build dependency settings: `onlyBuiltDependencies`, `onlyBuiltDependenciesFile`, `neverBuiltDependencies`, and `ignoredBuiltDependencies`.
|
||||
|
||||
Use the `allowBuilds` setting instead. It is a map where keys are package name patterns and values are booleans:
|
||||
- `true` means the package is allowed to run build scripts
|
||||
- `false` means the package is explicitly denied from running build scripts
|
||||
|
||||
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in `allowBuilds`, an error is printed.
|
||||
|
||||
Before:
|
||||
```yaml
|
||||
onlyBuiltDependencies:
|
||||
- electron
|
||||
onlyBuiltDependenciesFile: 'allowed-builds.json'
|
||||
neverBuiltDependencies:
|
||||
- core-js
|
||||
ignoredBuiltDependencies:
|
||||
- esbuild
|
||||
```
|
||||
|
||||
After:
|
||||
```yaml
|
||||
allowBuilds:
|
||||
electron: true
|
||||
core-js: false
|
||||
esbuild: false
|
||||
```
|
||||
13
.changeset/remove-deprecated-build-settings0.md
Normal file
13
.changeset/remove-deprecated-build-settings0.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
"@pnpm/types": major
|
||||
"@pnpm/config": major
|
||||
"@pnpm/core": major
|
||||
"@pnpm/headless": major
|
||||
"@pnpm/builder.policy": major
|
||||
"@pnpm/exec.build-commands": major
|
||||
"@pnpm/plugin-commands-installation": major
|
||||
"@pnpm/plugin-commands-rebuild": major
|
||||
"@pnpm/workspace.manifest-writer": major
|
||||
---
|
||||
|
||||
Remove deprecated build dependency settings: `onlyBuiltDependencies`, `onlyBuiltDependenciesFile`, `neverBuiltDependencies`, and `ignoredBuiltDependencies`.
|
||||
@@ -1,27 +1,16 @@
|
||||
import { type AllowBuild } from '@pnpm/types'
|
||||
import { expandPackageVersionSpecs } from '@pnpm/config.version-policy'
|
||||
import fs from 'fs'
|
||||
|
||||
export function createAllowBuildFunction (
|
||||
opts: {
|
||||
dangerouslyAllowAllBuilds?: boolean
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
onlyBuiltDependenciesFile?: string
|
||||
}
|
||||
): undefined | AllowBuild {
|
||||
if (opts.dangerouslyAllowAllBuilds) return () => true
|
||||
if (opts.onlyBuiltDependenciesFile != null || opts.onlyBuiltDependencies != null) {
|
||||
const onlyBuiltDeps = opts.onlyBuiltDependencies ?? []
|
||||
if (opts.onlyBuiltDependenciesFile) {
|
||||
onlyBuiltDeps.push(...JSON.parse(fs.readFileSync(opts.onlyBuiltDependenciesFile, 'utf8')))
|
||||
}
|
||||
const onlyBuiltDependencies = expandPackageVersionSpecs(onlyBuiltDeps)
|
||||
if (opts.onlyBuiltDependencies != null) {
|
||||
const onlyBuiltDependencies = expandPackageVersionSpecs(opts.onlyBuiltDependencies)
|
||||
return (pkgName, version) => onlyBuiltDependencies.has(pkgName) || onlyBuiltDependencies.has(`${pkgName}@${version}`)
|
||||
}
|
||||
if (opts.neverBuiltDependencies != null && opts.neverBuiltDependencies.length > 0) {
|
||||
const neverBuiltDependencies = new Set(opts.neverBuiltDependencies)
|
||||
return (pkgName) => !neverBuiltDependencies.has(pkgName)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
import path from 'path'
|
||||
import { createAllowBuildFunction } from '@pnpm/builder.policy'
|
||||
|
||||
it('should neverBuiltDependencies', () => {
|
||||
const allowBuild = createAllowBuildFunction({
|
||||
neverBuiltDependencies: ['foo'],
|
||||
})
|
||||
expect(typeof allowBuild).toBe('function')
|
||||
expect(allowBuild!('foo', '1.0.0')).toBeFalsy()
|
||||
expect(allowBuild!('bar', '1.0.0')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should onlyBuiltDependencies', () => {
|
||||
const allowBuild = createAllowBuildFunction({
|
||||
onlyBuiltDependencies: ['foo', 'qar@1.0.0 || 2.0.0'],
|
||||
@@ -30,28 +20,6 @@ it('should not allow patterns in onlyBuiltDependencies', () => {
|
||||
expect(allowBuild!('is-odd', '1.0.0')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should onlyBuiltDependencies set via a file', () => {
|
||||
const allowBuild = createAllowBuildFunction({
|
||||
onlyBuiltDependenciesFile: path.join(import.meta.dirname, 'onlyBuild.json'),
|
||||
})
|
||||
expect(typeof allowBuild).toBe('function')
|
||||
expect(allowBuild!('zoo', '1.0.0')).toBeTruthy()
|
||||
expect(allowBuild!('qar', '1.0.0')).toBeTruthy()
|
||||
expect(allowBuild!('bar', '1.0.0')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should onlyBuiltDependencies set via a file and config', () => {
|
||||
const allowBuild = createAllowBuildFunction({
|
||||
onlyBuiltDependencies: ['bar'],
|
||||
onlyBuiltDependenciesFile: path.join(import.meta.dirname, 'onlyBuild.json'),
|
||||
})
|
||||
expect(typeof allowBuild).toBe('function')
|
||||
expect(allowBuild!('zoo', '1.0.0')).toBeTruthy()
|
||||
expect(allowBuild!('qar', '1.0.0')).toBeTruthy()
|
||||
expect(allowBuild!('bar', '1.0.0')).toBeTruthy()
|
||||
expect(allowBuild!('esbuild', '1.0.0')).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should return undefined if no policy is set', () => {
|
||||
expect(createAllowBuildFunction({})).toBeUndefined()
|
||||
})
|
||||
|
||||
@@ -3,8 +3,6 @@ import { type Config } from './Config.js'
|
||||
export const DEPS_BUILD_CONFIG_KEYS = [
|
||||
'dangerouslyAllowAllBuilds',
|
||||
'onlyBuiltDependencies',
|
||||
'onlyBuiltDependenciesFile',
|
||||
'neverBuiltDependencies',
|
||||
'allowBuilds',
|
||||
] as const satisfies Array<keyof Config>
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@ export type OptionsFromRootManifest = {
|
||||
allowUnusedPatches?: boolean
|
||||
ignorePatchFailures?: boolean
|
||||
overrides?: Record<string, string>
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
onlyBuiltDependenciesFile?: string
|
||||
ignoredBuiltDependencies?: string[]
|
||||
packageExtensions?: Record<string, PackageExtension>
|
||||
ignoredOptionalDependencies?: string[]
|
||||
@@ -37,15 +35,9 @@ export function getOptionsFromRootManifest (manifestDir: string, manifest: Proje
|
||||
'allowUnusedPatches',
|
||||
'allowedDeprecatedVersions',
|
||||
'auditConfig',
|
||||
'auditConfig',
|
||||
'auditConfig',
|
||||
'configDependencies',
|
||||
'ignorePatchFailures',
|
||||
'ignoredBuiltDependencies',
|
||||
'ignoredOptionalDependencies',
|
||||
'neverBuiltDependencies',
|
||||
'onlyBuiltDependencies',
|
||||
'onlyBuiltDependenciesFile',
|
||||
'overrides',
|
||||
'packageExtensions',
|
||||
'patchedDependencies',
|
||||
@@ -74,9 +66,6 @@ export function getOptionsFromPnpmSettings (manifestDir: string | undefined, pnp
|
||||
settings.overrides = mapValues(createVersionReferencesReplacer(manifest), settings.overrides)
|
||||
}
|
||||
}
|
||||
if (pnpmSettings.onlyBuiltDependenciesFile && manifestDir != null) {
|
||||
settings.onlyBuiltDependenciesFile = path.join(manifestDir, pnpmSettings.onlyBuiltDependenciesFile)
|
||||
}
|
||||
if (pnpmSettings.patchedDependencies) {
|
||||
settings.patchedDependencies = { ...pnpmSettings.patchedDependencies }
|
||||
for (const [dep, patchFile] of Object.entries(pnpmSettings.patchedDependencies)) {
|
||||
@@ -93,6 +82,7 @@ export function getOptionsFromPnpmSettings (manifestDir: string | undefined, pnp
|
||||
}
|
||||
|
||||
if (pnpmSettings.allowBuilds) {
|
||||
settings.allowBuilds = pnpmSettings.allowBuilds
|
||||
settings.onlyBuiltDependencies ??= []
|
||||
settings.ignoredBuiltDependencies ??= []
|
||||
for (const [packagePattern, build] of Object.entries(pnpmSettings.allowBuilds)) {
|
||||
|
||||
@@ -412,6 +412,17 @@ export async function getConfig (opts: {
|
||||
workspaceManifest,
|
||||
})
|
||||
}
|
||||
} else if (cliOptions['global']) {
|
||||
// For global installs, read settings from pnpm-workspace.yaml in the global package directory
|
||||
const workspaceManifest = await readWorkspaceManifest(pnpmConfig.globalPkgDir)
|
||||
if (workspaceManifest) {
|
||||
addSettingsFromWorkspaceManifestToConfig(pnpmConfig, {
|
||||
configFromCliOpts,
|
||||
projectManifest: pnpmConfig.rootProjectManifest,
|
||||
workspaceDir: pnpmConfig.globalPkgDir,
|
||||
workspaceManifest,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,13 +470,8 @@ export async function getConfig (opts: {
|
||||
|
||||
overrideSupportedArchitecturesWithCLI(pnpmConfig, cliOptions)
|
||||
|
||||
if (opts.cliOptions['global']) {
|
||||
extractAndRemoveDependencyBuildOptions(pnpmConfig)
|
||||
if (!hasDependencyBuildOptions(pnpmConfig)) {
|
||||
Object.assign(pnpmConfig, globalDepsBuildConfig)
|
||||
} else {
|
||||
if (!hasDependencyBuildOptions(pnpmConfig)) {
|
||||
Object.assign(pnpmConfig, globalDepsBuildConfig)
|
||||
}
|
||||
}
|
||||
if (opts.cliOptions['save-peer']) {
|
||||
if (opts.cliOptions['save-prod']) {
|
||||
@@ -621,12 +627,6 @@ export async function getConfig (opts: {
|
||||
pnpmConfig.dev = true
|
||||
}
|
||||
|
||||
if (pnpmConfig.dangerouslyAllowAllBuilds) {
|
||||
if (pnpmConfig.neverBuiltDependencies && pnpmConfig.neverBuiltDependencies.length > 0) {
|
||||
warnings.push('You have set dangerouslyAllowAllBuilds to true. The dependencies listed in neverBuiltDependencies will run their scripts.')
|
||||
}
|
||||
pnpmConfig.neverBuiltDependencies = []
|
||||
}
|
||||
if (pnpmConfig.ci) {
|
||||
// Using a global virtual store in CI makes little sense,
|
||||
// as there is never a warm cache in that environment.
|
||||
|
||||
@@ -93,7 +93,7 @@ test('getOptionsFromRootManifest() should return onlyBuiltDependencies as undefi
|
||||
test('getOptionsFromRootManifest() should return the list from onlyBuiltDependencies', () => {
|
||||
const options = getOptionsFromRootManifest(process.cwd(), {
|
||||
pnpm: {
|
||||
onlyBuiltDependencies: ['electron'],
|
||||
allowBuilds: { electron: true },
|
||||
},
|
||||
})
|
||||
expect(options.onlyBuiltDependencies).toStrictEqual(['electron'])
|
||||
@@ -186,6 +186,11 @@ test('getOptionsFromRootManifest() converts allowBuilds', () => {
|
||||
},
|
||||
})
|
||||
expect(options).toStrictEqual({
|
||||
allowBuilds: {
|
||||
foo: true,
|
||||
bar: false,
|
||||
qar: 'warn',
|
||||
},
|
||||
onlyBuiltDependencies: ['foo'],
|
||||
ignoredBuiltDependencies: ['bar'],
|
||||
})
|
||||
|
||||
@@ -1281,38 +1281,6 @@ test('settings gitBranchLockfile in pnpm-workspace.yaml should take effect', asy
|
||||
expect(config.rawConfig['git-branch-lockfile']).toBe(true)
|
||||
})
|
||||
|
||||
test('when dangerouslyAllowAllBuilds is set to true neverBuiltDependencies is set to an empty array', async () => {
|
||||
const { config } = await getConfig({
|
||||
cliOptions: {
|
||||
'dangerously-allow-all-builds': true,
|
||||
},
|
||||
packageManager: {
|
||||
name: 'pnpm',
|
||||
version: '1.0.0',
|
||||
},
|
||||
})
|
||||
|
||||
expect(config.neverBuiltDependencies).toStrictEqual([])
|
||||
})
|
||||
|
||||
test('when dangerouslyAllowAllBuilds is set to true and neverBuiltDependencies not empty, a warning is returned', async () => {
|
||||
const workspaceDir = f.find('never-built-dependencies')
|
||||
process.chdir(workspaceDir)
|
||||
const { config, warnings } = await getConfig({
|
||||
cliOptions: {
|
||||
'dangerously-allow-all-builds': true,
|
||||
},
|
||||
packageManager: {
|
||||
name: 'pnpm',
|
||||
version: '1.0.0',
|
||||
},
|
||||
workspaceDir,
|
||||
})
|
||||
|
||||
expect(config.neverBuiltDependencies).toStrictEqual([])
|
||||
expect(warnings).toStrictEqual(['You have set dangerouslyAllowAllBuilds to true. The dependencies listed in neverBuiltDependencies will run their scripts.'])
|
||||
})
|
||||
|
||||
test('loads setting from environment variable pnpm_config_*', async () => {
|
||||
prepareEmpty()
|
||||
const { config } = await getConfig({
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"diskusage",
|
||||
"dislink",
|
||||
"dpkg",
|
||||
"drivelist",
|
||||
"duplexify",
|
||||
"eagain",
|
||||
"ebadplatform",
|
||||
|
||||
@@ -2,7 +2,6 @@ import { type Config } from '@pnpm/config'
|
||||
import { globalInfo } from '@pnpm/logger'
|
||||
import { type StrictModules, writeModulesManifest } from '@pnpm/modules-yaml'
|
||||
import { lexCompare } from '@pnpm/util.lex-comparator'
|
||||
import { type PnpmSettings } from '@pnpm/types'
|
||||
import renderHelp from 'render-help'
|
||||
import enquirer from 'enquirer'
|
||||
import chalk from 'chalk'
|
||||
@@ -92,25 +91,19 @@ export async function handler (opts: ApproveBuildsCommandOpts & RebuildCommandOp
|
||||
} as any) as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
const buildPackages = result.map(({ value }: { value: string }) => value)
|
||||
const ignoredPackages = automaticallyIgnoredBuilds.filter((automaticallyIgnoredBuild) => !buildPackages.includes(automaticallyIgnoredBuild))
|
||||
const updatedSettings: PnpmSettings = {}
|
||||
const allowBuilds: Record<string, boolean> = {}
|
||||
if (ignoredPackages.length) {
|
||||
if (opts.ignoredBuiltDependencies == null) {
|
||||
updatedSettings.ignoredBuiltDependencies = sortUniqueStrings(ignoredPackages)
|
||||
} else {
|
||||
updatedSettings.ignoredBuiltDependencies = sortUniqueStrings([
|
||||
...opts.ignoredBuiltDependencies,
|
||||
...ignoredPackages,
|
||||
])
|
||||
for (const pkg of [...ignoredPackages, ...opts.ignoredBuiltDependencies ?? []]) {
|
||||
allowBuilds[pkg] = false
|
||||
}
|
||||
}
|
||||
if (buildPackages.length) {
|
||||
if (opts.onlyBuiltDependencies == null) {
|
||||
updatedSettings.onlyBuiltDependencies = sortUniqueStrings(buildPackages)
|
||||
} else {
|
||||
updatedSettings.onlyBuiltDependencies = sortUniqueStrings([
|
||||
...opts.onlyBuiltDependencies,
|
||||
...buildPackages,
|
||||
])
|
||||
const onlyBuiltDependencies = [
|
||||
...opts.onlyBuiltDependencies ?? [],
|
||||
...buildPackages,
|
||||
]
|
||||
if (onlyBuiltDependencies.length) {
|
||||
for (const pkg of onlyBuiltDependencies) {
|
||||
allowBuilds[pkg] = true
|
||||
}
|
||||
}
|
||||
if (buildPackages.length) {
|
||||
@@ -130,12 +123,12 @@ Do you approve?`,
|
||||
await writeSettings({
|
||||
...opts,
|
||||
workspaceDir: opts.workspaceDir ?? opts.rootProjectManifestDir,
|
||||
updatedSettings,
|
||||
updatedSettings: { allowBuilds },
|
||||
})
|
||||
if (buildPackages.length) {
|
||||
return rebuild.handler({
|
||||
...opts,
|
||||
onlyBuiltDependencies: updatedSettings.onlyBuiltDependencies,
|
||||
onlyBuiltDependencies,
|
||||
}, buildPackages)
|
||||
} else if (modulesManifest) {
|
||||
delete modulesManifest.ignoredBuilds
|
||||
|
||||
@@ -2,7 +2,7 @@ import { type Config } from '@pnpm/config'
|
||||
import renderHelp from 'render-help'
|
||||
import { getAutomaticallyIgnoredBuilds } from './getAutomaticallyIgnoredBuilds.js'
|
||||
|
||||
export type IgnoredBuildsCommandOpts = Pick<Config, 'modulesDir' | 'dir' | 'rootProjectManifest' | 'lockfileDir'>
|
||||
export type IgnoredBuildsCommandOpts = Pick<Config, 'modulesDir' | 'dir' | 'ignoredBuiltDependencies' | 'lockfileDir'>
|
||||
|
||||
export const commandNames = ['ignored-builds']
|
||||
|
||||
@@ -22,7 +22,7 @@ export function rcOptionsTypes (): Record<string, unknown> {
|
||||
}
|
||||
|
||||
export async function handler (opts: IgnoredBuildsCommandOpts): Promise<string> {
|
||||
const ignoredBuiltDependencies = opts.rootProjectManifest?.pnpm?.ignoredBuiltDependencies ?? []
|
||||
const ignoredBuiltDependencies = opts.ignoredBuiltDependencies ?? []
|
||||
let { automaticallyIgnoredBuilds } = await getAutomaticallyIgnoredBuilds(opts)
|
||||
if (automaticallyIgnoredBuilds) {
|
||||
automaticallyIgnoredBuilds = automaticallyIgnoredBuilds
|
||||
@@ -35,12 +35,15 @@ export async function handler (opts: IgnoredBuildsCommandOpts): Promise<string>
|
||||
output += ' None'
|
||||
} else {
|
||||
output += ` ${automaticallyIgnoredBuilds.join('\n ')}
|
||||
hint: To allow the execution of build scripts for a package, add its name to "pnpm.onlyBuiltDependencies" in your "package.json", then run "pnpm rebuild".
|
||||
hint: If you don't want to build a package, add it to the "pnpm.ignoredBuiltDependencies" list.`
|
||||
hint: To allow the execution of build scripts for a package, add its name to "allowBuilds" and set to "true", then run "pnpm rebuild".
|
||||
hint: For example:
|
||||
hint: allowBuilds:
|
||||
hint: esbuild: true
|
||||
hint: If you don't want to build a package, set it to "false" instead.`
|
||||
}
|
||||
output += '\n'
|
||||
if (ignoredBuiltDependencies.length) {
|
||||
output += `\nExplicitly ignored package builds (via pnpm.ignoredBuiltDependencies):\n ${ignoredBuiltDependencies.join('\n ')}\n`
|
||||
output += `\nExplicitly ignored package builds (via allowBuilds):\n ${ignoredBuiltDependencies.join('\n ')}\n`
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`ignoredBuilds lists automatically ignored dependencies 1`] = `
|
||||
"Automatically ignored builds during installation:
|
||||
foo
|
||||
hint: To allow the execution of build scripts for a package, add its name to "pnpm.onlyBuiltDependencies" in your "package.json", then run "pnpm rebuild".
|
||||
hint: If you don't want to build a package, add it to the "pnpm.ignoredBuiltDependencies" list.
|
||||
hint: To allow the execution of build scripts for a package, add its name to "allowBuilds" and set to "true", then run "pnpm rebuild".
|
||||
hint: For example:
|
||||
hint: allowBuilds:
|
||||
hint: esbuild: true
|
||||
hint: If you don't want to build a package, set it to "false" instead.
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -12,10 +15,13 @@ exports[`ignoredBuilds lists both automatically and explicitly ignored dependenc
|
||||
"Automatically ignored builds during installation:
|
||||
foo
|
||||
bar
|
||||
hint: To allow the execution of build scripts for a package, add its name to "pnpm.onlyBuiltDependencies" in your "package.json", then run "pnpm rebuild".
|
||||
hint: If you don't want to build a package, add it to the "pnpm.ignoredBuiltDependencies" list.
|
||||
hint: To allow the execution of build scripts for a package, add its name to "allowBuilds" and set to "true", then run "pnpm rebuild".
|
||||
hint: For example:
|
||||
hint: allowBuilds:
|
||||
hint: esbuild: true
|
||||
hint: If you don't want to build a package, set it to "false" instead.
|
||||
|
||||
Explicitly ignored package builds (via pnpm.ignoredBuiltDependencies):
|
||||
Explicitly ignored package builds (via allowBuilds):
|
||||
qar
|
||||
zoo
|
||||
"
|
||||
@@ -25,7 +31,7 @@ exports[`ignoredBuilds lists explicitly ignored dependencies 1`] = `
|
||||
"Automatically ignored builds during installation:
|
||||
None
|
||||
|
||||
Explicitly ignored package builds (via pnpm.ignoredBuiltDependencies):
|
||||
Explicitly ignored package builds (via allowBuilds):
|
||||
bar
|
||||
"
|
||||
`;
|
||||
@@ -34,7 +40,7 @@ exports[`ignoredBuilds prints an info message when there is no node_modules 1`]
|
||||
"Automatically ignored builds during installation:
|
||||
Cannot identify as no node_modules found
|
||||
|
||||
Explicitly ignored package builds (via pnpm.ignoredBuiltDependencies):
|
||||
Explicitly ignored package builds (via allowBuilds):
|
||||
qar
|
||||
zoo
|
||||
"
|
||||
|
||||
@@ -4,12 +4,10 @@ import { install } from '@pnpm/plugin-commands-installation'
|
||||
import { type ApproveBuildsCommandOpts } from '@pnpm/exec.build-commands'
|
||||
import { type RebuildCommandOpts } from '@pnpm/plugin-commands-rebuild'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { type ProjectManifest } from '@pnpm/types'
|
||||
import { getConfig } from '@pnpm/config'
|
||||
import { readModulesManifest } from '@pnpm/modules-yaml'
|
||||
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
import { jest } from '@jest/globals'
|
||||
import { loadJsonFileSync } from 'load-json-file'
|
||||
import { omit } from 'ramda'
|
||||
import { tempDir } from '@pnpm/prepare-temp-dir'
|
||||
import { writePackageSync } from 'write-package'
|
||||
@@ -88,16 +86,15 @@ test('approve selected build', async () => {
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': '1.0.0',
|
||||
'@pnpm.e2e/install-script-example': '*',
|
||||
},
|
||||
pnpm: {
|
||||
overrides: {},
|
||||
},
|
||||
})
|
||||
|
||||
await approveSomeBuilds()
|
||||
|
||||
const manifest = loadJsonFileSync<ProjectManifest>(path.resolve('package.json'))
|
||||
expect(manifest.pnpm?.onlyBuiltDependencies).toStrictEqual(['@pnpm.e2e/pre-and-postinstall-scripts-example'])
|
||||
expect(manifest.pnpm?.ignoredBuiltDependencies).toStrictEqual(['@pnpm.e2e/install-script-example'])
|
||||
const workspaceManifest = readYamlFile<any>(path.resolve('pnpm-workspace.yaml')) // eslint-disable-line
|
||||
expect(workspaceManifest.allowBuilds).toStrictEqual({
|
||||
'@pnpm.e2e/install-script-example': false,
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': true,
|
||||
})
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeTruthy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeTruthy()
|
||||
@@ -155,62 +152,6 @@ test("works when root project manifest doesn't exist in a workspace", async () =
|
||||
})
|
||||
})
|
||||
|
||||
test('should update onlyBuiltDependencies when package.json exists with ignoredBuiltDependencies defined', async () => {
|
||||
const temp = tempDir()
|
||||
const rootProjectManifest = {
|
||||
dependencies: {
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': '1.0.0',
|
||||
'@pnpm.e2e/install-script-example': '*',
|
||||
},
|
||||
pnpm: {
|
||||
ignoredBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
},
|
||||
}
|
||||
|
||||
prepare(rootProjectManifest, {
|
||||
tempDir: temp,
|
||||
})
|
||||
|
||||
const workspaceManifestFile = path.join(temp, 'pnpm-workspace.yaml')
|
||||
writeYamlFile(workspaceManifestFile, { packages: ['packages/*'] })
|
||||
await approveSomeBuilds({ workspaceDir: temp, rootProjectManifestDir: temp, rootProjectManifest })
|
||||
|
||||
expect(readYamlFile(workspaceManifestFile)).toStrictEqual({
|
||||
packages: ['packages/*'],
|
||||
})
|
||||
expect(loadJsonFileSync<ProjectManifest>(path.join(temp, 'package.json'))!.pnpm).toStrictEqual({
|
||||
ignoredBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
})
|
||||
|
||||
test('should approve builds when package.json exists with onlyBuiltDependencies defined', async () => {
|
||||
const temp = tempDir()
|
||||
|
||||
prepare({
|
||||
dependencies: {
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': '1.0.0',
|
||||
'@pnpm.e2e/install-script-example': '*',
|
||||
},
|
||||
pnpm: {
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
},
|
||||
}, {
|
||||
tempDir: temp,
|
||||
})
|
||||
|
||||
const workspaceManifestFile = path.join(temp, 'pnpm-workspace.yaml')
|
||||
writeYamlFile(workspaceManifestFile, { packages: ['packages/*'] })
|
||||
await approveSomeBuilds({ workspaceDir: temp, rootProjectManifestDir: temp })
|
||||
|
||||
expect(readYamlFile(workspaceManifestFile)).toStrictEqual({
|
||||
packages: ['packages/*'],
|
||||
})
|
||||
expect(loadJsonFileSync<ProjectManifest>(path.join(temp, 'package.json'))!.pnpm).toStrictEqual({
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example', '@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
})
|
||||
|
||||
test('should approve builds with package.json that has no onlyBuiltDependencies and ignoredBuiltDependencies fields defined', async () => {
|
||||
const temp = tempDir()
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ test('ignoredBuilds lists automatically ignored dependencies', async () => {
|
||||
const output = await ignoredBuilds.handler({
|
||||
dir,
|
||||
modulesDir,
|
||||
rootProjectManifest: {},
|
||||
ignoredBuiltDependencies: [],
|
||||
})
|
||||
expect(output).toMatchSnapshot()
|
||||
})
|
||||
@@ -52,11 +52,7 @@ test('ignoredBuilds lists explicitly ignored dependencies', async () => {
|
||||
const output = await ignoredBuilds.handler({
|
||||
dir,
|
||||
modulesDir,
|
||||
rootProjectManifest: {
|
||||
pnpm: {
|
||||
ignoredBuiltDependencies: ['bar'],
|
||||
},
|
||||
},
|
||||
ignoredBuiltDependencies: ['bar'],
|
||||
})
|
||||
expect(output).toMatchSnapshot()
|
||||
})
|
||||
@@ -72,11 +68,7 @@ test('ignoredBuilds lists both automatically and explicitly ignored dependencies
|
||||
const output = await ignoredBuilds.handler({
|
||||
dir,
|
||||
modulesDir,
|
||||
rootProjectManifest: {
|
||||
pnpm: {
|
||||
ignoredBuiltDependencies: ['qar', 'zoo'],
|
||||
},
|
||||
},
|
||||
ignoredBuiltDependencies: ['qar', 'zoo'],
|
||||
})
|
||||
expect(output).toMatchSnapshot()
|
||||
})
|
||||
@@ -87,11 +79,7 @@ test('ignoredBuilds prints an info message when there is no node_modules', async
|
||||
const output = await ignoredBuilds.handler({
|
||||
dir,
|
||||
modulesDir,
|
||||
rootProjectManifest: {
|
||||
pnpm: {
|
||||
ignoredBuiltDependencies: ['qar', 'zoo'],
|
||||
},
|
||||
},
|
||||
ignoredBuiltDependencies: ['qar', 'zoo'],
|
||||
})
|
||||
expect(output).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -51,7 +51,7 @@ export type StrictRebuildOptions = {
|
||||
peersSuffixMaxLength: number
|
||||
strictStorePkgContentCheck: boolean
|
||||
fetchFullMetadata?: boolean
|
||||
} & Pick<Config, 'sslConfigs' | 'onlyBuiltDependencies' | 'onlyBuiltDependenciesFile' | 'neverBuiltDependencies' | 'ignoredBuiltDependencies'>
|
||||
} & Pick<Config, 'sslConfigs' | 'onlyBuiltDependencies' | 'ignoredBuiltDependencies'>
|
||||
|
||||
export type RebuildOptions = Partial<StrictRebuildOptions> &
|
||||
Pick<StrictRebuildOptions, 'storeDir' | 'storeController'> & Pick<Config, 'rootProjectManifest' | 'rootProjectManifestDir'>
|
||||
@@ -106,7 +106,7 @@ export async function extendRebuildOptions (
|
||||
...(opts.rootProjectManifest ? getOptionsFromRootManifest(opts.rootProjectManifestDir, opts.rootProjectManifest) : {}),
|
||||
}
|
||||
extendedOpts.registries = normalizeRegistries(extendedOpts.registries)
|
||||
if (extendedOpts.neverBuiltDependencies == null && extendedOpts.onlyBuiltDependencies == null && extendedOpts.onlyBuiltDependenciesFile == null) {
|
||||
if (extendedOpts.onlyBuiltDependencies == null) {
|
||||
extendedOpts.onlyBuiltDependencies = []
|
||||
}
|
||||
return extendedOpts
|
||||
|
||||
@@ -50,6 +50,7 @@ test('rebuilds dependencies', async () => {
|
||||
pending: false,
|
||||
registries: modulesManifest!.registries!,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example', 'test-git-fetch'],
|
||||
}, [])
|
||||
|
||||
modules = project.readModulesManifest()
|
||||
@@ -139,6 +140,7 @@ test('skipIfHasSideEffectsCache', async () => {
|
||||
registries: modulesManifest!.registries!,
|
||||
skipIfHasSideEffectsCache: true,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
}, [])
|
||||
|
||||
modules = project.readModulesManifest()
|
||||
@@ -176,6 +178,7 @@ test('rebuild does not fail when a linked package is present', async () => {
|
||||
pending: false,
|
||||
registries: modulesManifest!.registries!,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['local-pkg', 'is-positive'],
|
||||
}, [])
|
||||
|
||||
// see related issue https://github.com/pnpm/pnpm/issues/1155
|
||||
@@ -206,6 +209,7 @@ test('rebuilds specific dependencies', async () => {
|
||||
pending: false,
|
||||
registries: modulesManifest!.registries!,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['install-scripts-example-for-pnpm'],
|
||||
}, ['install-scripts-example-for-pnpm'])
|
||||
|
||||
project.hasNot('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall')
|
||||
@@ -265,6 +269,7 @@ test('rebuild with pending option', async () => {
|
||||
pending: true,
|
||||
registries: modules!.registries!,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example', 'install-scripts-example-for-pnpm'],
|
||||
}, [])
|
||||
|
||||
modules = project.readModulesManifest()
|
||||
@@ -318,6 +323,7 @@ test('rebuild dependencies in correct order', async () => {
|
||||
pending: false,
|
||||
registries: modules!.registries!,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/with-postinstall-a', '@pnpm.e2e/with-postinstall-b'],
|
||||
}, [])
|
||||
|
||||
modules = project.readModulesManifest()
|
||||
@@ -359,6 +365,7 @@ test('rebuild links bins', async () => {
|
||||
pending: true,
|
||||
registries: modules!.registries!,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/has-generated-bins-as-dep', '@pnpm.e2e/generated-bins'],
|
||||
}, [])
|
||||
|
||||
project.isExecutable('.bin/cmd1')
|
||||
@@ -400,51 +407,6 @@ test(`rebuild should not fail on incomplete ${WANTED_LOCKFILE}`, async () => {
|
||||
registries: modules!.registries!,
|
||||
reporter,
|
||||
storeDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example', '@pnpm.e2e/not-compatible-with-any-os'],
|
||||
}, [])
|
||||
})
|
||||
|
||||
test('never build neverBuiltDependencies', async () => {
|
||||
const project = prepare({
|
||||
pnpm: {
|
||||
neverBuiltDependencies: [],
|
||||
},
|
||||
})
|
||||
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}`,
|
||||
'--config.enableGlobalVirtualStore=false',
|
||||
])
|
||||
|
||||
const modulesManifest = 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(
|
||||
fs.existsSync(
|
||||
'node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-prepare.js'
|
||||
)
|
||||
).toBeFalsy()
|
||||
expect(
|
||||
fs.existsSync(
|
||||
'node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js'
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
||||
@@ -58,6 +58,7 @@ test('pnpm recursive rebuild', async () => {
|
||||
registries: modulesManifest!.registries!,
|
||||
selectedProjectsGraph,
|
||||
workspaceDir: process.cwd(),
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
}, [])
|
||||
|
||||
projects['project-1'].has('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')
|
||||
@@ -136,6 +137,7 @@ test('pnpm recursive rebuild with hoisted node linker', async () => {
|
||||
selectedProjectsGraph,
|
||||
lockfileDir: process.cwd(),
|
||||
workspaceDir: process.cwd(),
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
}, [])
|
||||
|
||||
rootProject.has('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')
|
||||
@@ -215,13 +217,14 @@ test('rebuild multiple packages in correct order', async () => {
|
||||
recursive: true,
|
||||
selectedProjectsGraph,
|
||||
workspaceDir: process.cwd(),
|
||||
onlyBuiltDependencies: ['project-1', 'project-2', 'project-3'],
|
||||
}, [])
|
||||
|
||||
expect(server1.getLines()).toStrictEqual(['project-1', 'project-2'])
|
||||
expect(server2.getLines()).toStrictEqual(['project-1', 'project-3'])
|
||||
})
|
||||
|
||||
test('never build neverBuiltDependencies', async () => {
|
||||
test('only build onlyBuiltDependencies (not others)', async () => {
|
||||
const projects = preparePackages([
|
||||
{
|
||||
name: 'project-1',
|
||||
@@ -285,7 +288,7 @@ test('never build neverBuiltDependencies', async () => {
|
||||
await rebuild.handler(
|
||||
{
|
||||
...DEFAULT_OPTS,
|
||||
neverBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
|
||||
@@ -28,7 +28,6 @@ export const DEFAULT_OPTS = {
|
||||
localAddress: undefined,
|
||||
lock: false,
|
||||
lockStaleDuration: 90,
|
||||
neverBuiltDependencies: [],
|
||||
networkConcurrency: 16,
|
||||
offline: false,
|
||||
pending: false,
|
||||
|
||||
@@ -151,11 +151,7 @@ export interface AuditConfig {
|
||||
|
||||
export interface PnpmSettings {
|
||||
configDependencies?: ConfigDependencies
|
||||
neverBuiltDependencies?: string[] // deprecated
|
||||
onlyBuiltDependencies?: string[] // deprecated
|
||||
onlyBuiltDependenciesFile?: string // deprecated
|
||||
allowBuilds?: Record<string, boolean | string>
|
||||
ignoredBuiltDependencies?: string[]
|
||||
overrides?: Record<string, string>
|
||||
packageExtensions?: Record<string, PackageExtension>
|
||||
ignoredOptionalDependencies?: string[]
|
||||
|
||||
@@ -72,9 +72,7 @@ export interface StrictInstallOptions {
|
||||
verifyStoreIntegrity: boolean
|
||||
engineStrict: boolean
|
||||
ignoredBuiltDependencies?: string[]
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
onlyBuiltDependenciesFile?: string
|
||||
nodeExecPath?: string
|
||||
nodeLinker: 'isolated' | 'hoisted' | 'pnp'
|
||||
nodeVersion?: string
|
||||
@@ -291,12 +289,9 @@ export function extendOptions (
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts.neverBuiltDependencies == null && opts.onlyBuiltDependencies == null && opts.onlyBuiltDependenciesFile == null) {
|
||||
if (opts.onlyBuiltDependencies == null) {
|
||||
opts.onlyBuiltDependencies = []
|
||||
}
|
||||
if (opts.onlyBuiltDependencies && opts.neverBuiltDependencies) {
|
||||
throw new PnpmError('CONFIG_CONFLICT_BUILT_DEPENDENCIES', 'Cannot have both neverBuiltDependencies and onlyBuiltDependencies')
|
||||
}
|
||||
const defaultOpts = defaults(opts)
|
||||
const extendedOpts: ProcessedInstallOptions = {
|
||||
...defaultOpts,
|
||||
|
||||
@@ -370,11 +370,9 @@ export async function mutateModules (
|
||||
if (!opts.ignoreScripts && ignoredBuilds?.size) {
|
||||
ignoredBuilds = await runUnignoredDependencyBuilds(opts, ignoredBuilds)
|
||||
}
|
||||
if (!opts.neverBuiltDependencies) {
|
||||
ignoredScriptsLogger.debug({
|
||||
packageNames: ignoredBuilds ? dedupePackageNamesFromIgnoredBuilds(ignoredBuilds) : [],
|
||||
})
|
||||
}
|
||||
ignoredScriptsLogger.debug({
|
||||
packageNames: ignoredBuilds ? dedupePackageNamesFromIgnoredBuilds(ignoredBuilds) : [],
|
||||
})
|
||||
|
||||
if ((reporter != null) && typeof reporter === 'function') {
|
||||
streamParser.removeListener('data', reporter)
|
||||
@@ -1085,7 +1083,6 @@ type InstallFunction = (
|
||||
patchedDependencies?: PatchGroupRecord
|
||||
makePartialCurrentLockfile: boolean
|
||||
needsFullResolution: boolean
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
overrides?: Record<string, string>
|
||||
updateLockfileMinorVersion: boolean
|
||||
|
||||
@@ -184,7 +184,12 @@ test('run pre/postinstall scripts. bin files should be linked in a hoisted node_
|
||||
const project = prepareEmpty()
|
||||
await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
testDefaults({ fastUnpack: false, nodeLinker: 'hoisted', targetDependenciesField: 'devDependencies' })
|
||||
testDefaults({
|
||||
fastUnpack: false,
|
||||
nodeLinker: 'hoisted',
|
||||
targetDependenciesField: 'devDependencies',
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
)
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-prepare.js')).toBeFalsy()
|
||||
@@ -212,7 +217,7 @@ test('running install scripts in a workspace that has no root project', async ()
|
||||
},
|
||||
mutation: 'install',
|
||||
rootDir: path.resolve('project-1') as ProjectRootDir,
|
||||
}, testDefaults({ fastUnpack: false, nodeLinker: 'hoisted' }))
|
||||
}, testDefaults({ fastUnpack: false, nodeLinker: 'hoisted', onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'] }))
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -27,7 +27,7 @@ test('run pre/postinstall scripts', async () => {
|
||||
const project = prepareEmpty()
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'],
|
||||
testDefaults({ fastUnpack: false, targetDependenciesField: 'devDependencies' })
|
||||
testDefaults({ fastUnpack: false, targetDependenciesField: 'devDependencies', onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'] })
|
||||
)
|
||||
|
||||
{
|
||||
@@ -46,7 +46,7 @@ test('run pre/postinstall scripts', async () => {
|
||||
// testing that the packages are not installed even though they are in lockfile
|
||||
// and that their scripts are not tried to be executed
|
||||
|
||||
await install(manifest, testDefaults({ fastUnpack: false, production: true }))
|
||||
await install(manifest, testDefaults({ fastUnpack: false, production: true, onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'] }))
|
||||
|
||||
{
|
||||
const generatedByPreinstall = project.requireModule('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall')
|
||||
@@ -95,6 +95,7 @@ test('run pre/postinstall scripts, when PnP is used and no symlinks', async () =
|
||||
enablePnp: true,
|
||||
symlink: false,
|
||||
targetDependenciesField: 'devDependencies',
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
)
|
||||
|
||||
@@ -108,7 +109,7 @@ test('testing that the bins are linked when the package with the bins was alread
|
||||
const project = prepareEmpty()
|
||||
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({}, ['@pnpm.e2e/hello-world-js-bin'], testDefaults({ fastUnpack: false }))
|
||||
await addDependenciesToPackage(manifest, ['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'], testDefaults({ fastUnpack: false, targetDependenciesField: 'devDependencies' }))
|
||||
await addDependenciesToPackage(manifest, ['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'], testDefaults({ fastUnpack: false, targetDependenciesField: 'devDependencies', onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'] }))
|
||||
|
||||
const generatedByPreinstall = project.requireModule('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall')
|
||||
expect(typeof generatedByPreinstall).toBe('function')
|
||||
@@ -119,7 +120,7 @@ test('testing that the bins are linked when the package with the bins was alread
|
||||
|
||||
test('run install scripts', async () => {
|
||||
const project = prepareEmpty()
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/install-script-example'], testDefaults({ fastUnpack: false }))
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/install-script-example'], testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['@pnpm.e2e/install-script-example'] }))
|
||||
|
||||
const generatedByInstall = project.requireModule('@pnpm.e2e/install-script-example/generated-by-install')
|
||||
expect(typeof generatedByInstall).toBe('function')
|
||||
@@ -202,6 +203,7 @@ test('INIT_CWD is always set to lockfile directory', async () => {
|
||||
}, testDefaults({
|
||||
fastUnpack: false,
|
||||
lockfileDir: rootDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/write-lifecycle-env'],
|
||||
}))
|
||||
|
||||
const childEnv = loadJsonFileSync<{ INIT_CWD: string }>(path.join(rootDir, 'node_modules/@pnpm.e2e/write-lifecycle-env/env.json'))
|
||||
@@ -217,7 +219,7 @@ test("reports child's output", async () => {
|
||||
|
||||
const reporter = sinon.spy()
|
||||
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/count-to-10'], testDefaults({ fastUnpack: false, reporter }))
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/count-to-10'], testDefaults({ fastUnpack: false, reporter, onlyBuiltDependencies: ['@pnpm.e2e/count-to-10'] }))
|
||||
|
||||
expect(reporter.calledWithMatch({
|
||||
depPath: '@pnpm.e2e/count-to-10@1.0.0',
|
||||
@@ -265,7 +267,7 @@ test("reports child's close event", async () => {
|
||||
const reporter = sinon.spy()
|
||||
|
||||
await expect(
|
||||
addDependenciesToPackage({}, ['@pnpm.e2e/failing-postinstall'], testDefaults({ reporter }))
|
||||
addDependenciesToPackage({}, ['@pnpm.e2e/failing-postinstall'], testDefaults({ reporter, onlyBuiltDependencies: ['@pnpm.e2e/failing-postinstall'] }))
|
||||
).rejects.toThrow()
|
||||
|
||||
expect(reporter.calledWithMatch({
|
||||
@@ -293,7 +295,7 @@ testOnNonWindows('lifecycle scripts have access to node-gyp', async () => {
|
||||
!p.includes(`${path.sep}.npm${path.sep}`))
|
||||
.join(path.delimiter)
|
||||
|
||||
await addDependenciesToPackage({}, ['drivelist@5.1.8'], testDefaults({ fastUnpack: false }))
|
||||
await addDependenciesToPackage({}, ['drivelist@5.1.8'], testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['drivelist'] }))
|
||||
|
||||
process.env[PATH] = initialPath
|
||||
})
|
||||
@@ -301,7 +303,7 @@ testOnNonWindows('lifecycle scripts have access to node-gyp', async () => {
|
||||
test('run lifecycle scripts of dependent packages after running scripts of their deps', async () => {
|
||||
const project = prepareEmpty()
|
||||
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/with-postinstall-a'], testDefaults({ fastUnpack: false }))
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/with-postinstall-a'], testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['@pnpm.e2e/with-postinstall-a', '@pnpm.e2e/with-postinstall-b'] }))
|
||||
|
||||
expect(+project.requireModule('.pnpm/@pnpm.e2e+with-postinstall-b@1.0.0/node_modules/@pnpm.e2e/with-postinstall-b/output.json')[0] < +project.requireModule('@pnpm.e2e/with-postinstall-a/output.json')[0]).toBeTruthy()
|
||||
})
|
||||
@@ -330,7 +332,7 @@ test('run prepare script for git-hosted dependencies', async () => {
|
||||
test('lifecycle scripts run before linking bins', async () => {
|
||||
const project = prepareEmpty()
|
||||
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({}, ['@pnpm.e2e/generated-bins'], testDefaults({ fastUnpack: false }))
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({}, ['@pnpm.e2e/generated-bins'], testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['@pnpm.e2e/generated-bins'] }))
|
||||
|
||||
project.isExecutable('.bin/cmd1')
|
||||
project.isExecutable('.bin/cmd2')
|
||||
@@ -341,7 +343,7 @@ test('lifecycle scripts run before linking bins', async () => {
|
||||
manifest,
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd() as ProjectRootDir,
|
||||
}, testDefaults({ frozenLockfile: true }))
|
||||
}, testDefaults({ frozenLockfile: true, onlyBuiltDependencies: ['@pnpm.e2e/generated-bins'] }))
|
||||
|
||||
project.isExecutable('.bin/cmd1')
|
||||
project.isExecutable('.bin/cmd2')
|
||||
@@ -350,7 +352,7 @@ test('lifecycle scripts run before linking bins', async () => {
|
||||
test('hoisting does not fail on commands that will be created by lifecycle scripts on a later stage', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({}, ['@pnpm.e2e/has-generated-bins-as-dep'], testDefaults({ fastUnpack: false, hoistPattern: '*' }))
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({}, ['@pnpm.e2e/has-generated-bins-as-dep'], testDefaults({ fastUnpack: false, hoistPattern: '*', onlyBuiltDependencies: ['@pnpm.e2e/has-generated-bins-as-dep', '@pnpm.e2e/generated-bins'] }))
|
||||
|
||||
// project.isExecutable('.pnpm/node_modules/.bin/cmd1')
|
||||
// project.isExecutable('.pnpm/node_modules/.bin/cmd2')
|
||||
@@ -362,7 +364,7 @@ test('hoisting does not fail on commands that will be created by lifecycle scrip
|
||||
manifest,
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd() as ProjectRootDir,
|
||||
}, testDefaults({ frozenLockfile: true, hoistPattern: '*' }))
|
||||
}, testDefaults({ frozenLockfile: true, hoistPattern: '*', onlyBuiltDependencies: ['@pnpm.e2e/has-generated-bins-as-dep', '@pnpm.e2e/generated-bins'] }))
|
||||
|
||||
// project.isExecutable('.pnpm/node_modules/.bin/cmd1')
|
||||
// project.isExecutable('.pnpm/node_modules/.bin/cmd2')
|
||||
@@ -423,7 +425,7 @@ test('dependency should not be added to current lockfile if it was not built suc
|
||||
manifest,
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd() as ProjectRootDir,
|
||||
}, testDefaults({ frozenLockfile: true }))
|
||||
}, testDefaults({ frozenLockfile: true, onlyBuiltDependencies: ['package-that-cannot-be-installed'] }))
|
||||
).rejects.toThrow()
|
||||
|
||||
expect(project.readCurrentLockfile()).toBeFalsy()
|
||||
@@ -435,53 +437,19 @@ test('scripts have access to unlisted bins when hoisting is used', async () => {
|
||||
await addDependenciesToPackage(
|
||||
{},
|
||||
['@pnpm.e2e/pkg-that-calls-unlisted-dep-in-hooks'],
|
||||
testDefaults({ fastUnpack: false, hoistPattern: '*' })
|
||||
testDefaults({ fastUnpack: false, hoistPattern: '*', onlyBuiltDependencies: ['@pnpm.e2e/pkg-that-calls-unlisted-dep-in-hooks'] })
|
||||
)
|
||||
|
||||
expect(project.requireModule('@pnpm.e2e/pkg-that-calls-unlisted-dep-in-hooks/output.json')).toStrictEqual(['Hello world!'])
|
||||
})
|
||||
|
||||
test('selectively ignore scripts in some dependencies by neverBuiltDependencies', async () => {
|
||||
prepareEmpty()
|
||||
const neverBuiltDependencies = ['@pnpm.e2e/pre-and-postinstall-scripts-example']
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'],
|
||||
testDefaults({ fastUnpack: false, neverBuiltDependencies })
|
||||
)
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
|
||||
rimraf('node_modules')
|
||||
|
||||
await install(manifest, testDefaults({ fastUnpack: false, frozenLockfile: true, neverBuiltDependencies }))
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('throw an exception when both neverBuiltDependencies and onlyBuiltDependencies are used', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
await expect(
|
||||
addDependenciesToPackage(
|
||||
{},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'],
|
||||
testDefaults({ onlyBuiltDependencies: ['@pnpm.e2e/foo'], neverBuiltDependencies: ['@pnpm.e2e/bar'] })
|
||||
)
|
||||
).rejects.toThrow(/Cannot have both/)
|
||||
})
|
||||
|
||||
test('selectively allow scripts in some dependencies by onlyBuiltDependencies', async () => {
|
||||
prepareEmpty()
|
||||
const reporter = sinon.spy()
|
||||
const onlyBuiltDependencies = ['@pnpm.e2e/install-script-example']
|
||||
const neverBuiltDependencies: string[] | undefined = undefined
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'],
|
||||
testDefaults({ fastUnpack: false, onlyBuiltDependencies, neverBuiltDependencies, reporter })
|
||||
testDefaults({ fastUnpack: false, onlyBuiltDependencies, reporter })
|
||||
)
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
@@ -500,7 +468,6 @@ test('selectively allow scripts in some dependencies by onlyBuiltDependencies',
|
||||
fastUnpack: false,
|
||||
frozenLockfile: true,
|
||||
ignoredBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
neverBuiltDependencies,
|
||||
onlyBuiltDependencies,
|
||||
reporter,
|
||||
}))
|
||||
@@ -519,10 +486,9 @@ test('selectively allow scripts in some dependencies by onlyBuiltDependencies us
|
||||
prepareEmpty()
|
||||
const reporter = sinon.spy()
|
||||
const onlyBuiltDependencies = ['@pnpm.e2e/install-script-example@1.0.0']
|
||||
const neverBuiltDependencies: string[] | undefined = undefined
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'],
|
||||
testDefaults({ fastUnpack: false, onlyBuiltDependencies, neverBuiltDependencies, reporter })
|
||||
testDefaults({ fastUnpack: false, onlyBuiltDependencies, reporter })
|
||||
)
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
@@ -541,7 +507,6 @@ test('selectively allow scripts in some dependencies by onlyBuiltDependencies us
|
||||
fastUnpack: false,
|
||||
frozenLockfile: true,
|
||||
ignoredBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
neverBuiltDependencies,
|
||||
onlyBuiltDependencies,
|
||||
reporter,
|
||||
}))
|
||||
@@ -560,7 +525,7 @@ test('lifecycle scripts have access to package\'s own binary by binary name', as
|
||||
const project = prepareEmpty()
|
||||
await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/runs-own-bin'],
|
||||
testDefaults({ fastUnpack: false })
|
||||
testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['@pnpm.e2e/runs-own-bin'] })
|
||||
)
|
||||
|
||||
project.isExecutable('.pnpm/@pnpm.e2e+runs-own-bin@1.0.0/node_modules/@pnpm.e2e/runs-own-bin/node_modules/.bin/runs-own-bin')
|
||||
@@ -580,7 +545,7 @@ test('lifecycle scripts run after linking root dependencies', async () => {
|
||||
manifest,
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd() as ProjectRootDir,
|
||||
}, testDefaults({ fastUnpack: false }))
|
||||
}, testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['@pnpm.e2e/postinstall-requires-is-positive'] }))
|
||||
|
||||
rimraf('node_modules')
|
||||
|
||||
@@ -588,7 +553,7 @@ test('lifecycle scripts run after linking root dependencies', async () => {
|
||||
manifest,
|
||||
mutation: 'install',
|
||||
rootDir: process.cwd() as ProjectRootDir,
|
||||
}, testDefaults({ fastUnpack: false, frozenLockfile: true }))
|
||||
}, testDefaults({ fastUnpack: false, frozenLockfile: true, onlyBuiltDependencies: ['@pnpm.e2e/postinstall-requires-is-positive'] }))
|
||||
|
||||
// if there was no exception, the test passed
|
||||
})
|
||||
@@ -718,6 +683,7 @@ test('run pre/postinstall scripts in a workspace that uses node-linker=hoisted',
|
||||
allProjects,
|
||||
fastUnpack: false,
|
||||
nodeLinker: 'hoisted',
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
}))
|
||||
const rootProject = assertProject(process.cwd())
|
||||
rootProject.has('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')
|
||||
@@ -736,7 +702,7 @@ test('run pre/postinstall scripts in a project that uses node-linker=hoisted. Sh
|
||||
const project = prepareEmpty()
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'],
|
||||
testDefaults({ fastUnpack: false, targetDependenciesField: 'devDependencies', nodeLinker: 'hoisted', sideEffectsCacheRead: true, sideEffectsCacheWrite: true })
|
||||
testDefaults({ fastUnpack: false, targetDependenciesField: 'devDependencies', nodeLinker: 'hoisted', sideEffectsCacheRead: true, sideEffectsCacheWrite: true, onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'] })
|
||||
)
|
||||
|
||||
{
|
||||
@@ -760,6 +726,7 @@ test('run pre/postinstall scripts in a project that uses node-linker=hoisted. Sh
|
||||
reporter,
|
||||
sideEffectsCacheRead: true,
|
||||
sideEffectsCacheWrite: true,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
)
|
||||
|
||||
@@ -771,13 +738,11 @@ test('run pre/postinstall scripts in a project that uses node-linker=hoisted. Sh
|
||||
|
||||
test('build dependencies that were not previously built after onlyBuiltDependencies changes', async () => {
|
||||
prepareEmpty()
|
||||
const neverBuiltDependencies: string[] | undefined = undefined
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({},
|
||||
['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'],
|
||||
testDefaults({
|
||||
fastUnpack: false,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
neverBuiltDependencies,
|
||||
})
|
||||
)
|
||||
|
||||
@@ -789,7 +754,6 @@ test('build dependencies that were not previously built after onlyBuiltDependenc
|
||||
fastUnpack: false,
|
||||
frozenLockfile: true,
|
||||
ignoredBuiltDependencies: [],
|
||||
neverBuiltDependencies,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'],
|
||||
}))
|
||||
|
||||
|
||||
@@ -549,7 +549,7 @@ test('bin specified in the directories property symlinked to .bin folder when pr
|
||||
testOnNonWindows('building native addons', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
await addDependenciesToPackage({}, ['diskusage@1.1.3'], testDefaults({ fastUnpack: false }))
|
||||
await addDependenciesToPackage({}, ['diskusage@1.1.3'], testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['diskusage'] }))
|
||||
|
||||
expect(fs.existsSync('node_modules/diskusage/build')).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -578,7 +578,9 @@ test('fail on a package with failing postinstall if the package is both an optio
|
||||
'@pnpm.e2e/has-failing-postinstall-dep': '1.0.0',
|
||||
},
|
||||
},
|
||||
testDefaults({})
|
||||
testDefaults({
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/has-failing-postinstall-dep', '@pnpm.e2e/failing-postinstall'],
|
||||
})
|
||||
)
|
||||
).rejects.toThrow()
|
||||
})
|
||||
|
||||
@@ -822,7 +822,7 @@ test('peer bins are linked', async () => {
|
||||
test('run pre/postinstall scripts of each variations of packages with peer dependencies', async () => {
|
||||
await addDistTag({ package: '@pnpm.e2e/peer-c', version: '1.0.0', distTag: 'latest' })
|
||||
prepareEmpty()
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/parent-of-pkg-with-events-and-peers', '@pnpm.e2e/pkg-with-events-and-peers', '@pnpm.e2e/peer-c@2.0.0'], testDefaults({ fastUnpack: false }))
|
||||
await addDependenciesToPackage({}, ['@pnpm.e2e/parent-of-pkg-with-events-and-peers', '@pnpm.e2e/pkg-with-events-and-peers', '@pnpm.e2e/peer-c@2.0.0'], testDefaults({ fastUnpack: false, onlyBuiltDependencies: ['@pnpm.e2e/pkg-with-events-and-peers'] }))
|
||||
|
||||
const pkgVariation1 = path.resolve('node_modules/.pnpm/@pnpm.e2e+pkg-with-events-and-peers@1.0.0_@pnpm.e2e+peer-c@1.0.0/node_modules')
|
||||
await okFile(path.join(pkgVariation1, '@pnpm.e2e/pkg-with-events-and-peers', 'generated-by-preinstall.js'))
|
||||
|
||||
@@ -79,6 +79,7 @@ test('using side effects cache', async () => {
|
||||
sideEffectsCacheRead: true,
|
||||
sideEffectsCacheWrite: true,
|
||||
verifyStoreIntegrity: false,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
}, {}, {}, { packageImportMethod: 'copy' })
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({}, ['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'], opts)
|
||||
|
||||
@@ -111,6 +112,7 @@ test('using side effects cache', async () => {
|
||||
sideEffectsCacheWrite: true,
|
||||
storeDir: opts.storeDir,
|
||||
verifyStoreIntegrity: false,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
}, {}, {}, { packageImportMethod: 'copy' })
|
||||
await addDependenciesToPackage(manifest, ['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'], opts2)
|
||||
|
||||
@@ -159,6 +161,7 @@ test('uploading errors do not interrupt installation', async () => {
|
||||
fastUnpack: false,
|
||||
sideEffectsCacheRead: true,
|
||||
sideEffectsCacheWrite: true,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
opts.storeController.upload = async () => {
|
||||
throw new Error('an unexpected error')
|
||||
@@ -179,6 +182,7 @@ test('a postinstall script does not modify the original sources added to the sto
|
||||
fastUnpack: false,
|
||||
sideEffectsCacheRead: true,
|
||||
sideEffectsCacheWrite: true,
|
||||
onlyBuiltDependencies: ['@pnpm/postinstall-modifies-source'],
|
||||
}, {}, {}, { packageImportMethod: 'hardlink' })
|
||||
await addDependenciesToPackage({}, ['@pnpm/postinstall-modifies-source@1.0.0'], opts)
|
||||
|
||||
@@ -211,6 +215,7 @@ test('a corrupted side-effects cache is ignored', async () => {
|
||||
fastUnpack: false,
|
||||
sideEffectsCacheRead: true,
|
||||
sideEffectsCacheWrite: true,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
const { updatedManifest: manifest } = await addDependenciesToPackage({}, ['@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0'], opts)
|
||||
|
||||
@@ -242,6 +247,7 @@ test('a corrupted side-effects cache is ignored', async () => {
|
||||
sideEffectsCacheRead: true,
|
||||
sideEffectsCacheWrite: true,
|
||||
storeDir: opts.storeDir,
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
await install(manifest, opts2)
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ export function testDefaults<T> (
|
||||
})
|
||||
const result = {
|
||||
cacheDir,
|
||||
neverBuiltDependencies: [] as string[],
|
||||
registries: {
|
||||
default: registry,
|
||||
},
|
||||
|
||||
@@ -104,10 +104,8 @@ export interface Project {
|
||||
|
||||
export interface HeadlessOptions {
|
||||
ignorePatchFailures?: boolean
|
||||
neverBuiltDependencies?: string[]
|
||||
ignoredBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
onlyBuiltDependenciesFile?: string
|
||||
autoInstallPeers?: boolean
|
||||
childConcurrency?: number
|
||||
currentLockfile?: LockfileObject
|
||||
|
||||
@@ -263,28 +263,41 @@ export async function handler (
|
||||
if (opts.argv.original.includes('--allow-build')) {
|
||||
throw new PnpmError('ALLOW_BUILD_MISSING_PACKAGE', 'The --allow-build flag is missing a package name. Please specify the package name(s) that are allowed to run installation scripts.')
|
||||
}
|
||||
if (opts.rootProjectManifest?.pnpm?.ignoredBuiltDependencies?.length) {
|
||||
const overlapDependencies = opts.rootProjectManifest.pnpm.ignoredBuiltDependencies.filter((dep) => opts.allowBuild?.includes(dep))
|
||||
if (opts.rootProjectManifest?.pnpm?.allowBuilds) {
|
||||
const ignoredBuiltDependencies = Object.keys(opts.rootProjectManifest.pnpm.allowBuilds)
|
||||
.filter(pkg => opts.rootProjectManifest!.pnpm!.allowBuilds![pkg] === false)
|
||||
const overlapDependencies = ignoredBuiltDependencies.filter((dep) => opts.allowBuild?.includes(dep))
|
||||
if (overlapDependencies.length) {
|
||||
throw new PnpmError('OVERRIDING_IGNORED_BUILT_DEPENDENCIES', `The following dependencies are ignored by the root project, but are allowed to be built by the current command: ${overlapDependencies.join(', ')}`, {
|
||||
hint: 'If you are sure you want to allow those dependencies to run installation scripts, remove them from the pnpm.ignoredBuiltDependencies list.',
|
||||
hint: 'If you are sure you want to allow those dependencies to run installation scripts, remove them from the pnpm.allowBuilds list (or change their value to true).',
|
||||
})
|
||||
}
|
||||
}
|
||||
opts.onlyBuiltDependencies = Array.from(new Set([
|
||||
...(opts.onlyBuiltDependencies ?? []),
|
||||
...opts.allowBuild,
|
||||
])).sort((a, b) => a.localeCompare(b))
|
||||
const allowBuilds: Record<string, boolean> = {}
|
||||
for (const pkg of opts.allowBuild) {
|
||||
allowBuilds[pkg] = true
|
||||
}
|
||||
if (opts.rootProjectManifestDir) {
|
||||
opts.rootProjectManifest = opts.rootProjectManifest ?? {}
|
||||
await writeSettings({
|
||||
...opts,
|
||||
workspaceDir: opts.workspaceDir ?? opts.rootProjectManifestDir,
|
||||
updatedSettings: {
|
||||
onlyBuiltDependencies: opts.onlyBuiltDependencies,
|
||||
allowBuilds,
|
||||
},
|
||||
})
|
||||
}
|
||||
// Pass the allowed packages to onlyBuiltDependencies so they can build during this install
|
||||
return installDeps({
|
||||
...opts,
|
||||
onlyBuiltDependencies: [
|
||||
...opts.onlyBuiltDependencies ?? [],
|
||||
...opts.allowBuild,
|
||||
],
|
||||
fetchFullMetadata: getFetchFullMetadata(opts),
|
||||
include,
|
||||
includeDirect: include,
|
||||
}, params)
|
||||
}
|
||||
return installDeps({
|
||||
...opts,
|
||||
|
||||
@@ -95,6 +95,7 @@ export type InstallDepsOptions = Pick<Config,
|
||||
| 'sharedWorkspaceLockfile'
|
||||
| 'shellEmulator'
|
||||
| 'tag'
|
||||
| 'onlyBuiltDependencies'
|
||||
| 'optional'
|
||||
| 'workspaceConcurrency'
|
||||
| 'workspaceDir'
|
||||
@@ -212,11 +213,18 @@ when running add/update with the --workspace option')
|
||||
linkWorkspacePackages: Boolean(opts.linkWorkspacePackages),
|
||||
}).graph
|
||||
|
||||
const recursiveRootManifestOpts = getOptionsFromRootManifest(opts.rootProjectManifestDir, opts.rootProjectManifest ?? {})
|
||||
await recursiveInstallThenUpdateWorkspaceState(allProjects,
|
||||
params,
|
||||
{
|
||||
...opts,
|
||||
...getOptionsFromRootManifest(opts.rootProjectManifestDir, opts.rootProjectManifest ?? {}),
|
||||
...recursiveRootManifestOpts,
|
||||
// Preserve onlyBuiltDependencies from opts if explicitly passed (e.g., from --allow-build flag)
|
||||
// and merge with any from the manifest
|
||||
onlyBuiltDependencies: [
|
||||
...recursiveRootManifestOpts.onlyBuiltDependencies ?? [],
|
||||
...opts.onlyBuiltDependencies ?? [],
|
||||
],
|
||||
forceHoistPattern,
|
||||
forcePublicHoistPattern,
|
||||
allProjectsGraph,
|
||||
@@ -247,9 +255,16 @@ when running add/update with the --workspace option')
|
||||
manifest = {}
|
||||
}
|
||||
|
||||
const rootManifestOpts = getOptionsFromRootManifest(opts.dir, (opts.dir === opts.rootProjectManifestDir ? opts.rootProjectManifest ?? manifest : manifest))
|
||||
const installOpts: Omit<MutateModulesOptions, 'allProjects'> = {
|
||||
...opts,
|
||||
...getOptionsFromRootManifest(opts.dir, (opts.dir === opts.rootProjectManifestDir ? opts.rootProjectManifest ?? manifest : manifest)),
|
||||
...rootManifestOpts,
|
||||
// Preserve onlyBuiltDependencies from opts if explicitly passed (e.g., from --allow-build flag)
|
||||
// and merge with any from the manifest
|
||||
onlyBuiltDependencies: [
|
||||
...rootManifestOpts.onlyBuiltDependencies ?? [],
|
||||
...opts.onlyBuiltDependencies ?? [],
|
||||
],
|
||||
forceHoistPattern,
|
||||
forcePublicHoistPattern,
|
||||
// In case installation is done in a multi-package repository
|
||||
|
||||
@@ -67,6 +67,7 @@ export type RecursiveOptions = CreateStoreControllerOptions & Pick<Config,
|
||||
| 'lockfileDir'
|
||||
| 'lockfileOnly'
|
||||
| 'modulesDir'
|
||||
| 'onlyBuiltDependencies'
|
||||
| 'rawLocalConfig'
|
||||
| 'registries'
|
||||
| 'rootProjectManifest'
|
||||
|
||||
20
pnpm-lock.yaml
generated
20
pnpm-lock.yaml
generated
@@ -7020,6 +7020,9 @@ importers:
|
||||
render-help:
|
||||
specifier: 'catalog:'
|
||||
version: 1.0.3
|
||||
write-yaml-file:
|
||||
specifier: 'catalog:'
|
||||
version: 5.0.0
|
||||
devDependencies:
|
||||
'@jest/globals':
|
||||
specifier: 'catalog:'
|
||||
@@ -7048,9 +7051,6 @@ importers:
|
||||
'@types/ramda':
|
||||
specifier: 'catalog:'
|
||||
version: 0.29.12
|
||||
write-yaml-file:
|
||||
specifier: 'catalog:'
|
||||
version: 5.0.0
|
||||
|
||||
releasing/plugin-commands-publishing:
|
||||
dependencies:
|
||||
@@ -18412,7 +18412,7 @@ snapshots:
|
||||
'@pnpm/fs.packlist': 2.0.0
|
||||
'@pnpm/logger': 1001.0.0
|
||||
'@pnpm/prepare-package': 1000.0.16(@pnpm/logger@1001.0.0)(typanion@3.14.0)
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@packages+logger)(@types/node@22.15.30)
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@1001.0.0)(@types/node@22.15.30)
|
||||
'@zkochan/rimraf': 3.0.2
|
||||
execa: safe-execa@0.1.2
|
||||
transitivePeerDependencies:
|
||||
@@ -18547,7 +18547,7 @@ snapshots:
|
||||
'@pnpm/find-workspace-dir': 1000.1.0
|
||||
'@pnpm/logger': 1001.0.0
|
||||
'@pnpm/types': 1000.6.0
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@packages+logger)(@types/node@22.15.30)
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@1001.0.0)(@types/node@22.15.30)
|
||||
'@pnpm/workspace.find-packages': 1000.0.25(@pnpm/logger@1001.0.0)(@pnpm/worker@1000.1.7(@pnpm/logger@1001.0.0)(@types/node@22.15.30))(typanion@3.14.0)
|
||||
'@pnpm/workspace.read-manifest': 1000.1.5
|
||||
load-json-file: 7.0.1
|
||||
@@ -18753,7 +18753,7 @@ snapshots:
|
||||
'@pnpm/store-controller-types': 1003.0.2
|
||||
'@pnpm/store.cafs': 1000.0.13
|
||||
'@pnpm/types': 1000.6.0
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@packages+logger)(@types/node@22.15.30)
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@1001.0.0)(@types/node@22.15.30)
|
||||
p-defer: 3.0.0
|
||||
p-limit: 3.1.0
|
||||
p-queue: 6.6.2
|
||||
@@ -18772,7 +18772,7 @@ snapshots:
|
||||
'@pnpm/store-controller-types': 1003.0.2
|
||||
'@pnpm/store.cafs': 1000.0.13
|
||||
'@pnpm/types': 1000.6.0
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@packages+logger)(@types/node@22.15.30)
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@1001.0.0)(@types/node@22.15.30)
|
||||
'@zkochan/rimraf': 3.0.2
|
||||
load-json-file: 6.2.0
|
||||
ramda: '@pnpm/ramda@0.28.1'
|
||||
@@ -19051,7 +19051,7 @@ snapshots:
|
||||
'@pnpm/graceful-fs': 1000.0.0
|
||||
'@pnpm/logger': 1001.0.0
|
||||
'@pnpm/prepare-package': 1000.0.16(@pnpm/logger@1001.0.0)(typanion@3.14.0)
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@packages+logger)(@types/node@22.15.30)
|
||||
'@pnpm/worker': 1000.1.7(@pnpm/logger@1001.0.0)(@types/node@22.15.30)
|
||||
'@zkochan/retry': 0.2.0
|
||||
lodash.throttle: 4.1.1
|
||||
p-map-values: 1.0.0
|
||||
@@ -19090,7 +19090,7 @@ snapshots:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
'@pnpm/worker@1000.1.7(@pnpm/logger@packages+logger)(@types/node@22.15.30)':
|
||||
'@pnpm/worker@1000.1.7(@pnpm/logger@1001.0.0)(@types/node@22.15.30)':
|
||||
dependencies:
|
||||
'@pnpm/cafs-types': 1000.0.0
|
||||
'@pnpm/create-cafs-store': 1000.0.14(@pnpm/logger@1001.0.0)
|
||||
@@ -19099,7 +19099,7 @@ snapshots:
|
||||
'@pnpm/exec.pkg-requires-build': 1000.0.8
|
||||
'@pnpm/fs.hard-link-dir': 1000.0.1(@pnpm/logger@1001.0.0)
|
||||
'@pnpm/graceful-fs': 1000.0.0
|
||||
'@pnpm/logger': link:packages/logger
|
||||
'@pnpm/logger': 1001.0.0
|
||||
'@pnpm/store.cafs': 1000.0.13
|
||||
'@pnpm/symlink-dependency': 1000.0.9(@pnpm/logger@1001.0.0)
|
||||
'@rushstack/worker-pool': 0.4.9(@types/node@22.15.30)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from 'fs'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { getIntegrity } from '@pnpm/registry-mock'
|
||||
import { sync as rimraf } from '@zkochan/rimraf'
|
||||
import { sync as readYamlFile } from 'read-yaml-file'
|
||||
import { sync as writeYamlFile } from 'write-yaml-file'
|
||||
import { execPnpm } from './utils/index.js'
|
||||
@@ -39,56 +38,6 @@ test('patch from configuration dependency is applied via updateConfig hook', asy
|
||||
expect(lockfile.patchedDependencies['@pnpm.e2e/foo'].path).toBe('node_modules/.pnpm-config/@pnpm.e2e/has-patch-for-foo/@pnpm.e2e__foo@100.0.0.patch')
|
||||
})
|
||||
|
||||
test('selectively allow scripts in some dependencies by onlyBuiltDependenciesFile', async () => {
|
||||
prepare({})
|
||||
writeYamlFile('pnpm-workspace.yaml', {
|
||||
configDependencies: {
|
||||
'@pnpm.e2e/build-allow-list': `1.0.0+${getIntegrity('@pnpm.e2e/build-allow-list', '1.0.0')}`,
|
||||
},
|
||||
onlyBuiltDependenciesFile: 'node_modules/.pnpm-config/@pnpm.e2e/build-allow-list/list.json',
|
||||
strictDepBuilds: false,
|
||||
})
|
||||
|
||||
await execPnpm(['add', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'])
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
|
||||
rimraf('node_modules')
|
||||
|
||||
await execPnpm(['install'])
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('selectively allow scripts in some dependencies by onlyBuiltDependenciesFile and onlyBuiltDependencies', async () => {
|
||||
prepare()
|
||||
writeYamlFile('pnpm-workspace.yaml', {
|
||||
configDependencies: {
|
||||
'@pnpm.e2e/build-allow-list': `1.0.0+${getIntegrity('@pnpm.e2e/build-allow-list', '1.0.0')}`,
|
||||
},
|
||||
onlyBuiltDependenciesFile: 'node_modules/.pnpm-config/@pnpm.e2e/build-allow-list/list.json',
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/pre-and-postinstall-scripts-example'],
|
||||
})
|
||||
|
||||
await execPnpm(['add', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'])
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeTruthy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeTruthy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
|
||||
rimraf('node_modules')
|
||||
|
||||
await execPnpm(['install'])
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeTruthy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeTruthy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('catalog applied by configurational dependency hook', async () => {
|
||||
const project = prepare({
|
||||
dependencies: {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { LAYOUT_VERSION } from '@pnpm/constants'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { type ProjectManifest } from '@pnpm/types'
|
||||
import isWindows from 'is-windows'
|
||||
import writeYamlFile from 'write-yaml-file'
|
||||
import {
|
||||
addDistTag,
|
||||
execPnpm,
|
||||
@@ -100,7 +101,12 @@ test('run lifecycle events of global packages in correct working directory', asy
|
||||
const pnpmHome = path.join(global, 'pnpm')
|
||||
const globalPkgDir = path.join(pnpmHome, 'global', String(LAYOUT_VERSION))
|
||||
fs.mkdirSync(globalPkgDir, { recursive: true })
|
||||
fs.writeFileSync(path.join(globalPkgDir, 'package.json'), JSON.stringify({ pnpm: { neverBuiltDependencies: [] } }))
|
||||
fs.writeFileSync(path.join(globalPkgDir, 'package.json'), JSON.stringify({}))
|
||||
writeYamlFile.sync(path.join(globalPkgDir, 'pnpm-workspace.yaml'), {
|
||||
allowBuilds: {
|
||||
'@pnpm.e2e/postinstall-calls-pnpm': true,
|
||||
},
|
||||
})
|
||||
|
||||
const env = {
|
||||
[PATH_NAME]: `${pnpmHome}${path.delimiter}${process.env[PATH_NAME]!}`,
|
||||
@@ -124,7 +130,7 @@ test.skip('dangerously-allow-all-builds=true in global config', async () => {
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
pnpm: {
|
||||
onlyBuiltDependencies: [], // don't allow any dependencies to be built
|
||||
allowBuilds: {}, // don't allow any dependencies to be built
|
||||
},
|
||||
}
|
||||
|
||||
@@ -160,7 +166,7 @@ test.skip('dangerously-allow-all-builds=true in global config', async () => {
|
||||
expect(fs.readdirSync(path.resolve('node_modules/@pnpm.e2e/postinstall-calls-pnpm'))).not.toContain('created-by-postinstall')
|
||||
|
||||
// global config should be used if local config did not specify
|
||||
delete manifest.pnpm!.onlyBuiltDependencies
|
||||
delete manifest.pnpm!.allowBuilds
|
||||
project.writePackageJson(manifest)
|
||||
fs.rmSync('node_modules', { recursive: true })
|
||||
fs.rmSync('pnpm-lock.yaml')
|
||||
@@ -179,7 +185,7 @@ test.skip('dangerously-allow-all-builds=false in global config', async () => {
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
pnpm: {
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/postinstall-calls-pnpm'],
|
||||
allowBuilds: { '@pnpm.e2e/postinstall-calls-pnpm': true },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -215,7 +221,7 @@ test.skip('dangerously-allow-all-builds=false in global config', async () => {
|
||||
expect(fs.readdirSync(path.resolve('node_modules/@pnpm.e2e/postinstall-calls-pnpm'))).toContain('created-by-postinstall')
|
||||
|
||||
// global config should be used if local config did not specify
|
||||
delete manifest.pnpm!.onlyBuiltDependencies
|
||||
delete manifest.pnpm!.allowBuilds
|
||||
project.writePackageJson(manifest)
|
||||
fs.rmSync('node_modules', { recursive: true })
|
||||
fs.rmSync('pnpm-lock.yaml')
|
||||
|
||||
@@ -2,12 +2,10 @@ import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { type PackageManifest, type ProjectManifest } from '@pnpm/types'
|
||||
import { sync as rimraf } from '@zkochan/rimraf'
|
||||
import PATH from 'path-name'
|
||||
import { loadJsonFileSync } from 'load-json-file'
|
||||
import writeYamlFile from 'write-yaml-file'
|
||||
import { execPnpmSync, pnpmBinLocation } from '../utils/index.js'
|
||||
import { getIntegrity } from '@pnpm/registry-mock'
|
||||
import { readWorkspaceManifest } from '@pnpm/workspace.read-manifest'
|
||||
|
||||
const pkgRoot = path.join(import.meta.dirname, '..', '..')
|
||||
@@ -108,9 +106,9 @@ test('dependency should not be added to package.json and lockfile if it was not
|
||||
const initialPkg = {
|
||||
name: 'foo',
|
||||
version: '1.0.0',
|
||||
pnpm: { neverBuiltDependencies: [] },
|
||||
}
|
||||
const project = prepare(initialPkg)
|
||||
await writeYamlFile('pnpm-workspace.yaml', { allowBuilds: { 'package-that-cannot-be-installed': true } })
|
||||
|
||||
const result = execPnpmSync(['install', 'package-that-cannot-be-installed@0.0.0'])
|
||||
|
||||
@@ -145,36 +143,6 @@ test('node-gyp is in the PATH', async () => {
|
||||
expect(result.status).toBe(0)
|
||||
})
|
||||
|
||||
test('selectively allow scripts in some dependencies by onlyBuiltDependenciesFile', async () => {
|
||||
prepare({
|
||||
pnpm: {
|
||||
configDependencies: {
|
||||
'@pnpm.e2e/build-allow-list': `1.0.0+${getIntegrity('@pnpm.e2e/build-allow-list', '1.0.0')}`,
|
||||
},
|
||||
onlyBuiltDependenciesFile: 'node_modules/.pnpm-config/@pnpm.e2e/build-allow-list/list.json',
|
||||
},
|
||||
})
|
||||
execPnpmSync(['add', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'])
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
|
||||
rimraf('node_modules')
|
||||
|
||||
execPnpmSync(['install', '--frozen-lockfile'])
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
|
||||
execPnpmSync(['rebuild'])
|
||||
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('selectively allow scripts in some dependencies by --allow-build flag', async () => {
|
||||
const project = prepare({})
|
||||
execPnpmSync(['add', '--allow-build=@pnpm.e2e/install-script-example', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'])
|
||||
@@ -183,10 +151,7 @@ test('selectively allow scripts in some dependencies by --allow-build flag', asy
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
|
||||
const manifest = loadJsonFileSync<ProjectManifest>('package.json')
|
||||
expect(manifest.pnpm?.onlyBuiltDependencies).toBeUndefined()
|
||||
const modulesManifest = await readWorkspaceManifest(project.dir())
|
||||
expect(modulesManifest?.onlyBuiltDependencies).toBeUndefined()
|
||||
expect(modulesManifest?.allowBuilds).toStrictEqual({ '@pnpm.e2e/install-script-example': true })
|
||||
})
|
||||
|
||||
@@ -201,22 +166,8 @@ test('--allow-build flag should specify the package', async () => {
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/@pnpm.e2e/install-script-example/generated-by-install.js')).toBeFalsy()
|
||||
|
||||
const manifest = loadJsonFileSync<ProjectManifest>('package.json')
|
||||
expect(manifest.pnpm?.onlyBuiltDependencies).toBeUndefined()
|
||||
const modulesManifest = await readWorkspaceManifest(project.dir())
|
||||
expect(modulesManifest?.onlyBuiltDependencies).toBeUndefined()
|
||||
})
|
||||
|
||||
test('selectively allow scripts in some dependencies by --allow-build flag overlap ignoredBuiltDependencies', async () => {
|
||||
prepare({
|
||||
pnpm: {
|
||||
ignoredBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
},
|
||||
})
|
||||
const result = execPnpmSync(['add', '--allow-build=@pnpm.e2e/install-script-example', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'])
|
||||
|
||||
expect(result.status).toBe(1)
|
||||
expect(result.stdout.toString()).toContain('The following dependencies are ignored by the root project, but are allowed to be built by the current command: @pnpm.e2e/install-script-example')
|
||||
expect(modulesManifest?.allowBuilds).toBeUndefined()
|
||||
})
|
||||
|
||||
test('preinstall script does not trigger verify-deps-before-run (#8954)', async () => {
|
||||
@@ -310,3 +261,15 @@ test('git dependencies with preparation scripts should be installed when dangero
|
||||
expect(result.status).toBe(0)
|
||||
expect(fs.existsSync('node_modules/test-git-fetch/dist/index.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('--allow-build flag should error when conflicting with allowBuilds: false', async () => {
|
||||
prepare({
|
||||
pnpm: {
|
||||
allowBuilds: { '@pnpm.e2e/install-script-example': false },
|
||||
},
|
||||
})
|
||||
const result = execPnpmSync(['add', '--allow-build=@pnpm.e2e/install-script-example', '@pnpm.e2e/pre-and-postinstall-scripts-example@1.0.0', '@pnpm.e2e/install-script-example'])
|
||||
|
||||
expect(result.status).toBe(1)
|
||||
expect(result.stdout.toString()).toContain('The following dependencies are ignored by the root project, but are allowed to be built by the current command: @pnpm.e2e/install-script-example')
|
||||
})
|
||||
|
||||
@@ -1251,11 +1251,7 @@ test('dependencies of workspace projects are built during headless installation'
|
||||
const projects = preparePackages([
|
||||
{
|
||||
location: '.',
|
||||
package: {
|
||||
pnpm: {
|
||||
neverBuiltDependencies: [],
|
||||
},
|
||||
},
|
||||
package: {},
|
||||
},
|
||||
{
|
||||
name: 'project-1',
|
||||
@@ -1270,6 +1266,9 @@ test('dependencies of workspace projects are built during headless installation'
|
||||
writeYamlFile('pnpm-workspace.yaml', {
|
||||
packages: ['**', '!store/**'],
|
||||
sharedWorkspaceLockfile: false,
|
||||
allowBuilds: {
|
||||
'@pnpm.e2e/pre-and-postinstall-scripts-example': true,
|
||||
},
|
||||
})
|
||||
|
||||
await execPnpm(['install', '--lockfile-only'])
|
||||
@@ -1890,9 +1889,6 @@ test('deploy should keep files created by lifecycle scripts', async () => {
|
||||
name: 'root',
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
pnpm: {
|
||||
neverBuiltDependencies: [],
|
||||
},
|
||||
},
|
||||
'project-0': {
|
||||
name: 'project-0',
|
||||
@@ -1914,6 +1910,9 @@ test('deploy should keep files created by lifecycle scripts', async () => {
|
||||
writeYamlFile('pnpm-workspace.yaml', {
|
||||
packages: ['**', '!store/**'],
|
||||
injectWorkspacePackages: true,
|
||||
allowBuilds: {
|
||||
'@pnpm.e2e/install-script-example': true,
|
||||
},
|
||||
})
|
||||
|
||||
const monorepoRoot = process.cwd()
|
||||
@@ -1941,9 +1940,6 @@ test('rebuild in a directory created with "pnpm deploy" and with "pnpm.neverBuil
|
||||
name: 'root',
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
pnpm: {
|
||||
neverBuiltDependencies: [],
|
||||
},
|
||||
},
|
||||
'project-0': {
|
||||
name: 'project-0',
|
||||
@@ -1965,6 +1961,9 @@ test('rebuild in a directory created with "pnpm deploy" and with "pnpm.neverBuil
|
||||
writeYamlFile('pnpm-workspace.yaml', {
|
||||
packages: ['**', '!store/**'],
|
||||
injectWorkspacePackages: true,
|
||||
allowBuilds: {
|
||||
'@pnpm.e2e/install-script-example': true,
|
||||
},
|
||||
})
|
||||
|
||||
const monorepoRoot = process.cwd()
|
||||
|
||||
@@ -5,11 +5,7 @@ test('`pnpm recursive rebuild` specific dependencies', async () => {
|
||||
const projects = preparePackages([
|
||||
{
|
||||
location: '.',
|
||||
package: {
|
||||
pnpm: {
|
||||
neverBuiltDependencies: [],
|
||||
},
|
||||
},
|
||||
package: {},
|
||||
},
|
||||
{
|
||||
name: 'project-1',
|
||||
@@ -42,7 +38,7 @@ test('`pnpm recursive rebuild` specific dependencies', async () => {
|
||||
projects['project-2'].hasNot('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')
|
||||
projects['project-2'].hasNot('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')
|
||||
|
||||
await execPnpm(['recursive', 'rebuild', 'install-scripts-example-for-pnpm'])
|
||||
await execPnpm(['recursive', 'rebuild', 'install-scripts-example-for-pnpm', '--config.dangerouslyAllowAllBuilds=true'])
|
||||
|
||||
projects['project-1'].hasNot('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-preinstall.js')
|
||||
projects['project-1'].hasNot('@pnpm.e2e/pre-and-postinstall-scripts-example/generated-by-postinstall.js')
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
"@zkochan/rimraf": "catalog:",
|
||||
"normalize-path": "catalog:",
|
||||
"ramda": "catalog:",
|
||||
"render-help": "catalog:"
|
||||
"render-help": "catalog:",
|
||||
"write-yaml-file": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@pnpm/logger": "catalog:"
|
||||
@@ -63,8 +64,7 @@
|
||||
"@pnpm/registry-mock": "catalog:",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@pnpm/workspace.filter-packages-from-dir": "workspace:*",
|
||||
"@types/ramda": "catalog:",
|
||||
"write-yaml-file": "catalog:"
|
||||
"@types/ramda": "catalog:"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19"
|
||||
|
||||
@@ -30,11 +30,17 @@ export interface CreateDeployFilesOptions {
|
||||
selectedProjectManifest: ProjectManifest
|
||||
projectId: ProjectId
|
||||
rootProjectManifestDir: string
|
||||
allowBuilds?: Record<string, boolean | string>
|
||||
}
|
||||
|
||||
export interface DeployWorkspaceManifest {
|
||||
allowBuilds?: Record<string, boolean | string>
|
||||
}
|
||||
|
||||
export interface DeployFiles {
|
||||
lockfile: LockfileObject
|
||||
manifest: ProjectManifest
|
||||
workspaceManifest?: DeployWorkspaceManifest
|
||||
}
|
||||
|
||||
export function createDeployFiles ({
|
||||
@@ -46,6 +52,7 @@ export function createDeployFiles ({
|
||||
selectedProjectManifest,
|
||||
projectId,
|
||||
rootProjectManifestDir,
|
||||
allowBuilds,
|
||||
}: CreateDeployFilesOptions): DeployFiles {
|
||||
const deployedProjectRealPath = path.resolve(lockfileDir, projectId)
|
||||
const inputSnapshot = lockfile.importers[projectId]
|
||||
@@ -160,6 +167,12 @@ export function createDeployFiles ({
|
||||
}
|
||||
}
|
||||
|
||||
if (allowBuilds) {
|
||||
result.workspaceManifest = {
|
||||
allowBuilds,
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import path from 'path'
|
||||
import { pick } from 'ramda'
|
||||
import { docsUrl } from '@pnpm/cli-utils'
|
||||
import { type Config, types as configTypes } from '@pnpm/config'
|
||||
import { WORKSPACE_MANIFEST_FILENAME } from '@pnpm/constants'
|
||||
import { fetchFromDir } from '@pnpm/directory-fetcher'
|
||||
import { createIndexedPkgImporter } from '@pnpm/fs.indexed-pkg-importer'
|
||||
import { isEmptyDirOrNothing } from '@pnpm/fs.is-empty-dir-or-nothing'
|
||||
@@ -12,6 +13,7 @@ import { PnpmError } from '@pnpm/error'
|
||||
import { getLockfileImporterId, readWantedLockfile, writeWantedLockfile } from '@pnpm/lockfile.fs'
|
||||
import rimraf from '@zkochan/rimraf'
|
||||
import renderHelp from 'render-help'
|
||||
import writeYamlFile from 'write-yaml-file'
|
||||
import { deployHook } from './deployHook.js'
|
||||
import { logger, globalWarn } from '@pnpm/logger'
|
||||
import { type Project } from '@pnpm/types'
|
||||
@@ -78,7 +80,7 @@ export function help (): string {
|
||||
|
||||
export type DeployOptions =
|
||||
& Omit<install.InstallCommandOptions, 'useLockfile'>
|
||||
& Pick<Config, 'forceLegacyDeploy'>
|
||||
& Pick<Config, 'allowBuilds' | 'forceLegacyDeploy'>
|
||||
|
||||
export async function handler (opts: DeployOptions, params: string[]): Promise<void> {
|
||||
if (!opts.workspaceDir) {
|
||||
@@ -240,15 +242,22 @@ async function deployFromSharedLockfile (
|
||||
selectedProjectManifest: selectedProject.manifest,
|
||||
projectId,
|
||||
rootProjectManifestDir,
|
||||
allowBuilds: opts.allowBuilds,
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
const filesToWrite: Array<Promise<void>> = [
|
||||
fs.promises.writeFile(
|
||||
path.join(deployDir, 'package.json'),
|
||||
JSON.stringify(deployFiles.manifest, undefined, 2) + '\n'
|
||||
),
|
||||
writeWantedLockfile(deployDir, deployFiles.lockfile),
|
||||
])
|
||||
]
|
||||
if (deployFiles.workspaceManifest) {
|
||||
filesToWrite.push(
|
||||
writeYamlFile(path.join(deployDir, WORKSPACE_MANIFEST_FILENAME), deployFiles.workspaceManifest)
|
||||
)
|
||||
}
|
||||
await Promise.all(filesToWrite)
|
||||
|
||||
try {
|
||||
await install.handler({
|
||||
|
||||
@@ -278,7 +278,7 @@ test('the deploy manifest should inherit some fields from the pnpm object from t
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
pnpm: {
|
||||
onlyBuiltDependencies: ['from-root'],
|
||||
allowBuilds: { 'from-root': true },
|
||||
overrides: {
|
||||
'is-positive': '2.0.0',
|
||||
},
|
||||
@@ -292,7 +292,7 @@ test('the deploy manifest should inherit some fields from the pnpm object from t
|
||||
'is-positive': '3.1.0',
|
||||
},
|
||||
pnpm: {
|
||||
onlyBuiltDependencies: ['from-project-0'],
|
||||
allowBuilds: { 'from-project-0': true },
|
||||
overrides: {
|
||||
'is-positive': '=1.0.0',
|
||||
},
|
||||
@@ -344,7 +344,7 @@ test('the deploy manifest should inherit some fields from the pnpm object from t
|
||||
|
||||
const manifest = readPackageJson('deploy') as ProjectManifest
|
||||
expect(manifest.pnpm).toStrictEqual({
|
||||
onlyBuiltDependencies: preparedManifests.root.pnpm!.onlyBuiltDependencies,
|
||||
allowBuilds: preparedManifests.root.pnpm!.allowBuilds,
|
||||
} as ProjectManifest['pnpm'])
|
||||
|
||||
expect(readPackageJson('deploy/node_modules/is-positive/')).toHaveProperty(['version'], preparedManifests.root.pnpm!.overrides!['is-positive'])
|
||||
@@ -1079,9 +1079,6 @@ test('deploy with a shared lockfile should keep files created by lifecycle scrip
|
||||
name: 'root',
|
||||
version: '0.0.0',
|
||||
private: true,
|
||||
pnpm: {
|
||||
neverBuiltDependencies: [],
|
||||
},
|
||||
},
|
||||
'project-0': {
|
||||
name: 'project-0',
|
||||
@@ -1117,6 +1114,7 @@ test('deploy with a shared lockfile should keep files created by lifecycle scrip
|
||||
rootProjectManifestDir: process.cwd(),
|
||||
recursive: true,
|
||||
lockfileDir: process.cwd(),
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
workspaceDir: process.cwd(),
|
||||
})
|
||||
expect(fs.existsSync('pnpm-lock.yaml')).toBeTruthy()
|
||||
@@ -1132,6 +1130,7 @@ test('deploy with a shared lockfile should keep files created by lifecycle scrip
|
||||
selectedProjectsGraph,
|
||||
sharedWorkspaceLockfile: true,
|
||||
lockfileDir: process.cwd(),
|
||||
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example'],
|
||||
workspaceDir: process.cwd(),
|
||||
}, ['deploy'])
|
||||
|
||||
|
||||
@@ -45,32 +45,7 @@ export async function updateWorkspaceManifest (dir: string, opts: {
|
||||
shouldBeUpdated = removePackagesFromWorkspaceCatalog(manifest, opts.allProjects ?? []) || shouldBeUpdated
|
||||
}
|
||||
|
||||
// If the current manifest has allowBuilds, convert old fields to allowBuilds format
|
||||
const updatedFields = { ...opts.updatedFields }
|
||||
if (manifest.allowBuilds != null || (manifest.onlyBuiltDependencies == null && manifest.ignoredBuiltDependencies == null)) {
|
||||
const allowBuilds: Record<string, boolean | string> = { ...manifest.allowBuilds }
|
||||
|
||||
// Convert onlyBuiltDependencies to allowBuilds with true values
|
||||
if (updatedFields.onlyBuiltDependencies != null) {
|
||||
for (const pattern of updatedFields.onlyBuiltDependencies) {
|
||||
allowBuilds[pattern] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Convert ignoredBuiltDependencies to allowBuilds with false values
|
||||
if (updatedFields.ignoredBuiltDependencies != null) {
|
||||
for (const pattern of updatedFields.ignoredBuiltDependencies) {
|
||||
allowBuilds[pattern] = false
|
||||
}
|
||||
}
|
||||
|
||||
// Update allowBuilds instead of the old fields
|
||||
if (manifest.allowBuilds != null || Object.keys(allowBuilds).length > 0) {
|
||||
updatedFields.allowBuilds = allowBuilds
|
||||
}
|
||||
delete updatedFields.onlyBuiltDependencies
|
||||
delete updatedFields.ignoredBuiltDependencies
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(updatedFields)) {
|
||||
if (!equals(manifest[key as keyof WorkspaceManifest], value)) {
|
||||
|
||||
@@ -8,13 +8,13 @@ import { sync as writeYamlFile } from 'write-yaml-file'
|
||||
test('updateWorkspaceManifest adds a new setting', async () => {
|
||||
const dir = tempDir(false)
|
||||
const filePath = path.join(dir, WORKSPACE_MANIFEST_FILENAME)
|
||||
writeYamlFile(filePath, { packages: ['*'], onlyBuiltDependencies: [] })
|
||||
writeYamlFile(filePath, { packages: ['*'], allowBuilds: {} })
|
||||
await updateWorkspaceManifest(dir, {
|
||||
updatedFields: { onlyBuiltDependencies: [] },
|
||||
updatedFields: { allowBuilds: {} },
|
||||
})
|
||||
expect(readYamlFile(filePath)).toStrictEqual({
|
||||
packages: ['*'],
|
||||
onlyBuiltDependencies: [],
|
||||
allowBuilds: {},
|
||||
})
|
||||
})
|
||||
|
||||
@@ -48,14 +48,13 @@ test('updateWorkspaceManifest updates allowBuilds', async () => {
|
||||
const filePath = path.join(dir, WORKSPACE_MANIFEST_FILENAME)
|
||||
writeYamlFile(filePath, { packages: ['*'], allowBuilds: { qar: 'warn' } })
|
||||
await updateWorkspaceManifest(dir, {
|
||||
updatedFields: { onlyBuiltDependencies: ['foo'], ignoredBuiltDependencies: ['bar'] },
|
||||
updatedFields: { allowBuilds: { foo: true, bar: false } },
|
||||
})
|
||||
expect(readYamlFile(filePath)).toStrictEqual({
|
||||
packages: ['*'],
|
||||
allowBuilds: {
|
||||
bar: false,
|
||||
foo: true,
|
||||
qar: 'warn',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user