-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Selective version resolution feature #4105
Conversation
src/cli/commands/install.js
Outdated
|
||
this.resolver = new PackageResolver(config, lockfile); | ||
this.resolutions = map(); | ||
this._resolutions = new Resolutions(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those names are a bit confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm so this.resolutions
was what was being previously used for flat mode - I didn't necessarily want to mess with it but the rfc said the plan was to eventually have flat mode replaced by resolutions so I kind of left both as is. How would you rename it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ResolutionMap
/ ResolutionRegistry
?
src/cli/index.js
Outdated
@@ -170,6 +170,7 @@ export function main({ | |||
const run = (): Promise<void> => { | |||
invariant(command, 'missing command'); | |||
return command.run(config, reporter, commander, commander.args).then(exitCode => { | |||
reporter.close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really need to call close
on the reporter? It will break the footer
call below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the reporter stuff is from the revert of the commit 280b6eb :( it was necessary to have the feature working after rebasing, but let me re-revert it once a fix lands.
src/package-resolver.js
Outdated
this.patternsByPackage = map(); | ||
this.fetchingPatterns = map(); | ||
this.fetchingQueue = new BlockingQueue('resolver fetching'); | ||
this.patterns = map(); | ||
this.resolutions = resolutions || new Resolutions(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use a default parameter instead of || new Resolutions(config)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're right! thanks :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that they have different semantics. The default parameter will only work if the argument is omitted. If the argument is falsy, it will be null in the end:
const fn = (arg = 42) => arg;
fn(null); // null
const fn = arg => arg || 42;
fn(null); // 42
It depends on what you are looking for.
src/resolutions.js
Outdated
return resolvedPattern; | ||
} | ||
|
||
const {version} = resolutions.find(({pattern}) => minimatch(path.join(...parentNames, name), pattern)) || {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably use an explicit .join('/')
, since path.join
is system-specific.
src/resolutions.js
Outdated
|
||
if (!semver.valid(version)) { | ||
this.reporter.warn(this.reporter.lang('invalidResolutionVersion', resolvedPattern)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This warning will cause issues when people will use the exotic resolvers such as file:
or git, which I assume will account for a fair percent of the feature usage (will allow people to fix a bug in a fork).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, my thought was that most people will put in versions and not exotic resolvers. But I can look into supporting the latter for v1 if you think it'll be most of the use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be best if we could support it for 1.0, yep. But we can merge this PR before that I you prefer, and iterate on it.
src/resolutions.js
Outdated
|
||
if (!semver.satisfies(version, range)) { | ||
this.reporter.warn(this.reporter.lang('incompatibleResolutionVersion', resolvedPattern, reqPattern)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The resolution value is a range, not a pinned reference. We should delay printing a warning until the range has been resolved (we can do the check directly in the resolvers).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gotcha
Nice PR! Left a few notes here and there, let me know what you think :) |
I've resolved the TODO item above and been working on supporting exotic ranges -- will try to post the revision and merge this weekend :) |
8eee43d
to
5c46448
Compare
I've run the tests locally and they failed to pass, I'll take some time to investigate a bit and see if my environment is responsible 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was my environment! Looks good to go :)
Best feature ever!!! |
Party time! @kaylieEB this work was impressive and we are all extremely grateful that you did all this work :) |
Thanks a lot for taking care of that :) |
Sorry for hijacking the topic, but was it ever a consideration to also allow filtering (nested) dependencies with this, eg by allowing "none", "skip" or "filter" in the resolution map? Seems like simple way to implement #4611. |
Summary
An implementation of yarnpkg/rfcs#68
resolutions
field of package.json, yarn will override specific versions of packages. This now includes ranges such as async@>0.9 <2.0 and exotic versions such as "async@https://github.com/caolan/async.gitgetResolvedPattern
has no idea about the parent requests, so this means if one nested dependency happens to have the same semver (say, package a hasleft-pad~1.0.0
and package b also hasleft-pad~1.0.0
), then they can end up being resolved to the same version defined in resolutions. However if they are different by any one character, such as semver range or version number, then they can individually be resolved. Imho I don't think it's too negative given that under normal circumstances, yarn will resolve both requests to the same package anyways.Test plan
I've modified / added scenarios to @victornoel's existing tests, and it didn't break existing functionalities. More tests coming soon!
//TODO: Add more test cases for warnings and ranges / exotic versions
(Directly nested dependencies pattern)
(All nested dependencies pattern)