Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ on:
description: "Version to tag when tag_with_version=true"
type: string
required: false
experimental:
description: "Build experimental image (main branch excluded)"
type: boolean
default: false

permissions:
contents: read
Expand Down Expand Up @@ -165,28 +169,37 @@ jobs:
DIGEST_LIST="${DIGEST_LIST} ${IMAGE}@${digest}"
done

# Create manifest for latest
docker buildx imagetools create -t "${IMAGE}:latest" ${DIGEST_LIST}

# Create manifest for SHA
docker buildx imagetools create -t "${IMAGE}:${FULL_SHA}" ${DIGEST_LIST}

# Create manifest for version if needed
if [ "${{ inputs.tag_with_version }}" = "true" ] && [ -n "${{ inputs.version }}" ]; then
docker buildx imagetools create -t "${IMAGE}:v${{ inputs.version }}" ${DIGEST_LIST}
if [ "${{ inputs.experimental }}" = "true" ]; then
# Experimental mode: only tag with commithash-experimental
docker buildx imagetools create -t "${IMAGE}:${FULL_SHA}-experimental" ${DIGEST_LIST}
else
# Standard mode: tag with latest and SHA
docker buildx imagetools create -t "${IMAGE}:latest" ${DIGEST_LIST}
docker buildx imagetools create -t "${IMAGE}:${FULL_SHA}" ${DIGEST_LIST}

# Create manifest for version if needed
if [ "${{ inputs.tag_with_version }}" = "true" ] && [ -n "${{ inputs.version }}" ]; then
docker buildx imagetools create -t "${IMAGE}:v${{ inputs.version }}" ${DIGEST_LIST}
fi
fi

- name: Output Image Information
run: |
IMAGE="${{ inputs.image }}"
NAME="${IMAGE##*/}"
FULL_SHA=$(git rev-parse HEAD)
TAGS="latest, ${FULL_SHA}"
if [ "${{ inputs.tag_with_version }}" = "true" ] && [ -n "${{ inputs.version }}" ]; then
TAGS="${TAGS}, v${{ inputs.version }}"
if [ "${{ inputs.experimental }}" = "true" ]; then
TAGS="${FULL_SHA}-experimental"
MODE="experimental"
else
TAGS="latest, ${FULL_SHA}"
MODE="standard"
if [ "${{ inputs.tag_with_version }}" = "true" ] && [ -n "${{ inputs.version }}" ]; then
TAGS="${TAGS}, v${{ inputs.version }}"
fi
fi
HUB_PATH=$(echo "${IMAGE}" | sed -E 's@^docker\.io/@@')
echo "✅ Successfully built and pushed ${NAME} multi-arch image"
echo "✅ Successfully built and pushed ${NAME} multi-arch image (${MODE} mode)"
echo "🏷️ Tags: ${TAGS}"
echo "🏗️ Platforms: linux/amd64, linux/arm64"
echo "🔗 View at: https://hub.docker.com/r/${HUB_PATH}"
61 changes: 54 additions & 7 deletions .github/workflows/docker-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ on:
description: "Git ref to build (branch, tag, or SHA)"
type: string
required: false
experimental:
description: "Build experimental image (main branch excluded)"
type: boolean
required: false
default: false

permissions:
contents: read
Expand All @@ -29,7 +34,7 @@ jobs:
EVENT_NAME="${GITHUB_EVENT_NAME}"
MERGE_SHA=$(jq -r '.pull_request.merge_commit_sha // empty' "$GITHUB_EVENT_PATH")
INPUT_REF=$(jq -r '.inputs.ref // empty' "$GITHUB_EVENT_PATH")

if [[ "$EVENT_NAME" == "pull_request" && -n "$MERGE_SHA" ]]; then
REF="$MERGE_SHA"
elif [[ -n "$INPUT_REF" ]]; then
Expand All @@ -38,18 +43,59 @@ jobs:
echo "Error: no merge commit or input ref provided" >&2
exit 1
fi

echo "ref=$REF" >> "$GITHUB_OUTPUT"

validate-experimental:
name: Validate Experimental Build
needs: resolve-ref
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.experimental == true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ needs.resolve-ref.outputs.ref }}
fetch-depth: 0

- name: Check if building from main branch
run: |
set -euo pipefail

# Get the current commit SHA
CURRENT_SHA=$(git rev-parse HEAD)

# Get the main branch SHA
MAIN_SHA=$(git rev-parse origin/main)
Comment on lines +66 to +69

Choose a reason for hiding this comment

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

P1 Badge Fetch main ref before comparing SHAs

The experimental gate relies on git rev-parse origin/main to detect builds from the default branch, but the preceding checkout only fetches the requested ref. On a workflow_dispatch run for a feature branch, the remote reference origin/main is not guaranteed to exist, so git rev-parse origin/main can fail with “unknown revision” and abort the job even when the ref is valid. Fetch origin main (or compare against refs/remotes/origin/main after an explicit fetch) before running this check so experimental builds don’t fail immediately.

Useful? React with 👍 / 👎.


# Check if we're on main
if [[ "$CURRENT_SHA" == "$MAIN_SHA" ]]; then
echo "❌ Error: Cannot build experimental images from the main branch"
echo "Experimental images are meant for pre-merge testing only"
exit 1
fi

# Also check if the ref input was explicitly 'main'
INPUT_REF=$(jq -r '.inputs.ref // empty' "$GITHUB_EVENT_PATH")
if [[ "$INPUT_REF" == "main" ]]; then
echo "❌ Error: Cannot build experimental images from 'main' ref"
echo "Experimental images are meant for pre-merge testing only"
exit 1
fi

echo "✅ Validation passed: building experimental image from non-main branch"

build:
name: Build and Push Images
needs: resolve-ref
needs: [resolve-ref, validate-experimental]
# Run only when the PR is merged and is NOT a release PR, or manual run.
if: |
github.event_name == 'workflow_dispatch' || (
github.event_name == 'pull_request' &&
github.event.pull_request.merged == true &&
!contains(github.event.pull_request.labels.*.name, 'release')
(success() || needs.validate-experimental.result == 'skipped') && (
github.event_name == 'workflow_dispatch' || (
github.event_name == 'pull_request' &&
github.event.pull_request.merged == true &&
!contains(github.event.pull_request.labels.*.name, 'release')
)
)
strategy:
matrix:
Expand All @@ -62,5 +108,6 @@ jobs:
file: ./${{ matrix.image }}/Dockerfile
push: true
tag_with_version: false
experimental: ${{ github.event_name == 'workflow_dispatch' && inputs.experimental || false }}
# Build from the resolved ref: merge commit for PRs, or provided ref, fallback to current SHA.
checkout_ref: ${{ needs.resolve-ref.outputs.ref }}
Loading