Add Velopack auto-update + v1.2.1 (#635)#115
Conversation
- Velopack NuGet package added - VelopackApp.Build().Run() in Program.Main() (proper entry point) - About > Check for Updates tries Velopack first (download + apply), falls back to browser-based GitHub check on Mac/Linux or when Velopack packages aren't available - Release pipeline: vpk pack produces Setup.exe, full/delta nupkg, uploaded alongside existing zip artifacts - Version bumped to 1.2.1 across all 4 projects Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR introduces Velopack integration for Windows application updates, bumps version numbers across all project files from 1.2.0 to 1.2.1, and updates the release workflow to build and upload Velopack artifacts alongside existing release assets. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/release.yml (1)
38-45:⚠️ Potential issue | 🔴 CriticalThe release creation order is correct, but the workflow will fail on the first release.
vpk download githubresolves the latest entry from the channel feed (releases.{channel}.json), not the latest Git tag. Since v1.2.1 is the first release withwinchannel assets, that feed won't exist yet, and the command at line 78 will fail with a 404 error.Add error handling to skip the download step on first release (when the channel feed doesn't yet exist), or check for the existence of the channel feed before attempting to download.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/release.yml around lines 38 - 45, The workflow fails on first release because "vpk download github" expects an existing channel feed (releases.{channel}.json); add a pre-check or error handling so the download is skipped when that feed doesn't exist. Specifically, around the step that runs the vpk download github command (referenced as "vpk download github" and the channel feed releases.{channel}.json), test for the feed's existence (e.g., an HTTP HEAD or curl -f) and only run vpk if it exists, or wrap the download in a conditional/try-fail-safe so a 404 does not fail the job; ensure the Create release step remains unchanged but downstream download logic handles missing feeds gracefully.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/PlanViewer.App/AboutWindow.axaml.cs`:
- Around line 81-110: CheckUpdate_Click can reuse stale
_velopackUpdate/_velopackMgr from a prior run if the new Velopack check throws;
reset the cached state at the start of the method (set _velopackUpdate and
_velopackMgr to null) and also ensure the exception path does not leave a prior
value in place, and add a defensive check in UpdateLink_Click to verify
_velopackUpdate is non-null before attempting to apply a Velopack release (and
show a friendly error if it is null).
---
Outside diff comments:
In @.github/workflows/release.yml:
- Around line 38-45: The workflow fails on first release because "vpk download
github" expects an existing channel feed (releases.{channel}.json); add a
pre-check or error handling so the download is skipped when that feed doesn't
exist. Specifically, around the step that runs the vpk download github command
(referenced as "vpk download github" and the channel feed
releases.{channel}.json), test for the feed's existence (e.g., an HTTP HEAD or
curl -f) and only run vpk if it exists, or wrap the download in a
conditional/try-fail-safe so a 404 does not fail the job; ensure the Create
release step remains unchanged but downstream download logic handles missing
feeds gracefully.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bfffe1ee-1ba9-46bc-81e7-dd827a3dc24c
📒 Files selected for processing (7)
.github/workflows/release.ymlsrc/PlanViewer.App/AboutWindow.axaml.cssrc/PlanViewer.App/PlanViewer.App.csprojsrc/PlanViewer.App/Program.cssrc/PlanViewer.Cli/PlanViewer.Cli.csprojsrc/PlanViewer.Core/PlanViewer.Core.csprojsrc/PlanViewer.Ssms.Installer/PlanViewer.Ssms.Installer.csproj
| private async void CheckUpdate_Click(object? sender, RoutedEventArgs e) | ||
| { | ||
| CheckUpdateButton.IsEnabled = false; | ||
| 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 | ||
| } | ||
| } |
There was a problem hiding this comment.
Clear cached update state before each check.
If a prior Windows check populated _velopackUpdate and a later Velopack check throws before Line 96 assigns a new value, the fallback branch can show a browser update while UpdateLink_Click still applies the stale Velopack release.
🛠️ Proposed fix
private async void CheckUpdate_Click(object? sender, RoutedEventArgs e)
{
CheckUpdateButton.IsEnabled = false;
UpdateStatusText.Text = "Checking...";
UpdateLink.IsVisible = false;
+ _updateUrl = null;
+ _velopackMgr = null;
+ _velopackUpdate = null;
// Try Velopack first (Windows only, supports download + apply)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
try
{
- _velopackMgr = new UpdateManager(
+ var velopackMgr = new UpdateManager(
new Velopack.Sources.GithubSource(
"https://github.com/erikdarlingdata/PerformanceStudio", null, false));
- _velopackUpdate = await _velopackMgr.CheckForUpdatesAsync();
- if (_velopackUpdate != null)
+ var velopackUpdate = await velopackMgr.CheckForUpdatesAsync();
+ if (velopackUpdate != null)
{
+ _velopackMgr = velopackMgr;
+ _velopackUpdate = velopackUpdate;
UpdateStatusText.Text = "Update available:";
- UpdateLink.Text = $"v{_velopackUpdate.TargetFullRelease.Version} — click to download and install";
+ UpdateLink.Text = $"v{velopackUpdate.TargetFullRelease.Version} — click to download and install";
UpdateLink.IsVisible = true;
CheckUpdateButton.IsEnabled = true;
return;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private async void CheckUpdate_Click(object? sender, RoutedEventArgs e) | |
| { | |
| CheckUpdateButton.IsEnabled = false; | |
| 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 | |
| } | |
| } | |
| private async void CheckUpdate_Click(object? sender, RoutedEventArgs e) | |
| { | |
| CheckUpdateButton.IsEnabled = false; | |
| UpdateStatusText.Text = "Checking..."; | |
| UpdateLink.IsVisible = false; | |
| _updateUrl = null; | |
| _velopackMgr = null; | |
| _velopackUpdate = null; | |
| // Try Velopack first (Windows only, supports download + apply) | |
| if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | |
| { | |
| try | |
| { | |
| var velopackMgr = new UpdateManager( | |
| new Velopack.Sources.GithubSource( | |
| "https://github.com/erikdarlingdata/PerformanceStudio", null, false)); | |
| var velopackUpdate = await velopackMgr.CheckForUpdatesAsync(); | |
| if (velopackUpdate != null) | |
| { | |
| _velopackMgr = velopackMgr; | |
| _velopackUpdate = velopackUpdate; | |
| 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 | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/PlanViewer.App/AboutWindow.axaml.cs` around lines 81 - 110,
CheckUpdate_Click can reuse stale _velopackUpdate/_velopackMgr from a prior run
if the new Velopack check throws; reset the cached state at the start of the
method (set _velopackUpdate and _velopackMgr to null) and also ensure the
exception path does not leave a prior value in place, and add a defensive check
in UpdateLink_Click to verify _velopackUpdate is non-null before attempting to
apply a Velopack release (and show a friendly error if it is null).
Summary
Adds Velopack auto-update for Windows. First release to test the full pipeline before porting to PerformanceMonitor.
App changes
VelopackApp.Build().Run()inMain()Pipeline changes
vpk download githubfetches previous release for delta generationvpk packproduces Setup.exe, full nupkg, delta nupkgvpk upload github --mergeattaches Velopack artifacts to the release alongside existing zipsExpected release artifacts
PerformanceStudio-win-x64.zip,linux-x64.zip,osx-x64.zip,osx-arm64.zip,SHA256SUMS.txtPerformanceStudio-1.2.1-win-full.nupkg,PerformanceStudio-1.2.1-win-delta.nupkg,PerformanceStudio-win-Setup.exe,RELEASES,releases.win.json🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores