Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [0.1.9] — 2026-06-01

### Fixed

- **Prerelease versions with multi-digit numeric identifiers compared as strings, so `rc.10` looked older than `rc.9`.** `ComparePrerelease` used `string.CompareOrdinal`, which orders `"rc.9"` after `"rc.10"` character-by-character (`'9'` > `'1'`). A CLI on `0.5.0-rc.9` running `update --prerelease` against a `0.5.0-rc.10` release therefore reported "Already up to date." Comparison now follows Semantic Versioning §11: dot-separated prerelease identifiers compare left to right, numeric identifiers compare numerically, numeric ranks below alphanumeric, and a longer identifier set outranks a shorter one with an equal prefix.

### Changed

- Bumped NuGet dependencies to their latest versions: `Microsoft.Extensions.DependencyInjection.Abstractions` and `Microsoft.Extensions.Http` 10.0.5 → 10.0.8, `Microsoft.SourceLink.GitHub` 8.0.0 → 10.0.300, and the test stack (`Microsoft.NET.Test.Sdk` 17.11.1 → 18.6.0, `xunit` 2.9.2 → 2.9.3, `xunit.runner.visualstudio` 2.8.2 → 3.1.5, `coverlet.collector` 6.0.2 → 10.0.1).

---

## [0.1.8] — 2026-05-27

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<PropertyGroup>
<PackageId>NextIteration.SpectreConsole.SelfUpdate</PackageId>
<Version>0.1.8</Version>
<Version>0.1.9</Version>
<Authors>Stuart Meeks</Authors>
<Description>Self-update for Spectre.Console CLIs: pluggable update sources (GitHub Releases over HTTP, GitHub Releases via gh CLI for private repos, generic HTTPS manifest, custom), SHA-256 verification, atomic file swap, and a drop-in `update` command.</Description>
<GeneratePackageOnBuild Condition="'$(Configuration)' == 'Release'">true</GeneratePackageOnBuild>
Expand Down Expand Up @@ -39,11 +39,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.8" />
<PackageReference Include="Spectre.Console" Version="0.55.2" />
<PackageReference Include="Spectre.Console.Cli" Version="0.55.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.300" PrivateAssets="All" />
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
<None Include="icon.png" Pack="true" PackagePath="" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,31 @@ internal static int ComparePrerelease(string? current, string? latest)
if (current is null && latest is null) return 0;
if (current is null) return 1; // no-prerelease > prerelease, so current is newer
if (latest is null) return -1; // current has prerelease, latest does not → current is older

// Semver §11: compare dot-separated identifiers left to right.
// Numeric identifiers compare numerically; numeric is always lower
// than alphanumeric; otherwise compare lexically (ASCII order). A
// larger set of identifiers outranks a smaller one when all preceding
// identifiers are equal.
var cParts = current.Split('.');
var lParts = latest.Split('.');
var shared = Math.Min(cParts.Length, lParts.Length);
for (var i = 0; i < shared; i++)
{
var cmp = ComparePrereleaseIdentifier(cParts[i], lParts[i]);
if (cmp != 0) return cmp;
}
return cParts.Length.CompareTo(lParts.Length);
}

private static int ComparePrereleaseIdentifier(string current, string latest)
{
var cNumeric = long.TryParse(current, out var cn);
var lNumeric = long.TryParse(latest, out var ln);

if (cNumeric && lNumeric) return cn.CompareTo(ln);
if (cNumeric) return -1; // numeric identifiers rank lower than alphanumeric
if (lNumeric) return 1;
return string.CompareOrdinal(current, latest);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="10.0.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ public void IsNewer_when_numeric_versions_compares_correctly(string current, str
[InlineData("1.0.0-beta", "1.0.0-alpha", false)] // beta > alpha lexicographically
[InlineData("1.0.0-beta.1", "1.0.0-beta.2", true)]
[InlineData("1.0.0-beta", "1.0.0-beta", false)]
// Numeric prerelease identifiers compare numerically, not lexically.
[InlineData("0.5.0-rc.9", "0.5.0-rc.10", true)] // rc.10 is newer than rc.9
[InlineData("0.5.0-rc.10", "0.5.0-rc.9", false)] // rc.9 is not newer than rc.10
[InlineData("1.0.0-alpha.2", "1.0.0-alpha.10", true)]
[InlineData("1.0.0-rc.1", "1.0.0-rc.1", false)]
// Fewer identifiers rank lower when the shared prefix is equal.
[InlineData("1.0.0-beta", "1.0.0-beta.1", true)]
[InlineData("1.0.0-beta.1", "1.0.0-beta", false)]
// Numeric identifiers rank lower than alphanumeric ones.
[InlineData("1.0.0-1", "1.0.0-alpha", true)]
[InlineData("1.0.0-alpha", "1.0.0-1", false)]
public void IsNewer_with_semver_prerelease_compares_correctly(string current, string latest, bool expected)
{
Assert.Equal(expected, UpdateChecker.IsNewer(current, latest));
Expand Down
Loading