Skip to content
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

Merged
merged 4 commits into from
Aug 14, 2017

Conversation

kaylie-alexa
Copy link
Member

@kaylie-alexa kaylie-alexa commented Aug 6, 2017

Summary

An implementation of yarnpkg/rfcs#68

  1. Based on a glob pattern specified in the 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.git
  2. Warnings are generated when
  • The glob pattern doesn't end with a valid package name (currently it only checks if it's empty after the last slash, since it's difficult to know what sub-dependencies exist at the time of install)
  • When the given resolution version is incompatible with the version specified in the request package.json (see screenshot)
  • When the given resolution version is an invalid semver (currently doesn't support exotic versions)
  1. Edge cases that won't be supported yet
  • Yarn's resolution method getResolvedPattern has no idea about the parent requests, so this means if one nested dependency happens to have the same semver (say, package a has left-pad~1.0.0 and package b also has left-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.
  • I have not yet implemented '**' case where all nested dependencies would resolve to particular version. I can't find any good use case for this.

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)
screen shot 2017-08-06 at 10 17 20 pm

(All nested dependencies pattern)
screen shot 2017-08-06 at 10 19 16 pm


this.resolver = new PackageResolver(config, lockfile);
this.resolutions = map();
this._resolutions = new Resolutions(config);
Copy link
Member

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

Copy link
Member Author

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?

Copy link
Member

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();
Copy link
Member

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

Copy link
Member Author

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.

this.patternsByPackage = map();
this.fetchingPatterns = map();
this.fetchingQueue = new BlockingQueue('resolver fetching');
this.patterns = map();
this.resolutions = resolutions || new Resolutions(config);
Copy link
Member

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)

Copy link
Member Author

Choose a reason for hiding this comment

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

you're right! thanks :)

Copy link
Contributor

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.

return resolvedPattern;
}

const {version} = resolutions.find(({pattern}) => minimatch(path.join(...parentNames, name), pattern)) || {};
Copy link
Member

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.


if (!semver.valid(version)) {
this.reporter.warn(this.reporter.lang('invalidResolutionVersion', resolvedPattern));
}
Copy link
Member

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).

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, 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.

Copy link
Member

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.


if (!semver.satisfies(version, range)) {
this.reporter.warn(this.reporter.lang('incompatibleResolutionVersion', resolvedPattern, reqPattern));
}
Copy link
Member

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).

Copy link
Member Author

Choose a reason for hiding this comment

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

gotcha

@arcanis
Copy link
Member

arcanis commented Aug 7, 2017

Nice PR! Left a few notes here and there, let me know what you think :)

@BYK BYK mentioned this pull request Aug 7, 2017
3 tasks
@cpojer cpojer added this to Active in Yarn 1.0 Aug 7, 2017
@cpojer cpojer moved this from Active to Awaiting Review in Yarn 1.0 Aug 7, 2017
@kaylie-alexa
Copy link
Member Author

I've resolved the TODO item above and been working on supporting exotic ranges -- will try to post the revision and merge this weekend :)

@BYK BYK self-assigned this Aug 9, 2017
@kaylie-alexa kaylie-alexa changed the title [WIP] Selective version resolution feature Selective version resolution feature Aug 12, 2017
@BYK BYK assigned arcanis and unassigned BYK Aug 14, 2017
@arcanis
Copy link
Member

arcanis commented Aug 14, 2017

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 👍

Copy link
Member

@arcanis arcanis left a 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 :)

@arcanis arcanis merged commit 634c239 into yarnpkg:master Aug 14, 2017
@bestander
Copy link
Member

Best feature ever!!!

@cpojer
Copy link
Contributor

cpojer commented Aug 14, 2017

Party time! @kaylieEB this work was impressive and we are all extremely grateful that you did all this work :)

@victornoel
Copy link
Contributor

Thanks a lot for taking care of that :)

@EmielM
Copy link

EmielM commented Nov 13, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

7 participants