diff --git a/.changeset/ignore-workspace-allow-builds.md b/.changeset/ignore-workspace-allow-builds.md new file mode 100644 index 0000000000..0be6f9a06e --- /dev/null +++ b/.changeset/ignore-workspace-allow-builds.md @@ -0,0 +1,6 @@ +--- +"@pnpm/installing.commands": patch +"pnpm": patch +--- + +Fixed `pnpm install --ignore-workspace` overwriting the `allowBuilds` map in `pnpm-workspace.yaml`. The ignored builds of a package with a build script were auto-populated into `allowBuilds` even though `--ignore-workspace` was passed, clobbering committed `true`/`false` values with the `set this to true or false` placeholder [#12469](https://github.com/pnpm/pnpm/issues/12469). diff --git a/config/reader/src/Config.ts b/config/reader/src/Config.ts index 1b2f818b1e..990fe8d217 100644 --- a/config/reader/src/Config.ts +++ b/config/reader/src/Config.ts @@ -232,6 +232,7 @@ export interface Config extends OptionsFromRootManifest { dedupePeerDependents?: boolean dedupePeers?: boolean patchesDir?: string + ignoreWorkspace?: boolean ignoreWorkspaceCycles?: boolean disallowWorkspaceCycles?: boolean packGzipLevel?: number diff --git a/installing/commands/src/handleIgnoredBuilds.ts b/installing/commands/src/handleIgnoredBuilds.ts index 3ca11963fc..207d4442b6 100644 --- a/installing/commands/src/handleIgnoredBuilds.ts +++ b/installing/commands/src/handleIgnoredBuilds.ts @@ -8,6 +8,7 @@ import { lexCompare } from '@pnpm/util.lex-comparator' export interface HandleIgnoredBuildsOpts { allowBuilds?: Record + ignoreWorkspace?: boolean rootProjectManifestDir?: string workspaceDir?: string strictDepBuilds?: boolean @@ -18,7 +19,9 @@ export async function handleIgnoredBuilds ( ignoredBuilds: IgnoredBuilds | undefined ): Promise { if (!ignoredBuilds?.size) return - await writeIgnoredBuildsToAllowBuilds(opts, ignoredBuilds) + if (!opts.ignoreWorkspace) { + await writeIgnoredBuildsToAllowBuilds(opts, ignoredBuilds) + } if (opts.strictDepBuilds) { throw new IgnoredBuildsError(ignoredBuilds) } diff --git a/installing/commands/src/installDeps.ts b/installing/commands/src/installDeps.ts index 0dea29ce91..0dfa07f519 100644 --- a/installing/commands/src/installDeps.ts +++ b/installing/commands/src/installDeps.ts @@ -117,6 +117,7 @@ export type InstallDepsOptions = Pick { + prepareEmpty() + + const workspaceManifestFile = path.resolve('pnpm-workspace.yaml') + const workspaceManifest = { + allowBuilds: { + esbuild: false, + }, + } + writeYamlFileSync(workspaceManifestFile, workspaceManifest) + const workspaceManifestBefore = fs.readFileSync(workspaceManifestFile, 'utf8') + + await handleIgnoredBuilds({ + ignoreWorkspace: true, + rootProjectManifestDir: process.cwd(), + }, new Set(['esbuild@0.25.0' as DepPath])) + + expect(fs.readFileSync(workspaceManifestFile, 'utf8')).toBe(workspaceManifestBefore) + expect(readYamlFileSync(workspaceManifestFile)).toStrictEqual(workspaceManifest) +}) diff --git a/pnpm/test/install/lifecycleScripts.ts b/pnpm/test/install/lifecycleScripts.ts index 928c57e841..af225406ac 100644 --- a/pnpm/test/install/lifecycleScripts.ts +++ b/pnpm/test/install/lifecycleScripts.ts @@ -333,6 +333,29 @@ test('auto-populated placeholders are merged with existing allowBuilds', async ( expect(manifest?.allowBuilds?.['@pnpm.e2e/pre-and-postinstall-scripts-example']).toBe('set this to true or false') }) +test('install --ignore-workspace does not overwrite allowBuilds in pnpm-workspace.yaml', () => { + prepare({ + dependencies: { + '@pnpm.e2e/pre-and-postinstall-scripts-example': '1.0.0', + }, + }) + writeYamlFileSync('pnpm-workspace.yaml', { + allowBuilds: { + '@pnpm.e2e/pre-and-postinstall-scripts-example': false, + }, + }) + const manifestBefore = fs.readFileSync('pnpm-workspace.yaml', 'utf8') + + const { status, stdout, stderr } = execPnpmSync(['install', '--ignore-workspace']) + + // The build is ignored (--ignore-workspace skips the allowBuilds entry), so the + // install ends in ERR_PNPM_IGNORED_BUILDS — the same code path that would have + // written the placeholder. The manifest must stay untouched regardless. + expect(status).toBe(1) + expect(`${stdout}${stderr}`).toContain('ERR_PNPM_IGNORED_BUILDS') + expect(fs.readFileSync('pnpm-workspace.yaml', 'utf8')).toBe(manifestBefore) +}) + test('selective rebuild preserves ignoredBuilds for packages not being rebuilt', async () => { const project = prepare({}) writeYamlFileSync('pnpm-workspace.yaml', {