Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions .github/workflows/pr-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# - owner-gate (product-autonomous vs platform; platform fail-closed)
# - hold-gate (red while a do-not-merge/hold label is present)
# - scope-gate (conventional commit title)
# - check-product (rule1–8 boundary checks)
# - check-product (generated registry drift + rule1–10 boundary checks)
# - test (build + vet + offline tests)
# - build-matrix (6 × platform)
#
Expand All @@ -21,7 +21,8 @@
# - Repository secret AUTO_MERGE_TOKEN is a bot/GitHub App token with
# contents:write + pull-requests:write. Do NOT use GITHUB_TOKEN for
# auto-merge: GitHub suppresses workflow runs triggered by GITHUB_TOKEN
# events, so a GITHUB_TOKEN-merged PR would not fire the master Release.
# events, which can hide post-merge CI/CD automation. Release is scheduled
# weekly and no longer depends on master push events.
# - Required approvals = 0. Do NOT set a global "require N approvals" — that
# would also block product autonomy. Platform approval is enforced by
# owner-gate (admin review), not by branch protection's approval count.
Expand Down Expand Up @@ -194,8 +195,8 @@ jobs:
auto-merge:
# Native GitHub auto-merge, only for product-autonomous eligible PRs. GitHub
# enforces required checks + (any) required approvals before the actual merge.
# Use a real automation identity instead of GITHUB_TOKEN so the resulting
# master push can trigger Release.
# Use a real automation identity instead of GITHUB_TOKEN so post-merge
# repository workflows/events are not suppressed.
if: github.event_name == 'pull_request' && needs.owner-gate.outputs.auto_merge == 'true'
needs: [owner-gate]
runs-on: ubuntu-latest
Expand All @@ -213,7 +214,7 @@ jobs:
run: |
set -euo pipefail
if [ -z "$AUTO_MERGE_TOKEN" ]; then
echo "::error::AUTO_MERGE_TOKEN is required for product auto-merge. Configure a bot/GitHub App token with contents:write and pull-requests:write so the post-merge master push triggers Release."
echo "::error::AUTO_MERGE_TOKEN is required for product auto-merge. Configure a bot/GitHub App token with contents:write and pull-requests:write so post-merge repository workflows/events are not suppressed."
exit 1
fi
- name: Enable auto-merge
Expand All @@ -229,6 +230,17 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.25' }
- name: Verify generated product registry
run: |
set -euo pipefail
go run ./hack/gen-products
if ! git diff --quiet -- cmd/products.gen.go; then
echo "::error file=cmd/products.gen.go,line=1::cmd/products.gen.go is out of date. Run 'go run ./hack/gen-products' from the repo root and commit the result."
git diff -- cmd/products.gen.go
exit 1
fi
echo "cmd/products.gen.go is up to date."
env: { GOPROXY: 'https://goproxy.cn,direct' }
- run: go run ./hack/check-product
env: { GOPROXY: 'https://goproxy.cn,direct' }

Expand Down
16 changes: 9 additions & 7 deletions .github/workflows/release-drift.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
# Release Drift Guard
#
# Detects the failure mode where master has releasable commits after the latest
# tag but no Release workflow produced the next patch version. This guard only
# Detects the failure mode where the weekly Release workflow misses its release
# window while master already had releasable commits waiting. This guard only
# alerts; release.yml remains the single writer of tags and GitHub Releases. It
# skips while Release is already queued/running and gives fresh master commits a
# short grace window to avoid noisy failures during normal release serialization.
# runs after the weekly release window, skips while Release is already
# queued/running, and gives fresh master commits a grace window so changes that
# land after the release window wait for the next week instead of failing drift.

name: Release Drift Guard

on:
schedule:
- cron: "17 * * * *"
# Tuesdays 03:00 Asia/Shanghai (Monday 19:00 UTC), four hours after Release.
- cron: "0 19 * * 1"
workflow_dispatch: {}

permissions:
Expand All @@ -37,7 +39,7 @@ jobs:
- name: Detect unreleased master changes
env:
GH_TOKEN: ${{ github.token }}
RELEASE_GRACE_SECONDS: "1200"
RELEASE_GRACE_SECONDS: "14400"
run: |
set -euo pipefail
Expand Down Expand Up @@ -75,7 +77,7 @@ jobs:
fi
if [ "$DETECT" != "$CURRENT" ] || [ -n "$RELEASABLE" ]; then
echo "::error::master has releasable commits after $CURRENT, but no release tag covers HEAD. Run the Release workflow on master."
echo "::error::master has releasable commits after $CURRENT outside the weekly release grace window, but no release tag covers HEAD. Check the weekly Release workflow or run it manually."
echo "current=$CURRENT"
echo "detected=$DETECT"
git log --oneline "$CURRENT"..HEAD
Expand Down
18 changes: 10 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Merge-to-release automation
# Weekly release automation
#
# Flow:
# 1. A PR merges to master (or workflow_dispatch for the first guarded run).
# 1. Once per week (or workflow_dispatch for an urgent/manual run), the
# workflow checks master for releasable commits since the latest tag.
# 2. Version policy: every release is a PATCH bump (0.3.3 → 0.3.4 → 0.3.5),
# regardless of whether the commits are feat or fix — we intentionally do
# NOT auto-minor on feat. svu is used in two roles here:
Expand All @@ -19,16 +20,17 @@
# 5. If there are no new releasable commits (feat/fix/perf/refactor/breaking),
# the job exits early without creating a release.
#
# Release is intentionally automatic after master updates. Product-autonomous
# PRs are admitted by PR Gate, then the master push from the automation identity
# triggers this workflow.
# Release is intentionally batched weekly. PRs are still admitted by PR Gate and
# normal CI/CD checks before merge; this workflow only decides whether the
# already-merged master branch should be published during the release window.

name: Release

on:
push:
branches: [master]
workflow_dispatch: {} # manual trigger for the first guarded run
schedule:
# Mondays 23:00 Asia/Shanghai (15:00 UTC).
- cron: "0 15 * * 1"
workflow_dispatch: {} # manual trigger for urgent releases or guarded runs

concurrency:
group: release
Expand Down
Loading
Loading