ci: improve go caches (#38730)

Cache saves have been rejected since June because the repo sat above its
10 GB allowance, so every PR run fell back to a cache built with an
older toolchain and rebuilt the backend from scratch.

- go version in the `gobuild` and `golint` keys and `restore-keys`
- seeder triggers on `go.mod` and gained `workflow_dispatch`
- single writer for the `gomod` cache, the two were racing
- new daily `cache-prune` workflow holding the total under a limit
- `cache: false` for `setup-go` in release and cron workflows, it held
815 MB
- add `workflow_dispatch` so the cache workflows can be triggered
on-demand

Assisted-by: Claude Code:claude-opus-5
This commit is contained in:
silverwind
2026-07-31 20:56:13 +00:00
committed by GitHub
parent 76a787a79d
commit 4f363d2748
8 changed files with 69 additions and 10 deletions
+16 -10
View File
@@ -2,12 +2,18 @@ name: go-caches
description: Restore the go module, build, and golangci-lint caches. Save only on the cache-seeder workflow.
# Only the cache-seeder workflow saves; rename requires updating cache-seeder.yml.
# The lint job restores but does not save the gobuild cache, so only one writer
# (the gobuild job) populates it and there is no contention on the cache key.
# The lint job restores but does not save the gobuild and gomod caches, so every key
# has a single writer and there is no contention on it.
# Seeder restores by exact key only (no restore-keys) so each go.sum seeds a clean
# cache and size stays bounded; do not add restore-keys here. PR runs keep them.
# The go version is part of the gobuild and golint keys because a toolchain bump
# invalidates every entry in them, so a cross-version fallback would restore
# gigabytes that no build can use. The module cache is version-independent.
inputs:
go-version:
description: Go version the build caches belong to
required: true
lint-cache:
description: Restore (and save in cache-seeder) ~/.cache/golangci-lint
default: "false"
@@ -15,12 +21,12 @@ inputs:
runs:
using: composite
steps:
- if: ${{ github.workflow == 'cache-seeder' }}
- if: ${{ github.workflow == 'cache-seeder' && inputs.lint-cache != 'true' }}
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/go/pkg/mod
key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
- if: ${{ github.workflow != 'cache-seeder' }}
- if: ${{ github.workflow != 'cache-seeder' || inputs.lint-cache == 'true' }}
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/go/pkg/mod
@@ -30,21 +36,21 @@ runs:
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
key: gobuild-${{ runner.os }}-${{ runner.arch }}-go${{ inputs.go-version }}-${{ hashFiles('go.sum') }}
- if: ${{ github.workflow != 'cache-seeder' || inputs.lint-cache == 'true' }}
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }}
key: gobuild-${{ runner.os }}-${{ runner.arch }}-go${{ inputs.go-version }}-${{ hashFiles('go.sum') }}
restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }}-go${{ inputs.go-version }}-
- if: ${{ inputs.lint-cache == 'true' && github.workflow == 'cache-seeder' }}
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/golangci-lint
key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }}
key: golint-${{ runner.os }}-${{ runner.arch }}-go${{ inputs.go-version }}-${{ hashFiles('go.sum', '.golangci.yml') }}
- if: ${{ inputs.lint-cache == 'true' && github.workflow != 'cache-seeder' }}
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/golangci-lint
key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }}
restore-keys: golint-${{ runner.os }}-${{ runner.arch }}
key: golint-${{ runner.os }}-${{ runner.arch }}-go${{ inputs.go-version }}-${{ hashFiles('go.sum', '.golangci.yml') }}
restore-keys: golint-${{ runner.os }}-${{ runner.arch }}-go${{ inputs.go-version }}-
+2
View File
@@ -14,6 +14,7 @@ runs:
steps:
- uses: ./.github/actions/free-disk-space
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7
id: setup-go
with:
go-version-file: go.mod
check-latest: true
@@ -21,4 +22,5 @@ runs:
- if: ${{ inputs.cache == 'true' }}
uses: ./.github/actions/go-cache
with:
go-version: ${{ steps.setup-go.outputs.go-version }}
lint-cache: ${{ inputs.lint-cache }}
+38
View File
@@ -0,0 +1,38 @@
name: cache-prune
# Keeps the repository's total cache size below a fixed limit, so that GitHub never
# rejects a save for being over the allowance.
on:
schedule:
- cron: "37 2 * * *" # every day at 02:37 UTC
workflow_dispatch:
workflow_call:
permissions:
actions: write # to delete caches
concurrency:
group: cache-prune
jobs:
prune:
runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea'
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
steps:
# Deletes least recently used first, the order GitHub itself evicts in, which takes
# superseded generations first as those stop being restored once a newer one exists.
- name: delete caches over the size limit
run: |
caches=$(gh cache list --limit 1000 --sort last_accessed_at --order asc --json id,key,sizeInBytes)
size=$(jq '[.[].sizeInBytes] | add // 0' <<< "$caches")
echo "cache usage: $((size / 1000000)) MB"
jq -r '.[] | "\(.id) \(.sizeInBytes) \(.key)"' <<< "$caches" |
while [ "$size" -gt 6500000000 ] && read -r id bytes key; do
echo "deleting $key"
gh cache delete "$id"
size=$((size - bytes))
done
+9
View File
@@ -8,10 +8,12 @@
name: cache-seeder
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "go.mod" # a toolchain bump invalidates the build caches
- "go.sum"
- ".golangci.yml"
- ".github/actions/go-cache/action.yml"
@@ -70,3 +72,10 @@ jobs:
- run: make ${{ matrix.target }}
env:
TAGS: ${{ matrix.tags }}
# reclaims the caches this run superseded, so the next save still fits in the allowance
prune:
needs: [gobuild, lint]
permissions:
actions: write
uses: ./.github/workflows/cache-prune.yml
+1
View File
@@ -17,6 +17,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
cache: false
- run: make generate-gitignore
timeout-minutes: 40
- name: push translations to repo
+1
View File
@@ -23,6 +23,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/node-setup
- run: make deps-frontend deps-backend
# xgo build
+1
View File
@@ -24,6 +24,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/node-setup
- run: make deps-frontend deps-backend
# xgo build
@@ -27,6 +27,7 @@ jobs:
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/node-setup
- run: make deps-frontend deps-backend
# xgo build