feat(updater): fixed-URL auto-update channel + silent retries
Some checks failed
CI / Typecheck + Tests (push) Has been cancelled
CI / Build (Windows) (push) Has been cancelled

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>
This commit is contained in:
AnRil
2026-05-18 15:23:41 +07:00
parent c9d4fc237e
commit f861af5db1
8 changed files with 186 additions and 116 deletions

View File

@@ -1,22 +1,31 @@
<#
.SYNOPSIS
Upload pre-built NSIS artifacts to an existing Gitea release.
Upload pre-built NSIS artifacts to a 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.
Uploads installer + blockmap + latest.yml to the release identified by -Tag.
If the release does not exist it is created (only for semver-looking tags;
for non-semver tags like 'update-channel' the release must exist already).
Same-named existing assets are replaced.
.PARAMETER Tag
Version tag, e.g. v0.3.0. Defaults to v<package.json version>.
Release tag to upload INTO. May be a version tag (v0.5.1) or a channel
tag (update-channel). Defaults to v<package.json version>.
.PARAMETER AssetVersion
Version of the artifacts being uploaded (e.g. 0.5.1). Defaults to the
numeric part of -Tag. Specify explicitly when uploading version-X.Y.Z
artifacts into a non-version tag (channel or bridge).
.EXAMPLE
pwsh scripts/upload-release-assets.ps1
pwsh scripts/upload-release-assets.ps1 -Tag v0.3.0
pwsh scripts/upload-release-assets.ps1 -Tag v0.5.0
pwsh scripts/upload-release-assets.ps1 -Tag update-channel -AssetVersion 0.5.1
pwsh scripts/upload-release-assets.ps1 -Tag v0.4.0 -AssetVersion 0.5.1
#>
param(
[string]$Tag
[string]$Tag,
[string]$AssetVersion
)
$ErrorActionPreference = 'Stop'
@@ -35,10 +44,18 @@ $root = Resolve-Path (Join-Path $PSScriptRoot '..')
Set-Location $root
if (-not $Tag) {
$version = (Get-Content package.json | ConvertFrom-Json).version
$Tag = "v$version"
$pkgVersion = (Get-Content package.json | ConvertFrom-Json).version
$Tag = "v$pkgVersion"
}
$version = $Tag.TrimStart('v')
if (-not $AssetVersion) {
# Derive from tag when possible (vX.Y.Z → X.Y.Z); otherwise read package.json.
if ($Tag -match '^v\d+\.\d+\.\d+') {
$AssetVersion = $Tag.TrimStart('v')
} else {
$AssetVersion = (Get-Content package.json | ConvertFrom-Json).version
}
}
$version = $AssetVersion
$installer = Join-Path 'release' "Exercise-Reminder-Setup-$version.exe"
$blockmap = "$installer.blockmap"
@@ -66,6 +83,10 @@ try {
Write-Host " Found release id=$($release.id)" -ForegroundColor DarkGray
} catch {
if ($_.Exception.Response.StatusCode.value__ -eq 404) {
if ($Tag -notmatch '^v\d+\.\d+\.\d+') {
Write-Error "Release '$Tag' not found and tag is not semver. Create it manually on Gitea (e.g. 'update-channel' is a one-time setup)."
exit 1
}
Write-Host " Not found, creating new release..." -ForegroundColor DarkGray
$prev = $null