feat(release): add upload-release-assets.ps1 helper
Скрипт догружает уже собранные NSIS-артефакты (.exe, .blockmap, latest.yml) в существующий Gitea release. Создаёт release если его нет, удаляет одноимённые активы перед перезаписью. Используется когда: - release.ps1 успел запушить тег, но упал на загрузке - релиз делался руками без артефактов - нужно перезалить артефакты после пересборки Большие файлы (>50MB) грузятся через curl.exe, потому что Invoke-RestMethod в PS 5.1 разрывает соединение на multipart upload 80+MB. Прогресс печатается отдельно для каждого файла. Использован для загрузки v0.3.0 артефактов. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
161
scripts/upload-release-assets.ps1
Normal file
161
scripts/upload-release-assets.ps1
Normal file
@@ -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<package.json version>.
|
||||
|
||||
.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', '<value>', '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"
|
||||
Reference in New Issue
Block a user