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

Reply via email to