-
Notifications
You must be signed in to change notification settings - Fork 607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[rush] Using pnpm, an unexpected version of a transitive dependency is installed #1142
Comments
Seeing similar issues in our repo. Basically means that shrinkwrap is useless... which is very worrying. |
@christiango this seems like it could be the same behavior you described in #1288. Let's use this thread to continue the discussion, since it has an actual repro we can talk about. After
And here's a summary the implementation from #1180 (comment):
Some observations:
Maybe we should upgrade Rush/PNPM for this repro and see if that solves it. |
Here's a proposal for disabling the installation optimization: #1300 If you want to simulate the effect of this feature manually, it's pretty easy:
|
In PNPM 3.x the shrinkwrap file is renamed, and its file format has also changed. The changes are described here: https://github.com/pnpm/spec/blob/master/lockfile/5.md#changes I suppose it would be possible to manually convert the file, but @elliottsj do you have an easy way to recreate your repro using PNPM 3.x? |
@octogonz Done; I've updated the repro using pnpm@3: elliottsj/rush-pnpm-bug@53660df I updated the pnpm-lock.yaml file by deleting the old shrinkwrap.yaml and running I tested it again, found the same results and updated the README.md. |
Thank you! |
@octogonz: If I understand this issue correctly, I believe I have created a standalone repro here: https://github.com/mikeharder/rush-dependency-versions |
@octogonz: I believe the root cause is rush passes the
I created a similar repro with just |
What does |
I believe
Here's my standalone
|
@mikeharder I think you're right! Thanks a ton for investigating this. I asked the PNPM developers about Could someone create a PR to remove this option, and see if it solves the problem? If so we should merge+publish that ASAP. |
I don't know much about either Rush or PNPM, but from the history I see that |
Where are you seeing that? I assumed we added it because it seemed like it would reduce churn, without considering its interaction with the installation optimization. |
@octogonz: If you feel it's safe to remove |
Using the repo in the first post, simply removing |
PNPMPNPM behavior seems a bit weird; it has a different behavior on 3.4.1 and 3.5.1. In
|
pnpm version | $ pnpm install --frozen-shrinkwrap |
$ pnpm install |
$ pnpm install --no-prefer-frozen-shrinkwrap |
---|---|---|---|
3.4.1 | installs react-focus-lock version 1.17.7 , does NOT update pnpm-lock.yaml |
installs react-focus-lock version 1.17.7 , does NOT update pnpm-lock.yaml |
🔴 installs react-focus-lock version 1.19.1 , updates pnpm-lock.yaml |
3.5.1 | installs react-focus-lock version 1.17.7 , does NOT update pnpm-lock.yaml |
🔴 installs react-focus-lock version 1.19.1 , updates pnpm-lock.yaml |
🔴 installs react-focus-lock version 1.19.1 , updates pnpm-lock.yaml |
In (repo-root)/common/temp
$ cd common/temp/
pnpm version | $ pnpm install --frozen-shrinkwrap |
$ pnpm install |
$ pnpm install --no-prefer-frozen-shrinkwrap |
---|---|---|---|
3.4.1 | installs react-focus-lock version 1.17.7 , does NOT update pnpm-lock.yaml |
🔴 installs react-focus-lock version 1.19.1 , updates pnpm-lock.yaml |
🔴 installs react-focus-lock version 1.19.1 , updates pnpm-lock.yaml |
3.5.1 | installs react-focus-lock version 1.17.7 , does NOT update pnpm-lock.yaml |
🔴 installs react-focus-lock version 1.19.1 , updates pnpm-lock.yaml |
🔴 installs react-focus-lock version 1.19.1 , updates pnpm-lock.yaml |
Rush with PNPM
Assuming that the PNPM behavior is accurate, rush is NOT syncing common/config/rush/pnpm-lock.yaml
with the updated lockfile common/temp/pnpm-lock.yaml
. This seems to the bug.
Rush 5.9.1 behavior: rush install passes --no-prefer-frozen-shrinkwrap
to pnpm. I tweaked this flag for the runs below.
Repo state after running rush install
:
rush version | pnpm version | react-focus-lock version |
common/config/rush/pnpm-lock.yaml updated? |
common/temp/pnpm-lock.yaml updated? |
---|---|---|---|---|
5.9.1 | 3.4.1 | 1.19.1 | 🔴 NO (not in sync) | YES |
5.9.1 minus --no-prefer-frozen-shrinkwrap |
3.4.1 | 1.19.1 | 🔴 NO (not in sync) | YES |
5.9.1 plus --frozen-shrinkwrap |
3.4.1 | 1.17.7 | NO | NO |
5.9.1 | 3.5.1 | 1.19.1 | 🔴 NO (not in sync) | YES |
5.9.1 minus --no-prefer-frozen-shrinkwrap |
3.5.1 | 1.19.1 | 🔴 NO (not in sync) | YES |
5.9.1 plus --frozen-shrinkwrap |
3.5.1 | 1.17.7 | NO | NO |
(Pnpm flags have been updated to replace the word shrinkwrap to lockfile, e.g. from --frozen-shrinkwrap
to --frozen-lockfile
.)
- Is
common/config/rush/pnpm-lock.yaml
expected to be in sync withcommon/temp/pnpm-lock.yaml
? If pnpm install is indeed working the way it's supposed to work (see the table above), thenrush
needs to sync the updated temp lockfile back tocommon/config/rush
. - Should new flags such as
--frozen-lockfile
be introduced to rush install? @mikeharder suggested the same thing above.
According to Pete's post, this is not a bug. In that case, |
(The words pnpm-lock/shrinkwrap/lockfile are used interchangeably in this section.)
Proposals
Rush adds
pnpm install seems to have some inconsistent behavior - I think this should be sorted out before we make changes to Rush. See pnpm/pnpm#1878. Locking versions of transitive dependencies❌ DO NOT USE
|
Update on the proposals1.
|
Someone should follow up and see what's the status with pnpm/pnpm#1876 |
From pnpm/pnpm#1876 (comment):
If I understand correctly, when the lockfile is incompatible with the PNPM version, he's saying that PNPM makes a "best effort" to follow the installation plan. The result is inaccurate and not even deterministic. If so, that should really be an error. The whole point of a lockfile is to guarantee a deterministic outcome. I opened pnpm/pnpm#1883 suggesting that PNPM report an error in this case: For example, if I'm not sure whether this fully explains the incorrect installations described in this issue (and #1288 and #1273), but it would definitely eliminate a troublesome variable from the equation. |
Wow, that was fast! The fix for pnpm/pnpm#1883 was already published as PNPM 3.5.3. It also includes the fix for pnpm/pnpm#1882. 😊 |
@mikeharder regarding your repro: https://github.com/mikeharder/rush-dependency-versions ...when I upgrade its rush.json to use |
@sachinjoseph regarding your repro: https://github.com/sachinjoseph/rush-pnpm-bug ...when I upgrade its rush.json to use "rushVersion": "5.9.1" and "pnpmVersion": "3.5.3", it seems to be fixed as well. react-focus-lock 1.17.7 is installed as expected. Let us know if not. BTW it seems that the fix for pnpm/pnpm#1883 was not to report an error; instead he simply made it so newer versions of PNPM correctly install the older lockfile format. |
@sachinjoseph This proposal seems okay. However Rush would need to either (1) drop support for PNPM versions <2.15.1, or else (2) only omit that flag in newer versions. |
@sachinjoseph This is the same behavior described in #1300. But that issue proposes that the "minimizeShrinkwrapChurn" optimization should /not/ be removed entirely, but merely made opt-in. Defining a setting in rush.json would give the feature a name and provide a natural place to write detailed comments explaining how it works. I agree that today this optimization is not documented anywhere, and that's quite confusing. I'm hesitant to remove this optimization entirely. In the sp-client monorepo, we were receiving constant complaints that would go like this: "My project2 is already using cool-library version 1.2.3. I simply want to add that dependency to project3 as well. Why are you forcing me to regenerate the shrinkwrap file? My project3 wants the exact same version of cool-library, and there it is in Rush's common folder!" Why people want to avoid regenerating: Any PR that diffs the shrinkwrap file will cause a Git merge conflict with all other PRs that diff the shrinkwrap file. The merge conflict can only be resolved by running Thus, the shrinkwrap file becomes a sort of mutex: All PRs that touch it will have to go in one at a time, waiting their turn. And it's psychologically the worst kind of lineup, because a Skinner-box gamble occurs at each step: After one PR merges into master, now there's a race to see which person can Now, there is another better solution: For PNPM at least, Zoltan created a pnpm/merge-driver package that enables a CI job to intelligently merge shrinkwrap diffs without having to run Unfortunately, we were not able to figure out how to use pnpm/merge-driver, because of a seeming limitation of GitHub and Azure DevOps: After the CI job clones the PR branch, it locally merges master into the working folder, to ensure the thing being built is as current as possible. This is a hardcoded build step in the CI system. (It sort of makes sense, as the web page UI wants to display whether the merge is blocked or not, so it needs to manage that operation.) Anyway, immediately before the merging happens, we would need the CI job to (1) install the pnpm/merge-driver software and (2) configure Git to use it. We could not figure out a way to do that; however, I wouldn't say we investigated it very deeply. Also, that was years ago. If someone can figure out how to use pnpm/merge-driver, then perhaps we could indeed eliminate Rush's "minimizeShrinkwrapChurn" optimization entirely. |
Thanks @octogonz for explaining this in detail. I like the idea of turning off shrinkwrap churn optimization as an opt-in for Rush 5.x. Let me investigate further if there's a way to use merge drivers on the server side for PRs. I have also asked this on Stack Overflow here. I think we could also come up with a CI job (workaround?) that helps with the shrinkwrap merge conflicts. The job outline would look like this:
Maybe we could also configure this job to automatically kick in if the merge conflict in a PR is only on the shrinkwrap file. On a different note, I have a question about maintaining the |
@octogonz pnpm/pnpm#1882 still repros for me on pnpm 3.5.3. Zoltan has reopened it and created a new issue at pnpm/pnpm#1889.
Verified that react-focus-lock 1.17.7 is installed on Rush 5.9.1/pnpm3.5.3 on my end as well. Thank you. :-) |
@octogonz The fix to pnpm/pnpm#1876 also means that rush update is now broken. Neither rush install nor rush update will upgrade react-focus-lock to 1.19.1 with pnpm 3.5.3+, because both these rush verbs internally call pnpm install. Rush needs to be updated in order to make rush update call pnpm update. |
For example, adding cool-library to project3 might shuffle its tree a bit. But how it gets shuffled should not be impacted by new versions getting published to the NPM registry, so the result is still deterministic. To see the exact changes, you can diff common/temp/pnpm-lockfile.yaml with pnpm-lockfile-preinstall.yaml. |
Yes, that makes sense to me. |
The state of this issueAs discussed above, the original issue (see comment) should be unblocked (but there's a regression, see the WARNING below!) by using pnpm v3.5.3 and Rush v5.9.1. @elliottsj @mikeharder @acoates-ms Can you confirm? WARNING: DO NOT use Rush with pnpm v3.5.3 in production! pnpm v3.5.3 has broken rush update; this would be addressed in an immediate patch release. Closing this issueOnce a new Rush release addresses the rush update regression, I think this issue could be closed. PR: #1340 Continuing the discussionThe discussion needs to continue to address the other issues though. I will summarize them here; we could open new issues if it makes more sense. PinsFor now let's put a pin in the following: That leaves us with proposals for rush install, rush update, and rush update --full: rush installOutline of current flow
Proposed changeFor pnpm 3.5.3+, change the install command in Step 3 from pnpm install --no-prefer-frozen-shrinkwrap to pnpm install --frozen-lockfile Rationale for this proposalPrevent the underlying package manager from causing changes to the lockfile so that rush install can be used by CI systems for installing the exact plan as depicted by the shrinkwrap. Blockers on this proposal:
TODO
rush updateOutline of current flowThe rush update behavior is more or less the same as rush install's described above. In addition, rush update syncs
Proposed changeFor 3.5.3+, change the install command in Step 3 from pnpm install --no-prefer-frozen-shrinkwrap to pnpm install Rationale for this proposalpnpm install (with no arguments regarding the lockfile) takes a conservative approach and minimizes changes to the lockfile by not updating versions unless it's necessary. This is what rush update is expected to do. See https://rushjs.io/pages/commands/rush_update/. Blockers on this proposal:None. TODO:
rush update --fullOutline of current flow
Proposed changeFor 3.5.3+, change the install command in Step 3 from pnpm install --no-prefer-frozen-shrinkwrap to pnpm install Rationale for this proposalWhile the flag Assumption: pnpm update and pnpm install work the same way in the absence of shrinkwrap file. (To confirm, I have asked this here pnpm/pnpm#1890 (comment).) Blockers on this proposal:None. TODO:
|
Note that Rush makes modifications to the shrinkwrap file (again as part of the install optimization): If tarball hashes are a problem, we could simply delete them as we do with Yarn: That's usually sufficient to prevent the package manager from complaining. |
You are essentially proposing to permanently disable the installation optimization without any switch to turn it back on again. Some considerations:
The optimization is admittedly fairly complex code and clearly brittle when PNPM changes its algorithm and file formats. It would be better to remove it. But it did work correctly when it was originally introduced, and the problem it handles is real. |
(BTW I will mention one other option: PNPM now has the ability to do monorepo installations itself including symlinking local projects and consolidating a common shrinkwrap file. For a long time I have wanted to get |
No, I am not proposing that we disable the optimization. I am proposing that we prevent the underlying package manager (pnpm or yarn or npm) from making any changes to the lockfile; let Rush and only Rush deal with the transformations/optimization/modifications on the shrinkwrap. Sorry my wording wasn't clear about this. Rationale to allow only Rush perform modifications on the shrinkwrap: Rush knows what it's doing to transform/optimize, but if Rush lets pnpm also modify the shrinkwrap then the outcome might not be deterministic. What do you think? |
After Rush's modifications the shrinkwrap file may be in an inconsistent state that the package manager is expected to fix. (Not sure if this applies to PNPM but it was true for NPM) |
If we could get the modifications to leave the shrinkwrap file in a consistent state, then we could use the Since not using the |
@octogonz: Confirmed 👍 |
As long as we invoke PNPM in a mode that will report an error if the shrinkwrap is in an inconsistent state, we'll know if it's not working. Maybe we should just give it a try. Implementing #1300 is also a really good idea. It's not a whole lot of work. I tagged it as "Effort: Medium" only because it will touches a number of files and requires some basic familiarity with the installation logic. |
This issue occurs due to bugs in PNPM and Rush which were addressed since this issue was opened. I verified that the repro provided no longer repros on Rush v5.10.0 and PNPM v3.5.3. I will open a new issue to discuss the additional proposals in this thread. Closing this issue. |
See https://github.com/elliottsj/rush-pnpm-bug
In summary, the latest version of transitive dependency react-focus-lock is being installed, despite having pinned an older version in shrinkwrap.yaml.
For now, the workaround I'm using is specifying the older version in common-versions.json:
The text was updated successfully, but these errors were encountered: