ci: speed up PR deploys by decoupling from standard image build#649
ci: speed up PR deploys by decoupling from standard image build#649
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a new reusable GitHub Actions workflow at Changes
Sequence Diagram(s)sequenceDiagram
participant Caller as GitHub Actions (caller)
participant Reusable as docker-build-image.yml (reusable wf)
participant Runner as Actions Runner
participant Buildx as Docker Buildx
participant DockerHub as Docker Hub
participant GHCR as GHCR
Caller->>Reusable: workflow_call(inputs: variant, suffix, dockerfile, description)
Reusable->>Runner: checkout, setup buildx, cleanup caches
Runner->>Buildx: build image with computed tags & OCI labels
Buildx->>DockerHub: push image tags
Buildx->>GHCR: push image tags
Runner-->>Reusable: return outputs (short_sha, pr_number, pushed_tags)
Reusable-->>Caller: outputs available to downstream jobs
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Extract shared docker build logic into a reusable workflow (docker-build-image.yml) to eliminate duplication. - build-cloud and build-standard now call the same reusable workflow - deploy-pr only waits for build-cloud (~3min vs ~12min) - Standard image still builds in parallel for releases Before: deploy-pr waited ~12 min (both images) After: deploy-pr waits ~3 min (cloud only) Signed-off-by: livepeer-robot <robot@livepeer.org>
a994f03 to
ea8de1f
Compare
🚀 fal.ai Preview Deployment
TestingConnect to this preview deployment by running this on your branch: 🧪 E2E tests will run automatically against this deployment. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/workflows/docker-build.yml (1)
31-39: Consider gatingbuild-standardoff PRs if it isn't needed for PR signal.This would reduce CI runtime/cost further while preserving the fast deploy path.
Optional tweak
build-standard: + if: github.event_name != 'pull_request' uses: ./.github/workflows/docker-build-image.yml with: variant: standard🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/docker-build.yml around lines 31 - 39, The build job named "build-standard" is currently run on PRs; gate it so it doesn't run for pull_request events by adding a conditional on the job (e.g., set if: github.event_name != 'pull_request' or a more specific expression) to the "build-standard" job declaration in .github/workflows/docker-build.yml so CI skips this job for PRs while preserving runs for pushes/other events.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/docker-build-image.yml:
- Around line 79-109: The Set image tag step currently interpolates
github.head_ref directly into the shell and uses a permissive sed; change it to
pass github.head_ref into the step via env (e.g., GITHUB_HEAD_REF) and compute
BRANCH_TAG from that env var, applying a stricter sanitization that only allows
Docker-safe characters [A-Za-z0-9_.-] (replace or remove any other characters
and collapse sequences to a single dash or underscore as desired), then use
BRANCH_TAG and SHORT_SHA as before when building TAGS and echoing to
GITHUB_OUTPUT; update the step that defines BRANCH_TAG and SHORT_SHA (the
branch/pull_request branch handling block) to use the env-sourced value and the
new regex-based sanitization.
---
Nitpick comments:
In @.github/workflows/docker-build.yml:
- Around line 31-39: The build job named "build-standard" is currently run on
PRs; gate it so it doesn't run for pull_request events by adding a conditional
on the job (e.g., set if: github.event_name != 'pull_request' or a more specific
expression) to the "build-standard" job declaration in
.github/workflows/docker-build.yml so CI skips this job for PRs while preserving
runs for pushes/other events.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d763dce5-a9fc-43bc-adc1-8a6e7c6692ec
📒 Files selected for processing (2)
.github/workflows/docker-build-image.yml.github/workflows/docker-build.yml
| - name: Set image tag | ||
| id: tag | ||
| run: | | ||
| DOCKERHUB="daydreamlive/scope" | ||
| GHCR="ghcr.io/daydreamlive/scope" | ||
| SUFFIX="${{ inputs.suffix }}" | ||
|
|
||
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | ||
| VERSION="${{ github.event.inputs.version }}" | ||
| TAGS="$DOCKERHUB:$VERSION$SUFFIX,$DOCKERHUB:latest$SUFFIX" | ||
| TAGS="$TAGS,$GHCR:$VERSION$SUFFIX,$GHCR:latest$SUFFIX" | ||
| elif [[ "${{ github.ref }}" == refs/tags/* ]]; then | ||
| VERSION_TAG="${{ github.ref_name }}" | ||
| VERSION="${VERSION_TAG#v}" | ||
| TAGS="$DOCKERHUB:$VERSION$SUFFIX,$DOCKERHUB:latest$SUFFIX" | ||
| TAGS="$TAGS,$GHCR:$VERSION$SUFFIX,$GHCR:latest$SUFFIX" | ||
| elif [ "${{ github.ref }}" == "refs/heads/main" ]; then | ||
| SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) | ||
| TAGS="$DOCKERHUB:main$SUFFIX,$DOCKERHUB:$SHORT_SHA$SUFFIX" | ||
| TAGS="$TAGS,$GHCR:main$SUFFIX,$GHCR:$SHORT_SHA$SUFFIX" | ||
| elif [ "${{ github.ref }}" == "refs/heads/runpod-serverless" ]; then | ||
| TAGS="$DOCKERHUB:runpod-serverless$SUFFIX" | ||
| TAGS="$TAGS,$GHCR:runpod-serverless$SUFFIX" | ||
| elif [ "${{ github.event_name }}" == "pull_request" ]; then | ||
| BRANCH_TAG=$(echo "${{ github.head_ref }}" | sed 's/\//-/g') | ||
| SHORT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7) | ||
| TAGS="$DOCKERHUB:$BRANCH_TAG$SUFFIX,$DOCKERHUB:$SHORT_SHA$SUFFIX" | ||
| TAGS="$TAGS,$GHCR:$BRANCH_TAG$SUFFIX,$GHCR:$SHORT_SHA$SUFFIX" | ||
| fi | ||
| echo "tags=$TAGS" >> $GITHUB_OUTPUT | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify no direct github.head_ref interpolation remains in workflow shell scripts.
rg -nP '\$\{\{\s*github\.head_ref\s*\}\}' .github/workflows -C2Repository: daydreamlive/scope
Length of output: 649
Use env to pass github.head_ref and apply stricter Docker tag sanitization.
Line 103 directly interpolates an untrusted pull request value into the shell script. Pass it via env and replace the sed pattern with a stricter regex that only permits Docker-safe characters (alphanumeric, underscore, period, dash).
Proposed fix
- name: Set image tag
id: tag
+ env:
+ HEAD_REF: ${{ github.head_ref }}
run: |
DOCKERHUB="daydreamlive/scope"
GHCR="ghcr.io/daydreamlive/scope"
SUFFIX="${{ inputs.suffix }}"
@@
elif [ "${{ github.event_name }}" == "pull_request" ]; then
- BRANCH_TAG=$(echo "${{ github.head_ref }}" | sed 's/\//-/g')
+ BRANCH_TAG=$(echo "$HEAD_REF" | sed 's#[^[:alnum:]_.-]#-#g')
SHORT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7)
TAGS="$DOCKERHUB:$BRANCH_TAG$SUFFIX,$DOCKERHUB:$SHORT_SHA$SUFFIX"
TAGS="$TAGS,$GHCR:$BRANCH_TAG$SUFFIX,$GHCR:$SHORT_SHA$SUFFIX"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Set image tag | |
| id: tag | |
| run: | | |
| DOCKERHUB="daydreamlive/scope" | |
| GHCR="ghcr.io/daydreamlive/scope" | |
| SUFFIX="${{ inputs.suffix }}" | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| TAGS="$DOCKERHUB:$VERSION$SUFFIX,$DOCKERHUB:latest$SUFFIX" | |
| TAGS="$TAGS,$GHCR:$VERSION$SUFFIX,$GHCR:latest$SUFFIX" | |
| elif [[ "${{ github.ref }}" == refs/tags/* ]]; then | |
| VERSION_TAG="${{ github.ref_name }}" | |
| VERSION="${VERSION_TAG#v}" | |
| TAGS="$DOCKERHUB:$VERSION$SUFFIX,$DOCKERHUB:latest$SUFFIX" | |
| TAGS="$TAGS,$GHCR:$VERSION$SUFFIX,$GHCR:latest$SUFFIX" | |
| elif [ "${{ github.ref }}" == "refs/heads/main" ]; then | |
| SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) | |
| TAGS="$DOCKERHUB:main$SUFFIX,$DOCKERHUB:$SHORT_SHA$SUFFIX" | |
| TAGS="$TAGS,$GHCR:main$SUFFIX,$GHCR:$SHORT_SHA$SUFFIX" | |
| elif [ "${{ github.ref }}" == "refs/heads/runpod-serverless" ]; then | |
| TAGS="$DOCKERHUB:runpod-serverless$SUFFIX" | |
| TAGS="$TAGS,$GHCR:runpod-serverless$SUFFIX" | |
| elif [ "${{ github.event_name }}" == "pull_request" ]; then | |
| BRANCH_TAG=$(echo "${{ github.head_ref }}" | sed 's/\//-/g') | |
| SHORT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7) | |
| TAGS="$DOCKERHUB:$BRANCH_TAG$SUFFIX,$DOCKERHUB:$SHORT_SHA$SUFFIX" | |
| TAGS="$TAGS,$GHCR:$BRANCH_TAG$SUFFIX,$GHCR:$SHORT_SHA$SUFFIX" | |
| fi | |
| echo "tags=$TAGS" >> $GITHUB_OUTPUT | |
| - name: Set image tag | |
| id: tag | |
| env: | |
| HEAD_REF: ${{ github.head_ref }} | |
| run: | | |
| DOCKERHUB="daydreamlive/scope" | |
| GHCR="ghcr.io/daydreamlive/scope" | |
| SUFFIX="${{ inputs.suffix }}" | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| TAGS="$DOCKERHUB:$VERSION$SUFFIX,$DOCKERHUB:latest$SUFFIX" | |
| TAGS="$TAGS,$GHCR:$VERSION$SUFFIX,$GHCR:latest$SUFFIX" | |
| elif [[ "${{ github.ref }}" == refs/tags/* ]]; then | |
| VERSION_TAG="${{ github.ref_name }}" | |
| VERSION="${VERSION_TAG#v}" | |
| TAGS="$DOCKERHUB:$VERSION$SUFFIX,$DOCKERHUB:latest$SUFFIX" | |
| TAGS="$TAGS,$GHCR:$VERSION$SUFFIX,$GHCR:latest$SUFFIX" | |
| elif [ "${{ github.ref }}" == "refs/heads/main" ]; then | |
| SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) | |
| TAGS="$DOCKERHUB:main$SUFFIX,$DOCKERHUB:$SHORT_SHA$SUFFIX" | |
| TAGS="$TAGS,$GHCR:main$SUFFIX,$GHCR:$SHORT_SHA$SUFFIX" | |
| elif [ "${{ github.ref }}" == "refs/heads/runpod-serverless" ]; then | |
| TAGS="$DOCKERHUB:runpod-serverless$SUFFIX" | |
| TAGS="$TAGS,$GHCR:runpod-serverless$SUFFIX" | |
| elif [ "${{ github.event_name }}" == "pull_request" ]; then | |
| BRANCH_TAG=$(echo "$HEAD_REF" | sed 's#[^[:alnum:]_.-]#-#g') | |
| SHORT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7) | |
| TAGS="$DOCKERHUB:$BRANCH_TAG$SUFFIX,$DOCKERHUB:$SHORT_SHA$SUFFIX" | |
| TAGS="$TAGS,$GHCR:$BRANCH_TAG$SUFFIX,$GHCR:$SHORT_SHA$SUFFIX" | |
| fi | |
| echo "tags=$TAGS" >> $GITHUB_OUTPUT |
🧰 Tools
🪛 actionlint (1.7.11)
[error] 81-81: "github.head_ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/docker-build-image.yml around lines 79 - 109, The Set
image tag step currently interpolates github.head_ref directly into the shell
and uses a permissive sed; change it to pass github.head_ref into the step via
env (e.g., GITHUB_HEAD_REF) and compute BRANCH_TAG from that env var, applying a
stricter sanitization that only allows Docker-safe characters [A-Za-z0-9_.-]
(replace or remove any other characters and collapse sequences to a single dash
or underscore as desired), then use BRANCH_TAG and SHORT_SHA as before when
building TAGS and echoing to GITHUB_OUTPUT; update the step that defines
BRANCH_TAG and SHORT_SHA (the branch/pull_request branch handling block) to use
the env-sourced value and the new regex-based sanitization.
Reusable workflows inherit GITHUB_TOKEN permissions from the caller workflow, not from their own job-level permissions block. Move permissions to workflow level so the reusable workflow can request packages:write for pushing Docker images. Signed-off-by: livepeer-robot <robot@livepeer.org>
✅ E2E Tests passed
Test ArtifactsCheck the workflow run for screenshots. |
Signed-off-by: Max Holland <max@livepeer.org>
Summary
Splits the docker build matrix into separate jobs so
deploy-pronly waits for the cloud image build.Problem
Currently
deploy-prhasneeds: build-and-push, which waits for the entire matrix to complete:So PR deploys wait ~12 minutes even though they only need the cloud image.
Solution
Split into two independent jobs:
build-cloud— faster (~3 min), used bydeploy-prbuild-standard— slower (~12 min), runs in parallelNow
deploy-prhasneeds: build-cloudand proceeds as soon as the cloud build completes.Impact
Standard image still builds (for releases/main) but no longer blocks the PR feedback loop.
Changes
build-and-pushmatrix intobuild-cloudandbuild-standardjobsdeploy-prnow depends only onbuild-cloudbuild-and-push→build-cloudSummary by CodeRabbit