name: Release # Triggered by pushing a version tag like `v1.0.0`. Builds Release, packs # into a Velopack release bundle, and uploads everything to a new GitHub # Release matching the tag name. Users running prior installed versions # will pick this up via the in-app "Check for updates" flow. on: push: tags: - 'v*' permissions: contents: write # required by `vpk upload github` to create the release jobs: release: name: Pack & publish release runs-on: windows-latest # Expose the resolved version so the winget submission job can reuse it # without re-parsing the tag. outputs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout uses: actions/checkout@v4 - name: Extract version from tag id: version shell: pwsh # Strip leading "v" so `v1.2.3` becomes `1.2.3` for vpk pack --packVersion. run: | $tag = "${{ github.ref_name }}" $version = $tag -replace '^v', '' "version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append Write-Host "Releasing version $version" - name: Setup .NET 10 uses: actions/setup-dotnet@v4 with: dotnet-version: '10.0.x' - name: Restore run: dotnet restore ClaudeSessionsSidekick.sln - name: Test (gate the release) run: dotnet test ClaudeSessionsSidekick.sln --configuration Release --verbosity minimal - name: Install Velopack CLI # Pin to the same version as the runtime NuGet package for reproducible # release bundles. Using `tool update` so re-runs of a failed release # job don't error with "tool already installed" from the cached PATH. run: dotnet tool update --global vpk --version 0.0.1298 || dotnet tool install --global vpk --version 0.0.1298 - name: Publish (Release, win-x64, self-contained) # Self-contained bundles the .NET 10 Desktop Runtime inside the app, so # the installer works on a clean machine with no runtime installed and # the winget sandbox can never fail on a missing-dependency check. The # trade-off is a larger download (~60-70 MB vs ~11 MB) — acceptable for a # winget/GitHub-distributed dev tool, and it ends the recurring # Microsoft.DotNet.DesktopRuntime.10 resolution failures in winget # validation. We do NOT trim: WPF reflection/XAML doesn't trim safely. # `-p:Version` stamps the assembly version from the git tag so the About # window shows e.g. "1.0.3" instead of the csproj fallback. run: > dotnet publish ClaudeSessionsSidekick.csproj --configuration Release --runtime win-x64 --self-contained true --output publish -p:Version=${{ steps.version.outputs.version }} - name: Pack with Velopack # `vpk pack` produces: # Releases/ <- delta + full nupkg + RELEASES manifest # Releases/*.exe <- single-file installer # `vpk upload github` picks these up and attaches them to the release. run: > vpk pack --packId ClaudeSessionsSidekick --packVersion ${{ steps.version.outputs.version }} --packDir publish --mainExe ClaudeSessionsSidekick.exe --packTitle "Claude Sessions Sidekick" --packAuthors "Rafał Zygmunt" --icon Resources/claude.ico - name: Upload to GitHub Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: > vpk upload github --repoUrl https://github.com/RafalZG/claude-sessions-sidekick --publish --releaseName "Claude Sessions Sidekick ${{ steps.version.outputs.version }}" --tag ${{ github.ref_name }} --token $env:GITHUB_TOKEN winget: # Auto-submit a manifest PR to microsoft/winget-pkgs once the GitHub release # is live. Skips pre-release tags (`v1.0.0-rc1` etc.) — only clean # `vMAJOR.MINOR.PATCH` tags go to the winget catalog, matching what the # winget moderators expect to see. name: Submit to winget catalog needs: release if: ${{ !contains(needs.release.outputs.version, '-') }} runs-on: windows-latest steps: - name: Publish manifest to winget-pkgs # `vedantmgoyal2009/winget-releaser` runs komac to regenerate the # manifest from the new Setup.exe, opens a fork PR against # microsoft/winget-pkgs, and waits for moderator review. Because the app # is now self-contained there is NO .NET runtime dependency to declare — # the manifest legitimately ships without a Dependencies block. The # published baseline (1.0.0) still lists Dependencies, so this first # self-contained release trips wingetbot's Manifest-Metadata-Consistency # check and needs a one-time moderator override; after it merges the new # baseline has no Dependencies and later releases stay consistent. # NOTE: komac mis-detects Velopack as Scope: machine — hand-fix the PR # branch to `Scope: user` (Velopack installs per-user to %LocalAppData%) # before requesting merge. # # WINGET_TOKEN is a classic PAT with `public_repo` scope on the # publishing account (RafalZG). Stored as a repo secret. The default # GITHUB_TOKEN cannot be used because it can't push to a personal fork # of an unrelated org's repo. # # Pinned to a `main`-branch SHA (2026-03-15) instead of the `v2` tag # because v2 (2025-01-27) predates the `release-notes-url` input. Without # that input wingetbot's Manifest-Metadata-Consistency check fails every # release — the 1.0.0 locale.yaml carries ReleaseNotesUrl, so every # subsequent version must too, and komac only emits the field when # `--release-notes-url` is passed. We hit this on v1.0.2 and had to # manually edit the PR-branch locale.yaml to unblock the merge. uses: vedantmgoyal2009/winget-releaser@7bd472be23763def6e16bd06cc8b1cdfab0e2fd5 with: identifier: RafalZG.ClaudeSessionsSidekick version: ${{ needs.release.outputs.version }} installers-regex: 'ClaudeSessionsSidekick-win-Setup\.exe$' release-notes-url: https://github.com/RafalZG/claude-sessions-sidekick/releases/tag/v${{ needs.release.outputs.version }} token: ${{ secrets.WINGET_TOKEN }}