From 6923ca02bd21226f35ccf6aa79112ed7f1c7d197 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 19 Aug 2026 14:59:28 +0200 Subject: [PATCH] ci: prune old releases, keeping the newest five MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Releases were retained forever. Each build is ~121 MB of attachments, so the Gitea server grew by that much on every push to main — five builds had already reached 606 MB, and nothing would have stopped it. The release job now deletes versioned releases beyond the newest five, and their tags with them (a tag survives its release and would otherwise pile up). Five keeps a previous build available for a friend or a bisect while staying well under a gigabyte. The 'latest' pointer is explicitly excluded from pruning: it is the launcher's feed, not a build. --- .gitea/workflows/ci.yml | 28 ++++++++++++++++++++++++++++ docs/ci-and-releases.md | 7 +++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 9ba13531..f775e9fb 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -180,3 +180,31 @@ jobs: -Uri "$api/releases/$($pointer.id)/assets?name=manifest.json" ` -Form @{ attachment = Get-Item bin/manifest.json } | Out-Null Write-Host "latest pointer now advertises $env:TAG" + + - name: Prune old releases + shell: pwsh + env: + KEEP: '5' + TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + $ErrorActionPreference = 'Stop' + $api = "${{ github.server_url }}/api/v1/repos/${{ github.repository }}" + $headers = @{ Authorization = "token $env:TOKEN" } + $keep = [int]$env:KEEP + + # Each build is ~121 MB of attachments, so without this the server + # grows by that much on EVERY push to main. Keep the newest $keep + # versioned releases: enough to grab a previous build or bisect a + # regression, bounded at well under a gigabyte. + $releases = Invoke-RestMethod -Method Get -Headers $headers -Uri "$api/releases?limit=100" + # Never touch the `latest` pointer — it is the launcher's feed, not a build. + $builds = @($releases | Where-Object { $_.tag_name -ne 'latest' } | + Sort-Object -Property created_at -Descending) + + Write-Host "$($builds.Count) versioned release(s); keeping $keep" + foreach ($old in ($builds | Select-Object -Skip $keep)) { + Invoke-RestMethod -Method Delete -Headers $headers -Uri "$api/releases/$($old.id)" | Out-Null + # The tag survives its release and would otherwise accumulate. + Invoke-RestMethod -Method Delete -Headers $headers -Uri "$api/tags/$($old.tag_name)" -SkipHttpErrorCheck | Out-Null + Write-Host " pruned $($old.tag_name)" + } diff --git a/docs/ci-and-releases.md b/docs/ci-and-releases.md index bc64eb3c..25c3eeec 100644 --- a/docs/ci-and-releases.md +++ b/docs/ci-and-releases.md @@ -86,8 +86,11 @@ route** (verified: 404) — unlike GitHub, there is no built-in stable URL for means deleting the old release *and* its tag; the tag outlives its release and would otherwise block recreation. -Versioned releases are kept, so an older build stays downloadable and the -launcher's local rollback still has something to fall back to. +The newest **5** versioned releases are kept and older ones are pruned with +their tags. Each build is ~121 MB of attachments, so retaining every one grew +the server by that much per push — 5 builds had already reached 606 MB. Five is +enough to grab a previous build or bisect a regression while staying bounded. +The `latest` pointer is never pruned; it is the feed, not a build. `tools/publish-bin.ps1 -BaseUrl ` builds the payloads; CI passes the tag's asset base. Running it locally is for inspection only —