fix: restore default workspace package patterns when packages field is missing (#10927)

* fix: restore ['.'] default for workspacePackagePatterns when packages field is missing

Commit 6eedf828b removed the ['.'] fallback for workspacePackagePatterns
when pnpm-workspace.yaml has no packages field. This caused findPackages
to default to ['.', '**'], discovering ALL directories with package.json
as workspace projects. This is the same regression that was previously
reverted in 595cd414f (close #10571), reintroduced by #10127.

Projects like cdxgen that use pnpm-workspace.yaml only for settings
(e.g. minimumReleaseAge) without a packages field were broken because
test data directories were picked up as workspace projects.

close #10909

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove unknown word from changeset

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(config): verify workspacePackagePatterns defaults to ['.'] without packages field

Adds a regression test to ensure pnpm-workspace.yaml without a packages
field defaults workspacePackagePatterns to ['.'] (root only), preventing
all directories from being discovered as workspace projects.
This commit is contained in:
Zoltan Kochan
2026-03-11 01:44:49 +01:00
committed by GitHub
parent 49d249bf7f
commit 5163697228
5 changed files with 24 additions and 1 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/config": patch
"pnpm": patch
---
Fix a regression where `pnpm-workspace.yaml` without a `packages` field caused all directories to be treated as workspace projects. This broke projects that use `pnpm-workspace.yaml` only for settings (e.g. `minimumReleaseAge`) without defining workspace packages [#10909](https://github.com/pnpm/pnpm/issues/10909).

View File

@@ -367,7 +367,7 @@ export async function getConfig (opts: {
if (pnpmConfig.workspaceDir != null) {
const workspaceManifest = await readWorkspaceManifest(pnpmConfig.workspaceDir)
pnpmConfig.workspacePackagePatterns = cliOptions['workspace-packages'] as string[] ?? workspaceManifest?.packages
pnpmConfig.workspacePackagePatterns = cliOptions['workspace-packages'] as string[] ?? workspaceManifest?.packages ?? ['.']
if (workspaceManifest) {
const newSettings = Object.assign(getOptionsFromPnpmSettings(pnpmConfig.workspaceDir, workspaceManifest, pnpmConfig.rootProjectManifest), configFromCliOpts)
for (const [key, value] of Object.entries(newSettings)) {

View File

@@ -0,0 +1 @@
minimumReleaseAge: '4320'

View File

@@ -640,6 +640,21 @@ test('reads workspacePackagePatterns', async () => {
expect(config.workspacePackagePatterns).toEqual(['packages/*'])
})
test('workspacePackagePatterns defaults to ["."] when pnpm-workspace.yaml has no packages field', async () => {
const workspaceDir = path.join(__dirname, 'fixtures/workspace-yaml-without-packages')
process.chdir(workspaceDir)
const { config } = await getConfig({
cliOptions: {},
packageManager: {
name: 'pnpm',
version: '1.0.0',
},
workspaceDir,
})
expect(config.workspacePackagePatterns).toEqual(['.'])
})
test('setting workspace-concurrency to negative number', async () => {
const workspaceDir = path.join(__dirname, 'fixtures/pkg-with-valid-workspace-yaml')
process.chdir(workspaceDir)

View File

@@ -315,6 +315,7 @@ test('recursive command with filter from config', async () => {
fs.writeFileSync('package.json', '{}', 'utf8')
writeYamlFile('pnpm-workspace.yaml', {
packages: ['*'],
filter: ['project-1', 'project-2'],
})
await execPnpm(['recursive', 'install'])