Skip to content

refactor(node): Re-write Yarn to no more rely on node_modules file hierarchy #9427

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

Merged
merged 4 commits into from
Apr 17, 2025

Conversation

fviernau
Copy link
Member

@fviernau fviernau commented Nov 14, 2024

See individual commits.

Part of: #9261.

@fviernau fviernau mentioned this pull request Jan 24, 2025
@fviernau fviernau force-pushed the yarn-rewrite branch 2 times, most recently from 6e4175d to 603c0d7 Compare March 19, 2025 09:14
Copy link

codecov bot commented Mar 19, 2025

Codecov Report

Attention: Patch coverage is 84.41558% with 24 lines in your changes missing coverage. Please review.

Project coverage is 56.47%. Comparing base (e161da3) to head (2139e12).
Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
...anagers/node/src/main/kotlin/yarn/WorkspaceInfo.kt 46.66% 5 Missing and 3 partials ⚠️
...managers/node/src/main/kotlin/yarn/YarnListNode.kt 55.55% 2 Missing and 6 partials ⚠️
...package-managers/node/src/main/kotlin/yarn/Yarn.kt 94.25% 0 Missing and 5 partials ⚠️
...node/src/main/kotlin/yarn/YarnDependencyHandler.kt 91.17% 0 Missing and 3 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #9427      +/-   ##
============================================
- Coverage     56.49%   56.47%   -0.03%     
+ Complexity     1587     1572      -15     
============================================
  Files           327      328       +1     
  Lines         12371    12381      +10     
  Branches       1145     1162      +17     
============================================
+ Hits           6989     6992       +3     
+ Misses         4927     4926       -1     
- Partials        455      463       +8     
Flag Coverage Δ
funTest-docker 68.70% <84.41%> (-0.14%) ⬇️
funTest-non-docker 33.26% <ø> (ø)
test-ubuntu-24.04 39.24% <5.19%> (-0.16%) ⬇️
test-windows-2022 39.22% <5.19%> (-0.16%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fviernau fviernau force-pushed the yarn-rewrite branch 5 times, most recently from 55d15ca to ac202b3 Compare March 20, 2025 14:08
@fviernau fviernau force-pushed the yarn-rewrite branch 2 times, most recently from aeb93b3 to b787994 Compare March 20, 2025 14:53
@fviernau fviernau marked this pull request as ready for review March 20, 2025 14:53
@fviernau fviernau requested a review from a team as a code owner March 20, 2025 14:53
@fviernau fviernau force-pushed the yarn-rewrite branch 2 times, most recently from 36effda to 961fc48 Compare March 20, 2025 15:36
private fun getInstalledModules(moduleDir: File) =
moduleDir.resolve("node_modules").walkBottomUp().filter {
it.isFile && it.name == "package.json"
}.mapTo(mutableListOf()) { parsePackageJson(it) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like all callers are fine with returning a sequence, so just drop the "To(mutableListOf())" part, keeping only "map". (Also, currently the function returns a mutable list due to the implicit return type.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the type explicit but kept it a list, as this is more handy with debugging.


override fun dependenciesFor(dependency: ModuleInfo): List<ModuleInfo> = dependency.dependencies.toList()
override fun linkageFor(dependency: YarnListNode): PackageLinkage = PackageLinkage.DYNAMIC
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are project dependencies, e.g. in a workspace, handled? I.e. why can this never be PackageLinkage.PROJECT_DYNAMIC compared to before?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had forgotten to implement this. Now, it supports project references inbetween workspace projects.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, as I believe tests had passed for your first iteration, does that mean that this functionality was not covered by test before?

Copy link
Member Author

@fviernau fviernau Mar 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, as I believe tests had passed for your first iteration, does that mean that this functionality was not covered by test before?

Yes, exactly. (I put on my TODO list to add tests for that, but consistent for all node managers. I didn't do it as part of this PR as it also wasn't covered by tests before.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. Although I have to admit that this decreases confidence in the rewrite a bit, as it's now harder to judge whether it changes behavior compared to before or not.

Can I ask for your timeline to add these tests? Because if this refactoring broke something, then it wouldn't be so good to let it go unnoticed for too long.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. Although I have to admit that this decreases confidence in the rewrite a bit, as it's now harder to judge whether it changes behavior compared to before or not.

Ok, then I'll make a PR prior to this one which enhance the tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I'm waiting for these tests before another review.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turned out that the existing implementation wasn't capable of handling it. So, I've fixed that and covered it with a test, see #10177.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, now it's ready again @sschuberth .

@fviernau fviernau force-pushed the yarn-rewrite branch 3 times, most recently from 1a79a8d to e6a3fdd Compare March 24, 2025 08:42
@fviernau fviernau requested a review from sschuberth March 24, 2025 08:42
@fviernau fviernau force-pushed the yarn-rewrite branch 2 times, most recently from 9395121 to ab027bd Compare April 16, 2025 11:56
packages = emptySet(),
issues = issues
issues = emptyList()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is intended that we now never get any issues here compared to before?

Copy link
Member Author

@fviernau fviernau Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveDependencies() is called for each (mapped) definition file, let's name it D.
We still do get an issue for each D, for which the at least one project's PackageJson which corresponds to D's workspace could not be parsed. The issue creation happens here: 1.

Copy link
Member

@sschuberth sschuberth Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, you're saying that the task of catching exceptions while parsing project files is now handed over from here to upstream PackageManager code, correct? Or in other words, your new implementation assumes that if you reach this line, there were no issues with parsing the project, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, you're saying that the task of catching exceptions while parsing project files is now handed over from here to upstream PackageManager code, correct?

Yes.

Or in other words, your new implementation assumes that if you reach this line, there were no issues with parsing the project, right?

Yes.

The use of `npm view` is an implementation detail of
`getRemotePackageDetails()`. While at it, use a reference to
`PackageJsonFile`.

Signed-off-by: Frank Viernau <[email protected]>
Prepare for re-use.

Signed-off-by: Frank Viernau <[email protected]>
Re-write large parts of `Yarn` to prefer extracting the needed
information from the output of the `yarn` CLI command. In particular,
the dependency tree is constructed now from the output of `yarn list`
instead of from the file hierarchy of the `node_modules` directory.
The approach is as follows:

1. Install the modules via `yarn install`.
2. Determine the workspace module dirs via `yarn workspaces list`.
3. Determine all module dirs by searching for any `package.json`.
4. Construct the scopes from `yarn list --json {--prod|--dev}`. Use
   the determined module dirs and workspace module dirs to decide
   whether a dependency is a project or a package.
5. Create project and packages by also parsing the `package.json`
   files in the module dirs.

Note: The `YarnDependencyHandlerTest` is removed, because the handler is
covered by the functional tests. This is consistent with other (Node)
package manager tests.

Signed-off-by: Frank Viernau <[email protected]>
@fviernau fviernau requested a review from sschuberth April 17, 2025 07:41
@sschuberth sschuberth enabled auto-merge (rebase) April 17, 2025 10:15
@sschuberth sschuberth merged commit cd56fa7 into main Apr 17, 2025
26 checks passed
@sschuberth sschuberth deleted the yarn-rewrite branch April 17, 2025 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants