Skip to content

Commit f7ce042

Browse files
rh0diumclaude
andcommitted
Optimize CI workflow: separate tests and release
- Move release job to separate release.yml triggered only on master push - Add PR verification to release workflow (prevents releases from admin bypasses) - Rename job display names to generic: Lint, Security, Coverage - Skip expensive jobs (tests, coverage, outdated) on merge queue branches - Keep Lint and Security running for merge queue status checks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3153797 commit f7ce042

File tree

2 files changed

+134
-36
lines changed

2 files changed

+134
-36
lines changed

.github/workflows/main.yml

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ name: Bootstrap Template Tags Tests
22

33
on:
44
push:
5-
merge_group:
5+
branches-ignore:
6+
- master # release.yml handles master
67
schedule:
78
- cron: '0 1 * * 5'
89

@@ -13,6 +14,7 @@ concurrency:
1314
jobs:
1415
outdated:
1516
name: Outdated packages
17+
if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
1618
runs-on: ubuntu-latest
1719
steps:
1820
- uses: actions/checkout@v4
@@ -31,7 +33,7 @@ jobs:
3133
run: pip list --outdated --not-required --user | grep . && echo "There are outdated packages" && exit 1 || echo "All packages up to date"
3234

3335
ruff:
34-
name: Ruff Format
36+
name: Lint
3537
runs-on: ubuntu-latest
3638
steps:
3739
- uses: actions/checkout@v4
@@ -53,7 +55,7 @@ jobs:
5355
run: ruff check
5456

5557
security:
56-
name: Bandit Security
58+
name: Security
5759
runs-on: ubuntu-latest
5860
steps:
5961
- uses: actions/checkout@v4
@@ -82,6 +84,7 @@ jobs:
8284
path: report.json
8385

8486
tests:
87+
if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
8588
name: Python ${{ matrix.python-version }} / ${{ matrix.db }} / Django ${{ matrix.django-version}}
8689
runs-on: ubuntu-latest
8790
continue-on-error: ${{ matrix.django-version == '~=6.0' || matrix.python-version == '3.14' }}
@@ -147,7 +150,8 @@ jobs:
147150
run: python demo/manage.py check
148151

149152
coverage:
150-
name: Upload Coverage to Codecov
153+
name: Coverage
154+
if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
151155
needs: [ tests ]
152156
runs-on: ubuntu-latest
153157
steps:
@@ -177,35 +181,3 @@ jobs:
177181
directory: .
178182
token: ${{ secrets.CODECOV_TOKEN }}
179183
fail_ci_if_error: true
180-
181-
release:
182-
name: Release
183-
runs-on: ubuntu-latest
184-
needs: ['outdated', 'ruff', 'security', 'tests', 'coverage']
185-
if: always() && github.ref == 'refs/heads/master' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
186-
permissions: write-all
187-
outputs:
188-
bumped: ${{ steps.release.outputs.bumped }}
189-
bump_version: ${{ steps.release.outputs.bump_version }}
190-
bump_sha: ${{ steps.release.outputs.bump_sha }}
191-
steps:
192-
- uses: actions/checkout@v4
193-
with:
194-
ref: master
195-
fetch-depth: 0 # Need full history for git tags and version calculation
196-
- uses: actions/setup-python@v5
197-
with:
198-
python-version: "3.13"
199-
- name: Install dependencies
200-
run: |
201-
pip install git+https://${{ secrets.ORGANIZATIONAL_REPO_TOKEN }}@github.com/pivotal-energy-solutions/tensor-infrastructure@master#egg=infrastructure
202-
- name: Release
203-
id: release
204-
env:
205-
PYTHONWARNINGS: once::DeprecationWarning
206-
GITHUB_TOKEN: ${{ secrets.ORGANIZATIONAL_REPO_TOKEN }}
207-
run: |
208-
bumper -P
209-
echo "bumped=$(jq '.bumped' out.json)" >> $GITHUB_OUTPUT
210-
echo "bump_version=$(jq '.bump_version' out.json)" >> $GITHUB_OUTPUT
211-
echo "bump_sha=$(jq '.bump_sha' out.json)" >> $GITHUB_OUTPUT

