Skip to content

ci: speed up PR deploys by decoupling from standard image build#649

Merged
mjh1 merged 3 commits intomainfrom
tessa/speed-up-pr-deploy
Mar 10, 2026
Merged

ci: speed up PR deploys by decoupling from standard image build#649
mjh1 merged 3 commits intomainfrom
tessa/speed-up-pr-deploy

Conversation

@livepeer-tessa
Copy link
Contributor

@livepeer-tessa livepeer-tessa commented Mar 10, 2026

Summary

Splits the docker build matrix into separate jobs so deploy-pr only waits for the cloud image build.

Problem

Currently deploy-pr has needs: build-and-push, which waits for the entire matrix to complete:

  • Cloud image: ~3 minutes
  • Standard image: ~12 minutes

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 by deploy-pr
  • build-standard — slower (~12 min), runs in parallel

Now deploy-pr has needs: build-cloud and proceeds as soon as the cloud build completes.

Impact

Before After
PR deploy waits ~12 min PR deploy waits ~3 min
E2E tests start after ~12 min E2E tests start after ~3 min

Standard image still builds (for releases/main) but no longer blocks the PR feedback loop.

Changes

  • Split build-and-push matrix into build-cloud and build-standard jobs
  • deploy-pr now depends only on build-cloud
  • Updated output references from build-and-pushbuild-cloud

Summary by CodeRabbit

  • Chores
    • Introduced modular, reusable CI workflows to build and push Docker images.
    • Added a dedicated reusable workflow to compute image tags, attach OCI metadata, and export short commit and PR identifiers for downstream steps.
    • Replaced matrix-based build with variant-specific reusable invocations; PR deploy now consumes build outputs (short SHA, PR number).
    • Reduced CI permissions and simplified tag logic.

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 10bfe626-7cb2-4af0-8c4d-4e0eacc3ecab

📥 Commits

Reviewing files that changed from the base of the PR and between 607726c and d5b000f.

📒 Files selected for processing (1)
  • .github/workflows/docker-build-image.yml

📝 Walkthrough

Walkthrough

Adds a new reusable GitHub Actions workflow at .github/workflows/docker-build-image.yml to build and push Docker images with parameterized inputs/outputs; refactors .github/workflows/docker-build.yml to call the reusable workflow for cloud and standard variants and to consume its outputs for PR deployment.

Changes

Cohort / File(s) Summary
New Reusable Docker Build Workflow
.github/workflows/docker-build-image.yml
Adds a reusable workflow (workflow_call) with inputs variant, suffix, dockerfile, description and outputs short_sha, pr_number. Sets up Buildx, logs into Docker Hub and GHCR, computes build metadata and dynamic tags for different event types, builds and pushes OCI-labeled images, and exposes pushed tags/metadata.
Refactored Main Build Workflow
.github/workflows/docker-build.yml
Replaces in-workflow matrix build-and-push with two invocations of the reusable workflow (cloud and standard). Updates deploy-pr and downstream steps to consume needs.build-cloud.outputs for short_sha and pr_number, simplifies tag handling, and adjusts permissions and PR-related messaging to use the reusable workflow outputs.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hopped through YAML with a joyful spring,

Built images bright and set them wing.
Inputs tidy, outputs clear,
Pushed my tags far and near.
🥕🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: decoupling PR deploys from the standard image build to reduce deployment time by eliminating the wait for a non-critical build step.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tessa/speed-up-pr-deploy

Comment @coderabbitai help to get the list of available commands and usage tips.

@mjh1 mjh1 self-requested a review March 10, 2026 15:23
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>
@livepeer-tessa livepeer-tessa force-pushed the tessa/speed-up-pr-deploy branch from a994f03 to ea8de1f Compare March 10, 2026 15:24
@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

🚀 fal.ai Preview Deployment

App ID daydream/scope-pr-649--preview
WebSocket wss://fal.run/daydream/scope-pr-649--preview/ws
Commit d5b000f

Testing

Connect to this preview deployment by running this on your branch:

uv run build && SCOPE_CLOUD_APP_ID="daydream/scope-pr-649--preview/ws" uv run daydream-scope

🧪 E2E tests will run automatically against this deployment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/docker-build.yml (1)

31-39: Consider gating build-standard off 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

📥 Commits

Reviewing files that changed from the base of the PR and between dbaa335 and ea8de1f.

📒 Files selected for processing (2)
  • .github/workflows/docker-build-image.yml
  • .github/workflows/docker-build.yml

Comment on lines +79 to +109
- 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

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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 -C2

Repository: 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.

Suggested change
- 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>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

✅ E2E Tests passed

Status passed
fal App daydream/scope-pr-649--preview
Run View logs

Test Artifacts

Check the workflow run for screenshots.

Signed-off-by: Max Holland <max@livepeer.org>
@mjh1 mjh1 merged commit 5d1800b into main Mar 10, 2026
7 of 8 checks passed
@mjh1 mjh1 deleted the tessa/speed-up-pr-deploy branch March 10, 2026 16:06
@coderabbitai coderabbitai bot mentioned this pull request Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants