Files
laude/scripts/release.ps1
AnRil f861af5db1
Some checks failed
CI / Typecheck + Tests (push) Has been cancelled
CI / Build (Windows) (push) Has been cancelled
feat(updater): fixed-URL auto-update channel + silent retries
The auto-update system used a per-version publish URL
(releases/download/v${version}), so each installed build only ever
checked its own release page for new versions. To deliver an update we
had to manually copy the new manifest into every old release — easy to
forget, and any half-uploaded state showed users red "check failed"
banners.

Architectural fix:

- New rolling 'update-channel' Gitea release. publish.url is now a
  fixed path (.../releases/download/update-channel) that never moves.
- release.ps1 uploads each new build to three places:
    1. vX.Y.Z          (historical archive + changelog)
    2. update-channel  (what every client polls)
    3. -BridgeTags     (transition: also fill in old releases so users
                       still on those versions can find the new build)
- upload-release-assets.ps1 gains -AssetVersion to upload version-X.Y.Z
  artifacts into a non-version tag (channel/bridge).

Resilience fixes for the updater itself:

- Hourly checks and the boot check now run in SILENT mode: network
  errors don't promote to a red error state, they're logged and
  retried on the next tick. Only user-initiated "Check now" surfaces
  errors. This prevents the cascade of "Ошибка проверки" cards on
  flaky networks or partial uploads.
- Boot check retries up to 3 times (30s/2m/5m backoff) before giving
  up until the hourly tick.
- Track lastCheckedAt; "Up to date" subtitle now shows "checked Nm ago".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 15:23:41 +07:00

168 lines
5.7 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<#
.SYNOPSIS
Локальный релиз: бамп версии -> коммит -> тег -> push -> сборка -> upload в Gitea.
.DESCRIPTION
Single-command release flow.
Каждый релиз публикует артефакты в ТРИ места:
1. Тег vX.Y.Z (исторический архив + changelog)
2. Тег update-channel (фиксированный URL для auto-updater)
3. Bridge-теги, указанные в -BridgeTags (для миграции пользователей со
старых версий, у которых запечён старый publish.url).
После того как все пользователи получили версию с новым (фиксированным)
publish.url, аргумент -BridgeTags можно перестать указывать.
.PARAMETER Bump
Какую часть semver инкрементировать: patch (по умолчанию), minor, major.
.PARAMETER Version
Точная версия (напр. "0.5.1"). Если задана, -Bump игнорируется.
.PARAMETER SkipBuild
Пропустить сборку (если уже собрано вручную, .exe лежит в release/).
.PARAMETER BridgeTags
Список старых тегов, в которые нужно ТАКЖЕ перезалить новые артефакты,
чтобы пользователи на этих версиях нашли апдейт. Например: v0.4.0,v0.5.0.
.PARAMETER DryRun
Показать что произойдёт, ничего не делая.
.EXAMPLE
pwsh scripts/release.ps1 -Bump patch
pwsh scripts/release.ps1 -Version 0.5.1 -BridgeTags v0.4.0,v0.5.0
.NOTES
Требует GITEA_TOKEN с правом write:repository.
Канал 'update-channel' должен существовать на Gitea (создаётся однократно).
#>
param(
[ValidateSet('patch', 'minor', 'major')]
[string]$Bump = 'patch',
[string]$Version,
[switch]$SkipBuild,
[string[]]$BridgeTags = @(),
[switch]$DryRun
)
$ErrorActionPreference = 'Stop'
$repoOwner = 'AnRil'
$repoName = 'laude'
$giteaHost = 'xn--90adajar8af4h.xn--p1ai/git'
$channelTag = 'update-channel'
# --- Pre-flight ----------------------------------------------------------
$root = Resolve-Path (Join-Path $PSScriptRoot '..')
Set-Location $root
if (-not $env:GITEA_TOKEN -and -not $DryRun) {
Write-Error 'GITEA_TOKEN not set.'
exit 1
}
$status = git status --porcelain
if ($status) {
Write-Error "Uncommitted changes. Commit or stash first."
exit 1
}
$branch = git rev-parse --abbrev-ref HEAD
if ($branch -ne 'main') {
Write-Warning "Branch is $branch, not main. Press Enter to continue or Ctrl+C to cancel."
Read-Host
}
# --- Compute next version ------------------------------------------------
$pkg = Get-Content package.json | ConvertFrom-Json
$current = $pkg.version
if ($Version) {
$next = $Version
} else {
$parts = $current.Split('.')
$major = [int]$parts[0]; $minor = [int]$parts[1]; $patch = [int]$parts[2]
switch ($Bump) {
'major' { $major++; $minor = 0; $patch = 0 }
'minor' { $minor++; $patch = 0 }
'patch' { $patch++ }
}
$next = "$major.$minor.$patch"
}
$tag = "v$next"
Write-Host ""
Write-Host "Release plan" -ForegroundColor Cyan
Write-Host " current : v$current"
Write-Host " next : $tag"
Write-Host " publish into : $tag, $channelTag$(if ($BridgeTags) { ', ' + ($BridgeTags -join ', ') })"
Write-Host ""
if ($DryRun) {
Write-Host '(dry run - exiting)' -ForegroundColor Yellow
exit 0
}
# --- Bump package.json --------------------------------------------------
Write-Host "Bumping package.json to $next..." -ForegroundColor Cyan
$pkgJson = (Get-Content package.json -Raw) -replace "`"version`":\s*`"$current`"", "`"version`": `"$next`""
Set-Content -Path package.json -Value $pkgJson -NoNewline -Encoding utf8
git add package.json
git commit -m "chore(release): $tag"
# --- Quality gates ------------------------------------------------------
if (-not $SkipBuild) {
Write-Host "Typecheck..." -ForegroundColor Cyan
npm run typecheck
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Write-Host "Tests..." -ForegroundColor Cyan
npm run test:run
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Write-Host "Building installer..." -ForegroundColor Cyan
npm run dist
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}
# --- Verify artifacts ---------------------------------------------------
$installer = Join-Path 'release' "Exercise-Reminder-Setup-$next.exe"
$blockmap = "$installer.blockmap"
$manifest = Join-Path 'release' 'latest.yml'
foreach ($f in @($installer, $blockmap, $manifest)) {
if (-not (Test-Path $f)) {
Write-Error "Artifact missing: $f"
exit 1
}
}
# --- Tag + push ---------------------------------------------------------
Write-Host "Tagging $tag and pushing..." -ForegroundColor Cyan
git tag -a $tag -m "Release $tag"
git push origin main
git push origin $tag
# --- Upload to all target releases --------------------------------------
$uploadScript = Join-Path $PSScriptRoot 'upload-release-assets.ps1'
$targets = @($tag, $channelTag) + $BridgeTags
foreach ($target in $targets) {
Write-Host ""
Write-Host "==> Uploading $next artifacts into release '$target'" -ForegroundColor Cyan
& powershell -ExecutionPolicy Bypass -File $uploadScript -Tag $target -AssetVersion $next
if ($LASTEXITCODE -ne 0) {
Write-Error "Upload to '$target' failed (exit $LASTEXITCODE)"
exit $LASTEXITCODE
}
}
$releaseUrl = "https://$giteaHost/$repoOwner/$repoName/releases/tag/$tag"
Write-Host ""
Write-Host "Release published" -ForegroundColor Green
Write-Host " $releaseUrl"
Write-Host ""
Write-Host "Auto-updater will pick up the new version within ~1 hour on all installed copies."