refactor: improve type checking when finding workspace packages#8214
refactor: improve type checking when finding workspace packages#8214
Conversation
| const allProjects = await findWorkspacePackages(workspaceDir, { | ||
| const workspaceManifest = await readWorkspaceManifest(workspaceDir) | ||
| const allProjects = await findWorkspacePackagesUsingPatterns(workspaceDir, { | ||
| patterns: workspaceManifest?.packages ?? ['.', '**'], |
There was a problem hiding this comment.
I added ?? ['.', '**'] here since that's what plugin-commands-completion is currently doing, but this feels like a bug to me. If there's no pnpm-workspace.yaml, I would think allProjects should be empty?
There was a problem hiding this comment.
You may still use pnpm i -r even outside a workspace.
| linkWorkspacePackages: false, | ||
| saveWorkspaceProtocol: 'rolling', | ||
| workspaceDir: process.cwd(), | ||
| workspaceManifest: { dir: process.cwd(), contents: workspaceManifest }, |
There was a problem hiding this comment.
It's a bit annoying that tests calling the install/add/import handlers need to pass in workspaceManifest directly.
One way to fix this would be to better distinguish between a workspaceManifest field that's (a) not yet read or (b) read, but empty. We would then call readWorkspaceManifest in the former case.
But that's a lot of complexity to make a few tests easier to write. I decided not to make the workspaceManifest config field more complicated.
pnpm/src/main.ts
Outdated
| engineStrict: config.engineStrict, | ||
| nodeVersion: config.nodeVersion ?? config.useNodeVersion, | ||
| patterns: cliOptions['workspace-packages'] ?? config.workspaceManifest?.contents.packages, | ||
| patterns: cliOptions['workspace-packages'] ?? config.workspaceManifest?.contents.packages ?? ['.', '**'], |
There was a problem hiding this comment.
This uncovered a potential problem with pnpm install --recursive. This is a case where a missing pnpm-workspace.yaml actually means everything is part of the workspace. I think this is a bug?
The current behavior of findWorkspacePackages() is:
- Use
opts.patternsif provided. - Use
pnpm-workspace.yaml'spackagesfield if the file is present. - Use
['.', '**']ifpnpm-workspace.yamlis not present.
Although the patterns argument here on line 203 is non-null, undefined could get passed in here since noUncheckedIndexedAccess is false.
Is it intended that pnpm install --recursive treats all folders with package.json files as workspace packages even when pnpm-workspace.yaml isn't on disk? That's the current behavior here. I added ?? ['.', '**'] to make this more clear and to satisfy the required patterns argument.
|
Opening this for review, but it's not required for catalogs. I wanted to see what this would look like if we made improvements to the type safety of |
|
Why don't we just make it a required option and remove the possibility of reading the workspace manifest from within |
|
That was roughly my intention with this PR. There were 3 approaches I was considering:
I took the 3rd approach, but happy to change to either (1) or (2). They all roughly have the effect of requiring |
9136a66 to
a26819b
Compare
|
This needs a rebase. |
|
Sounds good. I'll rebase now. Did you have a preference on whether we should introduce a new function for convenience of |
0560060 to
3858dd6
Compare
|
Latest force push contains a few notable changes:
|
pnpm/src/main.ts
Outdated
| engineStrict: config.engineStrict, | ||
| nodeVersion: config.nodeVersion ?? config.useNodeVersion, | ||
| patterns: config.workspacePackagePatterns, | ||
| patterns: config.workspacePackagePatterns ?? ['.', '**'], |
There was a problem hiding this comment.
Here's my prior comments on this here:
- fix: use
--workspace-packagesCLI overpnpm-workspace.yamlin more cases #8215 (comment) - fix: use
--workspace-packagesCLI overpnpm-workspace.yamlin more cases #8215 (comment)
I think the ?? ['.', '**'] is ugly and should be [] instead, but this would be a behavior change and breaks a few tests. I'm looking into fixing these tests, but wanted to push up a rebase for this PR in the meantime.
There was a problem hiding this comment.
I have made patterns optional, not default value is needed.
There was a problem hiding this comment.
One thing I was worried about with patterns being optional is developers in the future writing code in pnpm forgetting to pass in a value when calling findWorkspacePackages. Everything might work as expected when testing, but in production packages might get included from the default filter ['.', '**'] that shouldn't, and then users will get confused.
I think that's a general footgun with optional parameters.
| if (opts.workspaceDir && opts.workspacePackagePatterns) { | ||
| workspacePackagesArr = await findWorkspacePackages(opts.workspaceDir, { | ||
| ...opts, | ||
| patterns: opts.workspacePackagePatterns, |
There was a problem hiding this comment.
Maybe just add a default value for patterns in findWorkspacePackages. Otherwise the tests have to be updated with workspacePackagePatterns, which isn't even used in most cases because allProjects is passed.
There was a problem hiding this comment.
I noticed that above too. #8214 (comment)
A lot of tests have a common options setup that defaults values from @pnpm/config. Perhaps we could set those to ['.', '**'] for tests.
PR Stack
@pnpm/configfor reuse #8213Problem
After #8213, code within pnpm is expected to use the
patternsargument when callingfindWorkspacePackages. This avoids thepnpm-workspace.yamlfile from being read multiple times, which could cause strange consistency issues if the file is modified while pnpm is running. It also just feels silly to re-read this file when it's already in-memory.However, because the
patternsargument is optional, it's easy to forget to pass in a value for this argument.Changes
Making
patternsrequired when callingfindWorkspacePackages.findWorkspacePackagesshould be used within the pnpm repo.findWorkspacePackagesUsingManifestis now a convenience function that code outside of pnpm can call. This function continues to readpnpm-workspace.yamlautomatically.