# Shared Gitea Release helpers for the punktfunk Windows CI workflows (pwsh / PowerShell 7). # # Dot-source it, then call Ensure-GiteaRelease / Upsert-GiteaAsset: # . scripts/ci/gitea-release.ps1 # Mirrors scripts/ci/gitea-release.sh; parses JSON with ConvertFrom-Json (the Windows runner # has no python). Same idempotent semantics: Upsert-GiteaAsset deletes an existing asset of # the same name before uploading, so re-runs / rolling canary uploads don't 409. # # Env (Gitea Actions sets the first two automatically): # GITHUB_SERVER_URL e.g. https://git.unom.io # GITHUB_REPOSITORY e.g. unom/punktfunk # GITEA_TOKEN a PAT with repository (release) write scope — set from secrets.REGISTRY_TOKEN # (must carry write:repository, not only write:package) $ErrorActionPreference = 'Stop' function _GiteaApi { if (-not $env:GITHUB_SERVER_URL) { throw 'GITHUB_SERVER_URL unset' } if (-not $env:GITHUB_REPOSITORY) { throw 'GITHUB_REPOSITORY unset' } "$($env:GITHUB_SERVER_URL)/api/v1/repos/$($env:GITHUB_REPOSITORY)" } function _GiteaHeaders { if (-not $env:GITEA_TOKEN) { throw 'GITEA_TOKEN unset' } @{ Authorization = "token $($env:GITEA_TOKEN)" } } # Ensure-GiteaRelease TAG NAME PRERELEASE [TARGETCOMMITISH] -> release id # Idempotently create or fetch the release for TAG. Prerelease is 'true', 'false', or 'auto' # (auto marks it a prerelease iff TAG carries a `-` pre-release suffix, e.g. v0.2.0-rc1, so an # rc never becomes "Latest"). TargetCommitish (optional) creates the tag if missing. function Ensure-GiteaRelease { param( [Parameter(Mandatory)] [string]$Tag, [Parameter(Mandatory)] [string]$Name, [Parameter(Mandatory)] [string]$Prerelease, [string]$TargetCommitish ) $pre = if ($Prerelease -eq 'auto') { [bool]($Tag -match '-') } else { [System.Convert]::ToBoolean($Prerelease) } $api = _GiteaApi; $h = _GiteaHeaders $payload = @{ tag_name = $Tag; name = $Name; prerelease = $pre } if ($TargetCommitish) { $payload.target_commitish = $TargetCommitish } try { $r = Invoke-RestMethod -Method Post -Uri "$api/releases" -Headers $h ` -ContentType 'application/json' -Body ($payload | ConvertTo-Json -Compress) return $r.id } catch { # Almost always: the release already exists. Fetch it by tag; error if that fails too. $r = Invoke-RestMethod -Method Get -Uri "$api/releases/tags/$Tag" -Headers $h if (-not $r.id) { throw "gitea-release: could not create or find a release for tag '$Tag'" } return $r.id } } # Upsert-GiteaAsset RELEASEID FILE [NAME] # Attach FILE, replacing any existing asset of the same name first (idempotent). function Upsert-GiteaAsset { param( [Parameter(Mandatory)] [string]$ReleaseId, [Parameter(Mandatory)] [string]$File, [string]$Name ) if (-not (Test-Path $File)) { throw "gitea-release: asset file not found: $File" } if (-not $Name) { $Name = Split-Path $File -Leaf } $api = _GiteaApi; $h = _GiteaHeaders $assets = Invoke-RestMethod -Method Get -Uri "$api/releases/$ReleaseId/assets" -Headers $h $existing = $assets | Where-Object { $_.name -eq $Name } | Select-Object -First 1 if ($existing) { Invoke-RestMethod -Method Delete -Uri "$api/releases/$ReleaseId/assets/$($existing.id)" -Headers $h | Out-Null } $enc = [uri]::EscapeDataString($Name) # curl.exe for the multipart upload — matches the rest of the windows workflows. curl.exe -fsS -H "Authorization: token $($env:GITEA_TOKEN)" -o NUL ` -X POST "$api/releases/$ReleaseId/assets?name=$enc" -F "attachment=@$File" if ($LASTEXITCODE -ne 0) { throw "gitea-release: asset upload failed ($LASTEXITCODE): $Name" } Write-Output "gitea-release: uploaded '$Name' -> release $ReleaseId" }