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

Support floating prerelease and stable packages at the same time with the same version range (enable absolute latest scenario) (*-*) #3247

Merged
merged 13 commits into from
Mar 17, 2020
121 changes: 107 additions & 14 deletions src/NuGet.Core/NuGet.Versioning/FloatRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,37 @@ public bool Satisfies(NuGetVersion version)
if (_minVersion != null)
{
// everything beyond this point requires a version
if (_floatBehavior == NuGetVersionFloatBehavior.Prerelease)
if (_floatBehavior == NuGetVersionFloatBehavior.PrereleaseRevision)
{
// allow the stable version to match
return _minVersion.Major == version.Major
&& _minVersion.Minor == version.Minor
&& _minVersion.Patch == version.Patch
&& ((version.IsPrerelease && version.Release.StartsWith(_releasePrefix, StringComparison.OrdinalIgnoreCase))
|| !version.IsPrerelease);
}
else if (_floatBehavior == NuGetVersionFloatBehavior.PrereleasePatch)
{
// allow the stable version to match
return _minVersion.Major == version.Major
&& _minVersion.Minor == version.Minor
&& ((version.IsPrerelease && version.Release.StartsWith(_releasePrefix, StringComparison.OrdinalIgnoreCase))
|| !version.IsPrerelease);
}
else if (FloatBehavior == NuGetVersionFloatBehavior.PrereleaseMinor)
{
// allow the stable version to match
return _minVersion.Major == version.Major
&& ((version.IsPrerelease && version.Release.StartsWith(_releasePrefix, StringComparison.OrdinalIgnoreCase))
|| !version.IsPrerelease);
}
else if (FloatBehavior == NuGetVersionFloatBehavior.PrereleaseMajor)
{
// allow the stable version to match
return (version.IsPrerelease && version.Release.StartsWith(_releasePrefix, StringComparison.OrdinalIgnoreCase))
|| !version.IsPrerelease;
}
else if (_floatBehavior == NuGetVersionFloatBehavior.Prerelease)
{
// allow the stable version to match
return VersionComparer.Version.Equals(_minVersion, version)
Expand Down Expand Up @@ -134,9 +164,7 @@ public bool Satisfies(NuGetVersion version)
/// </summary>
public static FloatRange Parse(string versionString)
{
FloatRange range = null;

TryParse(versionString, out range);
TryParse(versionString, out FloatRange range);

return range;
}
Expand All @@ -150,23 +178,78 @@ public static bool TryParse(string versionString, out FloatRange range)

if (versionString != null)
{
var starPos = versionString.IndexOf('*');

var actualVersion = versionString;
var firstStarPosition = versionString.IndexOf('*');
var lastStarPosition = versionString.LastIndexOf('*');
string releasePrefix = null;

if (versionString.Length == 1
&& starPos == 0)
&& firstStarPosition == 0)
{
range = new FloatRange(NuGetVersionFloatBehavior.Major, new NuGetVersion(new Version(0, 0)));
}
// * must appear as the last char in the string.
else if (versionString.Length == 3
&& firstStarPosition == 0 && lastStarPosition == 2 && versionString[1] == '-')
{
range = new FloatRange(NuGetVersionFloatBehavior.AbsoluteLatest, new NuGetVersion("0.0.0-0"), releasePrefix: string.Empty);
}
else if (firstStarPosition != lastStarPosition && lastStarPosition != -1 && versionString.IndexOf('+') == -1)
{
var behavior = NuGetVersionFloatBehavior.None;
// 2 *s are only allowed in prerelease versions.
var dashPosition = versionString.IndexOf('-');
string actualVersion = null;

if (dashPosition != -1 &&
lastStarPosition == versionString.Length - 1 && // Last star is at the end of the full string
firstStarPosition == (dashPosition-1) // First star is right before the first dash.
)
{
// Get the stable part.
var stablePart = versionString.Substring(0, dashPosition - 1); // Get the part without the *
stablePart += "0";
var versionParts = stablePart.Split('.').Length;
switch (versionParts)
{
case 1:
behavior = NuGetVersionFloatBehavior.PrereleaseMajor;
break;
case 2:
behavior = NuGetVersionFloatBehavior.PrereleaseMinor;
break;
case 3:
behavior = NuGetVersionFloatBehavior.PrereleasePatch;
break;
case 4:
behavior = NuGetVersionFloatBehavior.PrereleaseRevision;
break;
default:
break;
}

var releaseVersion = versionString.Substring(dashPosition + 1);
releasePrefix = releaseVersion.Substring(0, releaseVersion.Length - 1);
var releasePart = releasePrefix;
if (releasePrefix.Length == 0 || releasePrefix.EndsWith("."))
{
// 1.0.0-* scenario, an empty label is not a valid version.
releasePart += "0";
}

actualVersion = stablePart + "-" + releasePart;
}

if (NuGetVersion.TryParse(actualVersion, out NuGetVersion version))
{
range = new FloatRange(behavior, version, releasePrefix);
}
}
// A single * can only appear as the last char in the string.
// * cannot appear in the metadata section after the +
else if (starPos == versionString.Length - 1 && versionString.IndexOf('+') == -1)
else if (lastStarPosition == versionString.Length - 1 && versionString.IndexOf('+') == -1)
{
var behavior = NuGetVersionFloatBehavior.None;

actualVersion = versionString.Substring(0, versionString.Length - 1);
var actualVersion = versionString.Substring(0, versionString.Length - 1);

if (versionString.IndexOf('-') == -1)
{
Expand Down Expand Up @@ -214,7 +297,6 @@ public static bool TryParse(string versionString, out FloatRange range)
NuGetVersion version = null;
if (NuGetVersion.TryParse(actualVersion, out version))
{
// there is no float range for this version
range = new FloatRange(behavior, version, releasePrefix);
}
}
Expand Down Expand Up @@ -259,9 +341,20 @@ public override string ToString()
case NuGetVersionFloatBehavior.Major:
result = "*";
break;
case NuGetVersionFloatBehavior.PrereleaseRevision:
result = string.Format(CultureInfo.InvariantCulture, "{0}.{1}.{2}.*-{3}*", MinVersion.Major, MinVersion.Minor, MinVersion.Patch, _releasePrefix);
break;
case NuGetVersionFloatBehavior.PrereleasePatch:
result = string.Format(CultureInfo.InvariantCulture, "{0}.{1}.*-{2}*", MinVersion.Major, MinVersion.Minor, _releasePrefix);
break;
case NuGetVersionFloatBehavior.PrereleaseMinor:
result = string.Format(CultureInfo.InvariantCulture, "{0}.*-{1}*", MinVersion.Major, _releasePrefix);
break;
case NuGetVersionFloatBehavior.PrereleaseMajor:
result = string.Format(CultureInfo.InvariantCulture, "*-{1}*", MinVersion.Major, _releasePrefix);
break;
case NuGetVersionFloatBehavior.AbsoluteLatest:
// TODO: how should this be denoted?
result = string.Empty;
result = "*-*";
break;
default:
break;
Expand Down
27 changes: 24 additions & 3 deletions src/NuGet.Core/NuGet.Versioning/NuGetVersionFloatBehavior.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace NuGet.Versioning
Expand Down Expand Up @@ -39,8 +39,29 @@ public enum NuGetVersionFloatBehavior
Major,

/// <summary>
/// Float major and pre-release
/// Float major and pre-release, *-*
/// </summary>
AbsoluteLatest
AbsoluteLatest,

/// <summary>
/// Float revision and pre-release x.y.z.*-*
/// </summary>
PrereleaseRevision,

/// <summary>
/// Float patch and pre-release x.y.*-*
/// </summary>
PrereleasePatch,

/// <summary>
/// Float minor and pre-release x.*-*
/// </summary>
PrereleaseMinor,

/// <summary>
/// Float major and prerelease, but only with partial prerelease *-rc.*.
/// *-* is captured by <see cref="AbsoluteLatest"/>
/// </summary>
PrereleaseMajor,
}
}
4 changes: 4 additions & 0 deletions src/NuGet.Core/NuGet.Versioning/VersionRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ public bool IsBetter(NuGetVersion current, NuGetVersion considering)
if (!HasPrereleaseBounds
&& considering.IsPrerelease
&& _floatRange?.FloatBehavior != NuGetVersionFloatBehavior.Prerelease
&& _floatRange?.FloatBehavior != NuGetVersionFloatBehavior.PrereleaseMajor
&& _floatRange?.FloatBehavior != NuGetVersionFloatBehavior.PrereleaseMinor
&& _floatRange?.FloatBehavior != NuGetVersionFloatBehavior.PrereleasePatch
&& _floatRange?.FloatBehavior != NuGetVersionFloatBehavior.PrereleaseRevision
&& _floatRange?.FloatBehavior != NuGetVersionFloatBehavior.AbsoluteLatest)
{
return false;
Expand Down
19 changes: 15 additions & 4 deletions src/NuGet.Core/NuGet.Versioning/VersionRangeFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public static VersionRange Parse(string value, bool allowFloating)
if (!TryParse(value, allowFloating, out versionInfo))
{
throw new ArgumentException(
String.Format(CultureInfo.CurrentCulture,
string.Format(CultureInfo.CurrentCulture,
Resources.Invalidvalue, value));
}

Expand Down Expand Up @@ -101,7 +101,7 @@ public static bool TryParse(string value, bool allowFloating, out VersionRange v

var charArray = trimmedValue.ToCharArray();

// * is the only range below 3 chars
// * is the only 1 char range
if (allowFloating
&& charArray.Length == 1
&& charArray[0] == '*')
Expand All @@ -116,6 +116,17 @@ public static bool TryParse(string value, bool allowFloating, out VersionRange v
return false;
}

// Special case *-*
if (allowFloating
&& charArray.Length == 3
&& charArray[0] == '*'
&& charArray[0] == '-'
&& charArray[0] == '*')
{
versionRange = new VersionRange(new NuGetVersion("0.0.0-0"), true, null, true, FloatRange.Parse(trimmedValue), originalString: value);
return true;
}

string minVersionString = null;
string maxVersionString = null;
var isMinInclusive = false;
Expand Down Expand Up @@ -195,7 +206,7 @@ public static bool TryParse(string value, bool allowFloating, out VersionRange v
minVersionString = trimmedValue;
}

if (!String.IsNullOrWhiteSpace(minVersionString))
if (!string.IsNullOrWhiteSpace(minVersionString))
{
// parse the min version string
if (allowFloating && minVersionString.Contains("*"))
Expand Down Expand Up @@ -224,7 +235,7 @@ public static bool TryParse(string value, bool allowFloating, out VersionRange v
}

// parse the max version string, the max cannot float
if (!String.IsNullOrWhiteSpace(maxVersionString))
if (!string.IsNullOrWhiteSpace(maxVersionString))
{
if (!NuGetVersion.TryParse(maxVersionString, out maxVersion))
{
Expand Down
1 change: 0 additions & 1 deletion src/NuGet.Core/NuGet.Versioning/VersionRangeFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ private string GetShortString(VersionRange range)
/// </summary>
private string GetNormalizedString(VersionRange range)
{
// TODO: write out the float version
var sb = new StringBuilder();

sb.Append(range.HasLowerBound && range.IsMinInclusive ? '[' : '(');
Expand Down
Loading