diff --git a/.gitea/workflows/coder-templates.yml b/.gitea/workflows/coder-templates.yml index 9c9c662..7f2356f 100644 --- a/.gitea/workflows/coder-templates.yml +++ b/.gitea/workflows/coder-templates.yml @@ -14,18 +14,25 @@ name: Provision Coder Templates # CODER_SESSION_TOKEN a token from `coder tokens create`, ideally under a # dedicated service account rather than a personal one # GITEA_PACKAGE_TOKEN a Gitea access token (user Settings > Applications) -# with write:package scope, for pushing templates/web's -# image to this instance's container registry. Only -# the octoturge account's own token is used - login() +# with write:package scope, for pushing each +# Dockerfile-having template's image to this +# instance's container registry. Only the octoturge +# account's own token is used - docker login below # hardcodes that username to match. # -# templates/web builds its Docker image here (build-web-image, on the -# dedicated "docker-build" runner - see templates/web/main.tf for why: that -# runner is scoped to this repo only and has host Docker socket access that -# the shared runner-1 deliberately doesn't). provision then just pulls the -# tag build-web-image produced, instead of building it itself at -# `terraform apply` time - keeps the slow Rust toolchain compile off of -# "someone is waiting to create a workspace". +# Any templates// that has its own Dockerfile gets its image built and +# pushed here (build-images, on the dedicated "docker-build" runner - see +# templates/web/main.tf for why: that runner is scoped to this repo only and +# has host Docker socket access that the shared runner-1 deliberately +# doesn't). provision then just pulls the tag build-images produced, instead +# of building it itself at `terraform apply` time - keeps a slow toolchain +# 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: push: @@ -36,35 +43,62 @@ on: workflow_dispatch: {} jobs: - build-web-image: + build-images: # The docker-build runner's docker_host: "" setting already auto-injects # /var/run/docker.sock into job containers - an explicit # container.volumes mount for the same path here fails at container # creation with "Duplicate mount point: /var/run/docker.sock". runs-on: docker-build + outputs: + failed_templates: ${{ steps.build.outputs.failed_templates }} steps: - name: Checkout 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: | 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 - if docker manifest inspect "$IMAGE" >/dev/null 2>&1; then - echo "$IMAGE already in the registry (Dockerfile unchanged), skipping build." - exit 0 - fi - docker build -t "$IMAGE" templates/web - docker push "$IMAGE" + + 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 + echo "$IMAGE already in the registry (Dockerfile unchanged), skipping build." + 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 + echo "::endgroup::" + done + + echo "failed_templates=${FAILED# }" >> "$GITHUB_OUTPUT" 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 env: CODER_URL: ${{ secrets.CODER_URL }} CODER_SESSION_TOKEN: ${{ secrets.CODER_SESSION_TOKEN }} + FAILED_TEMPLATES: ${{ needs.build-images.outputs.failed_templates }} steps: - name: Checkout (full history, needed to detect removed templates) uses: actions/checkout@v4 @@ -81,9 +115,16 @@ jobs: run: | set -e for dir in templates/*/; do - name="profiles-$(basename "$dir")" - echo "::group::Pushing $name from $dir" - coder templates push "$name" -d "$dir" --yes \ + name="$(basename "$dir")" + full="profiles-$name" + 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}" echo "::endgroup::" done