5
Vote

Upper bounds and prerelease gives undesired behavior

description

Scenario:
  1. Package Foo depends on package Bar
  2. The owner of Foo wants to be conservative about the dependency version range, so Foo specifies a version range of [1.0,2.0) indicating that any 1.x version is allowed, but 2.0 is not allowed
  3. The owner of Bar makes drastic breaking changes an publishes a prerelease version of 2.0-alpha
  4. A consumer of Foo opts to see prerelease packages and checks for and installs updates
Expected:
  • Bar is not updated to 2.0-alpha because Foo has a dependency version range of < 2.0
Actual:
  • Bar is updated to 2.0-alpha and the application is broken. This happens because 2.0-alpha is less than 2.0, technically meeting the version range, despite being against the intended meaning.

comments

JeffHandley wrote Mar 28, 2013 at 6:31 PM

Note that a "workaround" to this is for Foo to declare its dependency on Bar as [1.0,2.0-a). That's pretty undiscoverable though. Also, when I think "less than 2.0" I include any prerelease of 2.0 in that thought.

dotnetchris wrote Mar 28, 2013 at 6:33 PM

I support the current behavior. 2-alpha is less than 2.0. It should allow me to update to 2-alpha.

dotnetchris wrote Mar 28, 2013 at 6:40 PM

Although I guess from a clean package installation, i'd probably not want it to automatically install 2-alpha, hmm

dmarsh wrote Mar 28, 2013 at 7:09 PM

I think the answer is

JeffHandley wrote Mar 28, 2013 at 7:17 PM

Note that a previous issue was filed on this. I've closed it as a dupe of this one (since this one has commentary).

http://nuget.codeplex.com/workitem/3025

dotnetjunky wrote Mar 28, 2013 at 7:27 PM

@dmarsh, you think the answer is what? :)

XavierDecoster wrote Mar 28, 2013 at 8:04 PM

According to semver, whether pre-release or not is irrelevant in this scenario because it is overruled by the major version number. As such, anything 2.x - including a 2.0.0-alpha pre-release - should already be considered breaking.

The intent of the [1.0-2.0) constraint is to be conservative and exclude anything 2.x because of the breaking change(s). This also explains why we expect that the pre-release is ignored as well during updates of dependencies with such constraint.

I'm all in favor of adjusting the current nuget update behavior to match the expected behavior.

jalbert wrote Mar 28, 2013 at 9:42 PM

The current behavior violates the Principle of Least Astonishment. If I declare [1.0.0,2.0.0), using Semantic Versioning I am explicitly stating I do not want to consume any breaking changes. A pre-release version by definition contains breaking changes. Please change to match the expected behavior.

tilovell wrote Mar 29, 2013 at 12:52 AM

+1 for this being nonintuitive behavior.

The semver spec does state that prerelease versions 2.0-alpha are < 2.0. Seems logical.
It's also clear that the major version of anything that is 2.0-alpha is 2. Also seems logical.

I will claim the bug is in the nuget dependency spec language. Its the Nuget dependency language that decided that [1.0-2.0) means < 2.0 (== 2.0.0.0 < 2.0.0.0-alpha by semver)

Nuget dependency language should interpret it as {x : x where x.MajorVersion >=1 && x.MajorVersion < 2}.
This should mean
  • [1.0-2.0) accepts 1.0.0-alpha
  • [1.1-1.1.1.0) accepts 1.1.1.0-alpha etc

tilovell wrote Mar 29, 2013 at 4:46 PM

I started to doubt part of what I said last night.
It could be pretty surprising to some people that [1.0-2.0] includes prerelease versions of 1.0, as well as release versions.

What about if (just a rough idea)
[1.0-2.0] includes 1.0, 2.0, and 2.0 prerelease, but not 1.0 prerelease
[1.0-2.0) does not include 2.0 or 2.0 prerelease

and some syntax like [1.0pre-2.0] can be used to include both 1.0 and 1.0 prerelease?

and less likely version specs:
(1.0pre-2.0] includes 1.0 but not 1.0 prerelease
[1.0-2.0pre) does not include 2.0 or 2.0 prerelease

dotnetjunky wrote Mar 29, 2013 at 5:24 PM

I also brought up the idea of a new syntax with Jeff, but I'd like to be conservative and preserve the current behavior with the current syntax. The new syntax with allow including prerelease versions. So:

{1.0-2.0] : Include pre-release of 1.0
[1.0-2.0} : Don't include 2.0 pre-release