1- name : Code Quality & Auto-Format Checks
1+ name : Code Quality (PR-Mandatory)
22
3+ # Trigger explicitly for PRs + retain push events
34on :
4- pull_request :
5- types : [opened, synchronize, reopened]
65 push :
76 branches : [ main, master ]
87 pull_request :
98 branches : [ main, master ]
9+ types : [ opened, synchronize, reopened ] # Trigger on PR create/update/reopen
1010
1111env :
1212 PYTHON_VERSION : ' 3.13.7'
1313
1414jobs :
15- # Phase 1 : Ruff Auto-Format (no dependency file references )
16- ruff-auto-format :
17- name : " 📝 Ruff Auto- Format"
15+ # 1. PR-Adapted : Ruff Auto-Formatting (critical: commits to PR source branch )
16+ ruff-auto-format-pr :
17+ name : " 📝 Ruff Format (PR-Safe) "
1818 runs-on : ubuntu-latest
1919 permissions :
20- contents : write # For auto-commit
21- pull-requests : read
20+ contents : write # Required for auto-commits to PRs
21+ pull-requests : read # Required to fetch PR branch info
2222 outputs :
2323 changes_made : ${{ steps.format-check.outputs.changes_made }}
2424 steps :
25- - name : Checkout repository (critical for file access)
25+ - name : Checkout PR Source Branch
2626 uses : actions/checkout@v4
2727 with :
28- token : ${{ secrets.GITHUB_TOKEN }}
28+ token : ${{ secrets.GITHUB_TOKEN }} # Works for internal PRs; use PAT for forked PRs
2929 fetch-depth : 0
30- ref : ${{ github.head_ref || github.ref }}
31- path : . # Ensure repo is in default working dir
30+ ref : ${{ github.head_ref }} # Force checkout PR source branch (not target main)
31+ path : .
3232
33- - name : Set up Python (no cache based on dependency files)
33+ - name : Set up Python
3434 uses : actions/setup-python@v4
3535 with :
3636 python-version : ${{ env.PYTHON_VERSION }}
37- # Removed `cache-dependency-path` (no requirements/pyproject to reference)
38- cache : ' pip' # Still caches pip packages (e.g., ruff) for speed
37+ cache : ' pip' # Cache pip packages for faster installs
3938
40- - name : Install ruff (direct install, no dependency files)
39+ - name : Install ruff
4140 run : pip install ruff
4241 env :
43- PIP_DISABLE_PIP_VERSION_CHECK : 1
42+ PIP_DISABLE_PIP_VERSION_CHECK : 1 # Skip pip version check to speed up installs
4443
45- - name : Run ruff format & check changes
44+ - name : Run ruff format & detect changes
4645 id : format-check
4746 run : |
4847 ruff format .
4948 if git diff --quiet --exit-code; then
5049 echo "changes_made=false" >> $GITHUB_OUTPUT
5150 else
5251 echo "changes_made=true" >> $GITHUB_OUTPUT
52+ git diff --name-only # Show modified files in PR logs for review
5353 fi
5454
55- - name : Auto-commit & push formatting changes
55+ - name : Auto-commit format changes to PR
5656 if : steps.format-check.outputs.changes_made == 'true'
5757 run : |
58- git config --local user.name "GitHub Actions"
59- git config --local user.email "actions@github.com"
60- git add . && git commit -m "[auto] Fix code format with ruff" && git push
61-
62- # Phase 2: Setup Check Tools (no dependency file checks)
63- setup-check-tools :
64- name : " ⚙️ Setup Check Tools"
65- needs : ruff-auto-format
58+ git config --local user.name "GitHub Actions (PR Format)"
59+ git config --local user.email "pr-format@github.com"
60+ git add .
61+ git commit -m "[PR-auto] Fix code formatting with ruff"
62+ git push # Pushes to PR source branch; PR updates automatically
63+
64+ # 2. PR Control: Run checks only if PR has format changes or is merged
65+ setup-checks-pr :
66+ name : " ⚙️ Setup Tools (PR-Triggered)"
67+ needs : ruff-auto-format-pr
68+ # Condition: Run on push OR PR (with format changes OR merged status)
6669 if : >
6770 (github.event_name == 'push') ||
68- (github.event. pull_request &&
69- (needs.ruff-auto-format.outputs.changes_made == 'true' ||
71+ (github.event_name == ' pull_request' &&
72+ (needs.ruff-auto-format-pr .outputs.changes_made == 'true' ||
7073 github.event.pull_request.merged == true))
7174 runs-on : ubuntu-latest
7275 steps :
73- - name : Checkout repository
76+ - name : Checkout PR Source Branch
7477 uses : actions/checkout@v4
7578 with :
79+ ref : ${{ github.head_ref || github.ref }} # Use PR source branch (or push branch)
7680 path : .
77- fetch-depth : 1
7881
79- - name : Set up Python (no dependency file cache)
82+ - name : Set up Python
8083 uses : actions/setup-python@v4
8184 with :
8285 python-version : ${{ env.PYTHON_VERSION }}
83- cache : ' pip' # Caches tools (codespell/bandit) for downstream jobs
86+ cache : ' pip'
8487
85- - name : Install check tools (direct install, no dependency files)
86- run : |
87- pip install codespell bandit mypy ruff pytest
88+ - name : Install check tools directly (no dependency files)
89+ run : pip install codespell bandit mypy ruff pytest
8890 env :
8991 PIP_DISABLE_PIP_VERSION_CHECK : 1
9092
91- # --- Non-blocking Checks (no dependency file references) ---
92- spell-check :
93- name : " 🔍 Spell Check (Non-Blocking )"
94- needs : setup-check-tools
93+ # 3. PR Checks: All tools synced to PR "Checks" tab
94+ spell-check-pr :
95+ name : " 🔍 Spell Check (PR )"
96+ needs : setup-checks-pr
9597 runs-on : ubuntu-latest
9698 steps :
97- - name : Checkout repository
99+ - name : Checkout PR Source Branch
98100 uses : actions/checkout@v4
99101 with :
102+ ref : ${{ github.head_ref }}
100103 path : .
101104 - name : Set up Python
102105 uses : actions/setup-python@v4
103106 with :
104107 python-version : ${{ env.PYTHON_VERSION }}
105108 cache : ' pip'
106- - name : Run codespell
109+ - name : Run codespell (Non-Blocking in PR)
107110 run : codespell --skip="*.json,*.lock,*.csv" --ignore-words-list="xxx,yyy,zzz" --quiet-level=2 || true
108111
109- security-scan :
110- name : " 🔒 Security Scan (Non-Blocking )"
111- needs : setup-check-tools
112+ security-check-pr :
113+ name : " 🔒 Security Check (PR )"
114+ needs : setup-checks-pr
112115 runs-on : ubuntu-latest
113116 steps :
114- - name : Checkout repository
117+ - name : Checkout PR Source Branch
115118 uses : actions/checkout@v4
116119 with :
120+ ref : ${{ github.head_ref }}
117121 path : .
118122 - name : Set up Python
119123 uses : actions/setup-python@v4
120124 with :
121125 python-version : ${{ env.PYTHON_VERSION }}
122126 cache : ' pip'
123- - name : Run bandit
124- run : bandit -r . -f human -o bandit-results.txt -f json -o bandit-results.json || true
127+ - name : Run bandit (Non-Blocking in PR)
128+ run : bandit -r . -f human -o bandit-pr- results.txt -f json -o bandit-pr -results.json || true
125129
126- type-check :
127- name : " 🎯 Type Check (Non-Blocking )"
128- needs : setup-check-tools
130+ type-check-pr :
131+ name : " 🎯 Type Check (PR )"
132+ needs : setup-checks-pr
129133 runs-on : ubuntu-latest
130134 steps :
131- - name : Checkout repository
135+ - name : Checkout PR Source Branch
132136 uses : actions/checkout@v4
133137 with :
138+ ref : ${{ github.head_ref }}
134139 path : .
135140 - name : Set up Python
136141 uses : actions/setup-python@v4
137142 with :
138143 python-version : ${{ env.PYTHON_VERSION }}
139144 cache : ' pip'
140- - name : Run mypy
145+ - name : Run mypy (Non-Blocking in PR)
141146 run : mypy --ignore-missing-imports --show-error-codes . || true
142-
143- # --- Blocking Checks ---
144- lint-check :
145- name : " 🧹 Lint Check (Blocking)"
146- needs : setup-check-tools
147+ lint-check-pr :
148+ name : " 🧹 Lint Check (PR-Blocking)"
149+ needs : setup-checks-pr
147150 runs-on : ubuntu-latest
148151 steps :
149- - name : Checkout repository
152+ - name : Checkout PR Source Branch
150153 uses : actions/checkout@v4
151154 with :
155+ ref : ${{ github.head_ref }}
152156 path : .
153157 - name : Set up Python
154158 uses : actions/setup-python@v4
155159 with :
156160 python-version : ${{ env.PYTHON_VERSION }}
157161 cache : ' pip'
158- - name : Run ruff check
162+ - name : Run ruff check (Blocking in PR: Fix lint errors first)
159163 run : ruff check --output-format=concise .
160164
161- unit-tests :
162- name : " 🧪 Unit Tests (Blocking)"
163- needs : setup-check-tools
165+ test-pr :
166+ name : " 🧪 Unit Tests (PR- Blocking)"
167+ needs : setup-checks-pr
164168 runs-on : ubuntu-latest
165169 steps :
166- - name : Checkout repository
170+ - name : Checkout PR Source Branch
167171 uses : actions/checkout@v4
168172 with :
173+ ref : ${{ github.head_ref }}
169174 path : .
170175 - name : Set up Python
171176 uses : actions/setup-python@v4
172177 with :
173178 python-version : ${{ env.PYTHON_VERSION }}
174179 cache : ' pip'
175- - name : Run pytest
176- run : pytest # Adjust test command if your tests are in a subfolder (e.g., pytest tests/)
180+ - name : Run pytest (Blocking in PR: Fix test failures first)
181+ run : pytest
177182
178- # --- CodeQL Analysis ---
179- codeql-analysis :
180- name : " 🛡️ CodeQL Security Analysis "
181- needs : setup-check-tools
183+ # 4. PR Security Analysis: CodeQL results synced to PR "Security" tab
184+ codeql-pr :
185+ name : " 🛡️ CodeQL (PR) "
186+ needs : setup-checks-pr
182187 runs-on : ubuntu-latest
183188 permissions :
184189 actions : read
185190 contents : read
186- security-events : write
191+ security-events : write # Required to sync results to PR Security tab
187192 steps :
188- - name : Checkout repository
193+ - name : Checkout PR Source Branch
189194 uses : actions/checkout@v4
190195 with :
196+ ref : ${{ github.head_ref }}
191197 path : .
192198 - name : Initialize CodeQL
193199 uses : github/codeql-action/init@v2
@@ -198,19 +204,21 @@ jobs:
198204 - name : Perform CodeQL Analysis
199205 uses : github/codeql-action/analyze@v2
200206
201- # --- Final Summary ---
202- all -checks-summary :
203- name : " ✅ All Checks Summary"
204- needs : [spell-check, security-scan , type-check, lint-check, unit-tests , codeql-analysis ]
207+ # 5. PR Summary: Clear status in PR "Checks" tab
208+ pr -checks-summary :
209+ name : " ✅ PR All Checks Summary"
210+ needs : [spell-check-pr , security-check-pr , type-check-pr , lint-check-pr, test-pr , codeql-pr ]
205211 if : always()
206212 runs-on : ubuntu-latest
207213 steps :
208- - name : Print summary
214+ - name : Print PR Check Summary
209215 run : |
210- echo "Ruff auto-format changes: ${{ needs.ruff-auto-format.outputs.changes_made }}"
211- if [[ "${{ contains(needs.lint-check.result, 'failure') || contains(needs.unit-tests.result, 'failure') }}" == "true" ]]; then
212- echo "❌ Critical failure (lint/tests) - Fix required"
216+ echo "PR Source Branch: ${{ github.head_ref }}"
217+ echo "Formatting Changes Applied: ${{ needs.ruff-auto-format-pr.outputs.changes_made }}"
218+ # Block PR merge if critical checks (lint/tests) fail
219+ if [[ "${{ contains(needs.lint-check-pr.result, 'failure') || contains(needs.test-pr.result, 'failure') }}" == "true" ]]; then
220+ echo "❌ Critical PR Checks Failed (lint/tests) - Fix Before Merging"
213221 exit 1
214222 else
215- echo "✅ No critical failures "
223+ echo "✅ Critical PR Checks Passed - Non-blocking issues (spelling/type) are optional to fix "
216224 fi
0 commit comments