Add basic support for prerelease versions

This commit is contained in:
2025-09-24 16:49:10 -04:00
parent 4e824e2039
commit d2c7f27970
4 changed files with 104 additions and 48 deletions

View File

@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kaczor/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,30 +1,84 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using System.Globalization; using System.Globalization;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
namespace ChrisKaczor.ApplicationUpdate namespace ChrisKaczor.ApplicationUpdate
{ {
public partial class GitHubRelease public partial class GitHubRelease
{ {
[JsonProperty("tag_name")] private const string LatestSegment = "/latest";
public string? TagName { get; set; }
[JsonProperty("assets")] private static readonly HttpClient HttpClient = new()
public List<Asset>? Assets { get; set; } {
DefaultRequestHeaders =
{ UserAgent = { ProductInfoHeaderValue.Parse(UpdateCheck.ApplicationName.Replace(" ", "")) } }
};
private static GitHubRelease? FromJson(string json) =>
JsonConvert.DeserializeObject<GitHubRelease>(json, Converter.Settings);
private static List<GitHubRelease>? FromJsonArray(string json) =>
JsonConvert.DeserializeObject<List<GitHubRelease>>(json, Converter.Settings);
[JsonProperty("tag_name")] public string? TagName { get; set; }
[JsonProperty("assets")] public List<Asset>? Assets { get; set; }
[JsonProperty("prerelease")] public bool Prerelease { get; set; }
public static async Task<VersionInfo?> GetLatestAsync(string baseUrl)
{
try
{
var url = baseUrl.EndsWith(LatestSegment) ? baseUrl : baseUrl + LatestSegment;
var json = await HttpClient.GetStringAsync(url);
var release = FromJson(json);
var versionInfo = VersionInfo.CreateFromGitHubRelease(release);
return versionInfo;
}
catch (Exception)
{
return null;
}
}
public static async Task<VersionInfo?> GetLatestPrereleaseAsync(string baseUrl)
{
try
{
var url = baseUrl.EndsWith(LatestSegment) ? baseUrl[..^LatestSegment.Length] : baseUrl;
var json = await HttpClient.GetStringAsync(url);
var releases = FromJsonArray(json);
var release = releases?.FirstOrDefault();
if (release == null)
return null;
var versionInfo = VersionInfo.CreateFromGitHubRelease(release);
return versionInfo;
}
catch (Exception)
{
return null;
}
}
} }
public class Asset public class Asset
{ {
[JsonProperty("created_at")] [JsonProperty("created_at")] public DateTimeOffset? CreatedAt { get; set; }
public DateTimeOffset? CreatedAt { get; set; }
[JsonProperty("browser_download_url")] [JsonProperty("browser_download_url")] public string? BrowserDownloadUrl { get; set; }
public string? BrowserDownloadUrl { get; set; }
}
public partial class GitHubRelease
{
public static GitHubRelease? FromJson(string json) => JsonConvert.DeserializeObject<GitHubRelease>(json, Converter.Settings);
} }
internal class Converter internal class Converter

View File

@@ -45,9 +45,9 @@ public static class UpdateCheck
ApplicationUpdateMessage = applicationUpdateMessageDelegate; ApplicationUpdateMessage = applicationUpdateMessageDelegate;
} }
public static async Task<bool> CheckForUpdate() public static async Task<bool> CheckForUpdate(bool includePrerelease)
{ {
RemoteVersion = await VersionInfo.Load(UpdateServerType, UpdateServer, UpdateFile); RemoteVersion = await VersionInfo.Load(UpdateServerType, UpdateServer, UpdateFile, includePrerelease);
if (RemoteVersion == null) if (RemoteVersion == null)
return false; return false;
@@ -98,9 +98,9 @@ public static class UpdateCheck
return true; return true;
} }
public static async void DisplayUpdateInformation(bool showIfCurrent) public static async Task DisplayUpdateInformation(bool showIfCurrent, bool includePrerelease)
{ {
await CheckForUpdate(); await CheckForUpdate(includePrerelease);
// Check for an update // Check for an update
if (UpdateAvailable) if (UpdateAvailable)

View File

@@ -1,28 +1,35 @@
using System.Xml.Linq; using System.Net.Http.Headers;
using System.Xml.Linq;
namespace ChrisKaczor.ApplicationUpdate; namespace ChrisKaczor.ApplicationUpdate;
public class VersionInfo public class VersionInfo
{ {
private static readonly HttpClient HttpClient = new() { DefaultRequestHeaders = { UserAgent = { ProductInfoHeaderValue.Parse(UpdateCheck.ApplicationName) } } };
public Version? Version { get; set; } public Version? Version { get; set; }
public string? InstallFile { get; set; } public string? InstallFile { get; set; }
public DateTimeOffset? InstallCreated { get; set; } public DateTimeOffset? InstallCreated { get; set; }
public bool? Prerelease { get; set; }
public static async Task<VersionInfo?> Load(ServerType updateServerType, string server, string file) public static async Task<VersionInfo?> Load(ServerType updateServerType, string url, string file, bool includePrerelease)
{ {
return updateServerType switch return updateServerType switch
{ {
ServerType.Generic => LoadFile(server, file), ServerType.Generic => LoadFile(url, file, includePrerelease),
ServerType.GitHub => await LoadGitHub(server), ServerType.GitHub => await LoadGitHub(url, includePrerelease),
_ => null _ => null
}; };
} }
private static VersionInfo? LoadFile(string server, string file) private static VersionInfo? LoadFile(string url, string file, bool includePrerelease)
{ {
try try
{ {
var document = XDocument.Load(server + file); if (includePrerelease)
throw new NotSupportedException("Prerelease not currently supported for generic server type");
var document = XDocument.Load(url + file);
var versionInformationElement = document.Element("versionInformation"); var versionInformationElement = document.Element("versionInformation");
@@ -51,18 +58,15 @@ public class VersionInfo
} }
} }
private static async Task<VersionInfo?> LoadGitHub(string server) private static async Task<VersionInfo?> LoadGitHub(string baseUrl, bool includePrerelease)
{ {
try var versionInfo = includePrerelease ? await GitHubRelease.GetLatestPrereleaseAsync(baseUrl) : await GitHubRelease.GetLatestAsync(baseUrl);
return versionInfo;
}
internal static VersionInfo? CreateFromGitHubRelease(GitHubRelease? release)
{ {
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(UpdateCheck.ApplicationName);
var json = await httpClient.GetStringAsync(server);
var release = GitHubRelease.FromJson(json);
if (release?.TagName == null || release.Assets == null || release.Assets.Count == 0) if (release?.TagName == null || release.Assets == null || release.Assets.Count == 0)
return null; return null;
@@ -70,14 +74,10 @@ public class VersionInfo
{ {
Version = Version.Parse(release.TagName), Version = Version.Parse(release.TagName),
InstallFile = release.Assets[0].BrowserDownloadUrl, InstallFile = release.Assets[0].BrowserDownloadUrl,
InstallCreated = release.Assets[0].CreatedAt?.UtcDateTime InstallCreated = release.Assets[0].CreatedAt?.UtcDateTime,
Prerelease = release.Prerelease
}; };
return versionInfo; return versionInfo;
} }
catch (Exception)
{
return null;
}
}
} }