## Summary `artifactcache.Handler` was lowercasing cache keys before storing and returning them. This caused actions like `actions/setup-go` to treat every restore as a partial hit and re-upload the cache on every job run. Similar issue: [act#2497](https://github.com/nektos/act/issues/2497) ## Root Cause These actions build cache keys that include `RUNNER_OS` (e.g. `setup-go-Linux-x64-...` See [setup-go/cache-restore.ts](78961f6f84/src/cache-restore.ts (L11-L51)) ). In `gitea/runner`, `RUNNER_OS` is always `Linux` by default (See https://gitea.com/gitea/runner/search?q=RUNNER_OS). These actions decide whether to save the cache data in their post step using **strict** `===` comparison between the primary key and the key returned from the runner. See [setup-go cache-save.ts](78961f6f84/src/cache-save.ts (L44-L86)) . |State | Value| |--- | ---| |CachePrimaryKey | `setup-go-Linux-x64-ubuntu-22.04-go-1.24.9-abc123` | |CacheMatchedKey | `setup-go-linux-x64-ubuntu-22.04-go-1.24.9-abc123` | Because the runner's cache server lowercased the stored key, the response carried `setup-go-linux-...` while the action's primary key was `setup-go-Linux-...`. Strict equality failed, then the actions updated same data again. This repeated on every run, wasting disk and bandwidth. The duplicate blobs accumulate until GC . https://gitea.com/gitea/runner/actions/runs/462560/jobs/737401#jobstep-2-15  https://gitea.com/gitea/runner/actions/runs/462560/jobs/737401#jobstep-6-22  ## Fix Drop the `strings.ToLower` calls in `find` and `reserve` so the original key case is preserved end-to-end. This fix will invalidate existing "case insensitive" keys. ## Notes The [original act review](https://github.com/nektos/act/pull/1770/changes/BASE..d44b8d15649d9d09d1d891130b8f3962097a81f3#r1177624608) suggested making cache keys case-insensitive because `isExactKeyMatch` compares cache key ignoring case. However, the actions (`setup-go` / `setup-node` / `setup-ruby`) compare with strict `===` rather than `isExactKeyMatch`. --------- Co-authored-by: Nicolas <bircni@icloud.com> Reviewed-on: https://gitea.com/gitea/runner/pulls/947 Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com> Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-by: Nicolas <bircni@icloud.com> Co-authored-by: Zettat123 <zettat123@gmail.com> Co-committed-by: Zettat123 <zettat123@gmail.com>
Gitea Runner
Installation
Prerequisites
Docker Engine Community version is required for docker mode. To install Docker CE, follow the official install instructions.
Download pre-built binary
Visit here and download the right version for your platform.
Build from source
make build
Build a docker image
make docker
Quickstart
Actions are disabled by default, so you need to add the following to the configuration file of your Gitea instance to enable it:
[actions]
ENABLED=true
Register
./gitea-runner register
And you will be asked to input:
- Gitea instance URL, like
http://192.168.8.8:3000/. You should use your gitea instance ROOT_URL as the instance argument and you should not uselocalhostor127.0.0.1as instance IP; - Runner token, you can get it from
http://192.168.8.8:3000/admin/actions/runners; - Runner name, you can just leave it blank;
- Runner labels, you can just leave it blank.
The process looks like:
INFO Registering runner, arch=amd64, os=darwin, version=0.1.5.
WARN Runner in user-mode.
INFO Enter the Gitea instance URL (for example, https://gitea.com/):
http://192.168.8.8:3000/
INFO Enter the runner token:
fe884e8027dc292970d4e0303fe82b14xxxxxxxx
INFO Enter the runner name (if set empty, use hostname: Test.local):
INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest):
INFO Registering runner, name=Test.local, instance=http://192.168.8.8:3000/, labels=[ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04 ubuntu-20.04:docker://docker.gitea.com/runner-images:ubuntu-20.04].
DEBU Successfully pinged the Gitea instance server
INFO Runner registered successfully.
You can also register with command line arguments.
./gitea-runner register --instance http://192.168.8.8:3000 --token <my_runner_token> --no-interactive
If the registry succeed, it will run immediately. Next time, you could run the runner directly.
Run
./gitea-runner daemon
Run with docker
docker run -e GITEA_INSTANCE_URL=https://your_gitea.com -e GITEA_RUNNER_REGISTRATION_TOKEN=<your_token> -v /var/run/docker.sock:/var/run/docker.sock --name my_runner gitea/runner:nightly
Mount a volume on /data if you want the registration file and optional config to survive container recreation (see scripts/run.sh).
Configuration
The runner is configured with a YAML file. Generate a starting point (this matches what ships in the tree):
./gitea-runner generate-config > config.yaml
Pass it with -c / --config on any command that loads configuration (register, daemon, cache-server):
./gitea-runner -c config.yaml register
./gitea-runner -c config.yaml daemon
./gitea-runner -c config.yaml cache-server
Every option is described in config.example.yaml (the same content generate-config prints).
Without a config file
If you omit -c, built-in defaults apply (same as an empty YAML document). A small set of deprecated environment variables can still override parts of that default config, but only when no -c path was given; they are ignored if you use a config file:
| Variable | Effect |
|---|---|
GITEA_DEBUG |
If true, sets log level to debug |
GITEA_TRACE |
If true, sets log level to trace |
GITEA_RUNNER_CAPACITY |
Concurrent jobs (integer) |
GITEA_RUNNER_FILE |
Registration state file path (default .runner) |
GITEA_RUNNER_ENVIRON |
Extra job env vars as comma-separated KEY:VALUE pairs |
GITEA_RUNNER_ENV_FILE |
Path to an env file merged into job env (same idea as runner.env_file in YAML) |
Prefer a YAML file for all settings.
Registration vs config labels
If runner.labels is set in the YAML file, those labels are used during register and the --labels CLI flag is ignored.
External cache (actions/cache)
If cache.external_server is set, you must set cache.external_secret to the same value on this runner and on the standalone cache server. Run the server with gitea-runner cache-server using a config that defines cache.external_secret (and matching cache.dir / host / port as needed). Flags --dir, --host, and --port on cache-server override the file.
Official Docker image
Besides GITEA_INSTANCE_URL and GITEA_RUNNER_REGISTRATION_TOKEN, the image entrypoint supports optional variables such as CONFIG_FILE (passed through as -c), GITEA_RUNNER_LABELS, GITEA_RUNNER_EPHEMERAL, GITEA_RUNNER_ONCE, GITEA_RUNNER_NAME, GITEA_MAX_REG_ATTEMPTS, RUNNER_STATE_FILE, and GITEA_RUNNER_REGISTRATION_TOKEN_FILE. See scripts/run.sh for exact behavior.
For a fuller container-oriented walkthrough, see examples/docker.
When container.bind_workdir is enabled, stale task workspace directories can be cleaned while the runner is idle:
- directories older than
runner.workdir_cleanup_ageare removed (default:24h; set0to disable) - cleanup runs every
runner.idle_cleanup_interval(default:10m; set0to disable) - only purely numeric subdirectories under
container.workdir_parentare treated as task workspaces and may be removed - cleanup assumes
container.workdir_parentis not shared across multiple runners
Example Deployments
Check out the examples directory for sample deployment types.