gate :latest tag and CloudFront deploy to GitHub's latest release; skip docker rebuild if it's in dockerhub already

This commit is contained in:
dovholuknf
2026-05-29 10:34:41 -04:00
parent 87a2591f65
commit 20c0e596e4
2 changed files with 39 additions and 10 deletions
+27 -6
View File
@@ -3,14 +3,14 @@ name: Release Quickstart Workflow
# CloudFront function for a given release tag.
#
# Triggers:
# - release: published (a GitHub release has been published, with its
# assets already uploaded)
# - release: published (new release published -> build + push the versioned image, move :latest, deploy CloudFront)
# - release: edited (e.g. "Latest release" moved -> re-point :latest and CloudFront only; the image is NOT rebuilt)
# - workflow_dispatch (manual; required `release_tag` input)
#
# Both jobs are idempotent and independently re-runnable from the Actions UI.
on:
release:
types: [published]
types: [published, edited]
workflow_dispatch:
inputs:
release_tag:
@@ -42,6 +42,7 @@ jobs:
tag: ${{ steps.resolve.outputs.tag }}
sha: ${{ steps.resolve.outputs.sha }}
is_latest: ${{ steps.resolve.outputs.is_latest }}
eligible: ${{ steps.resolve.outputs.eligible }}
steps:
- name: Resolve release tag and commit SHA
id: resolve
@@ -64,9 +65,12 @@ jobs:
fi
if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ERROR: release tag '${TAG}' is not a release semver (expected vMAJOR.MINOR.PATCH)" >&2
exit 1
echo "INFO: '${TAG}' is not a release semver (prerelease/draft/other edit); skipping image + CloudFront."
echo "eligible=false" | tee -a "$GITHUB_OUTPUT"
echo "is_latest=false" | tee -a "$GITHUB_OUTPUT"
exit 0
fi
echo "eligible=true" | tee -a "$GITHUB_OUTPUT"
# resolve the commit the tag points at; this is the snapshot we will
# check out for both jobs so the Dockerfile, routes.yml, and python
@@ -105,6 +109,13 @@ jobs:
# rename without updating that file too.
name: Release Quickstart Job
needs: resolve-tag
# eligible, AND (a manual dispatch, OR a publish, OR it's now the latest).
# A non-latest edit (e.g. a typo fix on an old release) skips the job entirely.
if: >-
needs.resolve-tag.outputs.eligible == 'true'
&& (github.event_name != 'release'
|| github.event.action == 'published'
|| needs.resolve-tag.outputs.is_latest == 'true')
runs-on: ubuntu-24.04
env:
ZITI_QUICKSTART_IMAGE: ${{ vars.ZITI_QUICKSTART_IMAGE || 'docker.io/openziti/quickstart' }}
@@ -132,6 +143,8 @@ jobs:
path: release-src
- name: Set Up QEMU
# only needed to build the multi-arch image; an edit just re-points :latest
if: ${{ !(github.event_name == 'release' && github.event.action == 'edited') }}
uses: docker/setup-qemu-action@v4
with:
platforms: amd64,arm64
@@ -159,11 +172,18 @@ jobs:
if [[ "${{ github.event.inputs.force_latest }}" == "true" ]]; then
FORCE_LATEST_FLAG="--force-latest"
fi
SKIP_BUILD_FLAG=""
if [[ "${{ github.event_name }}" == "release" && "${{ github.event.action }}" == "edited" ]]; then
# an edit (e.g. moving "Latest release") must not rebuild the image;
# only re-point :latest to the now-latest tag
SKIP_BUILD_FLAG="--skip-build"
fi
bash workflow-src/dist/scripts/release-quickstart-image.sh \
--tag "${{ needs.resolve-tag.outputs.tag }}" \
--image-repo "${ZITI_QUICKSTART_IMAGE}" \
--context-dir release-src/quickstart/docker/image \
${FORCE_LATEST_FLAG}
${FORCE_LATEST_FLAG} \
${SKIP_BUILD_FLAG}
release-quickstart-cloudfront:
name: Deploy get.openziti.io CloudFront Function
@@ -176,6 +196,7 @@ jobs:
# newest release should re-point it. Older maintenance releases skip.
if: >-
github.repository_owner == 'openziti'
&& needs.resolve-tag.outputs.eligible == 'true'
&& (needs.resolve-tag.outputs.is_latest == 'true' || github.event.inputs.force_cloudfront == 'true')
runs-on: ubuntu-24.04
steps:
+12 -4
View File
@@ -7,11 +7,13 @@
# - moves :latest only when this tag IS the GitHub "Latest release" (or when
# --force-latest is passed), AND :latest does not already point at the same
# digest as :vX.Y.Z
# - --skip-build skips the :vX.Y.Z build/push entirely and only (re)evaluates
# the :latest move; used when re-pointing :latest without rebuilding
#
# Designed to be safely re-runnable from CI or a developer laptop.
#
# Usage:
# release-quickstart-image.sh --tag vX.Y.Z [--image-repo R] [--force-latest] [--dry-run]
# release-quickstart-image.sh --tag vX.Y.Z [--image-repo R] [--force-latest] [--skip-build] [--dry-run]
#
# Required environment:
# - docker CLI with buildx + an active builder (workflow does this)
@@ -30,6 +32,7 @@ IMAGE_REPO="${ZITI_QUICKSTART_IMAGE:-docker.io/openziti/quickstart}"
FORCE_LATEST="false"
DRY_RUN="false"
CONTEXT_DIR=""
SKIP_BUILD="false"
usage() {
cat <<EOF
@@ -39,6 +42,7 @@ Options:
--tag vX.Y.Z Release tag to build the image for (required).
--image-repo R Image repo (default: \$ZITI_QUICKSTART_IMAGE or docker.io/openziti/quickstart).
--force-latest Move :latest to this tag even if GitHub does not mark this release as latest.
--skip-build Skip building/pushing the :vX.Y.Z image; only (re)evaluate the :latest move.
--dry-run Print actions but do not build or push.
--context-dir DIR Path to the Docker build context (default: repo-relative quickstart/docker/image).
-h, --help Show this help.
@@ -50,6 +54,7 @@ while [[ $# -gt 0 ]]; do
--tag) TAG="$2"; shift 2 ;;
--image-repo) IMAGE_REPO="$2"; shift 2 ;;
--force-latest) FORCE_LATEST="true"; shift ;;
--skip-build) SKIP_BUILD="true"; shift ;;
--dry-run) DRY_RUN="true"; shift ;;
--context-dir) CONTEXT_DIR="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
@@ -73,7 +78,7 @@ if [[ -z "$CONTEXT_DIR" ]]; then
CONTEXT_DIR="quickstart/docker/image"
fi
if [[ ! -d "$CONTEXT_DIR" ]]; then
if [[ "$SKIP_BUILD" != "true" && ! -d "$CONTEXT_DIR" ]]; then
echo "ERROR: build context dir not found: $CONTEXT_DIR" >&2
exit 2
fi
@@ -110,6 +115,7 @@ echo " Image repo: $IMAGE_REPO"
echo " Tagged ref: $TAGGED_REF"
echo " Latest ref: $LATEST_REF"
echo " Force :latest: $FORCE_LATEST"
echo " Skip build: $SKIP_BUILD"
echo " Build context: $CONTEXT_DIR"
echo " Dry run: $DRY_RUN"
echo "============================================================"
@@ -120,7 +126,9 @@ echo ""
echo "---- Step 1: build & push $TAGGED_REF -----------------------"
echo ""
if image_exists "$TAGGED_REF"; then
if [[ "$SKIP_BUILD" == "true" ]]; then
echo "INFO: --skip-build set; not building or pushing $TAGGED_REF (expecting it to already exist)."
elif image_exists "$TAGGED_REF"; then
echo "INFO: $TAGGED_REF already exists in the registry; skipping build & push."
else
echo "INFO: $TAGGED_REF not found in the registry; building and pushing."
@@ -177,7 +185,7 @@ else
if [[ "$DRY_RUN" == "true" ]]; then
echo "[dry-run] would have built $TAGGED_REF in step 1; skipping :latest digest compare."
else
echo "ERROR: $TAGGED_REF has no digest after the build; aborting :latest move." >&2
echo "ERROR: $TAGGED_REF has no digest in the registry; cannot move :latest (was it built/pushed?)." >&2
exit 1
fi
elif [[ "$TAGGED_DIGEST" == "$LATEST_DIGEST" ]]; then