From 7504c9fef4007933189240c22640d1a07e81ad8b Mon Sep 17 00:00:00 2001 From: streamkit-devin Date: Sun, 23 Aug 2026 19:47:16 +0000 Subject: [PATCH] ci: isolate Docker image builders Signed-off-by: streamkit-devin --- .github/workflows/docker.yml | 27 +++++++++++---- .github/workflows/skit.yml | 3 ++ justfile | 6 +++- scripts/check_docker_workflow.py | 59 ++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 scripts/check_docker_workflow.py diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 3bdcc1033..14a28b7f3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -52,6 +52,7 @@ jobs: uses: actions/checkout@v5 - name: Set up Docker Buildx + id: buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry @@ -85,15 +86,19 @@ jobs: echo "EOF" } >> "$GITHUB_OUTPUT" + - name: Prepare CPU build cache + run: mkdir -p /mnt/docker-cache/cpu + - name: Build and push CPU image uses: docker/build-push-action@v5 with: + builder: ${{ steps.buildx.outputs.name }} context: . file: ./Dockerfile push: ${{ github.event_name == 'push' || inputs.push }} tags: ${{ steps.meta.outputs.tags }} - cache-from: type=local,src=/mnt/docker-cache - cache-to: type=local,dest=/mnt/docker-cache,mode=max + cache-from: type=local,src=/mnt/docker-cache/cpu + cache-to: type=local,dest=/mnt/docker-cache/cpu,mode=max platforms: linux/amd64 provenance: false @@ -109,6 +114,7 @@ jobs: uses: actions/checkout@v5 - name: Set up Docker Buildx + id: buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry @@ -142,15 +148,19 @@ jobs: echo "EOF" } >> "$GITHUB_OUTPUT" + - name: Prepare GPU build cache + run: mkdir -p /mnt/docker-cache/gpu + - name: Build and push GPU image uses: docker/build-push-action@v5 with: + builder: ${{ steps.buildx.outputs.name }} context: . file: ./Dockerfile.gpu push: ${{ github.event_name == 'push' || inputs.push }} tags: ${{ steps.meta.outputs.tags }} - cache-from: type=local,src=/mnt/docker-cache - cache-to: type=local,dest=/mnt/docker-cache,mode=max + cache-from: type=local,src=/mnt/docker-cache/gpu + cache-to: type=local,dest=/mnt/docker-cache/gpu,mode=max platforms: linux/amd64 provenance: false @@ -166,6 +176,7 @@ jobs: uses: actions/checkout@v5 - name: Set up Docker Buildx + id: buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry @@ -199,14 +210,18 @@ jobs: echo "EOF" } >> "$GITHUB_OUTPUT" + - name: Prepare Demo build cache + run: mkdir -p /mnt/docker-cache/demo + - name: Build and push Demo image uses: docker/build-push-action@v5 with: + builder: ${{ steps.buildx.outputs.name }} context: . file: ./Dockerfile.demo push: ${{ github.event_name == 'push' || inputs.push }} tags: ${{ steps.meta.outputs.tags }} - cache-from: type=local,src=/mnt/docker-cache - cache-to: type=local,dest=/mnt/docker-cache,mode=max + cache-from: type=local,src=/mnt/docker-cache/demo + cache-to: type=local,dest=/mnt/docker-cache/demo,mode=max platforms: linux/amd64 provenance: false diff --git a/.github/workflows/skit.yml b/.github/workflows/skit.yml index 58fbf4015..cbdcd4780 100644 --- a/.github/workflows/skit.yml +++ b/.github/workflows/skit.yml @@ -15,6 +15,9 @@ jobs: steps: - uses: actions/checkout@v5 + - name: Check Docker workflow + run: python3 scripts/check_docker_workflow.py + - uses: ./.github/actions/setup-skit with: rust-cache-key: skit-lint diff --git a/justfile b/justfile index a30dae829..9bdb0f218 100644 --- a/justfile +++ b/justfile @@ -351,6 +351,10 @@ lint-ui: install-ui @echo "Linting UI..." @bun run lint +# Validate Docker workflow builder and cache isolation +check-docker-workflow: + @python3 scripts/check_docker_workflow.py + # Auto-fix UI code formatting and linting issues [working-directory: 'ui'] fix-ui: install-ui @@ -538,7 +542,7 @@ build: build-skit build-ui build-plugins test: test-skit test-ui # Lint all code -lint: lint-skit lint-ui lint-plugins check-license-headers +lint: lint-skit lint-ui lint-plugins check-license-headers check-docker-workflow # Start full development environment (skit + frontend with hot reload) dev: install-ui diff --git a/scripts/check_docker_workflow.py b/scripts/check_docker_workflow.py new file mode 100644 index 000000000..47ded435c --- /dev/null +++ b/scripts/check_docker_workflow.py @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: © 2025 StreamKit Contributors +# +# SPDX-License-Identifier: MPL-2.0 + +from pathlib import Path +import re +import sys + + +WORKFLOW_PATH = Path(__file__).resolve().parents[1] / ".github/workflows/docker.yml" +EXPECTED_JOBS = { + "build-cpu": "/mnt/docker-cache/cpu", + "build-gpu": "/mnt/docker-cache/gpu", + "build-demo": "/mnt/docker-cache/demo", +} + + +def extract_job_blocks(workflow: str) -> dict[str, str]: + pattern = re.compile( + r"(?ms)^ (?Pbuild-cpu|build-gpu|build-demo):\n" + r"(?P.*?)(?=^ [A-Za-z0-9_-]+:\n|\Z)" + ) + return {match.group("job"): match.group("body") for match in pattern.finditer(workflow)} + + +def check_job(job: str, cache_path: str, block: str) -> list[str]: + checks = { + "setup-buildx step id": "id: buildx", + "explicit builder": "builder: ${{ steps.buildx.outputs.name }}", + "cache import": f"cache-from: type=local,src={cache_path}", + "cache export": f"cache-to: type=local,dest={cache_path},mode=max", + "cache directory preparation": f"mkdir -p {cache_path}", + } + return [f"{job}: missing {name}" for name, value in checks.items() if value not in block] + + +def main() -> int: + workflow = WORKFLOW_PATH.read_text() + blocks = extract_job_blocks(workflow) + errors = [ + f"{job}: job block not found" + for job in EXPECTED_JOBS + if job not in blocks + ] + for job, cache_path in EXPECTED_JOBS.items(): + if job in blocks: + errors.extend(check_job(job, cache_path, blocks[job])) + + if errors: + print("Docker workflow validation failed:", file=sys.stderr) + print("\n".join(f"- {error}" for error in errors), file=sys.stderr) + return 1 + + print("Docker workflow validation passed for build-cpu, build-gpu, and build-demo.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())