ci: put the launcher's update pointer in a release, and delete the dist branch
Some checks failed
CI / linux-portable (push) Failing after 3m22s
CI / windows-gate (push) Successful in 5m27s
CI / release (push) Has been skipped

The dist branch existed to carry ~120 MB payloads that could not go on main.
Once payloads became release attachments it held one 500-byte manifest.json,
so it was a whole branch for a reason that no longer applied.

The pointer is now a release asset too: each publish recreates a one-asset
 release naming the versioned build. Forgejo has no
/releases/latest/download/ route (404), so a pointer is still required — but
keeping it in a release means nothing about distribution lives in git: no
payload branch, no bot commits on main, and no push that could retrigger the
pipeline (which is why writing the manifest to main was not the answer either).

Recreating the tag deletes the old release AND its tag; the tag outlives its
release and would otherwise block recreation.

Versioned releases are retained, so older builds stay downloadable.
tools/publish-dist.ps1 is removed — publishing is CI's job now.
This commit is contained in:
Erik 2026-08-19 14:40:41 +02:00
parent 353231fe6e
commit ff01423f3f
6 changed files with 87 additions and 218 deletions

View file

@ -62,13 +62,12 @@ foreach ($candidate in @($Version, $MinimumLauncherVersion)) {
}
}
# Where the manifest says the payloads live. The CI pipeline passes the Gitea
# RELEASE asset base for the tag it is publishing, so payloads live outside git
# entirely; the default keeps the older dist-branch layout working for a manual
# local publish. The manifest itself always stays at the stable dist raw URL
# that ReleaseManifestClient.ProductionManifestUri points at.
# Where the manifest says the payloads live. Publishing is CI's job: the release
# workflow passes the Gitea RELEASE asset base for the tag it is creating. This
# default only makes a local build self-describing — it names a release tag that
# will not exist until CI publishes one.
$RawBase = if ([string]::IsNullOrWhiteSpace($BaseUrl)) {
'https://git.snakedesert.se/erik/acdream/raw/branch/dist/bin'
"https://git.snakedesert.se/erik/acdream/releases/download/$Version"
} else {
$BaseUrl.TrimEnd('/')
}
@ -247,8 +246,6 @@ if ($dirtyLocks.Count -gt 0) {
}
Write-Host ''
Write-Host 'Next — publish the feed to Gitea:' -ForegroundColor Cyan
Write-Host " pwsh -NoProfile -File tools/publish-dist.ps1"
Write-Host ''
Write-Host ' (bin/ is gitignored on purpose: publish-dist puts it on the' -ForegroundColor DarkGray
Write-Host ' Gitea-only dist branch, never on main / GitHub.)' -ForegroundColor DarkGray
Write-Host 'Releases are published by CI, not from here:' -ForegroundColor Cyan
Write-Host ' push to main -> .gitea/workflows/ci.yml -> Gitea Release' -ForegroundColor DarkGray
Write-Host ' This build is for local inspection; bin/ stays gitignored.' -ForegroundColor DarkGray

View file

@ -1,161 +0,0 @@
<#
.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'