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
140 changes: 124 additions & 16 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 @@ -148,32 +176,86 @@ public static bool TryParse(string versionString, out FloatRange range)
{
range = null;

if (versionString != null)
if (versionString != null && !string.IsNullOrWhiteSpace(versionString))
{
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.Equals("*-*"))
{
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 = CalculateVersionParts(stablePart);
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)
{
// replace the * with a 0
actualVersion += "0";

var versionParts = actualVersion.Split('.').Length;
var versionParts = CalculateVersionParts(actualVersion);

if (versionParts == 2)
{
Expand Down Expand Up @@ -214,7 +296,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 All @@ -233,6 +314,22 @@ public static bool TryParse(string versionString, out FloatRange range)
return range != null;
}

private static int CalculateVersionParts(string line)
{
var count = 1;
if (line != null)
{
for (var i = 0; i < line.Length; i++)
{
if (line[i] == '.')
{
count++;
}
}
}
return count;
}

/// <summary>
/// Create a floating version string in the format: 1.0.0-alpha-*
/// </summary>
Expand All @@ -259,9 +356,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
8 changes: 4 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 Down Expand Up @@ -195,7 +195,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 +224,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