perf(ci): pull from GHCR when image exists instead of just skipping

When a base or app image already exists in GHCR, pull it to the local
runner rather than exiting after the manifest check. This makes the
image immediately available for any downstream steps (security scanning,
smoke tests, dependent builds) without a rebuild.

Flow per image job:
  exists=true  → docker pull <image>:<branch> (fast, ~seconds)
  exists=false → full build + push to GHCR

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 22:31:45 +00:00
parent 0d7e7faf9c
commit 199a33c8c4

View File

@@ -1421,6 +1421,12 @@ jobs:
echo "Image $IMAGE not found — will build"
fi
- name: Pull existing image from GHCR
if: steps.check.outputs.exists == 'true'
shell: bash
run: |
docker pull "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}"
- name: Extract metadata (tags, labels)
id: meta
if: steps.check.outputs.exists != 'true'
@@ -1446,7 +1452,9 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.image }}
cache-from: |
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}
type=gha,scope=${{ matrix.image }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}
build-args: |
BUILD_DATE=${{ github.event.head_commit.timestamp || github.run_started_at }}
@@ -1506,6 +1514,12 @@ jobs:
echo "Image $IMAGE not found — will build"
fi
- name: Pull existing image from GHCR
if: steps.check.outputs.exists == 'true'
shell: bash
run: |
docker pull "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}"
- name: Extract metadata (tags, labels)
id: meta
if: steps.check.outputs.exists != 'true'
@@ -1531,7 +1545,9 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.image }}
cache-from: |
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}
type=gha,scope=${{ matrix.image }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}
build-args: |
BASE_REGISTRY=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
@@ -1569,8 +1585,28 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check if image already exists in GHCR
id: check
shell: bash
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/devcontainer:${{ github.ref_name }}"
if docker manifest inspect "$IMAGE" > /dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "Image $IMAGE already exists — skipping build"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "Image $IMAGE not found — will build"
fi
- name: Pull existing image from GHCR
if: steps.check.outputs.exists == 'true'
shell: bash
run: |
docker pull "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/devcontainer:${{ github.ref_name }}"
- name: Extract metadata (tags, labels)
id: meta
if: steps.check.outputs.exists != 'true'
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/devcontainer
@@ -1584,6 +1620,7 @@ jobs:
- name: Build and push Docker image
id: build
if: steps.check.outputs.exists != 'true'
uses: docker/build-push-action@v6
with:
context: .
@@ -1592,7 +1629,9 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=devcontainer
cache-from: |
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/devcontainer:${{ github.ref_name }}
type=gha,scope=devcontainer
cache-to: type=gha,mode=max,scope=devcontainer
build-args: |
BASE_REGISTRY=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
@@ -1600,6 +1639,7 @@ jobs:
VCS_REF=${{ github.sha }}
- name: Generate artifact attestation
if: steps.check.outputs.exists != 'true'
uses: actions/attest-build-provenance@v4
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/devcontainer
@@ -1657,8 +1697,28 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check if image already exists in GHCR
id: check
shell: bash
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}"
if docker manifest inspect "$IMAGE" > /dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "Image $IMAGE already exists — skipping build"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "Image $IMAGE not found — will build"
fi
- name: Pull existing image from GHCR
if: steps.check.outputs.exists == 'true'
shell: bash
run: |
docker pull "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}"
- name: Extract metadata (tags, labels)
id: meta
if: steps.check.outputs.exists != 'true'
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}
@@ -1672,6 +1732,7 @@ jobs:
- name: Build and push Docker image
id: build
if: steps.check.outputs.exists != 'true'
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
@@ -1679,7 +1740,9 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.image }}
cache-from: |
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}:${{ github.ref_name }}
type=gha,scope=${{ matrix.image }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}
build-args: |
BASE_REGISTRY=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
@@ -1688,6 +1751,7 @@ jobs:
VERSION=${{ steps.meta.outputs.version }}
- name: Generate artifact attestation
if: steps.check.outputs.exists != 'true'
uses: actions/attest-build-provenance@v4
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }}