1
- name : Code Quality (PR-Mandatory)
1
+ name : Mandatory PR Code Quality Checks
2
2
3
- # Trigger explicitly for PRs + retain push events
3
+ # Force trigger for ALL PR events + retain push (for post-merge validation)
4
4
on :
5
5
push :
6
- branches : [ main, master ]
6
+ branches : [ main, master ] # Only for merged PR validation
7
7
pull_request :
8
8
branches : [ main, master ]
9
- types : [ opened, synchronize, reopened ] # Trigger on PR create/update/reopen
9
+ types : [ opened, synchronize, reopened, edited ] # Trigger on ANY PR change
10
10
11
11
env :
12
12
PYTHON_VERSION : ' 3.13.7'
13
13
14
14
jobs :
15
- # 1. PR-Adapted : Ruff Auto-Formatting (critical: commits to PR source branch)
16
- ruff-auto-format-pr :
17
- name : " 📝 Ruff Format (PR-Safe) "
15
+ # 1. Mandatory PR Step : Ruff Auto-Format (pushes back to PR source branch)
16
+ pr- ruff-auto-format :
17
+ name : " 📝 PR: Ruff Auto-Format "
18
18
runs-on : ubuntu-latest
19
19
permissions :
20
- contents : write # Required for auto-commits to PRs
21
- pull-requests : read # Required to fetch PR branch info
20
+ contents : write # Critical for pushing format fixes to PR
21
+ pull-requests : write # Required to update PR status
22
22
outputs :
23
23
changes_made : ${{ steps.format-check.outputs.changes_made }}
24
24
steps :
25
- - name : Checkout PR Source Branch
25
+ - name : Checkout PR SOURCE BRANCH (MANDATORY FOR PR)
26
26
uses : actions/checkout@v4
27
27
with :
28
- token : ${{ secrets.GITHUB_TOKEN }} # Works for internal PRs; use PAT for forked PRs
28
+ token : ${{ secrets.PR_ACCESS_PAT || secrets. GITHUB_TOKEN }} # Use PAT for forked PRs
29
29
fetch-depth : 0
30
- ref : ${{ github.head_ref }} # Force checkout PR source branch (not target main)
30
+ ref : ${{ github.head_ref }} # MUST target PR source (not main)
31
31
path : .
32
32
33
33
- name : Set up Python
34
34
uses : actions/setup-python@v4
35
35
with :
36
36
python-version : ${{ env.PYTHON_VERSION }}
37
- cache : ' pip' # Cache pip packages for faster installs
37
+ cache : ' pip'
38
38
39
39
- name : Install ruff
40
40
run : pip install ruff
41
41
env :
42
- PIP_DISABLE_PIP_VERSION_CHECK : 1 # Skip pip version check to speed up installs
42
+ PIP_DISABLE_PIP_VERSION_CHECK : 1
43
43
44
- - name : Run ruff format & detect changes
44
+ - name : Run format & detect changes
45
45
id : format-check
46
46
run : |
47
47
ruff format .
48
48
if git diff --quiet --exit-code; then
49
49
echo "changes_made=false" >> $GITHUB_OUTPUT
50
50
else
51
51
echo "changes_made=true" >> $GITHUB_OUTPUT
52
- git diff --name-only # Show modified files in PR logs for review
52
+ git diff --name-only >> pr_format_changes.txt # Log changes for PR review
53
53
fi
54
54
55
- - name : Auto-commit format changes to PR
55
+ - name : Push fixes to PR source branch
56
56
if : steps.format-check.outputs.changes_made == 'true'
57
57
run : |
58
- git config --local user.name "GitHub Actions (PR Format )"
59
- git config --local user.email "pr-format @github.com"
58
+ git config --local user.name "GitHub Actions (PR Bot )"
59
+ git config --local user.email "pr-bot @github.com"
60
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)
69
- if : >
70
- (github.event_name == 'push') ||
71
- (github.event_name == 'pull_request' &&
72
- (needs.ruff-auto-format-pr.outputs.changes_made == 'true' ||
73
- github.event.pull_request.merged == true))
61
+ git commit -m "[PR AUTO-FIX] Code formatting via ruff"
62
+ git push # Updates PR automatically—no manual push needed
63
+
64
+ - name : Comment format changes on PR (MANDATORY VISIBILITY)
65
+ if : steps.format-check.outputs.changes_made == 'true' && github.event_name == 'pull_request'
66
+ uses : actions/github-script@v7
67
+ with :
68
+ script : |
69
+ const changes = require('fs').readFileSync('pr_format_changes.txt', 'utf8');
70
+ github.rest.issues.createComment({
71
+ owner: context.repo.owner,
72
+ repo: context.repo.repo,
73
+ issue_number: context.issue.number,
74
+ body: `🔄 Auto-formatting changes applied to these files:\n\`\`\`\n${changes}\n\`\`\``
75
+ });
76
+
77
+ # 2. Mandatory PR Step: Setup tools (ONLY runs for PRs)
78
+ pr-setup-tools :
79
+ name : " ⚙️ PR: Setup Check Tools"
80
+ needs : pr-ruff-auto-format
81
+ if : github.event_name == 'pull_request' # MANDATORY: Only execute for PRs
74
82
runs-on : ubuntu-latest
75
83
steps :
76
- - name : Checkout PR Source Branch
84
+ - name : Checkout PR source branch
77
85
uses : actions/checkout@v4
78
86
with :
79
- ref : ${{ github.head_ref || github.ref }} # Use PR source branch (or push branch)
87
+ ref : ${{ github.head_ref }}
80
88
path : .
81
89
82
90
- name : Set up Python
@@ -85,112 +93,100 @@ jobs:
85
93
python-version : ${{ env.PYTHON_VERSION }}
86
94
cache : ' pip'
87
95
88
- - name : Install check tools directly (no dependency files)
96
+ - name : Install PR check tools
89
97
run : pip install codespell bandit mypy ruff pytest
90
98
env :
91
99
PIP_DISABLE_PIP_VERSION_CHECK : 1
92
100
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
101
+ # 3. Mandatory PR Checks (all sync to PR "Checks" tab)
102
+ pr- spell-check :
103
+ name : " 🔍 PR: Spell Check (Non-Blocking )"
104
+ needs : pr- setup-tools
97
105
runs-on : ubuntu-latest
98
106
steps :
99
- - name : Checkout PR Source Branch
107
+ - name : Checkout PR source branch
100
108
uses : actions/checkout@v4
101
109
with :
102
110
ref : ${{ github.head_ref }}
103
111
path : .
104
- - name : Set up Python
105
- uses : actions/setup-python@v4
106
- with :
107
- python-version : ${{ env.PYTHON_VERSION }}
108
- cache : ' pip'
109
- - name : Run codespell (Non-Blocking in PR)
112
+ - name : Run codespell
110
113
run : codespell --skip="*.json,*.lock,*.csv" --ignore-words-list="xxx,yyy,zzz" --quiet-level=2 || true
111
114
112
- security-check-pr :
113
- name : " 🔒 Security Check (PR )"
114
- needs : setup-checks-pr
115
+ pr- security-check :
116
+ name : " 🔒 PR: Security Check (Non-Blocking )"
117
+ needs : pr- setup-tools
115
118
runs-on : ubuntu-latest
116
119
steps :
117
- - name : Checkout PR Source Branch
120
+ - name : Checkout PR source branch
118
121
uses : actions/checkout@v4
119
122
with :
120
123
ref : ${{ github.head_ref }}
121
124
path : .
122
- - name : Set up Python
123
- uses : actions/setup-python@v4
125
+ - name : Run bandit
126
+ run : bandit -r . -f human -o pr_bandit_results.txt -f json -o pr_bandit_results.json || true
127
+ pr-security-check :
128
+ name : " 🔒 PR: Security Check (Non-Blocking)"
129
+ needs : pr-setup-tools
130
+ runs-on : ubuntu-latest
131
+ steps :
132
+ - name : Checkout PR source branch
133
+ uses : actions/checkout@v4
124
134
with :
125
- python-version : ${{ env.PYTHON_VERSION }}
126
- cache : ' pip '
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
135
+ ref : ${{ github.head_ref }}
136
+ path : .
137
+ - name : Run bandit
138
+ run : bandit -r . -f human -o pr_bandit_results .txt -f json -o pr_bandit_results .json || true
129
139
130
- type-check-pr :
131
- name : " 🎯 Type Check (PR )"
132
- needs : setup-checks-pr
140
+ pr- type-check :
141
+ name : " 🎯 PR: Type Check (Non-Blocking )"
142
+ needs : pr- setup-tools
133
143
runs-on : ubuntu-latest
134
144
steps :
135
- - name : Checkout PR Source Branch
145
+ - name : Checkout PR source branch
136
146
uses : actions/checkout@v4
137
147
with :
138
148
ref : ${{ github.head_ref }}
139
149
path : .
140
- - name : Set up Python
141
- uses : actions/setup-python@v4
142
- with :
143
- python-version : ${{ env.PYTHON_VERSION }}
144
- cache : ' pip'
145
- - name : Run mypy (Non-Blocking in PR)
150
+ - name : Run mypy
146
151
run : mypy --ignore-missing-imports --show-error-codes . || true
147
- lint-check-pr :
148
- name : " 🧹 Lint Check (PR-Blocking)"
149
- needs : setup-checks-pr
152
+
153
+ pr-lint-check :
154
+ name : " 🧹 PR: Lint Check (BLOCKING)"
155
+ needs : pr-setup-tools
150
156
runs-on : ubuntu-latest
151
157
steps :
152
- - name : Checkout PR Source Branch
158
+ - name : Checkout PR source branch
153
159
uses : actions/checkout@v4
154
160
with :
155
161
ref : ${{ github.head_ref }}
156
162
path : .
157
- - name : Set up Python
158
- uses : actions/setup-python@v4
159
- with :
160
- python-version : ${{ env.PYTHON_VERSION }}
161
- cache : ' pip'
162
- - name : Run ruff check (Blocking in PR: Fix lint errors first)
163
- run : ruff check --output-format=concise .
163
+ - name : Run ruff check
164
+ run : ruff check --output-format=concise . # Fails PR if lint errors exist
164
165
165
- test-pr :
166
- name : " 🧪 Unit Tests (PR-Blocking )"
167
- needs : setup-checks-pr
166
+ pr-unit-tests :
167
+ name : " 🧪 PR: Unit Tests (BLOCKING )"
168
+ needs : pr- setup-tools
168
169
runs-on : ubuntu-latest
169
170
steps :
170
- - name : Checkout PR Source Branch
171
+ - name : Checkout PR source branch
171
172
uses : actions/checkout@v4
172
173
with :
173
174
ref : ${{ github.head_ref }}
174
175
path : .
175
- - name : Set up Python
176
- uses : actions/setup-python@v4
177
- with :
178
- python-version : ${{ env.PYTHON_VERSION }}
179
- cache : ' pip'
180
- - name : Run pytest (Blocking in PR: Fix test failures first)
181
- run : pytest
176
+ - name : Run pytest
177
+ run : pytest # Fails PR if test failures exist
182
178
183
- # 4. PR Security Analysis : CodeQL results synced to PR "Security" tab
184
- codeql-pr :
185
- name : " 🛡️ CodeQL (PR) "
186
- needs : setup-checks-pr
179
+ # 4. Mandatory PR Security: CodeQL (syncs to PR "Security" tab)
180
+ pr-codeql :
181
+ name : " 🛡️ PR: CodeQL Analysis "
182
+ needs : pr- setup-tools
187
183
runs-on : ubuntu-latest
188
184
permissions :
189
185
actions : read
190
186
contents : read
191
- security-events : write # Required to sync results to PR Security tab
187
+ security-events : write # Mandatory for PR security alerts
192
188
steps :
193
- - name : Checkout PR Source Branch
189
+ - name : Checkout PR source branch
194
190
uses : actions/checkout@v4
195
191
with :
196
192
ref : ${{ github.head_ref }}
@@ -201,24 +197,22 @@ lint-check-pr:
201
197
languages : python
202
198
- name : Autobuild
203
199
uses : github/codeql-action/autobuild@v2
204
- - name : Perform CodeQL Analysis
200
+ - name : Analyze
205
201
uses : github/codeql-action/analyze@v2
206
202
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 ]
211
- if : always()
203
+ # 5. Mandatory PR Step: Block invalid merges
204
+ pr-merge-gate :
205
+ name : " 🚫 PR: Merge Gate (MANDATORY) "
206
+ needs : [pr- spell-check, pr- security-check, pr- type-check, pr- lint-check, pr-unit-tests, pr-codeql ]
207
+ if : github.event_name == 'pull_request'
212
208
runs-on : ubuntu-latest
213
209
steps :
214
- - name : Print PR Check Summary
210
+ - name : Check PR validity
215
211
run : |
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"
212
+ # Block merge if ANY blocking check fails
213
+ if [[ "${{ contains(needs.pr-lint-check.result, 'failure') || contains(needs.pr-unit-tests.result, 'failure') || contains(needs.pr-codeql.result, 'failure') }}" == "true" ]]; then
214
+ echo "❌ PR CANNOT be merged: Blocking checks (lint/tests/CodeQL) failed."
221
215
exit 1
222
216
else
223
- echo "✅ Critical PR Checks Passed - Non- blocking issues (spelling/type) are optional to fix "
217
+ echo "✅ PR is merge-ready: All blocking checks passed. "
224
218
fi
0 commit comments