11name : Release Gate
2-
32on :
43 pull_request :
54 types : [closed]
65 branches : [main]
6+ paths : [".releases/**"]
7+
8+ concurrency :
9+ group : release-gate
10+ cancel-in-progress : false
711
812jobs :
9- release-gate :
10- name : Tag and update release branches
13+ create- release-tag :
14+ name : Create tag and dispatch release
1115 runs-on : ubuntu-latest
12- # Only run when a release/ branch is merged (not just closed)
13- if : |
14- github.event.pull_request.merged == true &&
15- startsWith(github.event.pull_request.head.ref, 'release/v')
16-
16+ timeout-minutes : 5
17+ if : github.event.pull_request.merged == true
1718 permissions :
1819 contents : write
19-
20+ actions : write
2021 steps :
21- - uses : actions/create-github-app-token@v1
22+ - name : Fail if App credentials are not configured
23+ run : |
24+ if [ -z "${{ secrets.APP_ID }}" ] || [ -z "${{ secrets.APP_PRIVATE_KEY }}" ]; then
25+ echo "❌ APP_ID and APP_PRIVATE_KEY must be configured."
26+ echo "For fork testing, install a personal GitHub App on the fork,"
27+ echo "create a private key, and add both as repository secrets."
28+ exit 1
29+ fi
30+
31+ - uses : actions/checkout@v6
32+ with :
33+ fetch-depth : 0
34+
35+ - uses : actions/create-github-app-token@v3
2236 id : app-token
2337 with :
2438 app-id : ${{ secrets.APP_ID }}
2539 private-key : ${{ secrets.APP_PRIVATE_KEY }}
2640
27- - uses : actions/checkout@v4
41+ - uses : actions/setup-python@v6
2842 with :
29- # Full history required for version comparison against existing tags
30- # and for the fast-forward push to stable/beta.
31- fetch-depth : 0
32- token : ${{ steps.app-token.outputs.token }}
33-
34- - name : Extract and validate version
35- id : version
36- env :
37- BRANCH_REF : ${{ github.event.pull_request.head.ref }}
38- run : |
39- BRANCH="$BRANCH_REF"
40- NEW_VERSION="${BRANCH#release/}"
41- echo "new=${NEW_VERSION}" >> $GITHUB_OUTPUT
43+ python-version : " 3.x"
4244
43- # Determine if this is an RC
44- if echo "$NEW_VERSION" | grep -qE '\-rc[0-9]+$'; then
45- echo "is_rc=true" >> $GITHUB_OUTPUT
46- else
47- echo "is_rc=false" >> $GITHUB_OUTPUT
48- fi
45+ - name : Install Python deps
46+ run : pip install pyyaml
4947
50- - name : Validate version is strictly increasing
48+ - name : Create tag from release request
49+ id : gate
5150 env :
52- NEW_VERSION : ${{ steps.version.outputs.new }}
51+ GH_TOKEN : ${{ steps.app-token.outputs.token }}
52+ REPO : ${{ github.repository }}
53+ BASE_SHA : ${{ github.event.pull_request.base.sha }}
54+ MERGE_SHA : ${{ github.event.pull_request.merge_commit_sha }}
5355 run : |
54- # Get the latest tag; if none exist yet, skip the comparison
55- LATEST_TAG=$(git tag --list 'v*' --sort=-version:refname | head -n1)
56- if [ -z "$LATEST_TAG" ]; then
57- echo "No existing tags found — skipping version comparison"
58- exit 0
56+ python .github/workflows/release/release.py gate | tee /tmp/gate-output.txt
57+ TAG=$(grep '^tag=' /tmp/gate-output.txt | tail -1 | cut -d= -f2-)
58+ COMMIT=$(grep '^commit=' /tmp/gate-output.txt | tail -1 | cut -d= -f2-)
59+ echo "tag=$TAG" >> $GITHUB_OUTPUT
60+ echo "commit=$COMMIT" >> $GITHUB_OUTPUT
61+
62+ if [ -z "$TAG" ] || [ -z "$COMMIT" ]; then
63+ echo "❌ gate did not emit tag= / commit= outputs"
64+ exit 1
5965 fi
66+ echo "Gate outputs: $TAG @ $COMMIT"
6067
61- LATEST_VERSION="${LATEST_TAG#v}"
62-
63- python3 - <<EOF
64- import sys
65- from packaging.version import Version
66-
67- def normalize(v):
68- # Convert vX.Y.Z-rcQ → X.Y.ZrcQ (PEP 440)
69- return v.replace("-rc", "rc")
70-
71- new = Version(normalize("$NEW_VERSION"))
72- latest = Version(normalize("$LATEST_VERSION"))
73-
74- print(f"Latest tag : {latest}")
75- print(f"New version: {new}")
76-
77- if new <= latest:
78- print(f"\n❌ {new} is not strictly greater than current {latest}")
79- sys.exit(1)
80-
81- print(f"\n✅ Version order is valid")
82- EOF
83-
84- - name : Configure git
85- run : |
86- git config user.name "commit-boost-release-bot[bot]"
87- git config user.email "commit-boost-release-bot[bot]@users.noreply.github.com"
88-
89- - name : Create and push tag
68+ - name : Dispatch release workflow
9069 env :
91- VERSION : ${{ steps.version.outputs.new }}
70+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
9271 run : |
93- git tag "$VERSION" HEAD
94- git push origin "$VERSION"
95- # Branch fast-forwarding happens in release.yml after all artifacts
96- # are successfully built. stable/beta are never touched if the build fails.
72+ gh workflow run release.yml \
73+ --ref main \
74+ -f tag=${{ steps.gate.outputs.tag }}
0 commit comments