<ItemGroup>
<PackageReference Include="NuGetPlayLib" Version="1.*" />
</ItemGroup>Expected: It should throw an error as it would have if the dependency was specified as:
<ItemGroup>
<PackageReference Include="NuGetPlayLib" Version="[1.0.0, 2.0.0)" />
</ItemGroup>
Actual: It resolves to version 2.0.0
For reference look at the documentation:
http://blog.nuget.org/20170316/NuGet-now-fully-integrated-into-MSBuild.html
Users can specify [1.*, 2.0.0) to enforce an upper bound.
A floating range is treated as two ranges currently.
In the case of 1.* the preferred range is 1.MAXINT, the nearest version to that will be used. Versions below the bounds of [1.0.0, ) will be considered errors.
I find this non-intuitive. The 1.* seems like it should match to just 1.MAXINT. Was there a requirement to match to the nearest version if the pattern match doesn't happen? I find the usecase a bit weird.
The wildcard is matched to what's highest the feed first, and then acts like a normal range afterwards. So if the feed has 1.1.0,1.2.0,1.3.0,2.0.0 and you look for 1.* Then it's effectively turned to 1.3 without a maximum.
Like @emgarten mentioned then - if you have [1.*, 2.0) then it's effectively turned to [1.3, 2.0) which gives you the clamped range you were looking for.
However there is a problem if a wildcard automatically adds a maximum.
Let's say you have project Q that uses library A and B, and A and B use package X. If A says X 1.4 is ideal, and B says X 2.2 is ideal, then Q gets X 2.2 which is the lowest matching package in the intersection of ranges.
But if a wildcard also implies a maximum and A says X 1.* is ideal, and B says X 2.* is ideal, then Q will get a restore error because the ranges [1.3, 2.0) and [2.0, 3.0) have no intersection.
The major version might not seem so bad, but you'd have the same problem with any non-identical wildcard... 1.5.* and 1.6.* will exclude each other, but 1.5.4 and 1.6.1 will happily select 1.6.1 for you.
That said - I do think this is a case where you should get the "under-versioning" warning. Just like if I say 1.3 is ideal and restore ends up handing me 2.0 I'll get a warning, if I say 1.* is ideal and restore ends up with 2.0 I should get that same warning.
@lodejard I see 2 issues with the current behavior using wild card:
Wow... that's completely awkward. Docs say:
A floating or wildcard dependency version is specified with the * wildcard, as with 6.0.. This version specification says "use the latest 6.0.x version"; 4. means "use the latest 4.x version."
In reality, 4.* means [4.*, ). That's a bummer as if package sources don't have any versions with Major=4 at all - NuGet will happily resolve 5.0.0 or whatever is available there next.
But even [4.0.0, 4.1.0) (assuming it resolves to the highest applicable version) does not solve the issue: 4.1.0-prerelease.label matches that range as well. Therefore, taking the explanations in this thread into account, the correct range to specify what is expected from 4.* by most people would be [4.0.0, 4.1.0-0).
How many people would write it correctly from the first time? And what is the point in having 4.* implemented as it is now, namely [4.*, )? To be honest, I struggle to find a real case when I'd like version 5.0.0 to match reference 4.* silently.
In fact, even the last one is not right because of #912 as it won't consider pre-release versions if there is at least one version without pre-release label (i.e. 4.0.1-rc won't be considered if there is 4.0.0 present in the feed). Complete bummer, seems not possible to do at all. [4.0.0-*, 4.1.0-0) does not work either.
Most helpful comment
Wow... that's completely awkward. Docs say:
In reality,
4.*means[4.*, ). That's a bummer as if package sources don't have any versions with Major=4 at all - NuGet will happily resolve5.0.0or whatever is available there next.But even
[4.0.0, 4.1.0)(assuming it resolves to the highest applicable version) does not solve the issue:4.1.0-prerelease.labelmatches that range as well. Therefore, taking the explanations in this thread into account, the correct range to specify what is expected from4.*by most people would be[4.0.0, 4.1.0-0).How many people would write it correctly from the first time? And what is the point in having
4.*implemented as it is now, namely[4.*, )? To be honest, I struggle to find a real case when I'd like version5.0.0to match reference4.*silently.