feat(launcher): Gitea-backed alpha update feed replaces the GitHub Releases source
The launcher reported "no client available" because its update source was
pinned to a GitHub Releases manifest in a PRIVATE repo — nothing anonymous
could ever be fetched from it. Switch the feed to the PUBLIC Gitea repo so a
friend needs no account, and add the two commands that publish it.
- ReleaseManifestClient.ProductionManifestUri now points at
git.snakedesert.se/erik/acdream raw on the `dist` branch. No update
machinery changed: the existing strict reader already accepts any HTTPS
manifest, so this is a URL swap plus a build script.
- tools/publish-bin.ps1 publishes the payloads into /bin and writes
bin/manifest.json (schema v1, SHA-256 + size per artifact):
client-win-x64.zip AcDream.App + acdream-headless
launcher-win-x64.zip acdream-launcher + co-deployed acdream-bake
Stamps InformationalVersion ONLY — never -p:Version, which also rewrites
project-reference versions inside the committed packages.<rid>.lock.json
files and churned every one of them with a throwaway build stamp.
- tools/publish-dist.ps1 pushes /bin to the Gitea-only `dist` branch from a
throwaway worktree, leaving the developer's checkout, index, and HEAD
untouched. It refuses a GitHub remote outright.
Why `dist` and not main: the launcher payload is ~103 MB because the launcher
and its co-deployed bake CLI are each self-contained single files (deliberate,
see AcDream.Launcher.csproj). GitHub hard-rejects files over 100 MB, and all
three refs currently track main, so payloads on main would break every GitHub
push. `dist` is a single-commit orphan branch that each publish REPLACES, so
superseded builds never accumulate. /bin stays gitignored repo-wide and is
force-added only on that branch.
Verified live: manifest and both payloads serve anonymously over HTTPS, and a
downloaded client payload matches its declared SHA-256 and size byte for byte.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8be14d3992
commit
600c331ac6
5 changed files with 410 additions and 6 deletions
161
tools/publish-dist.ps1
Normal file
161
tools/publish-dist.ps1
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Publishes the /bin alpha feed to the Gitea-only `dist` branch.
|
||||
|
||||
.DESCRIPTION
|
||||
Copies the payloads written by tools/publish-bin.ps1 onto an orphan `dist`
|
||||
branch and pushes it to Gitea (the `origin` remote). The launcher's update
|
||||
check reads that branch's raw URLs.
|
||||
|
||||
Why a separate branch, not main:
|
||||
* The launcher payload is ~103 MB. GitHub hard-rejects any file over
|
||||
100 MB, so payloads on main would break every GitHub push.
|
||||
* Each build is ~150 MB. On main that weight would land in the history
|
||||
every developer clones forever.
|
||||
`dist` is a single-commit ORPHAN branch — each publish REPLACES it, so the
|
||||
feed never accumulates old builds. Nothing on it is a parent of main.
|
||||
|
||||
.PARAMETER Remote
|
||||
Remote to publish to. Defaults to `origin` (Gitea). Never pass the GitHub
|
||||
remote: the payload exceeds its per-file limit.
|
||||
|
||||
.EXAMPLE
|
||||
pwsh -NoProfile -File tools/publish-bin.ps1
|
||||
pwsh -NoProfile -File tools/publish-dist.ps1
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Remote = 'origin',
|
||||
[switch]$KeepHistory
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -lt 7) {
|
||||
throw 'publish-dist requires PowerShell 7 or newer.'
|
||||
}
|
||||
|
||||
$RepoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
|
||||
$BinRoot = Join-Path $RepoRoot 'bin'
|
||||
$ManifestPath = Join-Path $BinRoot 'manifest.json'
|
||||
|
||||
if (-not (Test-Path -LiteralPath $ManifestPath)) {
|
||||
throw "No feed found at '$ManifestPath'. Run tools/publish-bin.ps1 first."
|
||||
}
|
||||
|
||||
$manifest = Get-Content -LiteralPath $ManifestPath -Raw | ConvertFrom-Json
|
||||
$version = $manifest.version
|
||||
if ([string]::IsNullOrWhiteSpace($version)) {
|
||||
throw 'The manifest has no version.'
|
||||
}
|
||||
|
||||
$payloads = @(Get-ChildItem -LiteralPath $BinRoot -File -Filter *.zip)
|
||||
if ($payloads.Count -eq 0) {
|
||||
throw "No .zip payloads in '$BinRoot'. Run tools/publish-bin.ps1 first."
|
||||
}
|
||||
|
||||
$remoteUrl = (& git -C $RepoRoot remote get-url $Remote 2>&1)
|
||||
if ($LASTEXITCODE) { throw "Remote '$Remote' is not configured." }
|
||||
if ($remoteUrl -match 'github\.com') {
|
||||
throw "Refusing to publish payloads to '$Remote' ($remoteUrl): GitHub " +
|
||||
'rejects files over 100 MB and the alpha feed is Gitea-only.'
|
||||
}
|
||||
|
||||
Write-Host "Publishing alpha feed $version to $Remote ($remoteUrl)" -ForegroundColor Cyan
|
||||
foreach ($payload in $payloads) {
|
||||
' {0,-26} {1,8:N1} MB' -f $payload.Name, ($payload.Length / 1MB) | Write-Host
|
||||
}
|
||||
|
||||
# A throwaway worktree keeps the developer's checkout, index, and HEAD
|
||||
# completely untouched while the dist branch is built and pushed.
|
||||
$stamp = [DateTime]::UtcNow.ToString('yyyyMMddHHmmss')
|
||||
$workTree = Join-Path ([IO.Path]::GetTempPath()) "acdream-dist-$stamp"
|
||||
$branch = 'dist'
|
||||
# Build under a unique local branch and push it AS dist. Reusing the name
|
||||
# locally breaks the second publish outright: `checkout --orphan dist` fails
|
||||
# once a local dist ref exists (observed 2026-08-18).
|
||||
$stagingBranch = "dist-publish-$stamp"
|
||||
|
||||
try {
|
||||
if ($KeepHistory) {
|
||||
& git -C $RepoRoot fetch $Remote $branch 2>&1 | Out-Null
|
||||
$hasRemoteBranch = -not $LASTEXITCODE
|
||||
& git -C $RepoRoot worktree add --no-checkout -b $stagingBranch $workTree `
|
||||
$(if ($hasRemoteBranch) { "$Remote/$branch" } else { 'HEAD' }) 2>&1 | Out-Null
|
||||
if ($LASTEXITCODE) { throw 'Could not create the dist worktree.' }
|
||||
& git -C $workTree checkout . 2>&1 | Out-Null
|
||||
}
|
||||
else {
|
||||
# Default: one commit, no ancestry. Each publish REPLACES the branch so
|
||||
# superseded payloads never pile up in the object store.
|
||||
& git -C $RepoRoot worktree add --detach $workTree 2>&1 | Out-Null
|
||||
if ($LASTEXITCODE) { throw 'Could not create the dist worktree.' }
|
||||
& git -C $workTree checkout --orphan $stagingBranch 2>&1 | Out-Null
|
||||
if ($LASTEXITCODE) { throw 'Could not start the dist branch.' }
|
||||
& git -C $workTree rm -rf --cached . 2>&1 | Out-Null
|
||||
Get-ChildItem -LiteralPath $workTree -Force |
|
||||
Where-Object { $_.Name -ne '.git' } |
|
||||
Remove-Item -Recurse -Force
|
||||
}
|
||||
|
||||
$targetBin = Join-Path $workTree 'bin'
|
||||
if (Test-Path -LiteralPath $targetBin) {
|
||||
Remove-Item -LiteralPath $targetBin -Recurse -Force
|
||||
}
|
||||
$null = New-Item -ItemType Directory -Path $targetBin -Force
|
||||
Copy-Item -LiteralPath $ManifestPath -Destination $targetBin
|
||||
foreach ($payload in $payloads) {
|
||||
Copy-Item -LiteralPath $payload.FullName -Destination $targetBin
|
||||
}
|
||||
|
||||
$readme = @"
|
||||
# acdream alpha feed
|
||||
|
||||
Published by ``tools/publish-dist.ps1``. This branch carries ONLY the launcher
|
||||
update feed — it has no source history and is never merged into ``main``.
|
||||
|
||||
Current release: **$version**
|
||||
|
||||
## For players
|
||||
|
||||
1. Download ``bin/launcher-win-x64.zip``.
|
||||
2. Unzip it anywhere and run ``acdream-launcher.exe``.
|
||||
3. The launcher installs the game client and keeps both up to date.
|
||||
|
||||
You need Asheron's Call's DAT files for first-run setup.
|
||||
"@
|
||||
[IO.File]::WriteAllText(
|
||||
(Join-Path $workTree 'README.md'),
|
||||
$readme,
|
||||
[Text.UTF8Encoding]::new($false))
|
||||
|
||||
# bin/ is gitignored repo-wide (so main can never take the payloads by
|
||||
# accident) — force-add it here, where it is the whole point of the branch.
|
||||
& git -C $workTree add -f bin README.md
|
||||
if ($LASTEXITCODE) { throw 'Could not stage the feed.' }
|
||||
|
||||
& git -C $workTree commit -q -m "release: acdream alpha $version" 2>&1 | Out-Null
|
||||
if ($LASTEXITCODE) {
|
||||
Write-Host 'Nothing changed since the last publish.' -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
& git -C $workTree push --force $Remote "${stagingBranch}:${branch}"
|
||||
if ($LASTEXITCODE) { throw "Push to $Remote/$branch failed." }
|
||||
}
|
||||
finally {
|
||||
if (Test-Path -LiteralPath $workTree) {
|
||||
& git -C $RepoRoot worktree remove --force $workTree 2>&1 | Out-Null
|
||||
if (Test-Path -LiteralPath $workTree) {
|
||||
Remove-Item -LiteralPath $workTree -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
& git -C $RepoRoot worktree prune 2>&1 | Out-Null
|
||||
# The staging branch exists only to carry one publish to the remote.
|
||||
& git -C $RepoRoot branch -D $stagingBranch 2>&1 | Out-Null
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host "Published $version." -ForegroundColor Green
|
||||
Write-Host 'Feed: https://git.snakedesert.se/erik/acdream/raw/branch/dist/bin/manifest.json'
|
||||
Write-Host 'Players: https://git.snakedesert.se/erik/acdream/src/branch/dist'
|
||||
Loading…
Add table
Add a link
Reference in a new issue