Velopack Integration Guide
GenHub uses Velopack for application installation and automatic updates across Windows and Linux platforms.
Overview
Velopack provides:
- Zero-config installers - Generate installers automatically from your build output
- Automatic updates - Delta updates that only download changed files
- Cross-platform - Single solution for Windows and Linux
- GitHub Releases integration - Seamless updates from GitHub
- CI Artifact Updates - Subscribe to PR builds for testing
How It Works
1. Application Startup
When GenHub starts, VelopackApp.Build().Run() is called first in Program.cs. This handles:
- First-run initialization
- Update installation on startup
- Install/uninstall hooks
- Update preparation
2. Update Checking
GenHub supports two update sources:
GitHub Releases (Stable Channel)
The VelopackUpdateManager service checks for stable releases:
var updateInfo = await _velopackUpdateManager.CheckForUpdatesAsync();
if (updateInfo != null)
{
// Update available
await _velopackUpdateManager.DownloadUpdatesAsync(updateInfo, progress);
_velopackUpdateManager.ApplyUpdatesAndRestart(updateInfo);
}PR Artifacts (Testing Channel)
Users can subscribe to specific Pull Request builds for testing:
// Subscribe to PR #3
_userSettingsService.Update(s => s.SubscribedPrNumber = 3);
// Check for PR updates
var prInfo = await _velopackUpdateManager.GetSubscribedPrInfoAsync();
if (prInfo?.LatestArtifact != null)
{
// Install PR build
await _velopackUpdateManager.InstallPrArtifactAsync(prInfo, progress);
}3. Update Flow
- Check - Application queries GitHub Releases or PR artifacts for new versions
- Download - Packages are downloaded (delta updates when possible)
- Apply - Update is staged and applied
- Restart - Application restarts with new version
Versioning Scheme
GenHub uses a custom versioning scheme optimized for continuous integration:
Version Format
0.0.{RUN_NUMBER}[-pr{PR_NUMBER}][+{BUILD_METADATA}]Components:
0.0.X- Base version (0.0 indicates pre-1.0 development)RUN_NUMBER- GitHub Actions run number (auto-incrementing)-pr{N}- Optional PR number for pull request builds+{HASH}- Build metadata (git commit hash, stripped for comparison)
Examples
# Main branch build (run #157)
0.0.157
# PR #3 build (run #160)
0.0.160-pr3
# Full version with build metadata
0.0.160-pr3+051baf8.051baf832a894f542e60d3e4c2471c7d4dd753daVersion Comparison
GenHub strips build metadata (everything after +) when comparing versions:
// These are considered the same version:
"0.0.160-pr3+051baf8..."
"0.0.160-pr3+18d0017..."
// Both compare as: "0.0.160-pr3"This allows users to reinstall the same PR build with different commits without version conflicts.
Update Channels
GenHub provides two update channels that users can switch between:
Stable Channel
- Source: GitHub Releases
- Versions:
0.0.X(no PR suffix) - Updates: Only stable builds from main branch
- Recommended for: Production use
Artifacts Channel (PR Subscription)
- Source: GitHub Actions CI artifacts
- Versions:
0.0.X-prYformat - Updates: Specific PR builds
- Recommended for: Testing features, bug fixes
- Requires: GitHub Personal Access Token (PAT) with
reposcope
Subscribing to PR Builds
- Navigate to Settings → Updates
- Click "Manage Updates & PRs"
- Enter GitHub PAT (if not already configured)
- Select a PR from the list
- Click "Subscribe"
The app will now check for updates from that PR instead of stable releases.
Unsubscribing
- Open "Manage Updates & PRs"
- Click "Unsubscribe" on the currently subscribed PR
- App returns to stable channel
Building Releases
Prerequisites
- .NET 8 SDK
- Velopack CLI tool:
dotnet tool install -g vpk
Version Number Generation
GenHub uses GitHub Actions run numbers for versioning:
# CI builds (PRs and main branch)
VERSION: 0.0.${{ github.run_number }}[-pr${{ github.event.pull_request.number }}]
# Example outputs:
# Main branch: 0.0.157
# PR #3: 0.0.160-pr3Manual Build Process
Windows
# Set version
$VERSION = "0.0.157" # Or "0.0.160-pr3" for PR builds
# Publish the application
dotnet publish GenHub/GenHub.Windows/GenHub.Windows.csproj `
-c Release `
--self-contained `
-r win-x64 `
-o ./publish/windows `
-p:Version=$VERSION
# Package with Velopack
vpk pack `
--packId GenHub `
--packVersion $VERSION `
--packDir ./publish/windows `
--mainExe GenHub.Windows.exe `
--packTitle "GenHub" `
--packAuthors "Community Outpost" `
--icon GenHub/GenHub/Assets/Icons/generalshub.ico `
--outputDir ./releasesLinux
# Set version
VERSION="0.0.157" # Or "0.0.160-pr3" for PR builds
# Publish the application
dotnet publish GenHub/GenHub.Linux/GenHub.Linux.csproj \
-c Release \
--self-contained \
-r linux-x64 \
-o ./publish/linux \
-p:Version=$VERSION
# Package with Velopack
vpk pack \
--packId GenHub \
--packVersion $VERSION \
--packDir ./publish/linux \
--mainExe GenHub.Linux \
--packTitle "GenHub" \
--packAuthors "Community Outpost" \
--icon GenHub/GenHub/Assets/Icons/generalshub.ico \
--outputDir ./releasesAutomated CI/CD
GenHub includes GitHub Actions workflows:
.github/workflows/ci.yml - Continuous Integration
Runs on every push and PR:
- Builds for Windows and Linux
- Packages with Velopack using
0.0.{RUN_NUMBER}[-pr{PR_NUMBER}]versioning - Uploads artifacts to GitHub Actions
- Generates
releases.win.jsonandreleases.linux.jsonmetadata
Artifacts uploaded:
genhub-velopack-windows-{VERSION}- Windows installer and packagesgenhub-velopack-linux-{VERSION}- Linux packagesgenhub-metadata-windows-{VERSION}- Update metadata (releases.win.json)genhub-metadata-linux-{VERSION}- Update metadata (releases.linux.json)
.github/workflows/release.yml - Stable Releases
Triggered by version tags (v*):
- Builds releases for Windows and Linux
- Creates GitHub Release
- Uploads installers and packages
- Publishes update feed for automatic updates
To trigger a stable release:
git tag v0.0.157
git push origin v0.0.157Release Artifacts
After packaging, Velopack generates:
Windows
- GenHub-{Version}-Setup.exe - Full installer (installs to
%LOCALAPPDATA%\GenHub) - GenHub-{Version}-full.nupkg - Full release package
- GenHub-{Version}-delta.nupkg - Delta update package (if previous version exists)
- GenHub-{Version}-Portable.zip - Portable version (no installation required)
- releases.win.json - Update feed manifest (JSON format)
Linux
- GenHub-{Version}-linux-x64.AppImage - AppImage installer
- GenHub-{Version}-full.nupkg - Full release package
- GenHub-{Version}-delta.nupkg - Delta update package
- releases.linux.json - Update feed manifest (JSON format)
Note: Velopack v0.0.942+ uses JSON format (releases.*.json) instead of the legacy RELEASES file.
Installation Locations
Windows Installation
- Installation Directory:
%LOCALAPPDATA%\GenHub\(e.g.,C:\Users\YourName\AppData\Local\GenHub\) - User Data:
%APPDATA%\GenHub\ - Update Cache:
%LOCALAPPDATA%\GenHub\packages\
Note: Velopack uses a "one-click" installer that always installs to LocalAppData. This location:
- Does not require administrator privileges
- Is standard for modern auto-updating applications (VS Code, Discord, Slack, etc.)
- Enables seamless automatic updates
- Is isolated per-user for better security
Linux Installation
- Installation Directory:
~/.local/share/GenHub/ - User Data:
~/.config/GenHub/ - Update Cache:
~/.cache/GenHub/
The app ID GenHub ensures clean, predictable installation paths without vendor prefixes.
Update Features
Dismiss Updates
Users can dismiss update notifications:
// In UpdateNotificationViewModel
private void DismissUpdate()
{
// Persist dismissed version to prevent showing again
_userSettingsService.Update(s => s.DismissedUpdateVersion = LatestVersion);
IsUpdateAvailable = false;
}Dismissed updates won't reappear until a different version is available.
PR Update Priority
When subscribed to a PR:
- PR updates take priority over stable releases
- Version comparison ignores build metadata
- Users can "switch" to any PR build regardless of version number
- Unsubscribing returns to stable channel
Build Metadata Handling
Build metadata (commit hashes) is:
- Included in the version string for tracking
- Displayed in the UI for transparency
- Stripped during version comparison to avoid false updates
- Logged for debugging purposes
Example:
Display: v0.0.160-pr3 (051baf8)
Full version: 0.0.160-pr3+051baf8.051baf832a894f542e60d3e4c2471c7d4dd753da
Comparison: 0.0.160-pr3Testing Updates Locally
1. Create Test Release
vpk pack --packId GenHub --packVersion 0.0.100 --packDir ./publish --mainExe GenHub.Windows.exe -o ./test-releases2. Create Second Version
Update your code, then:
vpk pack --packId GenHub --packVersion 0.0.101 --packDir ./publish --mainExe GenHub.Windows.exe -o ./test-releases --delta ./test-releases/releases.win.json3. Test Update
Point UpdateManager to local directory:
var source = new SimpleWebSource("file:///C:/path/to/test-releases");
var manager = new UpdateManager(source);Architecture
Components
- VelopackApp - Handles application lifecycle hooks
- VelopackUpdateManager - Service for checking/downloading/applying updates
- IVelopackUpdateManager - Interface for update operations
- UpdateInfo - Model containing update metadata from Velopack
- ArtifactUpdateInfo - Model for PR artifact metadata
- PullRequestInfo - Model for PR information and artifacts
- UpdateProgress - Progress reporting model
Integration Points
Program.cs- VelopackApp.Build().Run() initializationAppUpdateModule.cs- DI registrationVelopackUpdateManager.cs- Update service implementationUpdateNotificationViewModel.cs- UI logic for update notificationsMainViewModel.cs- Main window update badge logic
Key Services
public interface IVelopackUpdateManager
{
// Stable channel updates
Task<UpdateInfo?> CheckForUpdatesAsync(CancellationToken cancellationToken = default);
Task DownloadUpdatesAsync(UpdateInfo updateInfo, IProgress<UpdateProgress>? progress = null);
void ApplyUpdatesAndRestart(UpdateInfo updateInfo);
// PR artifact updates
Task<PullRequestInfo?> GetSubscribedPrInfoAsync(CancellationToken cancellationToken = default);
Task InstallPrArtifactAsync(PullRequestInfo prInfo, IProgress<UpdateProgress>? progress = null, CancellationToken cancellationToken = default);
// Properties
bool HasUpdateAvailableFromGitHub { get; }
string? LatestVersionFromGitHub { get; }
}Troubleshooting
Updates Not Working in Development
Velopack only works when the app is installed. When running from Visual Studio or dotnet run, updates are disabled. This is expected behavior.
To test updates:
- Build a Velopack package
- Install it using the Setup.exe
- Run the installed app
Update Check Fails
- GitHub Releases: Ensure repository is public or provide authentication
- PR Artifacts: Requires GitHub PAT with
reposcope - Verify GitHub Releases/Actions contain Velopack packages
- Check network connectivity
- Review logs for specific error messages
Version Comparison Issues
GenHub strips build metadata before comparison. If updates aren't detected:
- Check version format:
0.0.Xor0.0.X-prY - Verify build metadata is after
+symbol - Review logs for version comparison details
PR Artifact Installation Fails
Common issues:
"No update found from PR artifact"
- Current version >= target version
- Velopack won't "downgrade" by default
- Solution: Uninstall and run Setup.exe from PR artifact
"Already installed"
- Same base version with different build metadata
- This is expected - versions are identical
Authentication errors
- GitHub PAT missing or invalid
- PAT needs
reposcope for private repos
App Doesn't Restart After Update
- Ensure using
ApplyUpdatesAndRestart()notApplyUpdatesAndExit() - Check logs for update application errors
- Verify update package integrity
Security Considerations
GitHub Personal Access Tokens
- Storage: Tokens are stored in Windows Credential Manager (Windows) or Keyring (Linux)
- Scope: Only
reposcope is required - Usage: Only for downloading PR artifacts
- Rotation: Users can update/remove tokens at any time
Update Verification
Velopack verifies package integrity using:
- SHA256 checksums in metadata files
- Package signatures (if configured)
- HTTPS for all downloads
