Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/yellow-beds-wear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@pnpm/plugin-commands-rebuild": patch
"@pnpm/default-reporter": patch
"@pnpm/headless": patch
"@pnpm/build-modules": patch
"@pnpm/core": patch
"pnpm": patch
---

`pnpm install` should build any dependencies that were added to `onlyBuiltDependencies` and were not built yet [#10256](https://github.com/pnpm/pnpm/pull/10256).
8 changes: 7 additions & 1 deletion cli/default-reporter/src/reporterForClient/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { reportContext } from './reportContext.js'
import { reportExecutionTime } from './reportExecutionTime.js'
import { reportDeprecations } from './reportDeprecations.js'
import { reportHooks } from './reportHooks.js'
import { reportIgnoredBuilds } from './reportIgnoredBuilds.js'
import { reportInstallChecks } from './reportInstallChecks.js'
import { reportInstallingConfigDeps } from './reportInstallingConfigDeps.js'
import { reportLifecycleScripts } from './reportLifecycleScripts.js'
Expand Down Expand Up @@ -156,9 +157,14 @@ export function reporterForClient (
env: opts.env,
filterPkgsDiff: opts.filterPkgsDiff,
pnpmConfig: opts.pnpmConfig,
approveBuildsInstructionText: opts.approveBuildsInstructionText,
}))
}
outputs.push(
reportIgnoredBuilds(log$, {
pnpmConfig: opts.pnpmConfig,
approveBuildsInstructionText: opts.approveBuildsInstructionText,
})
)
}

return outputs
Expand Down
34 changes: 34 additions & 0 deletions cli/default-reporter/src/reporterForClient/reportIgnoredBuilds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { type Config } from '@pnpm/config'
import { type IgnoredScriptsLog } from '@pnpm/core-loggers'
import { lexCompare } from '@pnpm/util.lex-comparator'
import * as Rx from 'rxjs'
import { map } from 'rxjs/operators'
import boxen from 'boxen'

