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

v4 #99

Merged
merged 11 commits into from
Sep 11, 2014
Merged

v4 #99

merged 11 commits into from
Sep 11, 2014

Conversation

isaacs
Copy link
Contributor

@isaacs isaacs commented Sep 9, 2014

  1. Revert ^ behavior to SemVer 2.x.
  2. Handle prereleases in less surprising ways.
  3. Document desugaring advanced range syntax to simple comparators.

@isaacs
Copy link
Contributor Author

isaacs commented Sep 9, 2014

Made it so that updates didn't break the linting (ie, split up the "lint" commit and squashed against the commits that added the lint failures).

@othiym23
Copy link
Contributor

othiym23 commented Sep 9, 2014

One important change (worth reading in full):

Prerelease Tags

If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will only be allowed to satisfy comparator sets if at least one comparator with the same major/minor/patch tuple also has a prerelease tag.

For example, the range >1.2.3-alpha.3 would be allowed to match the version 1.2.3-alpha.7, but it would not be satisfied by 3.4.5-alpha.9, even though 3.4.5-alpha.9 is technically "greater than" 1.2.3-alpha.3 according to the SemVer sort rules. The version range only accepts prerelease tags on the 1.2.3 version.

The purpose for this behavior is twofold. First, prerelease versions frequently are updated very quickly, and contain many breaking changes that are (by the author's design) not yet fit for public consumption. Therefore, by default, they are excluded from range matching semantics.

Second, a user who has opted into using a prerelease version has clearly indicated the intent to use that specific set of alpha/beta/rc versions. By including a prerelease tag in the range, the user is indicating that they are aware of the risk. However, it is still not appropriate to assume that they have opted into taking a similar risk on the next set of prerelease versions.

@isaacs
Copy link
Contributor Author

isaacs commented Sep 9, 2014

Possible doc clarification? What do you think?

diff --git a/README.md b/README.md
index 145132e..93068b8 100644
--- a/README.md
+++ b/README.md
@@ -58,11 +58,12 @@ For example, the comparator `>=1.2.7` would match the versions
 `1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`
 or `1.1.0`.

-Comparators can be joined in a range by whitespace to indicate
-**intersection**, or by a double-pipe `||` to indicate **union**.
+Comparators can be joined by whitespace to form a `comparator set`,
+which is satisfied by the **intersection** of all of the comparators
+it includes.

-A range is composed of one or more `comparator sets`, joined by `||`.
-A version matches a range if and only if every comparator in at least
+A range is composed of one or more comparator sets, joined by `||`.  A
+version matches a range if and only if every comparator in at least
 one of the `||`-separated comparator sets is satisfied by the version.

 For example, the range `>=1.2.7 <1.3.0` would match the versions

The purpose for this behavior is twofold. First, prerelease versions
frequently are updated very quickly, and contain many breaking changes
that are (by the author's design) not yet fit for public consumption.
Therefor, by default, they are excluded from range matching semantics.
Copy link
Contributor

Choose a reason for hiding this comment

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

'Therefor' → 'Therefore'

@othiym23
Copy link
Contributor

othiym23 commented Sep 9, 2014

I like it! But I would! 🔬

@othiym23
Copy link
Contributor

othiym23 commented Sep 9, 2014

If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will only be allowed to satisfy comparator sets if at least one comparator with the same major/minor/patch tuple also has a prerelease tag.

Most languages that use tuples use (major, minor, patch) (or some other kinds of bracketing) as the notation for them. Follow that convention?

@othiym23
Copy link
Contributor

othiym23 commented Sep 9, 2014

I'd like to see an example of a prerelease tag for the tilde operator as well as the caret operator in the README.

@othiym23
Copy link
Contributor

othiym23 commented Sep 9, 2014

@timoxley @rvagg @domenic @terinjokes @Raynos feedback?

* `1` := `1.x.x` := `>=1.0.0 <2.0.0`
* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`

#### Tilde Ranges `~1.2.3` `~1.2` `~1`
Copy link

Choose a reason for hiding this comment

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

This could do with an example including 0.x.y just to be absolutely clear that the behaviour <1 there is the same as >1, important since ^ is so quirky <1. Perhaps even mention that the behaviour is the same across all majors?

@isaacs
Copy link
Contributor Author

isaacs commented Sep 9, 2014

@rvagg Added some doc updates to address your comments. Please keep them coming! We'll probably want to squash all the documentation down before actually merging, though.

@rvagg
Copy link

rvagg commented Sep 9, 2014

I appreciate the fix to the pre-release behaviour here, effectively turning it in to dev releases which makes sense since they are often "beta" or "alpha". The only place where I've used them differently is in releases of readable-stream which is trying to keep (minor,patch) parity with core so pre-releases offer(ed) flexibility to add intermediate releases. However that's an odd case and that parity isn't absolutely necessary.

Still far too much significance placed in <1 for ^ for my tastes, better than current behaviour and roughly aligns with the spirit of the spec I suppose but keeping 0.0.x as an additional special case is odd. Since I'm avoiding both ^ and <1 these days and we appear to have shifted to encouraging people to start at 1.0.0 now it doesn't bother me so much.

/cc @DamonOehlman

@isaacs
Copy link
Contributor Author

isaacs commented Sep 9, 2014

Still far too much significance placed in <1 for ^ for my tastes, better than current behaviour and roughly aligns with the spirit of the spec I suppose but keeping 0.0.x as an additional special case is odd. Since I'm avoiding both ^ and <1 these days and we appear to have shifted to encouraging people to start at 1.0.0 now it doesn't bother me so much.

I'm actually in agreement with you there. It'd be nice if we could just ditch the "0.x is magic" entirely. The "0.x.y is not SemVer" approach in the specification is just way too hazardous, but just as a matter of observed behavior, people frequently DO make breaking changes between 0.x.y and 0.x+1.y, and much more rarely between 1.x.y and 1.x+1.y. Glitchy or not, the node-semver 2.x caret behavior seems to match most closely to most of our users' expectations, since >99% of them have not read much of the semver.org specification anyway.

between `0.2.4` and `0.3.0` releases, which is a common practice.
However, it presumes that there will *not* be breaking changes between
`0.2.4` and `0.2.5`. It allows for changes that are presumed to be
additive (but non-breaking), according to commonly observed practices.
Copy link

Choose a reason for hiding this comment

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

+1 good doc addition. Needs some education effort around this. Probably makes sense to take a more in-depth look at <1 in the nodesource blog semver series (we have a ^ article coming out tomorrow).

@othiym23
Copy link
Contributor

othiym23 commented Sep 9, 2014

@rvagg

Since I'm avoiding both ^ and <1 these days

What are you using instead of ^? ~? Explicit ranges? Are there aspects of ^ you dislike in addition to its behavior < 1? ^ was introduced (and made default) to try to pave a cowpath for Node's semver use, and I'm interested in finding out what other cowpaths there are.

@rvagg
Copy link

rvagg commented Sep 9, 2014

@isaacs: fair enough, I can get on board with that I think, we just need to focus on (1) education and (2) making sure package authors have the tools to deal with wayward dependency authors (underscore springs to mind)

@terinjokes
Copy link

@othiym23 I've started to move my packages to using explicit comparator sets, largely to be explicit about <1 behavior.

@rvagg
Copy link

rvagg commented Sep 9, 2014

@othiym23 I'm still strongly in favour of ~ but am also opting for explicit ranges in many cases (where I don't have too many other maintainers to convince of my opinions!) as it provides clarity above the shifting definitions of the sugared range specifiers (well, ^ is shifting, which leads to uncertainty about sugar in general).

Regarding ~ over ^, from my rant on npm-explicit-deps:

An ^ range will automatically include newer versions of dependencies to your library long after you've released it in a tested state. You should be exercising greater control over what dependencies are coupled with your libraries and applications or you're asking for trouble. Some Node.js developers go so far as to pin exact dependency versions and upgrade them explicitly. My current preference is to use the ~ range so that my libraries can take advantage of patch releases. I don't want to take the risk of including wildly changing versions of a dependency, even if the fact that the major version hasn't changed is supposed to mean that there are no breaking changes. I don't trust myself enough to do versioning properly and consistently over a long period of time so why would I trust anybody else?

@othiym23
Copy link
Contributor

othiym23 commented Sep 9, 2014

@rvagg @maxogden decides whether to pin or use ranges with dependencies based on his evaluation of packages and their authors. While I don't want to impose that level of discernment on npm users in general, after watching all the arguments about underscore (some of which have made it onto npm issues), I think that training is a much better solution than technology. In fact, that aspect of semver is purely social.

@isaacs
Copy link
Contributor Author

isaacs commented Sep 9, 2014

Note: we've also made init-package-json default to 1.0.0 as the first version a package.json starts out with.

And, while node-semver v3 was indeed disruptive, it never went out as part of an "official" npm or node release, so by making node-semver v4 follow the same ^ behavior as semver v2, we can avoid most of the uncomfortable "shifting" for our users.

@Raynos
Copy link

Raynos commented Sep 11, 2014

we could special-case the meaning of ^ in peer-dependencies for a release

This is something worth thinking about, since peer dependencies should be deprecated / deleted so its cool to add back compat hacks to them.


For example, the range `>1.2.3-alpha.3` would be allowed to match the
version `1.2.3-alpha.7`, but it would *not* be satisfied by
`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater
Copy link

Choose a reason for hiding this comment

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

It's not clear whether >1.2.3-alpha.3 matches 3.4.5.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it would. I'll add a bit to that effect tomorrow morning.

@Raynos
Copy link

Raynos commented Sep 11, 2014

this change looks ok. It's a pity that <1 semantics are really messy but the community is really messy.

There might be value in a best practices paragraph in the README.

## Best practices

When authoring a library it's recommended that you follow the semver specification.

Because the semver specification has a special case for version <1 it's recommended
that you start authoring modules at v1.0.0 from the start and follow the semver specification
from there on.

@Raynos
Copy link

Raynos commented Sep 11, 2014

There is a seperate issue we can talk about which is make npm version warn / complain at you if your version is still below 1.0.0.

The version range <1.0.0 causes a lot of complexity, bikeshedding, opinion and subtle bugs. If the npm version tool can recommend module authors to avoid that version range completely then these problems can be avoided.

@othiym23
Copy link
Contributor

There is a seperate issue we can talk about which is make npm version warn / complain at you if your version is still below 1.0.0.

I like this idea, but indeed, this is an issue for npm, not node-semver.

@rvagg
Copy link

rvagg commented Sep 11, 2014

As I start to think more about the education effort involved here I come back to my concerns about maintaining three separate behaviours for ^ at (>0).y.z, 0.(>0).z and 0.0.z. You can't describe what ^ is in a sentence like you can with ~ and only the most thorough of nerds really want to have to reserve brain-space for trivia like this. We should be aiming to give people a tool that (a) just works and (b) doesn't surprise, so it gets out of their way entirely and lets them do what is actually important to them (which is not semver ranges).

For the same reason I'm strongly in disagreement with adding a new range specifier, two is more than enough and anybody with strong enough opinions can just use explicit ranges. Same goes for adding special behaviour for peerDependencies unfortunately, they are hard enough to grok as it is without overloading even more special-casing.

@othiym23 perhaps you could add a --save-explicit-range option that saves the desugared range generated by the active --save-prefix (then I can deprecate npm-explicit-deps!). Whether that ends up defaulting to true can be a separate discussion but at least we'd have something to experiment with. My experience with explicit dependencies is that while they add much-needed clarity about what you're wanting, they are also slightly too verbose to be human-parsable at a glance, particularly when you have to include -0: https://github.com/rvagg/servertest/blob/master/package.json#L22-L30

@isaacs
Copy link
Contributor Author

isaacs commented Sep 11, 2014

Re "Best practices" npm init already has been defaulting to 1.0.0 for some time now, and we've seen a significant (but still slow) growth in 1.x publishes. Not sure if that's just normal growth, or an effect of init, but we'll see.

@isaacs
Copy link
Contributor Author

isaacs commented Sep 11, 2014

I'm in agreement with @rvagg that special-casing peerDeps (more) is a pretty bad idea. They should be reduced in their relevance to a mere warning, but that's an issue for a different repo ;)

@othiym23
Copy link
Contributor

For those following this issue, we're going to land this PR and publish it as node-semver@4.0.0, which will be included in npm@2.0.0-beta.4. That does not imply that we're unwilling to consider further tweaks to get this stuff right before the release of npm@2.0.0 – integers are cheap, and if we need to make breaking changes, it's not a big deal to bump node-semver's major version again before npm 2 goes out.

Simplify range expansions to remove -0 everywhere.

Only allow -prerelease versions that have a -prerelease tag on a version
in the range with the same exact X.Y.Z tuple.
Document partial versions in hyphen ranges (Fix #76)
@isaacs
Copy link
Contributor Author

isaacs commented Sep 11, 2014

Squashed all the documentation into a single commit, and organized a few other things in the history.

@isaacs isaacs merged commit f71a46b into master Sep 11, 2014
@isaacs
Copy link
Contributor Author

isaacs commented Sep 11, 2014

Published version 4.0.0 to npm as semver@v4-rc.

So, we can ship this in a npm 2 beta, and get some proper play-testing with the new semantics. If there's any more significant breaking changes necessary, we probably won't run out of integers, like @othiym23 said :)

@othiym23 othiym23 deleted the v4 branch September 13, 2014 09:45
@othiym23
Copy link
Contributor

semver@4.0.0 is included in npm@2.0.0 (we finally nailed down npm/npm#6043!), which is currently dist-tagged as npm@next. If it turns out these semantics are terrible, we can try again with npm@3, which should be along pretty soon.

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.

7 participants