fix(releases): strip prerelease and build metadata before version compare
System.Version can't parse SemVer prerelease ("-alpha") or MinVer build
metadata ("+sha") suffixes, so an installed 1.0.2-alpha was treated as
unparseable. Reduce both sides to their numeric core before comparing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,13 +6,16 @@ public static class VersionComparer
|
|||||||
{
|
{
|
||||||
public static VersionCompareResult Compare(string latest, string current)
|
public static VersionCompareResult Compare(string latest, string current)
|
||||||
{
|
{
|
||||||
var latestTrimmed = (latest ?? "").TrimStart('v', 'V');
|
var unparseable = !Version.TryParse(CoreVersion(latest), out var lv)
|
||||||
var currentTrimmed = (current ?? "").TrimStart('v', 'V');
|
| !Version.TryParse(CoreVersion(current), out var cv);
|
||||||
|
|
||||||
var unparseable = !Version.TryParse(latestTrimmed, out var lv)
|
|
||||||
| !Version.TryParse(currentTrimmed, out var cv);
|
|
||||||
|
|
||||||
if (unparseable) return new VersionCompareResult(false, true);
|
if (unparseable) return new VersionCompareResult(false, true);
|
||||||
return new VersionCompareResult(lv > cv, false);
|
return new VersionCompareResult(lv > cv, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduce a tag/version to its numeric core: drop a leading "v", MinVer build
|
||||||
|
// metadata ("+sha"), and any SemVer prerelease suffix ("-alpha") — none of
|
||||||
|
// which System.Version can parse. So "v1.0.2-alpha+abc" -> "1.0.2".
|
||||||
|
private static string CoreVersion(string value)
|
||||||
|
=> (value ?? "").TrimStart('v', 'V').Split('+')[0].Split('-')[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ public class VersionComparerTests
|
|||||||
[InlineData("v0.2.0", "0.1.0", true, false)]
|
[InlineData("v0.2.0", "0.1.0", true, false)]
|
||||||
[InlineData("0.2.0", "v0.1.0", true, false)]
|
[InlineData("0.2.0", "v0.1.0", true, false)]
|
||||||
[InlineData("1.0.0.0", "0.99.99.99", true, false)]
|
[InlineData("1.0.0.0", "0.99.99.99", true, false)]
|
||||||
|
// Prerelease and build-metadata suffixes are stripped to the numeric core
|
||||||
|
// before comparing (System.Version can't parse them otherwise).
|
||||||
|
[InlineData("0.2.0-beta", "0.1.0", true, false)]
|
||||||
|
[InlineData("0.2.0", "0.1.0-alpha", true, false)]
|
||||||
|
[InlineData("1.2.0", "1.0.2-alpha", true, false)] // real-world: installed 1.0.2-alpha -> 1.2.0
|
||||||
|
[InlineData("v1.0.2-alpha+1c764dae", "1.0.0", true, false)] // v-prefix + prerelease + build metadata combined
|
||||||
|
[InlineData("1.0.2-alpha+abc", "1.0.2-alpha", false, false)] // same core -> not newer
|
||||||
|
[InlineData("1.2.0-rc1", "1.2.0", false, false)] // prerelease of an already-installed release
|
||||||
public void Compare_ParseableVersions(string latest, string current, bool expectedNewer, bool expectedUnparseable)
|
public void Compare_ParseableVersions(string latest, string current, bool expectedNewer, bool expectedUnparseable)
|
||||||
{
|
{
|
||||||
var result = VersionComparer.Compare(latest, current);
|
var result = VersionComparer.Compare(latest, current);
|
||||||
@@ -17,9 +25,8 @@ public class VersionComparerTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("0.2.0-beta", "0.1.0")]
|
|
||||||
[InlineData("0.2.0", "0.1.0-alpha")]
|
|
||||||
[InlineData("garbage", "0.1.0")]
|
[InlineData("garbage", "0.1.0")]
|
||||||
|
[InlineData("0.2.0", "garbage")]
|
||||||
[InlineData("", "0.1.0")]
|
[InlineData("", "0.1.0")]
|
||||||
public void Compare_UnparseableReturnsNotNewer(string latest, string current)
|
public void Compare_UnparseableReturnsNotNewer(string latest, string current)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user