From 71f764f3d0d7cc0bc5a41e9ec1d30be70ab2f2b7 Mon Sep 17 00:00:00 2001 From: Reinier van der Leer Date: Thu, 12 Feb 2026 12:57:28 +0100 Subject: [PATCH] Inject caching config into docker compose for e2e test --- .github/workflows/platform-frontend-ci.yml | 39 ++++---- .../scripts/generate-docker-ci-compose.py | 93 +++++++++++++++++++ 2 files changed, 113 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/scripts/generate-docker-ci-compose.py diff --git a/.github/workflows/platform-frontend-ci.yml b/.github/workflows/platform-frontend-ci.yml index 6410daae9f..e8082569cc 100644 --- a/.github/workflows/platform-frontend-ci.yml +++ b/.github/workflows/platform-frontend-ci.yml @@ -174,29 +174,30 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - - name: Cache Docker layers - uses: actions/cache@v5 with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-frontend-test-${{ hashFiles('autogpt_platform/docker-compose.yml', 'autogpt_platform/backend/Dockerfile', 'autogpt_platform/backend/pyproject.toml', 'autogpt_platform/backend/poetry.lock') }} - restore-keys: | - ${{ runner.os }}-buildx-frontend-test- + driver-opts: network=host + + - name: Build Docker images with cache + working-directory: autogpt_platform + run: | + pip install pyyaml + python ../.github/workflows/scripts/generate-docker-ci-compose.py \ + --source docker-compose.platform.yml \ + --output docker-compose.ci.yml \ + --cache-from "type=gha" \ + --cache-to "type=gha,mode=max" \ + --backend-scope "platform-backend-${{ hashFiles('autogpt_platform/backend/Dockerfile', 'autogpt_platform/backend/poetry.lock', 'autogpt_platform/backend/backend') }}" \ + --frontend-scope "platform-frontend-${{ hashFiles('autogpt_platform/frontend/Dockerfile', 'autogpt_platform/frontend/pnpm-lock.yaml', 'autogpt_platform/frontend/src') }}" + + docker compose -f docker-compose.yml -f docker-compose.ci.yml build --parallel + env: + NEXT_PUBLIC_PW_TEST: true + DOCKER_BUILDKIT: 1 - name: Run docker compose - run: | - NEXT_PUBLIC_PW_TEST=true docker compose -f ../docker-compose.yml up -d + run: docker compose -f ../docker-compose.yml up -d --no-build env: - DOCKER_BUILDKIT: 1 - BUILDX_CACHE_FROM: type=local,src=/tmp/.buildx-cache - BUILDX_CACHE_TO: type=local,dest=/tmp/.buildx-cache-new,mode=max - - - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - if [ -d "/tmp/.buildx-cache-new" ]; then - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - fi + NEXT_PUBLIC_PW_TEST: true - name: Wait for services to be ready run: | diff --git a/.github/workflows/scripts/generate-docker-ci-compose.py b/.github/workflows/scripts/generate-docker-ci-compose.py new file mode 100644 index 0000000000..1248b3cc4e --- /dev/null +++ b/.github/workflows/scripts/generate-docker-ci-compose.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +""" +Generate a docker-compose.ci.yml with cache configuration for all services +that have a build key in the source compose file. +""" + +import argparse + +import yaml + + +def main(): + parser = argparse.ArgumentParser( + description="Generate docker-compose cache override file" + ) + parser.add_argument( + "--source", + default="docker-compose.platform.yml", + help="Source compose file to read (default: docker-compose.platform.yml)", + ) + parser.add_argument( + "--output", + default="docker-compose.ci.yml", + help="Output compose file to write (default: docker-compose.ci.yml)", + ) + parser.add_argument( + "--cache-from", + default="type=local,src=/tmp/.buildx-cache", + help="Cache source configuration", + ) + parser.add_argument( + "--cache-to", + default="type=local,dest=/tmp/.buildx-cache-new,mode=max", + help="Cache destination configuration", + ) + parser.add_argument( + "--backend-scope", + default="", + help="GHA cache scope for backend services (e.g., platform-backend-{hash})", + ) + parser.add_argument( + "--frontend-scope", + default="", + help="GHA cache scope for frontend service (e.g., platform-frontend-{hash})", + ) + args = parser.parse_args() + + with open(args.source, "r") as f: + compose = yaml.safe_load(f) + + ci_compose = {"services": {}} + for service_name, service_config in compose.get("services", {}).items(): + if "build" not in service_config: + continue + + cache_from = args.cache_from + cache_to = args.cache_to + + # Determine scope based on Dockerfile path + if "type=gha" in args.cache_from or "type=gha" in args.cache_to: + dockerfile = service_config["build"].get("dockerfile", "Dockerfile") + if "frontend" in dockerfile: + scope = args.frontend_scope + elif "backend" in dockerfile: + scope = args.backend_scope + else: + # Skip services that don't clearly match frontend/backend + continue + + if scope: + if "type=gha" in args.cache_from: + cache_from = f"{args.cache_from},scope={scope}" + if "type=gha" in args.cache_to: + cache_to = f"{args.cache_to},scope={scope}" + + ci_compose["services"][service_name] = { + "build": { + "cache_from": [cache_from], + "cache_to": [cache_to], + } + } + + with open(args.output, "w") as f: + yaml.dump(ci_compose, f, default_flow_style=False) + + services = list(ci_compose["services"].keys()) + print(f"Generated {args.output} with cache config for {len(services)} services:") + for svc in services: + print(f" - {svc}") + + +if __name__ == "__main__": + main()