From 9cb7476a5428bee77add66eeca860c9b5117d398 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 07:01:29 +0000 Subject: [PATCH 1/3] ci: auto-publish a release when the project version changes Extend the Release workflow to also run on pushes to master. It reads from the csproj and, if no matching v tag exists yet, builds and publishes the GitHub Release automatically. Pushing master without a version change is a no-op, so releases are never spammed. Manual tag pushes and workflow_dispatch keep working as before. https://claude.ai/code/session_01FhKJ3kR6pgaR4N3sWSfbFX --- .github/workflows/release.yml | 57 +++++++++++++++++++++++++++-------- README.md | 15 +++++---- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d260b1b..0d6b4fb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,12 +2,14 @@ name: Release on: push: + branches: + - master tags: - 'v*.*.*' workflow_dispatch: inputs: tag_name: - description: 'Release tag (example: v2.1.0)' + description: 'Release tag (example: v2.2.0)' required: true type: string @@ -28,20 +30,47 @@ jobs: with: dotnet-version: '9.0.x' - - name: Resolve tag - id: tag + - name: Resolve release tag + id: resolve shell: pwsh run: | - if ("${{ github.event_name }}" -eq "workflow_dispatch") { - "tag=${{ inputs.tag_name }}" >> $env:GITHUB_OUTPUT - } else { - "tag=${{ github.ref_name }}" >> $env:GITHUB_OUTPUT + $proceed = 'true' + if ($env:GITHUB_EVENT_NAME -eq 'push' -and $env:GITHUB_REF -like 'refs/tags/*') { + # Manual tag push: use the pushed tag. + $tag = $env:GITHUB_REF_NAME } + elseif ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') { + # Manual run: use the provided tag. + $tag = '${{ inputs.tag_name }}' + } + else { + # Push to master: derive the tag from the project version and + # only release if that tag does not already exist. + $csproj = Get-Content "Proxmox Desktop/ProxmoxDesktop.csproj" -Raw + if ($csproj -notmatch '([^<]+)') { + Write-Error "InformationalVersion not found in csproj"; exit 1 + } + $version = $Matches[1].Trim() + $tag = "v$version" + git fetch --tags --quiet + if (git tag -l $tag) { + Write-Host "Tag $tag already exists - nothing to release." + $proceed = 'false' + } + else { + Write-Host "New version detected: $tag" + } + } + "tag=$tag" >> $env:GITHUB_OUTPUT + "proceed=$proceed" >> $env:GITHUB_OUTPUT + Write-Host "Resolved tag=$tag proceed=$proceed" - name: Restore + if: steps.resolve.outputs.proceed == 'true' run: dotnet restore "Proxmox Desktop/ProxmoxDesktop.csproj" - name: Publish (self-contained win-x64) + if: steps.resolve.outputs.proceed == 'true' shell: pwsh run: | dotnet publish "Proxmox Desktop/ProxmoxDesktop.csproj" ` @@ -53,20 +82,22 @@ jobs: -o output/ProxmoxDesktop - name: Create ZIP + if: steps.resolve.outputs.proceed == 'true' shell: pwsh run: | Compress-Archive ` -Path output/ProxmoxDesktop/* ` - -DestinationPath output/ProxmoxDesktop-${{ steps.tag.outputs.tag }}-win-x64.zip + -DestinationPath output/ProxmoxDesktop-${{ steps.resolve.outputs.tag }}-win-x64.zip - name: Create GitHub Release + if: steps.resolve.outputs.proceed == 'true' uses: softprops/action-gh-release@v2 with: - tag_name: ${{ steps.tag.outputs.tag }} - name: "Proxmox Desktop ${{ steps.tag.outputs.tag }}" + tag_name: ${{ steps.resolve.outputs.tag }} + name: "Proxmox Desktop ${{ steps.resolve.outputs.tag }}" body: | ## 📦 Installation - 1. Download `ProxmoxDesktop-${{ steps.tag.outputs.tag }}-win-x64.zip` + 1. Download `ProxmoxDesktop-${{ steps.resolve.outputs.tag }}-win-x64.zip` 2. Extract anywhere 3. Run `ProxmoxDesktop.exe` @@ -76,9 +107,9 @@ jobs: - Windows 10 (build 17763+) or Windows 11 - [WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) *(pre-installed on Windows 11)* - [Virt-Viewer + UsbDk](https://www.spice-space.org/download.html) *(SPICE only)* - files: output/ProxmoxDesktop-${{ steps.tag.outputs.tag }}-win-x64.zip + files: output/ProxmoxDesktop-${{ steps.resolve.outputs.tag }}-win-x64.zip generate_release_notes: true draft: false - prerelease: ${{ contains(steps.tag.outputs.tag, '-beta') || contains(steps.tag.outputs.tag, '-rc') }} + prerelease: ${{ contains(steps.resolve.outputs.tag, '-beta') || contains(steps.resolve.outputs.tag, '-rc') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index e87b9a6..35d2d74 100644 --- a/README.md +++ b/README.md @@ -93,18 +93,21 @@ Every push to `master` and every pull request automatically triggers a build. If ### Release -Releases are created in two ways: +Releases are created three ways: -**Option 1 — Git tag** (from your machine): +**Option 1 — Automatic on version bump** *(recommended)*: +Bump `` in `Proxmox Desktop/ProxmoxDesktop.csproj`, commit and merge to `master`. The Release workflow reads the version, and if no `v` tag exists yet, it builds, zips and publishes the GitHub Release automatically. Pushing `master` without changing the version is a no-op, so it never spams releases. + +**Option 2 — Git tag** (from your machine): ```bash -git tag v2.1.0 -git push origin v2.1.0 +git tag v2.2.0 +git push origin v2.2.0 ``` -**Option 2 — Manual trigger** (from GitHub UI): +**Option 3 — Manual trigger** (from GitHub UI): 1. Go to [Actions → Release](../../actions/workflows/release.yml) 2. Click **Run workflow** -3. Enter the tag name (e.g. `v2.1.0`) and confirm +3. Enter the tag name (e.g. `v2.2.0`) and confirm Tags containing `-beta` or `-rc` are automatically marked as pre-releases. From a01040649e45c2b47422777ad46866d5cc84efce Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 07:22:07 +0000 Subject: [PATCH 2/3] fix(login): surface the real auth error instead of "Invalid server response" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PostTicketAsync collapsed every non-2xx response (and a null body) into the same vague "Invalid server response." message — so a rejected login (HTTP 401) looked like a server/protocol problem. Capture the status code and report it: 401 -> "check username, password and realm, and enter the TOTP code if 2FA is enabled", other codes -> "Login rejected by the server (HTTP )". https://claude.ai/code/session_01FhKJ3kR6pgaR4N3sWSfbFX --- Proxmox Desktop/Api/ApiClient.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Proxmox Desktop/Api/ApiClient.cs b/Proxmox Desktop/Api/ApiClient.cs index 5f52d96..028c0bb 100644 --- a/Proxmox Desktop/Api/ApiClient.cs +++ b/Proxmox Desktop/Api/ApiClient.cs @@ -65,10 +65,14 @@ public async Task LoginAsync( if (!string.IsNullOrWhiteSpace(otp)) form["otp"] = otp; TicketResponse? result; - try { result = await PostTicketAsync(form, ct); } + HttpStatusCode status; + try { (result, status) = await PostTicketWithStatusAsync(form, ct); } catch (Exception ex) { return LoginResult.Failure($"Cannot reach server: {ex.Message}"); } - if (result is null) return LoginResult.Failure("Invalid server response."); + if (result is null) + return LoginResult.Failure(status == HttpStatusCode.Unauthorized + ? "Login rejected — check username, password and realm, and enter the TOTP code if 2FA is enabled." + : $"Login rejected by the server (HTTP {(int)status})."); if (result.Ticket?.Contains("PVE:!tfa!") == true) return string.IsNullOrWhiteSpace(otp) @@ -261,12 +265,16 @@ private async Task GetRawAsync(string path, CancellationToken ct) private async Task PostTicketAsync( Dictionary form, CancellationToken ct) + => (await PostTicketWithStatusAsync(form, ct)).Data; + + private async Task<(TicketResponse? Data, HttpStatusCode Status)> PostTicketWithStatusAsync( + Dictionary form, CancellationToken ct) { var resp = await _http.PostAsync( "access/ticket", new FormUrlEncodedContent(form), ct); - if (!resp.IsSuccessStatusCode) return null; var body = await resp.Content.ReadAsStringAsync(ct); - return JsonSerializer.Deserialize>(body, _json)?.Data; + if (!resp.IsSuccessStatusCode) return (null, resp.StatusCode); + return (JsonSerializer.Deserialize>(body, _json)?.Data, resp.StatusCode); } private async Task> FetchMachinesAsync( From f420686096dc1adda068b4be1347c142fb47da2a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 11:20:29 +0000 Subject: [PATCH 3/3] chore: bump version to 2.2.1 Carries the login error-message fix and (once on master) enables the auto-release workflow to publish v2.2.1 automatically. https://claude.ai/code/session_01FhKJ3kR6pgaR4N3sWSfbFX --- Proxmox Desktop/ProxmoxDesktop.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Proxmox Desktop/ProxmoxDesktop.csproj b/Proxmox Desktop/ProxmoxDesktop.csproj index b583f92..1cb30de 100644 --- a/Proxmox Desktop/ProxmoxDesktop.csproj +++ b/Proxmox Desktop/ProxmoxDesktop.csproj @@ -10,8 +10,8 @@ true ProxmoxDesktop ProxmoxDesktop - 2.2.0.0 - 2.2.0 + 2.2.1.0 + 2.2.1 x64 win-x64 win-x64