diff --git a/scripts/upload-release-assets.ps1 b/scripts/upload-release-assets.ps1 new file mode 100644 index 0000000..b600d08 --- /dev/null +++ b/scripts/upload-release-assets.ps1 @@ -0,0 +1,161 @@ +<# +.SYNOPSIS + Upload pre-built NSIS artifacts to an existing Gitea release. + +.DESCRIPTION + Use when the tag v* is already pushed (e.g. release.ps1 succeeded up to + push but failed on upload, or release was created manually without assets). + If a release for the tag does not exist yet, it is created. If it exists, + same-name assets are replaced. + +.PARAMETER Tag + Version tag, e.g. v0.3.0. Defaults to v. + +.EXAMPLE + pwsh scripts/upload-release-assets.ps1 + pwsh scripts/upload-release-assets.ps1 -Tag v0.3.0 +#> +param( + [string]$Tag +) + +$ErrorActionPreference = 'Stop' + +$repoOwner = 'AnRil' +$repoName = 'laude' +$giteaHost = 'xn--90adajar8af4h.xn--p1ai/git' +$apiBase = "https://$giteaHost/api/v1" + +if (-not $env:GITEA_TOKEN) { + Write-Error "GITEA_TOKEN not set. Set it via [Environment]::SetEnvironmentVariable('GITEA_TOKEN', '', 'User') and open a new PowerShell session." + exit 1 +} + +$root = Resolve-Path (Join-Path $PSScriptRoot '..') +Set-Location $root + +if (-not $Tag) { + $version = (Get-Content package.json | ConvertFrom-Json).version + $Tag = "v$version" +} +$version = $Tag.TrimStart('v') + +$installer = Join-Path 'release' "Exercise-Reminder-Setup-$version.exe" +$blockmap = "$installer.blockmap" +$manifest = Join-Path 'release' 'latest.yml' +foreach ($f in @($installer, $blockmap, $manifest)) { + if (-not (Test-Path $f)) { + Write-Error "Artifact not found: $f. Build first with: npm run dist" + exit 1 + } +} + +$headers = @{ + Authorization = "token $env:GITEA_TOKEN" + Accept = 'application/json' +} + +# --- Find or create release ---------------------------------------------- +Write-Host "Looking for existing release $Tag..." -ForegroundColor Cyan +$release = $null +try { + $release = Invoke-RestMethod ` + -Uri "$apiBase/repos/$repoOwner/$repoName/releases/tags/$Tag" ` + -Method Get ` + -Headers $headers + Write-Host " Found release id=$($release.id)" -ForegroundColor DarkGray +} catch { + if ($_.Exception.Response.StatusCode.value__ -eq 404) { + Write-Host " Not found, creating new release..." -ForegroundColor DarkGray + + $prev = $null + try { + $prevTagOutput = & git describe --tags --abbrev=0 "$Tag^" 2>$null + if ($LASTEXITCODE -eq 0 -and $prevTagOutput) { + $prev = $prevTagOutput.Trim() + } + } catch { + $prev = $null + } + if ($prev) { + $log = (& git log --pretty=format:"- %s" "$prev..$Tag") -join "`n" + } else { + # No prior tag — list last 10 commits up to this tag. + $log = (& git log --pretty=format:"- %s" -n 10 "$Tag") -join "`n" + } + $body = "### Changes`n`n$log`n`n---`n`nInstaller below: run it; if app is already installed, it updates in place and keeps your settings." + + $payload = @{ + tag_name = $Tag + name = "Exercise Reminder $Tag" + body = $body + draft = $false + prerelease = $false + } | ConvertTo-Json -Depth 5 + + $release = Invoke-RestMethod ` + -Uri "$apiBase/repos/$repoOwner/$repoName/releases" ` + -Method Post ` + -Headers $headers ` + -Body $payload ` + -ContentType 'application/json' + Write-Host " Created release id=$($release.id)" -ForegroundColor Green + } else { + throw + } +} + +# --- Delete existing assets with same names (to allow re-upload) --------- +$existing = Invoke-RestMethod ` + -Uri "$apiBase/repos/$repoOwner/$repoName/releases/$($release.id)/assets" ` + -Method Get ` + -Headers $headers +foreach ($asset in @($installer, $blockmap, $manifest)) { + $name = Split-Path $asset -Leaf + $found = $existing | Where-Object { $_.name -eq $name } + if ($found) { + Write-Host "Removing existing asset $name (id=$($found.id))..." -ForegroundColor Yellow + Invoke-RestMethod ` + -Uri "$apiBase/repos/$repoOwner/$repoName/releases/$($release.id)/assets/$($found.id)" ` + -Method Delete ` + -Headers $headers | Out-Null + } +} + +# --- Upload assets ------------------------------------------------------- +# Use curl.exe (bundled with Win10+) because Invoke-RestMethod in PS 5.1 +# chokes on large multipart uploads (>50MB) over slower connections. +$curlCmd = Get-Command curl.exe -ErrorAction SilentlyContinue +if ($curlCmd) { + $curl = $curlCmd.Source +} else { + $curl = "$env:SystemRoot\System32\curl.exe" + if (-not (Test-Path $curl)) { + Write-Error "curl.exe not found. Install via 'winget install curl' or add to PATH." + exit 1 + } +} + +foreach ($asset in @($installer, $blockmap, $manifest)) { + $name = Split-Path $asset -Leaf + $size = (Get-Item $asset).Length + Write-Host ("Uploading {0} ({1:N1} MB)..." -f $name, ($size / 1MB)) -ForegroundColor Cyan + $uri = "$apiBase/repos/$repoOwner/$repoName/releases/$($release.id)/assets?name=$([uri]::EscapeDataString($name))" + # -f: fail on HTTP errors; -s -S: silent but show errors; --data-binary @file + & $curl ` + --fail-with-body ` + --silent --show-error ` + -H "Authorization: token $env:GITEA_TOKEN" ` + -H "Content-Type: application/octet-stream" ` + --data-binary "@$asset" ` + $uri + if ($LASTEXITCODE -ne 0) { + Write-Error "Upload failed for $name (curl exit $LASTEXITCODE)" + exit 1 + } +} + +$releaseUrl = "https://$giteaHost/$repoOwner/$repoName/releases/tag/$Tag" +Write-Host "" +Write-Host "Release assets uploaded" -ForegroundColor Green +Write-Host " $releaseUrl"