Skip to content

Commit 22b7749

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 dffa62e commit 22b7749

2 files changed

Lines changed: 135 additions & 36 deletions

File tree

.github/workflows/main.yml

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ name: Django States Tests
22

33
on:
44
push:
5+
branches-ignore:
6+
- master # release.yml handles master
57
schedule:
68
- cron: '0 1 * * 5'
79

@@ -12,6 +14,7 @@ concurrency:
1214
jobs:
1315
outdated:
1416
name: Outdated packages
17+
if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
1518
runs-on: ubuntu-latest
1619
steps:
1720
- uses: actions/checkout@v4
@@ -49,7 +52,7 @@ jobs:
4952
run: black --check .
5053

5154
ruff:
52-
name: Ruff
55+
name: Lint
5356
runs-on: ubuntu-latest
5457
steps:
5558
- uses: actions/checkout@v4
@@ -64,7 +67,7 @@ jobs:
6467
pip install .
6568
pip install .[test]
6669
67-
- name: Ruff
70+
- name: Lint
6871
run: ruff check
6972

7073
pre-commit:
@@ -88,7 +91,7 @@ jobs:
8891
run: pre-commit run --all-files --show-diff-on-failure
8992

9093
security:
91-
name: Bandit Security
94+
name: Security
9295
runs-on: ubuntu-latest
9396
steps:
9497
- uses: actions/checkout@v4
@@ -117,6 +120,7 @@ jobs:
117120
path: report.json
118121

119122
tests:
123+
if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
120124
name: Python ${{ matrix.python-version }} / ${{ matrix.db }} / Django ${{ matrix.django-version}}
121125
runs-on: ubuntu-latest
122126
# continue-on-error: ${{ matrix.django-version == '~=5.0' }}
@@ -182,7 +186,8 @@ jobs:
182186
run: python demo_app/manage.py check
183187

184188
coverage:
185-
name: Upload Coverage to Codecov
189+
name: Coverage
190+
if: ${{ !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
186191
needs: [tests]
187192
runs-on: ubuntu-latest
188193
steps:
@@ -212,35 +217,3 @@ jobs:
212217
directory: .
213218
token: ${{ secrets.CODECOV_TOKEN }}
214219
fail_ci_if_error: true
215-
216-
release:
217-
name: Release
218-
runs-on: ubuntu-latest
219-
needs: ['outdated', 'black', 'pre-commit', 'security', 'tests', 'coverage']
220-
if: github.ref == 'refs/heads/master' # Only run on master
221-
permissions: write-all
222-
outputs:
223-
bumped: ${{ steps.release.outputs.bumped }}
224-
bump_version: ${{ steps.release.outputs.bump_version }}
225-
bump_sha: ${{ steps.release.outputs.bump_sha }}
226-
steps:
227-
- uses: actions/checkout@v4
228-
with:
229-
ref: master
230-
fetch-depth: 0 # Need full history for git tags and version calculation
231-
- uses: actions/setup-python@v5
232-
with:
233-
python-version: "3.13"
234-
- name: Install dependencies
235-
run: |
236-
pip install git+https://${{ secrets.ORGANIZATIONAL_REPO_TOKEN }}@github.com/pivotal-energy-solutions/tensor-infrastructure@master#egg=infrastructure
237-
- name: Release
238-
id: release
239-
env:
240-
PYTHONWARNINGS: once::DeprecationWarning
241-
GITHUB_TOKEN: ${{ secrets.ORGANIZATIONAL_REPO_TOKEN }}
242-
run: |
243-
bumper -P
244-
echo "bumped=$(jq '.bumped' out.json)" >> $GITHUB_OUTPUT
245-
echo "bump_version=$(jq '.bump_version' out.json)" >> $GITHUB_OUTPUT
246-
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)