The CI runner is full-dind: job and app containers share one daemon, which is also shared with production and other workflows (per the comment at the existing cleanup step). The current cleanup handles our stack (compose down -v), our network, and our DB volume — but three things still accumulate on that daemon between runs:
dangling images/layers from rebuilding flight-ops-ci every run
BuildKit cache (persists by design)
leaked job containers from interrupted runs (the start-of-run docker volume rm flight-ci_flight-db guard exists precisely because interrupted runs skip end-of-run cleanup)
What this PR does
Adds ONE step to .gitea/workflows/ci.yml, placed after the existing "Cleanup e2e stack + network" step:
- name:Prune runner dind leftoversif:always()run:docker system prune -af || echo "::warning::dind prune failed — see logs"
docker system prune -af reclaims exactly the three categories above (all unused images incl. tagged-but-unused, build cache, stopped containers).
Why -af without --volumes is the safe choice on a shared daemon
No --volumes: named volumes may hold other workflows' persistent data — the daemon is shared with production ("never leave our stack or network behind" applies to volumes too). This project's own flight-ci_flight-db volume is already dropped by the existing cleanup steps, so there is nothing of ours left for prune to touch.
Non-fatal:|| echo "::warning::..." (same annotation style the workflow already uses) means a prune failure can never mask or break the run's real result — worst case we log a warning and leave the leftovers for the next run.
if: always(): runs even when tests fail, so failed runs don't leak their rebuild layers either.
Scope
No app/TS changes; no new env vars; existing steps untouched. CI validates the workflow itself (YAML parses clean locally). Version bumped to 0.67.0 with a CHANGELOG entry.
## What accumulates on the runner between runs
The CI runner is full-dind: job and app containers share one daemon, which is also shared with production and other workflows (per the comment at the existing cleanup step). The current cleanup handles our stack (`compose down -v`), our network, and our DB volume — but three things still accumulate on that daemon between runs:
- **dangling images/layers** from rebuilding `flight-ops-ci` every run
- **BuildKit cache** (persists by design)
- **leaked job containers** from interrupted runs (the start-of-run `docker volume rm flight-ci_flight-db` guard exists precisely because interrupted runs skip end-of-run cleanup)
## What this PR does
Adds ONE step to `.gitea/workflows/ci.yml`, placed after the existing "Cleanup e2e stack + network" step:
```yaml
- name: Prune runner dind leftovers
if: always()
run: docker system prune -af || echo "::warning::dind prune failed — see logs"
```
`docker system prune -af` reclaims exactly the three categories above (all unused images incl. tagged-but-unused, build cache, stopped containers).
## Why `-af` without `--volumes` is the safe choice on a shared daemon
- **No `--volumes`:** named volumes may hold other workflows' persistent data — the daemon is shared with production ("never leave our stack or network behind" applies to volumes too). This project's own `flight-ci_flight-db` volume is already dropped by the existing cleanup steps, so there is nothing of ours left for prune to touch.
- **Non-fatal:** `|| echo "::warning::..."` (same annotation style the workflow already uses) means a prune failure can never mask or break the run's real result — worst case we log a warning and leave the leftovers for the next run.
- **`if: always()`:** runs even when tests fail, so failed runs don't leak their rebuild layers either.
## Scope
No app/TS changes; no new env vars; existing steps untouched. CI validates the workflow itself (YAML parses clean locally). Version bumped to 0.67.0 with a CHANGELOG entry.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What accumulates on the runner between runs
The CI runner is full-dind: job and app containers share one daemon, which is also shared with production and other workflows (per the comment at the existing cleanup step). The current cleanup handles our stack (
compose down -v), our network, and our DB volume — but three things still accumulate on that daemon between runs:flight-ops-cievery rundocker volume rm flight-ci_flight-dbguard exists precisely because interrupted runs skip end-of-run cleanup)What this PR does
Adds ONE step to
.gitea/workflows/ci.yml, placed after the existing "Cleanup e2e stack + network" step:docker system prune -afreclaims exactly the three categories above (all unused images incl. tagged-but-unused, build cache, stopped containers).Why
-afwithout--volumesis the safe choice on a shared daemon--volumes: named volumes may hold other workflows' persistent data — the daemon is shared with production ("never leave our stack or network behind" applies to volumes too). This project's ownflight-ci_flight-dbvolume is already dropped by the existing cleanup steps, so there is nothing of ours left for prune to touch.|| echo "::warning::..."(same annotation style the workflow already uses) means a prune failure can never mask or break the run's real result — worst case we log a warning and leave the leftovers for the next run.if: always(): runs even when tests fail, so failed runs don't leak their rebuild layers either.Scope
No app/TS changes; no new env vars; existing steps untouched. CI validates the workflow itself (YAML parses clean locally). Version bumped to 0.67.0 with a CHANGELOG entry.