1+ name : Code Quality Checks
2+
3+ on :
4+ pull_request :
5+ branches : [main, dev]
6+ types : [opened, synchronize, reopened, ready_for_review]
7+
8+ concurrency :
9+ group : ${{ github.workflow }}-${{ github.ref }}
10+ cancel-in-progress : true
11+
12+ jobs :
13+ file-quality :
14+ name : File Quality Checks
15+ runs-on : ubuntu-latest
16+ if : github.event.pull_request.draft == false
17+
18+ steps :
19+ - name : Checkout code
20+ uses : actions/checkout@v4
21+ with :
22+ fetch-depth : 0
23+
24+ - name : Fetch base branch
25+ run : |
26+ # Ensure we have the base branch reference for comparison
27+ git fetch origin ${{ github.base_ref }}:${{ github.base_ref }} 2>/dev/null || git fetch origin ${{ github.base_ref }} 2>/dev/null || true
28+
29+ - name : Set up Python
30+ uses : actions/setup-python@v5
31+ with :
32+ python-version : ' 3.12'
33+
34+ - name : Install pre-commit
35+ run : pip install pre-commit
36+
37+ - name : Cache pre-commit hooks
38+ uses : actions/cache@v4
39+ with :
40+ path : ~/.cache/pre-commit
41+ key : pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
42+ restore-keys : |
43+ pre-commit-
44+
45+ - name : Install hook environments (cache)
46+ run : pre-commit install-hooks
47+
48+ - name : Run file quality checks on changed files
49+ run : |
50+ # Get list of changed files and run specific hooks on them
51+ if git show-ref --verify --quiet refs/heads/${{ github.base_ref }}; then
52+ BASE_REF="${{ github.base_ref }}"
53+ elif git show-ref --verify --quiet refs/remotes/origin/${{ github.base_ref }}; then
54+ BASE_REF="origin/${{ github.base_ref }}"
55+ else
56+ echo "Base branch reference not found, running file quality hooks on all files"
57+ pre-commit run --all-files check-yaml check-json check-toml check-merge-conflict check-added-large-files debug-statements check-case-conflict
58+ exit 0
59+ fi
60+
61+ echo "Running file quality hooks on changed files against $BASE_REF"
62+
63+ # Run each hook individually on changed files
64+ SKIP=detect-secrets,bandit,ruff,ruff-format,prettier,eslint,typescript-check-web,typescript-check-extension,commitizen \
65+ pre-commit run --from-ref $BASE_REF --to-ref HEAD || exit_code=$?
66+
67+ # Exit with the same code as pre-commit
68+ exit ${exit_code:-0}
69+
70+ security-scan :
71+ name : Security Scan
72+ runs-on : ubuntu-latest
73+ if : github.event.pull_request.draft == false
74+
75+ steps :
76+ - name : Checkout code
77+ uses : actions/checkout@v4
78+ with :
79+ fetch-depth : 0
80+
81+ - name : Fetch base branch
82+ run : |
83+ git fetch origin ${{ github.base_ref }}:${{ github.base_ref }} 2>/dev/null || git fetch origin ${{ github.base_ref }} 2>/dev/null || true
84+
85+ - name : Set up Python
86+ uses : actions/setup-python@v5
87+ with :
88+ python-version : ' 3.12'
89+
90+ - name : Install pre-commit
91+ run : pip install pre-commit
92+
93+ - name : Cache pre-commit hooks
94+ uses : actions/cache@v4
95+ with :
96+ path : ~/.cache/pre-commit
97+ key : pre-commit-security-${{ hashFiles('.pre-commit-config.yaml') }}
98+ restore-keys : |
99+ pre-commit-security-
100+
101+ - name : Install hook environments (cache)
102+ run : pre-commit install-hooks
103+
104+ - name : Run security scans on changed files
105+ run : |
106+ # Get base ref for comparison
107+ if git show-ref --verify --quiet refs/heads/${{ github.base_ref }}; then
108+ BASE_REF="${{ github.base_ref }}"
109+ elif git show-ref --verify --quiet refs/remotes/origin/${{ github.base_ref }}; then
110+ BASE_REF="origin/${{ github.base_ref }}"
111+ else
112+ echo "Base branch reference not found, running security scans on all files"
113+ echo "⚠️ This may take longer than normal"
114+ pre-commit run --all-files detect-secrets bandit
115+ exit 0
116+ fi
117+
118+ echo "Running security scans on changed files against $BASE_REF"
119+
120+ # Run only security hooks on changed files
121+ SKIP=check-yaml,check-json,check-toml,check-merge-conflict,check-added-large-files,debug-statements,check-case-conflict,ruff,ruff-format,prettier,eslint,typescript-check-web,typescript-check-extension,commitizen \
122+ pre-commit run --from-ref $BASE_REF --to-ref HEAD || exit_code=$?
123+
124+ # Exit with the same code as pre-commit
125+ exit ${exit_code:-0}
126+
127+ python-backend :
128+ name : Python Backend Quality
129+ runs-on : ubuntu-latest
130+ if : github.event.pull_request.draft == false
131+
132+ steps :
133+ - name : Checkout code
134+ uses : actions/checkout@v4
135+ with :
136+ fetch-depth : 0
137+
138+ - name : Set up Python
139+ uses : actions/setup-python@v5
140+ with :
141+ python-version : ' 3.12'
142+
143+ - name : Install UV
144+ uses : astral-sh/setup-uv@v3
145+
146+ - name : Check if backend files changed
147+ id : backend-changes
148+ uses : dorny/paths-filter@v3
149+ with :
150+ filters : |
151+ backend:
152+ - 'surfsense_backend/**'
153+
154+ - name : Cache dependencies
155+ if : steps.backend-changes.outputs.backend == 'true'
156+ uses : actions/cache@v4
157+ with :
158+ path : |
159+ ~/.cache/uv
160+ surfsense_backend/.venv
161+ key : python-deps-${{ hashFiles('surfsense_backend/uv.lock') }}
162+
163+ - name : Install dependencies
164+ if : steps.backend-changes.outputs.backend == 'true'
165+ working-directory : surfsense_backend
166+ run : uv sync
167+
168+ - name : Install pre-commit for backend checks
169+ if : steps.backend-changes.outputs.backend == 'true'
170+ run : pip install pre-commit
171+
172+ - name : Cache pre-commit hooks
173+ if : steps.backend-changes.outputs.backend == 'true'
174+ uses : actions/cache@v4
175+ with :
176+ path : ~/.cache/pre-commit
177+ key : pre-commit-backend-${{ hashFiles('.pre-commit-config.yaml') }}
178+ restore-keys : |
179+ pre-commit-backend-
180+
181+ - name : Install hook environments (cache)
182+ if : steps.backend-changes.outputs.backend == 'true'
183+ run : pre-commit install-hooks
184+
185+ - name : Run Python backend quality checks
186+ if : steps.backend-changes.outputs.backend == 'true'
187+ run : |
188+ # Get base ref for comparison
189+ if git show-ref --verify --quiet refs/heads/${{ github.base_ref }}; then
190+ BASE_REF="${{ github.base_ref }}"
191+ elif git show-ref --verify --quiet refs/remotes/origin/${{ github.base_ref }}; then
192+ BASE_REF="origin/${{ github.base_ref }}"
193+ else
194+ echo "Base branch reference not found, running Python backend checks on all files"
195+ pre-commit run --all-files ruff ruff-format
196+ exit 0
197+ fi
198+
199+ echo "Running Python backend checks on changed files against $BASE_REF"
200+
201+ # Run only ruff hooks on changed Python files
202+ SKIP=detect-secrets,bandit,check-yaml,check-json,check-toml,check-merge-conflict,check-added-large-files,debug-statements,check-case-conflict,prettier,eslint,typescript-check-web,typescript-check-extension,commitizen \
203+ pre-commit run --from-ref $BASE_REF --to-ref HEAD || exit_code=$?
204+
205+ # Exit with the same code as pre-commit
206+ exit ${exit_code:-0}
207+
208+ quality-gate :
209+ name : Quality Gate
210+ runs-on : ubuntu-latest
211+ needs : [file-quality, security-scan, python-backend]
212+ if : always()
213+
214+ steps :
215+ - name : Check all jobs status
216+ run : |
217+ if [[ "${{ needs.file-quality.result }}" == "failure" ||
218+ "${{ needs.security-scan.result }}" == "failure" ||
219+ "${{ needs.python-backend.result }}" == "failure" ]]; then
220+ echo "❌ Code quality checks failed"
221+ exit 1
222+ else
223+ echo "✅ All code quality checks passed"
224+ fi
0 commit comments