This is an automated email from the ASF dual-hosted git repository.
villebro pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/superset-kubernetes-operator.git
The following commit(s) were added to refs/heads/main by this push:
new 1c44b34 ci: run CI on release branches and gate release publishing on
it (#227)
1c44b34 is described below
commit 1c44b34cbb4d0acc8350f3fe5b58a9bc8ebf6d0b
Author: Ville Brofeldt <[email protected]>
AuthorDate: Thu Jul 23 13:50:41 2026 -0700
ci: run CI on release branches and gate release publishing on it (#227)
* ci: run CI on release branches
CI, Test, and License workflows only triggered on main, so `<major>.<minor>`
release branches (e.g. 0.2) — where RCs are cut — got no CI at all: no unit
/
integration / e2e tests, and no govulncheck or Trivy vulnerability scans. A
release could be tagged from a branch that nothing had scanned.
Extend the push and pull_request branch filters to also match release
branches
(`[0-9]+.[0-9]+`) so they run the same gate as main. docs.yml is
intentionally
left out (its gh-deploy must stay main-only); scorecard/fuzz/sync run on
their
own schedules.
Note: this gives release branches CI visibility. Blocking a bad publish is a
separate step — release.yml is tag-triggered and still runs independently of
branch CI.
* ci: gate release publishing on required checks passing
Part two of running CI on release branches: `release.yml` is tag-triggered
and
previously published (image + chart, signed) regardless of whether the
tagged
commit's CI was green. Add a `preflight` job that the publish job depends
on; it
waits for the branch-protection required status checks — read from
`.asf.yaml`,
so the gate follows whatever `main` requires — to pass on the tagged
commit, and
fails the release if any didn't. Release branches now run that same CI, so
the
tagged commit already carries the check runs.
Only release tags are gated; pushes to `main` and workflow_dispatch
(throwaway
dev images) proceed unchanged. Docs updated to push the release branch and
let
CI go green before pushing the tag.
---
.github/workflows/ci.yaml | 6 ++-
.github/workflows/license.yml | 6 ++-
.github/workflows/release.yml | 23 ++++++++++
.github/workflows/test.yaml | 6 ++-
docs/contributing/releasing.md | 12 +++++-
scripts/verify-release-ci.sh | 96 ++++++++++++++++++++++++++++++++++++++++++
6 files changed, 141 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index ed2dc9c..0bf3548 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -16,10 +16,12 @@
name: CI
on:
+ # Also run on `<major>.<minor>` release branches (e.g. 0.2) so release
branches
+ # get the same CI gate — tests plus govulncheck and Trivy scans — as main.
push:
- branches: [main]
+ branches: [main, '[0-9]+.[0-9]+']
pull_request:
- branches: [main]
+ branches: [main, '[0-9]+.[0-9]+']
permissions:
contents: read
diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml
index fe55034..1684b64 100644
--- a/.github/workflows/license.yml
+++ b/.github/workflows/license.yml
@@ -16,10 +16,12 @@
name: License
on:
+ # Also run on `<major>.<minor>` release branches (e.g. 0.2) so the Apache Rat
+ # license check gates release branches as well as main.
push:
- branches: [main]
+ branches: [main, '[0-9]+.[0-9]+']
pull_request:
- branches: [main]
+ branches: [main, '[0-9]+.[0-9]+']
permissions:
contents: read
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 243af48..e6268c4 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -29,8 +29,31 @@ permissions:
contents: read
jobs:
+ # Gate: for release tags, refuse to publish unless the branch-protection
+ # required status checks all passed on the tagged commit. Release branches
run
+ # the same CI as main, so the commit already carries those check runs. A
no-op
+ # for main / workflow_dispatch (throwaway dev images).
+ preflight:
+ name: Verify CI passed
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ checks: read
+ steps:
+ - name: Checkout
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 #
v7.0.0
+ with:
+ persist-credentials: false
+ - name: Install yq
+ run: bash scripts/install-yq.sh
+ - name: Verify required checks passed for this commit
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: bash scripts/verify-release-ci.sh
+
release:
name: Build and publish image
+ needs: preflight
runs-on: ubuntu-latest
permissions:
contents: read
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index cdfedee..fbd9789 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -16,10 +16,12 @@
name: Test
on:
+ # Also run on `<major>.<minor>` release branches (e.g. 0.2) so release
branches
+ # get the same test gate (unit, integration, e2e) as main.
push:
- branches: [main]
+ branches: [main, '[0-9]+.[0-9]+']
pull_request:
- branches: [main]
+ branches: [main, '[0-9]+.[0-9]+']
permissions:
contents: read
diff --git a/docs/contributing/releasing.md b/docs/contributing/releasing.md
index 50cd7cc..42053fc 100644
--- a/docs/contributing/releasing.md
+++ b/docs/contributing/releasing.md
@@ -77,6 +77,8 @@ While the project is pre-1.0, all versions use `0.x.y` to
signal instability per
The release workflow (`.github/workflows/release.yml`) builds multi-platform
images and pushes them to GHCR. It runs automatically on pushes to `main`
(producing `dev` and `sha-<commit>` tags) and on version tags (producing semver
tags). It can also be triggered manually via `workflow_dispatch`.
+For **version tags**, publishing is gated: a preflight job
(`scripts/verify-release-ci.sh`) waits for the branch-protection required
status checks — the same set `main` enforces, read from `.asf.yaml` — to pass
on the tagged commit, and fails the release if any didn't. Release branches run
the same CI as `main`, so the tagged commit (the release-branch HEAD) already
carries those check runs. Push the release branch and let its CI go green
**before** pushing the tag, so the gate confirms [...]
+
**Image tagging:**
| Trigger | Image tag | Example |
@@ -129,8 +131,12 @@ scripts/release-rc.sh 0.2.0 --expect-rc 1
# Build and verify signed source artifacts before pushing anything.
scripts/release-source.sh
-# Push branch + tag to trigger the release workflow after source verification.
-git push origin 0.2 v0.2.0-rc1
+# Push the release branch first and wait for its CI to go green (release
+# branches run the full suite). Then push the tag — the release workflow gates
+# publishing on those required checks passing for the tagged commit.
+git push origin 0.2
+# ... wait for CI on the 0.2 branch to complete successfully ...
+git push origin v0.2.0-rc1
```
Running the script again from the same release branch increments the RC number
automatically (rc1, rc2, ...).
@@ -209,6 +215,8 @@ scripts/release-email.sh result > dist/0.2.0-rc1/RESULT.txt
After the ASF vote passes, the `scripts/release-finalize.sh` script tags the
final release on the same commit as the voted RC. Do not commit changelog date
updates or other polish before finalizing; those changes were not part of the
voted source release.
+Because the final tag points at the already-tested RC commit, the release
workflow's CI gate is satisfied immediately from the checks that ran for the RC.
+
```sh
# From the 0.2 branch
scripts/release-finalize.sh 0.2.0
diff --git a/scripts/verify-release-ci.sh b/scripts/verify-release-ci.sh
new file mode 100755
index 0000000..e022b35
--- /dev/null
+++ b/scripts/verify-release-ci.sh
@@ -0,0 +1,96 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Release publish gate: verify that the branch-protection required status
checks
+# all passed on the commit being released before the release workflow publishes
+# anything.
+#
+# The required checks are read from .asf.yaml (the single source of truth for
+# branch protection) rather than hard-coded here, so the gate follows whatever
+# main requires. Those same workflows run on release branches (see the branch
+# filters in ci.yaml/test.yaml/license.yml), so the tagged commit — the release
+# branch HEAD — carries their check runs.
+#
+# Only release tags (refs/tags/v*) are gated; pushes to main and
workflow_dispatch
+# runs (which publish the throwaway `dev`/`sha-` images) proceed without
waiting.
+#
+# Requires: gh (with GH_TOKEN), yq. Env: GITHUB_REF, GITHUB_SHA,
GITHUB_REPOSITORY.
+
+set -euo pipefail
+
+REF="${GITHUB_REF:-}"
+SHA="${GITHUB_SHA:?GITHUB_SHA is required}"
+REPO="${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}"
+TIMEOUT_SECONDS="${CI_GATE_TIMEOUT_SECONDS:-1800}" # 30 minutes
+POLL_SECONDS="${CI_GATE_POLL_SECONDS:-20}"
+
+case "${REF}" in
+ refs/tags/v*) ;;
+ *) echo "Ref ${REF:-<none>} is not a release tag; skipping the CI gate.";
exit 0 ;;
+esac
+
+mapfile -t REQUIRED < <(yq -r \
+ '.github.protected_branches.main.required_status_checks.contexts[]'
.asf.yaml)
+if [ "${#REQUIRED[@]}" -eq 0 ]; then
+ echo "No required_status_checks contexts found in .asf.yaml" >&2
+ exit 1
+fi
+
+echo "Gating release of ${SHA} on required checks:"
+printf ' - %s\n' "${REQUIRED[@]}"
+
+deadline=$(( SECONDS + TIMEOUT_SECONDS ))
+while :; do
+ # name<TAB>status<TAB>conclusion<TAB>started_at for every check run on the
commit.
+ runs="$(gh api --paginate "repos/${REPO}/commits/${SHA}/check-runs" \
+ -q '.check_runs[] | [.name, .status, (.conclusion // ""), .started_at] |
@tsv')"
+
+ pending=()
+ failed=()
+ for name in "${REQUIRED[@]}"; do
+ # Most recent run for this check name (ISO-8601 started_at sorts
lexically).
+ latest="$(printf '%s\n' "${runs}" | awk -F'\t' -v n="${name}" '$1==n' |
sort -t$'\t' -k4 | tail -1)"
+ if [ -z "${latest}" ]; then
+ pending+=("${name} (not started)")
+ continue
+ fi
+ status="$(printf '%s' "${latest}" | cut -f2)"
+ conclusion="$(printf '%s' "${latest}" | cut -f3)"
+ if [ "${status}" != "completed" ]; then
+ pending+=("${name} (${status})")
+ elif [ "${conclusion}" != "success" ]; then
+ failed+=("${name} -> ${conclusion}")
+ fi
+ done
+
+ if [ "${#failed[@]}" -gt 0 ]; then
+ echo "Refusing to publish — required checks did not pass on ${SHA}:" >&2
+ printf ' - %s\n' "${failed[@]}" >&2
+ exit 1
+ fi
+ if [ "${#pending[@]}" -eq 0 ]; then
+ echo "All required checks passed on ${SHA}; proceeding with the release."
+ exit 0
+ fi
+ if [ "${SECONDS}" -ge "${deadline}" ]; then
+ echo "Timed out after ${TIMEOUT_SECONDS}s waiting for required checks on
${SHA}:" >&2
+ printf ' - %s\n' "${pending[@]}" >&2
+ echo "Push the release branch and let CI finish before pushing the tag."
>&2
+ exit 1
+ fi
+ echo "Waiting on: ${pending[*]}"
+ sleep "${POLL_SECONDS}"
+done