diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4b9a5ee..bd2cea0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,6 +64,22 @@ jobs: dotnet publish src/PlanViewer.App/PlanViewer.App.csproj -c Release -r osx-x64 --self-contained -o publish/osx-x64 dotnet publish src/PlanViewer.App/PlanViewer.App.csproj -c Release -r osx-arm64 --self-contained -o publish/osx-arm64 + - name: Create Velopack release (Windows) + if: steps.check.outputs.EXISTS == 'false' + shell: pwsh + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ steps.version.outputs.VERSION }} + run: | + dotnet tool install -g vpk + New-Item -ItemType Directory -Force -Path releases/velopack + + # Download previous release for delta generation + vpk download github --repoUrl https://github.com/${{ github.repository }} --channel win -o releases/velopack + + # Pack Windows release + vpk pack -u PerformanceStudio -v $env:VERSION -p publish/win-x64 -e PlanViewer.App.exe -o releases/velopack --channel win + - name: Package and upload if: steps.check.outputs.EXISTS == 'false' shell: pwsh @@ -116,7 +132,7 @@ jobs: Compress-Archive -Path "$wrapperDir/*" -DestinationPath "releases/PerformanceStudio-$rid.zip" -Force } - # Checksums + # Checksums (zips only, Velopack has its own checksums) $checksums = Get-ChildItem releases/*.zip | ForEach-Object { $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower() "$hash $($_.Name)" @@ -125,5 +141,8 @@ jobs: Write-Host "Checksums:" $checksums | ForEach-Object { Write-Host $_ } - # Upload + # Upload zips + checksums gh release upload "v$env:VERSION" releases/*.zip releases/SHA256SUMS.txt --clobber + + # Upload Velopack artifacts + vpk upload github --repoUrl https://github.com/${{ github.repository }} --channel win -o releases/velopack --releaseName "v$env:VERSION" --tag "v$env:VERSION" --merge diff --git a/src/PlanViewer.App/AboutWindow.axaml.cs b/src/PlanViewer.App/AboutWindow.axaml.cs index 9ed0f3f..934d8d8 100644 --- a/src/PlanViewer.App/AboutWindow.axaml.cs +++ b/src/PlanViewer.App/AboutWindow.axaml.cs @@ -16,6 +16,7 @@ using Avalonia.Interactivity; using PlanViewer.App.Mcp; using PlanViewer.App.Services; +using Velopack; namespace PlanViewer.App; @@ -74,6 +75,8 @@ private async void CopyMcpCommand_Click(object? sender, RoutedEventArgs e) } private string? _updateUrl; + private UpdateManager? _velopackMgr; + private UpdateInfo? _velopackUpdate; private async void CheckUpdate_Click(object? sender, RoutedEventArgs e) { @@ -81,6 +84,32 @@ private async void CheckUpdate_Click(object? sender, RoutedEventArgs e) UpdateStatusText.Text = "Checking..."; UpdateLink.IsVisible = false; + // Try Velopack first (Windows only, supports download + apply) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + try + { + _velopackMgr = new UpdateManager( + new Velopack.Sources.GithubSource( + "https://github.com/erikdarlingdata/PerformanceStudio", null, false)); + + _velopackUpdate = await _velopackMgr.CheckForUpdatesAsync(); + if (_velopackUpdate != null) + { + UpdateStatusText.Text = "Update available:"; + UpdateLink.Text = $"v{_velopackUpdate.TargetFullRelease.Version} — click to download and install"; + UpdateLink.IsVisible = true; + CheckUpdateButton.IsEnabled = true; + return; + } + } + catch + { + // Velopack packages may not exist yet — fall through + } + } + + // Fallback: GitHub API check (opens browser) var currentVersion = Assembly.GetExecutingAssembly().GetName().Version ?? new Version(0, 0, 0); var result = await UpdateChecker.CheckAsync(currentVersion); @@ -103,8 +132,30 @@ private async void CheckUpdate_Click(object? sender, RoutedEventArgs e) CheckUpdateButton.IsEnabled = true; } - private void UpdateLink_Click(object? sender, PointerPressedEventArgs e) + private async void UpdateLink_Click(object? sender, PointerPressedEventArgs e) { + // Velopack download + apply + if (_velopackMgr != null && _velopackUpdate != null) + { + try + { + UpdateLink.IsVisible = false; + UpdateStatusText.Text = "Downloading update..."; + + await _velopackMgr.DownloadUpdatesAsync(_velopackUpdate); + + UpdateStatusText.Text = "Update downloaded — restarting..."; + _velopackMgr.ApplyUpdatesAndRestart(_velopackUpdate.TargetFullRelease); + } + catch (Exception ex) + { + UpdateStatusText.Text = $"Update failed: {ex.Message}"; + UpdateLink.IsVisible = false; + } + return; + } + + // Fallback: open browser if (_updateUrl != null) OpenUrl(_updateUrl); } diff --git a/src/PlanViewer.App/PlanViewer.App.csproj b/src/PlanViewer.App/PlanViewer.App.csproj index 2a1bc48..9220722 100644 --- a/src/PlanViewer.App/PlanViewer.App.csproj +++ b/src/PlanViewer.App/PlanViewer.App.csproj @@ -6,7 +6,7 @@ app.manifest EDD.ico true - 1.2.0 + 1.2.1 Erik Darling Darling Data LLC Performance Studio @@ -32,6 +32,7 @@ + diff --git a/src/PlanViewer.App/Program.cs b/src/PlanViewer.App/Program.cs index 5e569b4..a7d2132 100644 --- a/src/PlanViewer.App/Program.cs +++ b/src/PlanViewer.App/Program.cs @@ -3,6 +3,7 @@ using System.IO; using System.IO.Pipes; using System.Threading; +using Velopack; namespace PlanViewer.App; @@ -14,6 +15,8 @@ class Program [STAThread] public static void Main(string[] args) { + VelopackApp.Build().Run(); + // If another instance is running, send the file path to it and exit if (args.Length > 0 && TrySendToRunningInstance(args[0])) return; diff --git a/src/PlanViewer.Cli/PlanViewer.Cli.csproj b/src/PlanViewer.Cli/PlanViewer.Cli.csproj index d38fd5d..15e7897 100644 --- a/src/PlanViewer.Cli/PlanViewer.Cli.csproj +++ b/src/PlanViewer.Cli/PlanViewer.Cli.csproj @@ -11,7 +11,7 @@ enable PlanViewer.Cli planview - 1.2.0 + 1.2.1 Erik Darling Darling Data LLC Performance Studio diff --git a/src/PlanViewer.Core/PlanViewer.Core.csproj b/src/PlanViewer.Core/PlanViewer.Core.csproj index 3eab7bb..44835c5 100644 --- a/src/PlanViewer.Core/PlanViewer.Core.csproj +++ b/src/PlanViewer.Core/PlanViewer.Core.csproj @@ -5,7 +5,7 @@ enable enable PlanViewer.Core - 1.2.0 + 1.2.1 Erik Darling Darling Data LLC SQL Performance Studio diff --git a/src/PlanViewer.Ssms.Installer/PlanViewer.Ssms.Installer.csproj b/src/PlanViewer.Ssms.Installer/PlanViewer.Ssms.Installer.csproj index 8d607d5..7809dac 100644 --- a/src/PlanViewer.Ssms.Installer/PlanViewer.Ssms.Installer.csproj +++ b/src/PlanViewer.Ssms.Installer/PlanViewer.Ssms.Installer.csproj @@ -6,7 +6,7 @@ InstallSsmsExtension PlanViewer.Ssms.Installer app.manifest - 1.2.0 + 1.2.1 Erik Darling Darling Data LLC SQL Performance Studio