-
Notifications
You must be signed in to change notification settings - Fork 0
161 lines (142 loc) · 5.96 KB
/
Copy pathcode-quality.yml
File metadata and controls
161 lines (142 loc) · 5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
name: Code Quality Analysis
on:
schedule:
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
code-quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install UV
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: "backend/uv.lock"
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version-file: frontend/package.json
- name: Verify Bun runtime
run: bun --version
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "24"
- name: Install just
uses: extractions/setup-just@v2
- name: Install backend dependencies
run: cd backend && uv sync --dev
- name: Install frontend dependencies
run: cd frontend && bun install --frozen-lockfile
- name: Install code quality tools
run: npm install -g jscpd fallow
- name: Run fallow analysis (frontend — SvelteKit)
run: cd frontend && npx fallow --format json --sarif-file fallow-results.sarif > fallow-results.json
continue-on-error: true
- name: Upload fallow SARIF results (frontend)
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: frontend/fallow-results.sarif
category: fallow-frontend
- name: Run duplication analysis (backend only)
run: just duplication
- name: Run complexity analysis
run: just complexity
- name: Run dead code analysis (backend — Python)
run: cd backend && uv run vulture app/ vulture_whitelist.py --min-confidence 80 2>&1 | tee ../vulture-report.txt
continue-on-error: true
- name: Run dead code analysis (frontend — SvelteKit)
run: cd frontend && npx fallow dead-code --format json > ../fallow-frontend-dead-code.json
continue-on-error: true
- name: Check quality thresholds
run: |
echo "=== Quality Threshold Check ==="
FAIL=0
if [ -f jscpd-report/jscpd-report.html ]; then
# Scope to the "Duplicated Lines" stat card; a bare grep for digits
# before % matches CSS values like width:100% earlier in the HTML.
DUP_PCT=$(grep -A1 'Duplicated Lines' jscpd-report/jscpd-report.html | grep -oP '\d+(?:\.\d+)?(?=%)' | head -1)
if [ -z "$DUP_PCT" ]; then
echo "::warning::Could not parse duplication percentage from jscpd report"
DUP_PCT=0
fi
echo "Duplication: ${DUP_PCT}%"
if awk "BEGIN {exit !($DUP_PCT > 20)}"; then
echo "::error::Duplication above 20% threshold: ${DUP_PCT}%"
FAIL=1
fi
else
echo "::error::jscpd report not found — duplication analysis may have failed"
FAIL=1
fi
if [ -f vulture-report.txt ]; then
DEAD_COUNT=$(grep -c ':' vulture-report.txt 2>/dev/null | tr -d '[:space:]' || echo "0")
echo "Dead code items (Python): ${DEAD_COUNT}"
if [ "$DEAD_COUNT" -gt 50 ] 2>/dev/null; then
echo "::error::Dead code items above 50 threshold: ${DEAD_COUNT}"
FAIL=1
fi
else
echo "::warning::vulture report not found — Python dead code analysis skipped"
fi
if [ -f fallow-frontend-dead-code.json ]; then
SVELTE_DEAD=$(python3 -c "import json; d=json.load(open('fallow-frontend-dead-code.json')); print(len(d.get('deadCode',{}).get('unusedFiles',[])))" 2>/dev/null)
if [ -z "$SVELTE_DEAD" ]; then
echo "::warning::Could not parse fallow-svelte dead code JSON"
SVELTE_DEAD=0
fi
echo "SvelteKit dead files: ${SVELTE_DEAD}"
if [ "$SVELTE_DEAD" -gt 20 ] 2>/dev/null; then
echo "::error::SvelteKit dead files above 20 threshold: ${SVELTE_DEAD}"
FAIL=1
fi
else
echo "::warning::fallow-svelte dead code results not found — SvelteKit analysis skipped"
fi
if [ "$FAIL" -eq 1 ]; then
echo "::error::Quality thresholds exceeded — see annotations above"
exit 1
fi
echo "All quality thresholds passed"
- name: Upload reports
uses: actions/upload-artifact@v4
if: always()
with:
name: code-quality-reports
path: |
jscpd-report/
vulture-report.txt
frontend/fallow-results.json
frontend/fallow-results.sarif
fallow-frontend-dead-code.json
- name: Create failure issue
if: failure()
uses: actions/github-script@v7
with:
script: |
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const date = new Date().toISOString().split('T')[0];
const existing = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'nightly-quality',
state: 'open'
});
if (existing.data.length > 0) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existing.data[0].number,
body: `Nightly quality check failed again on ${date}.\n[View run](${runUrl})`
});
} else {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Nightly code quality check failed',
labels: ['nightly-quality'],
body: `The nightly code quality analysis failed on ${date}.\n\n[View run](${runUrl})\n\nCheck the quality thresholds in the workflow and address the issues.`
});
}