.github/workflows/release.yml

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
8+
jobs:
9+
release:
10+
name: Release
11+
runs-on: ubuntu-latest
12+
permissions: write-all
13+
outputs:
14+
bumped: ${{ steps.release.outputs.bumped }}
15+
bump_version: ${{ steps.release.outputs.bump_version }}
16+
bump_sha: ${{ steps.release.outputs.bump_sha }}
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
ref: master
21+
fetch-depth: 0
22+
23+
- name: Verify commit came from a PR with passing checks
24+
id: verify
25+
env:
26+
GH_TOKEN: ${{ github.token }}
27+
run: |
28+
echo "🔍 Checking if commit ${{ github.sha }} came from a valid PR..."
29+
for i in 1 2 3; do
30+
PR_JSON=$(gh api repos/${{ github.repository }}/commits/${{ github.sha }}/pulls 2>/dev/null || echo "[]")
31+
PR_COUNT=$(echo "$PR_JSON" | jq 'length')
32+
if [ "$PR_COUNT" -gt 0 ]; then
33+
break
34+
fi
35+
echo " Attempt $i: No PR found yet, waiting 2s..."
36+
sleep 2
37+
done
38+
39+
if [ "$PR_COUNT" -eq 0 ]; then
40+
echo "❌ This commit did not come from a PR - skipping release"
41+
echo "should_release=false" >> $GITHUB_OUTPUT
42+
exit 0
43+
fi
44+
45+
PR_NUMBER=$(echo "$PR_JSON" | jq -r '.[0].number')
46+
HEAD_SHA=$(echo "$PR_JSON" | jq -r '.[0].head.sha')
47+
PR_TITLE=$(echo "$PR_JSON" | jq -r '.[0].title')
48+
echo "📋 Found PR #$PR_NUMBER: $PR_TITLE"
49+
50+
REQUIRED_CHECKS=("Lint" "Security" "Coverage")
51+
ALL_PASSED=true
52+
for CHECK_NAME in "${REQUIRED_CHECKS[@]}"; do
53+
RESULT=$(gh api repos/${{ github.repository }}/commits/$HEAD_SHA/check-runs \
54+
--jq ".check_runs[] | select(.name == \"$CHECK_NAME\") | .conclusion" 2>/dev/null | head -1)
55+
if [ "$RESULT" = "success" ]; then
56+
echo " ✅ $CHECK_NAME: passed"
57+
else
58+
echo " ❌ $CHECK_NAME: $RESULT"
59+
ALL_PASSED=false
60+
fi
61+
done
62+
63+
if [ "$ALL_PASSED" = "false" ]; then
64+
echo "❌ Required checks did not pass - skipping release"
65+
echo "should_release=false" >> $GITHUB_OUTPUT
66+
exit 0
67+
fi
68+
69+
echo "✅ All required checks passed on PR #$PR_NUMBER"
70+
echo "should_release=true" >> $GITHUB_OUTPUT
71+
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
72+
73+
- name: Skip release notification
74+
if: steps.verify.outputs.should_release != 'true'
75+
run: |
76+
echo "⚠️ Release skipped - commit did not meet release criteria"
77+
78+
- uses: actions/setup-python@v5
79+
if: steps.verify.outputs.should_release == 'true'
80+
with:
81+
python-version: "3.13"
82+
83+
- name: Install dependencies
84+
if: steps.verify.outputs.should_release == 'true'
85+
run: |
86+
pip install git+https://${{ secrets.ORGANIZATIONAL_REPO_TOKEN }}@github.com/pivotal-energy-solutions/tensor-infrastructure@master#egg=infrastructure
87+
88+
- name: Release
89+
id: release
90+
if: steps.verify.outputs.should_release == 'true'
91+
env:
92+
PYTHONWARNINGS: once::DeprecationWarning
93+
GITHUB_TOKEN: ${{ secrets.ORGANIZATIONAL_REPO_TOKEN }}
94+
GH_TOKEN: ${{ github.token }}
95+
run: |
96+
echo "🚀 Creating release for PR #${{ steps.verify.outputs.pr_number }}..."
97+
bumper -P
98+
echo "bumped=$(jq '.bumped' out.json)" >> $GITHUB_OUTPUT
99+
echo "bump_version=$(jq '.bump_version' out.json)" >> $GITHUB_OUTPUT
100+
echo "bump_sha=$(jq '.bump_sha' out.json)" >> $GITHUB_OUTPUT
101+
102+
VERSION=$(jq -r '.bump_version' out.json)
103+
BUMPED=$(jq -r '.bumped' out.json)
104+
105+
if [ "$BUMPED" = "true" ]; then
106+
PR_INFO=$(gh api repos/${{ github.repository }}/pulls/${{ steps.verify.outputs.pr_number }} --jq '{title: .title, user: .user.login, html_url: .html_url}')
107+
PR_TITLE=$(echo "$PR_INFO" | jq -r '.title')
108+
PR_AUTHOR=$(echo "$PR_INFO" | jq -r '.user')
109+
PR_URL=$(echo "$PR_INFO" | jq -r '.html_url')
110+
111+
cat >> $GITHUB_STEP_SUMMARY << EOF
112+
## 🚀 Release $VERSION
113+
114+
| | |
115+
|---|---|
116+
| **Version** | \`$VERSION\` |
117+
| **PR** | [#${{ steps.verify.outputs.pr_number }}]($PR_URL) |
118+
| **Title** | $PR_TITLE |
119+
| **Author** | @$PR_AUTHOR |
120+
| **Commit** | \`${{ github.sha }}\` |
121+
122+
### Release Assets
123+
- 📦 [View Release](https://github.com/${{ github.repository }}/releases/tag/$VERSION)
124+
- 🏷️ Tag: \`$VERSION\`
125+
EOF
126+
fi

0 commit comments

Comments
 (0)