diff --git a/src/ClaudeDo.Releases/SelfUpdateResult.cs b/src/ClaudeDo.Releases/SelfUpdateResult.cs new file mode 100644 index 0000000..82acdca --- /dev/null +++ b/src/ClaudeDo.Releases/SelfUpdateResult.cs @@ -0,0 +1,3 @@ +namespace ClaudeDo.Releases; + +public sealed record InstallerAssetMatch(ReleaseAsset Asset, string Version); diff --git a/src/ClaudeDo.Releases/SelfUpdater.cs b/src/ClaudeDo.Releases/SelfUpdater.cs new file mode 100644 index 0000000..b5df89d --- /dev/null +++ b/src/ClaudeDo.Releases/SelfUpdater.cs @@ -0,0 +1,22 @@ +using System.Text.RegularExpressions; + +namespace ClaudeDo.Releases; + +public static partial class SelfUpdater +{ + [GeneratedRegex(@"^ClaudeDo\.Installer-(?[\d\.]+)\.exe$", RegexOptions.IgnoreCase)] + private static partial Regex InstallerAssetRegex(); + + public static InstallerAssetMatch? FindInstallerAsset(IEnumerable assets) + { + foreach (var asset in assets) + { + var m = InstallerAssetRegex().Match(asset.Name); + if (m.Success) + { + return new InstallerAssetMatch(asset, m.Groups["version"].Value); + } + } + return null; + } +} diff --git a/tests/ClaudeDo.Releases.Tests/SelfUpdaterTests.cs b/tests/ClaudeDo.Releases.Tests/SelfUpdaterTests.cs new file mode 100644 index 0000000..9abaf70 --- /dev/null +++ b/tests/ClaudeDo.Releases.Tests/SelfUpdaterTests.cs @@ -0,0 +1,44 @@ +namespace ClaudeDo.Releases.Tests; + +public class SelfUpdaterAssetMatchingTests +{ + [Fact] + public void FindInstallerAsset_PicksInstallerExeByPattern() + { + var assets = new[] + { + new ReleaseAsset("ClaudeDo-0.3.0-win-x64.zip", "https://x/app.zip", 10), + new ReleaseAsset("ClaudeDo.Installer-0.3.0.exe", "https://x/inst.exe", 20), + new ReleaseAsset("checksums.txt", "https://x/checks", 1), + }; + + var result = SelfUpdater.FindInstallerAsset(assets); + + Assert.NotNull(result); + Assert.Equal("ClaudeDo.Installer-0.3.0.exe", result!.Asset.Name); + Assert.Equal("0.3.0", result.Version); + } + + [Fact] + public void FindInstallerAsset_ReturnsNullWhenAbsent() + { + var assets = new[] + { + new ReleaseAsset("ClaudeDo-0.3.0-win-x64.zip", "https://x/app.zip", 10), + }; + + Assert.Null(SelfUpdater.FindInstallerAsset(assets)); + } + + [Fact] + public void FindInstallerAsset_IgnoresAppZipThatContainsInstaller() + { + var assets = new[] + { + new ReleaseAsset("ClaudeDo.Installer.Portable-0.3.0.zip", "https://x/1", 1), + new ReleaseAsset("not-the-installer.exe", "https://x/2", 1), + }; + + Assert.Null(SelfUpdater.FindInstallerAsset(assets)); + } +}