export function reportIgnoredBuilds (
log$: {
ignoredScripts: Rx.Observable<IgnoredScriptsLog>
},
opts: {
pnpmConfig?: Config
// This is used by Bit CLI
approveBuildsInstructionText?: string
}
): Rx.Observable<Rx.Observable<{ msg: string }>> {
return log$.ignoredScripts.pipe(
map((ignoredScripts) => {
if (ignoredScripts.packageNames && ignoredScripts.packageNames.length > 0 && !opts.pnpmConfig?.strictDepBuilds) {
const msg = boxen(`Ignored build scripts: ${Array.from(ignoredScripts.packageNames).sort(lexCompare).join(', ')}.
${opts.approveBuildsInstructionText ?? `Run "pnpm approve-builds${opts.pnpmConfig?.cliOptions?.global ? ' -g' : ''}" to pick which dependencies should be allowed to run scripts.`}`, {
title: 'Warning',
padding: 1,
margin: 0,
borderStyle: 'round',
borderColor: 'yellow',
})
return Rx.of({ msg })
}
return Rx.NEVER
})
)
}
21 changes: 1 addition & 20 deletions cli/default-reporter/src/reporterForClient/reportSummary.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import path from 'path'
import {
type IgnoredScriptsLog,
type DeprecationLog,
type PackageManifestLog,
type RootLog,
type SummaryLog,
} from '@pnpm/core-loggers'
import { type Config } from '@pnpm/config'
import { lexCompare } from '@pnpm/util.lex-comparator'
import * as Rx from 'rxjs'
import { map, take } from 'rxjs/operators'
import boxen from 'boxen'
import chalk from 'chalk'
import semver from 'semver'
import { EOL } from '../constants.js'
Expand Down Expand Up @@ -40,16 +37,13 @@ export function reportSummary (
summary: Rx.Observable<SummaryLog>
root: Rx.Observable<RootLog>
packageManifest: Rx.Observable<PackageManifestLog>
ignoredScripts: Rx.Observable<IgnoredScriptsLog>
},
opts: {
cmd: string
cwd: string
env: NodeJS.ProcessEnv
filterPkgsDiff?: FilterPkgsDiff
pnpmConfig?: Config
// This is used by Bit CLI
approveBuildsInstructionText?: string
}
): Rx.Observable<Rx.Observable<{ msg: string }>> {
const pkgsDiff$ = getPkgsDiff(log$, { prefix: opts.cwd })
Expand All @@ -59,12 +53,11 @@ export function reportSummary (

return Rx.combineLatest(
pkgsDiff$,
log$.ignoredScripts.pipe(Rx.startWith({ packageNames: undefined })),
summaryLog$
)
.pipe(
take(1),
map(([pkgsDiff, ignoredScripts]) => {
map(([pkgsDiff]) => {
let msg = ''
for (const depType of ['prod', 'optional', 'peer', 'dev', 'nodeModulesOnly'] as const) {
let diffs: PackageDiff[] = Object.values(pkgsDiff[depType as keyof typeof pkgsDiff])
Expand All @@ -89,18 +82,6 @@ export function reportSummary (
msg += EOL
}
}
if (ignoredScripts.packageNames && ignoredScripts.packageNames.length > 0 && !opts.pnpmConfig?.strictDepBuilds) {
msg += EOL
msg += boxen(`Ignored build scripts: ${Array.from(ignoredScripts.packageNames).sort(lexCompare).join(', ')}.
${opts.approveBuildsInstructionText ?? `Run "pnpm approve-builds${opts.pnpmConfig?.cliOptions?.global ? ' -g' : ''}" to pick which dependencies should be allowed to run scripts.`}`, {
title: 'Warning',
padding: 1,
margin: 0,
borderStyle: 'round',
borderColor: 'yellow',
})
msg += EOL
}
return Rx.of({ msg })
})
)
Expand Down
3 changes: 1 addition & 2 deletions exec/build-modules/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from 'path'
import util from 'util'
import { calcDepState, type DepsStateCache } from '@pnpm/calc-dep-state'
import { getWorkspaceConcurrency } from '@pnpm/config'
import { skippedOptionalDependencyLogger, ignoredScriptsLogger } from '@pnpm/core-loggers'
import { skippedOptionalDependencyLogger } from '@pnpm/core-loggers'
import { runPostinstallHooks } from '@pnpm/lifecycle'
import { linkBins, linkBinsOfPackages } from '@pnpm/link-bins'
import { logger } from '@pnpm/logger'
Expand Down Expand Up @@ -97,7 +97,6 @@ export async function buildModules<T extends string> (
}
}
const packageNames = Array.from(ignoredPkgs)
ignoredScriptsLogger.debug({ packageNames })
return { ignoredBuilds: packageNames }
}

Expand Down
7 changes: 5 additions & 2 deletions exec/plugin-commands-rebuild/src/implementation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ export async function rebuildSelectedPkgs (
projects: Array<{ buildIndex: number, manifest: ProjectManifest, rootDir: ProjectRootDir }>,
pkgSpecs: string[],
maybeOpts: RebuildOptions
): Promise<void> {
): Promise<{ ignoredBuilds?: string[] }> {
const reporter = maybeOpts?.reporter
if ((reporter != null) && typeof reporter === 'function') {
streamParser.on('data', reporter)
}
const opts = await extendRebuildOptions(maybeOpts)
const ctx = await getContext({ ...opts, allProjects: projects })

if (ctx.currentLockfile?.packages == null) return
if (ctx.currentLockfile?.packages == null) return {}
const packages = ctx.currentLockfile.packages

const searched: PackageSelector[] = pkgSpecs.map((arg) => {
Expand Down Expand Up @@ -149,6 +149,9 @@ export async function rebuildSelectedPkgs (
virtualStoreDir: ctx.virtualStoreDir,
virtualStoreDirMaxLength: ctx.virtualStoreDirMaxLength,
})
return {
ignoredBuilds: ignoredPkgs,
}
}

export async function rebuildProjects (
Expand Down
2 changes: 2 additions & 0 deletions pkg-manager/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@pnpm/catalogs.protocol-parser": "workspace:*",
"@pnpm/catalogs.resolver": "workspace:*",
"@pnpm/catalogs.types": "workspace:*",
"@pnpm/config.version-policy": "workspace:*",
"@pnpm/constants": "workspace:*",
"@pnpm/core-loggers": "workspace:*",
"@pnpm/crypto.hash": "workspace:*",
Expand Down Expand Up @@ -96,6 +97,7 @@
"@pnpm/parse-wanted-dependency": "workspace:*",
"@pnpm/patching.config": "workspace:*",
"@pnpm/pkg-manager.direct-dep-linker": "workspace:*",
"@pnpm/plugin-commands-rebuild": "workspace:*",
"@pnpm/read-modules-dir": "workspace:*",
"@pnpm/read-project-manifest": "workspace:*",
"@pnpm/remove-bins": "workspace:*",
Expand Down
42 changes: 37 additions & 5 deletions pkg-manager/core/src/install/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createAllowBuildFunction } from '@pnpm/builder.policy'
import { parseCatalogProtocol } from '@pnpm/catalogs.protocol-parser'
import { resolveFromCatalog, matchCatalogResolveResult, type CatalogResultMatcher } from '@pnpm/catalogs.resolver'
import { type Catalogs } from '@pnpm/catalogs.types'
import { createPackageVersionPolicy } from '@pnpm/config.version-policy'
import {
LAYOUT_VERSION,
LOCKFILE_VERSION,
Expand Down Expand Up @@ -48,6 +49,7 @@ import { logger, globalInfo, streamParser } from '@pnpm/logger'
import { getAllDependenciesFromManifest, getAllUniqueSpecs } from '@pnpm/manifest-utils'
import { writeModulesManifest } from '@pnpm/modules-yaml'
import { type PatchGroupRecord, groupPatchedDependencies } from '@pnpm/patching.config'
import { rebuildSelectedPkgs } from '@pnpm/plugin-commands-rebuild'
import { safeReadProjectManifestOnly } from '@pnpm/read-project-manifest'
import {
getWantedDependencies,
Expand Down Expand Up @@ -357,20 +359,27 @@ export async function mutateModules (
// @ts-expect-error
globalInfo(`The integrity of ${global['verifiedFileIntegrity']} files was checked. This might have caused installation to take longer.`)
}
if ((reporter != null) && typeof reporter === 'function') {
streamParser.removeListener('data', reporter)
}

if (opts.mergeGitBranchLockfiles) {
await cleanGitBranchLockfiles(ctx.lockfileDir)
}

let ignoredBuilds = result.ignoredBuilds
if (!opts.ignoreScripts && ignoredBuilds?.length) {
ignoredBuilds = await runUnignoredDependencyBuilds(opts, ignoredBuilds)
}
ignoredScriptsLogger.debug({ packageNames: ignoredBuilds })

if ((reporter != null) && typeof reporter === 'function') {
streamParser.removeListener('data', reporter)
}

return {
updatedCatalogs: result.updatedCatalogs,
updatedProjects: result.updatedProjects,
stats: result.stats ?? { added: 0, removed: 0, linkedToRoot: 0 },
depsRequiringBuild: result.depsRequiringBuild,
ignoredBuilds: result.ignoredBuilds,
ignoredBuilds,
}

interface InnerInstallResult {
Expand Down Expand Up @@ -869,6 +878,30 @@ Note that in CI environments, this setting is enabled by default.`,
}
}

async function runUnignoredDependencyBuilds (opts: StrictInstallOptions, previousIgnoredBuilds: string[]): Promise<string[]> {
if (!opts.onlyBuiltDependencies?.length) {
return previousIgnoredBuilds
}
const onlyBuiltDeps = createPackageVersionPolicy(opts.onlyBuiltDependencies)
const pkgsToBuild = previousIgnoredBuilds.flatMap((ignoredPkg) => {
const matchResult = onlyBuiltDeps(ignoredPkg)
if (matchResult === true) {
return [ignoredPkg]
} else if (Array.isArray(matchResult)) {
return matchResult.map(version => `${ignoredPkg}@${version}`)
}
return []
})
if (pkgsToBuild.length) {
return (await rebuildSelectedPkgs(opts.allProjects, pkgsToBuild, {
...opts,
reporter: undefined, // We don't want to attach the reporter again, it was already attached.
rootProjectManifestDir: opts.lockfileDir,
})).ignoredBuilds ?? previousIgnoredBuilds
}
return previousIgnoredBuilds
}

function cacheExpired (prunedAt: string, maxAgeInMinutes: number): boolean {
return ((Date.now() - new Date(prunedAt).valueOf()) / (1000 * 60)) > maxAgeInMinutes
}
Expand Down Expand Up @@ -1357,7 +1390,6 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
})).ignoredBuilds
if (ignoredBuilds == null && ctx.modulesFile?.ignoredBuilds?.length) {
ignoredBuilds = ctx.modulesFile.ignoredBuilds
ignoredScriptsLogger.debug({ packageNames: ignoredBuilds })
}
}
}
Expand Down
29 changes: 29 additions & 0 deletions pkg-manager/core/test/install/lifecycleScripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -764,3 +764,32 @@ test('run pre/postinstall scripts in a project that uses node-linker=hoisted. Sh
message: `An error occurred while uploading ${path.resolve('node_modules/@pnpm.e2e/pre-and-postinstall-scripts-example')}`,
}))
})

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/[email protected]', '@pnpm.e2e/install-script-example'],
testDefaults({
fastUnpack: false,
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example'],
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()

await install(manifest, testDefaults({
fastUnpack: false,
frozenLockfile: true,
ignoredBuiltDependencies: [],
neverBuiltDependencies,
onlyBuiltDependencies: ['@pnpm.e2e/install-script-example', '@pnpm.e2e/[email protected]'],
}))

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()
})
6 changes: 6 additions & 0 deletions pkg-manager/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
{
"path": "../../config/parse-overrides"
},
{
"path": "../../config/version-policy"
},
{
"path": "../../crypto/hash"
},
Expand All @@ -60,6 +63,9 @@
{
"path": "../../exec/lifecycle"
},
{
"path": "../../exec/plugin-commands-rebuild"
},
{
"path": "../../fs/read-modules-dir"
},
Expand Down
2 changes: 0 additions & 2 deletions pkg-manager/headless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
WANTED_LOCKFILE,
} from '@pnpm/constants'
import {
ignoredScriptsLogger,
packageManifestLogger,
progressLogger,
stageLogger,
Expand Down Expand Up @@ -560,7 +559,6 @@ export async function headlessInstall (opts: HeadlessOptions): Promise<Installat
})).ignoredBuilds
if (ignoredBuilds == null && opts.modulesFile?.ignoredBuilds?.length) {
ignoredBuilds = opts.modulesFile.ignoredBuilds
ignoredScriptsLogger.debug({ packageNames: ignoredBuilds })
}
}

Expand Down
Loading