ci: build every template's image independently, skip only failed ones
Fixes a regression where the whole provision job (all 6 templates) was skipped whenever build-web-image failed, since Actions skips a job whose needs: dependency failed by default. Generalizes the single web-image build step into a loop over every templates/*/Dockerfile, building and pushing each independently so one failure doesn't block the rest, and reports failures via a job output. provision now runs unconditionally (if: always()) and skips pushing only the specific template(s) whose image build failed this run, leaving their previous working version in place instead of pushing one with no matching registry tag.
This commit is contained in:
@@ -14,18 +14,25 @@ name: Provision Coder Templates
|
|||||||
# CODER_SESSION_TOKEN a token from `coder tokens create`, ideally under a
|
# CODER_SESSION_TOKEN a token from `coder tokens create`, ideally under a
|
||||||
# dedicated service account rather than a personal one
|
# dedicated service account rather than a personal one
|
||||||
# GITEA_PACKAGE_TOKEN a Gitea access token (user Settings > Applications)
|
# GITEA_PACKAGE_TOKEN a Gitea access token (user Settings > Applications)
|
||||||
# with write:package scope, for pushing templates/web's
|
# with write:package scope, for pushing each
|
||||||
# image to this instance's container registry. Only
|
# Dockerfile-having template's image to this
|
||||||
# the octoturge account's own token is used - login()
|
# instance's container registry. Only the octoturge
|
||||||
|
# account's own token is used - docker login below
|
||||||
# hardcodes that username to match.
|
# hardcodes that username to match.
|
||||||
#
|
#
|
||||||
# templates/web builds its Docker image here (build-web-image, on the
|
# Any templates/<env>/ that has its own Dockerfile gets its image built and
|
||||||
# dedicated "docker-build" runner - see templates/web/main.tf for why: that
|
# pushed here (build-images, on the dedicated "docker-build" runner - see
|
||||||
# runner is scoped to this repo only and has host Docker socket access that
|
# templates/web/main.tf for why: that runner is scoped to this repo only and
|
||||||
# the shared runner-1 deliberately doesn't). provision then just pulls the
|
# has host Docker socket access that the shared runner-1 deliberately
|
||||||
# tag build-web-image produced, instead of building it itself at
|
# doesn't). provision then just pulls the tag build-images produced, instead
|
||||||
# `terraform apply` time - keeps the slow Rust toolchain compile off of
|
# of building it itself at `terraform apply` time - keeps a slow toolchain
|
||||||
# "someone is waiting to create a workspace".
|
# compile off of "someone is waiting to create a workspace".
|
||||||
|
#
|
||||||
|
# Each template's image is built independently - one Dockerfile failing to
|
||||||
|
# build doesn't stop the others from building, and provision skips pushing
|
||||||
|
# only the specific template(s) whose image build failed this run (leaving
|
||||||
|
# their previous, already-working Coder template version in place) rather
|
||||||
|
# than skipping every template or pushing one with no matching image.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -36,35 +43,62 @@ on:
|
|||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-web-image:
|
build-images:
|
||||||
# The docker-build runner's docker_host: "" setting already auto-injects
|
# The docker-build runner's docker_host: "" setting already auto-injects
|
||||||
# /var/run/docker.sock into job containers - an explicit
|
# /var/run/docker.sock into job containers - an explicit
|
||||||
# container.volumes mount for the same path here fails at container
|
# container.volumes mount for the same path here fails at container
|
||||||
# creation with "Duplicate mount point: /var/run/docker.sock".
|
# creation with "Duplicate mount point: /var/run/docker.sock".
|
||||||
runs-on: docker-build
|
runs-on: docker-build
|
||||||
|
outputs:
|
||||||
|
failed_templates: ${{ steps.build.outputs.failed_templates }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build and push templates/web's image (skips if the tag already exists)
|
- name: Build and push every template's image (skips a tag that's already in the registry)
|
||||||
|
id: build
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
TAG="$(sha1sum templates/web/Dockerfile | cut -d' ' -f1)"
|
|
||||||
IMAGE="git.octoturge.com/octo-tech/profiles-web:${TAG}"
|
|
||||||
echo "${{ secrets.GITEA_PACKAGE_TOKEN }}" | docker login git.octoturge.com -u octoturge --password-stdin
|
echo "${{ secrets.GITEA_PACKAGE_TOKEN }}" | docker login git.octoturge.com -u octoturge --password-stdin
|
||||||
|
|
||||||
|
FAILED=""
|
||||||
|
for dockerfile in templates/*/Dockerfile; do
|
||||||
|
[ -e "$dockerfile" ] || continue
|
||||||
|
dir="$(dirname "$dockerfile")"
|
||||||
|
name="$(basename "$dir")"
|
||||||
|
TAG="$(sha1sum "$dockerfile" | cut -d' ' -f1)"
|
||||||
|
IMAGE="git.octoturge.com/octo-tech/profiles-${name}:${TAG}"
|
||||||
|
|
||||||
|
echo "::group::${name}"
|
||||||
if docker manifest inspect "$IMAGE" >/dev/null 2>&1; then
|
if docker manifest inspect "$IMAGE" >/dev/null 2>&1; then
|
||||||
echo "$IMAGE already in the registry (Dockerfile unchanged), skipping build."
|
echo "$IMAGE already in the registry (Dockerfile unchanged), skipping build."
|
||||||
exit 0
|
elif docker build -t "$IMAGE" "$dir" && docker push "$IMAGE"; then
|
||||||
|
echo "Built and pushed $IMAGE"
|
||||||
|
else
|
||||||
|
echo "::warning::Failed to build/push $IMAGE - templates/$name will be skipped this run."
|
||||||
|
FAILED="$FAILED $name"
|
||||||
fi
|
fi
|
||||||
docker build -t "$IMAGE" templates/web
|
echo "::endgroup::"
|
||||||
docker push "$IMAGE"
|
done
|
||||||
|
|
||||||
|
echo "failed_templates=${FAILED# }" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
provision:
|
provision:
|
||||||
needs: build-web-image
|
# needs: build-images orders this after the image builds (so a fresh
|
||||||
|
# template push never points at a tag that isn't in the registry yet)
|
||||||
|
# without making every template's reprovisioning depend on ALL builds
|
||||||
|
# succeeding - if:always() overrides the default "skip if a dependency
|
||||||
|
# failed" behavior, since build-images only fails outright on an
|
||||||
|
# infra-level problem (e.g. registry login); a single template's build
|
||||||
|
# failure is reported via failed_templates instead and only skips that
|
||||||
|
# one template below.
|
||||||
|
needs: build-images
|
||||||
|
if: always()
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
CODER_URL: ${{ secrets.CODER_URL }}
|
CODER_URL: ${{ secrets.CODER_URL }}
|
||||||
CODER_SESSION_TOKEN: ${{ secrets.CODER_SESSION_TOKEN }}
|
CODER_SESSION_TOKEN: ${{ secrets.CODER_SESSION_TOKEN }}
|
||||||
|
FAILED_TEMPLATES: ${{ needs.build-images.outputs.failed_templates }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout (full history, needed to detect removed templates)
|
- name: Checkout (full history, needed to detect removed templates)
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -81,9 +115,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
for dir in templates/*/; do
|
for dir in templates/*/; do
|
||||||
name="profiles-$(basename "$dir")"
|
name="$(basename "$dir")"
|
||||||
echo "::group::Pushing $name from $dir"
|
full="profiles-$name"
|
||||||
coder templates push "$name" -d "$dir" --yes \
|
case " $FAILED_TEMPLATES " in
|
||||||
|
*" $name "*)
|
||||||
|
echo "::warning::Skipping $full - its Docker image failed to build this run (see build-images), leaving the previous template version in place."
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "::group::Pushing $full from $dir"
|
||||||
|
coder templates push "$full" -d "$dir" --yes \
|
||||||
-m "auto-provisioned from ${GITHUB_SHA:0:12}"
|
-m "auto-provisioned from ${GITHUB_SHA:0:12}"
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
done
|
done
|
||||||
|
|||||||
Reference in New Issue
Block a user