Mirrored from GitHub github.com/roostorg/coop
0

Configure Feed

Select the types of activity you want to include in your feed.

ci: make image pulls resilient to Docker Hub flakiness (#824)

* ci: make image pulls resilient to Docker Hub flakiness

Intermittent CI failures came from transient Docker Hub registry/auth
timeouts (auth.docker.io / registry-1.docker.io) during image pulls at
`docker compose run` time. These are timeouts, not rate limits, so
authenticating wouldn't help (and can't on fork PRs anyway).

For each compose job in apply_pr_checks.yaml:

- Configure a docker.io pull-through mirror (mirror.gcr.io) via
/etc/docker/daemon.json, bypassing the flaky Docker Hub auth/token
path. No secrets, so it still works on fork PRs.
- Pre-pull/build the images each job needs in a 3-attempt retry loop
before the real steps. Images are then cached locally, so the existing
`docker compose run` steps don't hit the registry -- isolating a flaky
pull to the retried prep step without masking real lint/build/test
failures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: extract image-prep into a composite action

The mirror-config + retry-pull logic was duplicated across all three
compose jobs. Extract it into a local composite action
(.github/actions/prepare-docker-images) parameterized by the services to
pull/build, so each job calls it in one step.

Inputs are passed via env rather than interpolated into the run script,
matching the repo's zizmor template-injection guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: run dockerised checks when CI plumbing changes

The check_api_server / check_generated_graphql / frontend jobs are gated
by paths-filter on server/** and client/**, so a PR that only touches CI
or docker plumbing (this workflow, the compose file, the Dockerfile, the
prepare-docker-images action) skipped all of them -- meaning changes to
the image-pull setup were never actually exercised in CI.

Add those plumbing paths to the server and client filters via a YAML
anchor so the relevant jobs run when they change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

+77
+51
.github/actions/prepare-docker-images/action.yml
··· 1 + name: Prepare Docker images 2 + description: > 3 + Pull (and optionally build) images from a docker-compose 4 + file, with special handling to avoid flakiness (since Docker Hub 5 + sometimes returns errors for no good reason). 6 + 7 + inputs: 8 + pull: 9 + description: Space-separated compose services whose images should be pulled. 10 + required: false 11 + default: '' 12 + build: 13 + description: Space-separated compose services that should be built. 14 + required: false 15 + default: '' 16 + 17 + runs: 18 + using: composite 19 + steps: 20 + - name: Configure Docker Hub mirror 21 + # Route docker.io pulls through Google's pull-through cache to avoid 22 + # transient Docker Hub registry/auth timeouts. 23 + shell: bash 24 + run: | 25 + sudo mkdir -p /etc/docker 26 + echo '{"registry-mirrors":["https://mirror.gcr.io"]}' | sudo tee /etc/docker/daemon.json 27 + sudo systemctl restart docker 28 + 29 + - name: Pre-pull images (with retry) 30 + shell: bash 31 + env: 32 + PULL_SERVICES: ${{ inputs.pull }} 33 + BUILD_SERVICES: ${{ inputs.build }} 34 + run: | 35 + # In addition to using the registry mirror above, we also 36 + # retry Docker image pulls a few times to handle flakiness. 37 + for attempt in 1 2 3; do 38 + ok=true 39 + if [ -n "$PULL_SERVICES" ]; then 40 + docker compose pull --quiet $PULL_SERVICES || ok=false 41 + fi 42 + if [ "$ok" = true ] && [ -n "$BUILD_SERVICES" ]; then 43 + docker compose build --quiet $BUILD_SERVICES || ok=false 44 + fi 45 + if [ "$ok" = true ]; then exit 0; fi 46 + if [ "$attempt" -lt 3 ]; then 47 + echo "::warning::image prep attempt $attempt failed; retrying in $((attempt * 15))s" 48 + sleep $((attempt * 15)) 49 + fi 50 + done 51 + echo "::error::image prep failed after 3 attempts"; exit 1
+26
.github/workflows/apply_pr_checks.yaml
··· 31 31 id: filter 32 32 with: 33 33 filters: | 34 + # Changes to the dockerised CI plumbing re-run the jobs that 35 + # depend on it, so this workflow, the compose file, and the 36 + # Dockerfile are exercised even when no app code changed. 37 + docker: &docker 38 + - 'docker-compose.yaml' 39 + - 'Dockerfile' 40 + - '.env.githubci' 41 + - '.github/workflows/apply_pr_checks.yaml' 42 + - '.github/actions/prepare-docker-images/**' 34 43 server: 35 44 - 'server/**' 45 + - *docker 36 46 client: 37 47 - 'client/**' 48 + - *docker 38 49 db: 39 50 - 'db/**' 40 51 migrator: ··· 70 81 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 71 82 with: 72 83 persist-credentials: false 84 + - name: Prepare Docker images 85 + uses: ./.github/actions/prepare-docker-images 86 + with: 87 + build: codegen-check 73 88 - name: Check generated GraphQL is up to date 74 89 run: docker compose run --rm --quiet-pull codegen-check 75 90 ··· 172 187 with: 173 188 persist-credentials: false 174 189 190 + - name: Prepare Docker images 191 + uses: ./.github/actions/prepare-docker-images 192 + with: 193 + pull: postgres scylla clickhouse redis 194 + build: backend test 195 + 175 196 - name: Lint 176 197 run: docker compose run --rm --quiet-pull backend npm run lint 177 198 ··· 209 230 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 210 231 with: 211 232 persist-credentials: false 233 + 234 + - name: Prepare Docker images 235 + uses: ./.github/actions/prepare-docker-images 236 + with: 237 + build: client 212 238 213 239 - name: Lint client 214 240 run: docker compose run --rm --quiet-pull client npm run lint