feat: ignoring the build of specific dependencies (#3080)

* feat: ignoring the build of specific dependencies

close #3071

* test: add test for neverBuiltDependencies

* docs: add changesets

* test: lockfile-file
This commit is contained in:
Zoltan Kochan
2021-01-23 16:27:39 +02:00
committed by GitHub
parent bcfe4890c4
commit 9ad8c27bf0
11 changed files with 100 additions and 3 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/lockfile-file": minor
"@pnpm/lockfile-types": minor
---
Add optional neverBuiltDependencies property to the lockfile object.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/resolve-dependencies": minor
---
New option added for ignore scripts in specified dependencies: `neverBuiltDependencies`.

View File

@@ -0,0 +1,6 @@
---
"supi": minor
"@pnpm/types": minor
---
Allow to ignore builds of specified dependencies throught the `pnpm.neverBuiltDependencies` field in `package.json`.

View File

@@ -72,7 +72,7 @@ function isEmptyLockfile (lockfile: Lockfile) {
type LockfileFile = Omit<Lockfile, 'importers'> & Partial<ProjectSnapshot> & Partial<Pick<Lockfile, 'importers'>>
function normalizeLockfile (lockfile: Lockfile, forceSharedFormat: boolean) {
export function normalizeLockfile (lockfile: Lockfile, forceSharedFormat: boolean) {
let lockfileToSave!: LockfileFile
if (!forceSharedFormat && R.equals(R.keys(lockfile.importers), ['.'])) {
lockfileToSave = {
@@ -112,6 +112,13 @@ function normalizeLockfile (lockfile: Lockfile, forceSharedFormat: boolean) {
if (lockfileToSave.overrides && R.isEmpty(lockfileToSave.overrides)) {
delete lockfileToSave.overrides
}
if (lockfileToSave.neverBuiltDependencies) {
if (R.isEmpty(lockfileToSave.neverBuiltDependencies)) {
delete lockfileToSave.neverBuiltDependencies
} else {
lockfileToSave.neverBuiltDependencies = lockfileToSave.neverBuiltDependencies.sort()
}
}
return lockfileToSave
}

View File

@@ -0,0 +1,33 @@
import { LOCKFILE_VERSION } from '@pnpm/constants'
import { normalizeLockfile } from '@pnpm/lockfile-file/lib/write'
test('empty overrides and neverBuiltDependencies are removed during lockfile normalization', () => {
expect(normalizeLockfile({
lockfileVersion: LOCKFILE_VERSION,
overrides: {},
neverBuiltDependencies: [],
packages: {},
importers: {
foo: {
dependencies: {
bar: 'link:../bar',
},
specifiers: {
bar: 'link:../bar',
},
},
},
}, false)).toStrictEqual({
lockfileVersion: LOCKFILE_VERSION,
importers: {
foo: {
dependencies: {
bar: 'link:../bar',
},
specifiers: {
bar: 'link:../bar',
},
},
},
})
})

View File

@@ -2,6 +2,7 @@ export interface Lockfile {
importers: Record<string, ProjectSnapshot>
lockfileVersion: number
packages?: PackageSnapshots
neverBuiltDependencies?: string[]
overrides?: Record<string, string>
}

View File

@@ -128,6 +128,7 @@ export interface ResolutionContext {
currentLockfile: Lockfile
linkWorkspacePackagesDepth: number
lockfileDir: string
neverBuiltDependencies: Set<string>
storeController: StoreController
// the IDs of packages that are not installable
skipped: Set<string>
@@ -786,6 +787,7 @@ async function resolveDependency (
depPath,
force: ctx.force,
hasBin,
neverBuiltDependencies: ctx.neverBuiltDependencies,
pkg,
pkgResponse,
prepare,
@@ -838,6 +840,7 @@ function getResolvedPackage (
depPath: string
force: boolean
hasBin: boolean
neverBuiltDependencies: Set<string>
pkg: PackageManifest
pkgResponse: PackageResponse
prepare: boolean
@@ -871,7 +874,8 @@ function getResolvedPackage (
peerDependenciesMeta: options.pkg.peerDependenciesMeta,
prepare: options.prepare,
prod: !options.wantedDependency.dev && !options.wantedDependency.optional,
requiresBuild: options.dependencyLockfile && Boolean(options.dependencyLockfile.requiresBuild),
requiresBuild: options.neverBuiltDependencies.has(options.pkg.name)
? false : (options.dependencyLockfile && Boolean(options.dependencyLockfile.requiresBuild)),
resolution: options.pkgResponse.body.resolution,
version: options.pkg.version,
}

View File

@@ -53,6 +53,7 @@ export interface ResolveDependenciesOptions {
hooks: {
readPackage?: ReadPackageHook
}
neverBuiltDependencies?: Set<string>
nodeVersion: string
registries: Registries
pnpmVersion: string
@@ -85,6 +86,7 @@ export default async function<T> (
forceFullResolution: opts.forceFullResolution,
linkWorkspacePackagesDepth: opts.linkWorkspacePackagesDepth ?? -1,
lockfileDir: opts.lockfileDir,
neverBuiltDependencies: opts.neverBuiltDependencies ?? new Set(),
nodeVersion: opts.nodeVersion,
outdatedDependencies: {} as {[pkgId: string]: string},
pendingNodes: [] as PendingNode[],

View File

@@ -148,6 +148,7 @@ export async function mutateModules (
const overrides = rootProjectManifest
? rootProjectManifest.pnpm?.overrides ?? rootProjectManifest.resolutions
: undefined
const neverBuiltDependencies = rootProjectManifest?.pnpm?.neverBuiltDependencies ?? []
if (!R.isEmpty(overrides ?? {})) {
const versionsOverrider = createVersionsOverrider(overrides!)
if (opts.hooks.readPackage) {
@@ -175,8 +176,10 @@ export async function mutateModules (
return result
async function _install (): Promise<Array<{ rootDir: string, manifest: ProjectManifest }>> {
const needsFullResolution = !R.equals(ctx.wantedLockfile.overrides ?? {}, overrides ?? {})
const needsFullResolution = !R.equals(ctx.wantedLockfile.overrides ?? {}, overrides ?? {}) ||
!R.equals((ctx.wantedLockfile.neverBuiltDependencies ?? []).sort(), (neverBuiltDependencies ?? []).sort())
ctx.wantedLockfile.overrides = overrides
ctx.wantedLockfile.neverBuiltDependencies = neverBuiltDependencies
const frozenLockfile = opts.frozenLockfile ||
opts.frozenLockfileIfExists && ctx.existsWantedLockfile
if (
@@ -434,6 +437,7 @@ export async function mutateModules (
currentLockfileIsUpToDate: !ctx.existsWantedLockfile || ctx.currentLockfileIsUpToDate,
makePartialCurrentLockfile,
needsFullResolution,
neverBuiltDependencies,
overrides,
update: opts.update || !installsOnly,
updateLockfileMinorVersion: true,
@@ -580,6 +584,7 @@ async function installInContext (
opts: StrictInstallOptions & {
makePartialCurrentLockfile: boolean
needsFullResolution: boolean
neverBuiltDependencies: string[]
overrides?: Record<string, string>
updateLockfileMinorVersion: boolean
preferredVersions?: PreferredVersions
@@ -667,6 +672,7 @@ async function installInContext (
hooks: opts.hooks,
linkWorkspacePackagesDepth: opts.linkWorkspacePackagesDepth ?? (opts.saveWorkspaceProtocol ? 0 : -1),
lockfileDir: opts.lockfileDir,
neverBuiltDependencies: new Set(opts.neverBuiltDependencies),
nodeVersion: opts.nodeVersion,
pnpmVersion: opts.packageManager.name === 'pnpm' ? opts.packageManager.version : '',
preferWorkspacePackages: opts.preferWorkspacePackages,

View File

@@ -432,3 +432,29 @@ test('scripts have access to unlisted bins when hoisting is used', async () => {
expect(project.requireModule('pkg-that-calls-unlisted-dep-in-hooks/output.json')).toStrictEqual(['Hello world!'])
})
test('selectively ignore scripts in some dependencies', async () => {
const project = prepareEmpty()
const neverBuiltDependencies = ['pre-and-postinstall-scripts-example']
const manifest = await addDependenciesToPackage({ pnpm: { neverBuiltDependencies } },
['pre-and-postinstall-scripts-example', 'install-script-example'],
await testDefaults({ fastUnpack: false })
)
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
expect(await exists('node_modules/install-script-example/generated-by-install.js')).toBeTruthy()
const lockfile = await project.readLockfile()
expect(lockfile.neverBuiltDependencies).toStrictEqual(neverBuiltDependencies)
expect(lockfile.packages['/pre-and-postinstall-scripts-example/1.0.0'].requiresBuild).toBe(undefined)
expect(lockfile.packages['/install-script-example/1.0.0'].requiresBuild).toBeTruthy()
await rimraf('node_modules')
await install(manifest, await testDefaults({ fastUnpack: false, frozenLockfile: true }))
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
expect(await exists('node_modules/install-script-example/generated-by-install.js')).toBeTruthy()
})

View File

@@ -83,6 +83,7 @@ export type DependencyManifest = BaseManifest & Required<Pick<BaseManifest, 'nam
export type ProjectManifest = BaseManifest & {
pnpm?: {
neverBuiltDependencies?: string[]
overrides?: Record<string, string>
}
private?: boolean