Skip to content

Commit 2993dc3

Browse files
committed
Test: Bash Print in CI/CD - Pipeline with detailed information about coverage, duplication and complexity
1 parent 847fb33 commit 2993dc3

2 files changed

Lines changed: 277 additions & 2 deletions

File tree

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
name: SonarCloud Full Metrics (main branch)
2+
3+
on:
4+
push:
5+
branches: [main, master, sonarqube]
6+
pull_request:
7+
branches: [main, master, sonarqube]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
full-metrics:
15+
name: Full Project Report
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
24+
# =====================================================
25+
# Backend-Tests + Coverage
26+
# =====================================================
27+
- name: Set up Python
28+
uses: actions/setup-python@v5
29+
with:
30+
python-version: "3.10"
31+
32+
- name: Install backend deps
33+
working-directory: project/backend
34+
run: |
35+
python -m pip install --upgrade pip
36+
python -m pip install -r requirements.txt
37+
python -m pip install "pytest-cov>=5,<7" "coverage>=7"
38+
39+
- name: Run backend tests with coverage
40+
working-directory: project
41+
run: |
42+
python -m pytest \
43+
--cov=backend \
44+
--cov-report=xml:backend/coverage.xml \
45+
backend/tests/
46+
continue-on-error: true
47+
48+
# =====================================================
49+
# SonarCloud Scan
50+
# =====================================================
51+
- name: SonarQube Scan
52+
uses: SonarSource/sonarqube-scan-action@v3
53+
with:
54+
projectBaseDir: project
55+
args: >
56+
-Dsonar.projectKey=GalacticCodeGambit_LazyCook
57+
-Dsonar.organization=galacticcodegambit
58+
-Dproject.settings=sonar-project.properties
59+
-Dsonar.python.coverage.reportPaths=backend/coverage.xml
60+
-Dsonar.python.version=3.10
61+
env:
62+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
63+
64+
- name: Wait for analysis
65+
id: qg
66+
uses: SonarSource/sonarqube-quality-gate-action@master
67+
timeout-minutes: 5
68+
continue-on-error: true
69+
with:
70+
scanMetadataReportFile: project/.scannerwork/report-task.txt
71+
env:
72+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
73+
74+
# =====================================================
75+
# Voller Projekt-Report ins Job-Summary
76+
# =====================================================
77+
- name: Render Full Metrics
78+
if: always()
79+
env:
80+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
81+
SONAR_HOST: https://sonarcloud.io
82+
QG_STATUS: ${{ steps.qg.outputs.quality-gate-status }}
83+
run: |
84+
set +e
85+
KEY="GalacticCodeGambit_LazyCook"
86+
OUT="$GITHUB_STEP_SUMMARY"
87+
88+
# Alle relevanten Branch-Metriken auf einen Schwung holen
89+
METRICS="alert_status,bugs,vulnerabilities,code_smells,security_hotspots,security_hotspots_reviewed,coverage,line_coverage,branch_coverage,lines_to_cover,uncovered_lines,duplicated_lines_density,duplicated_blocks,duplicated_files,duplicated_lines,complexity,cognitive_complexity,classes,functions,statements,files,ncloc,comment_lines,comment_lines_density,sqale_rating,reliability_rating,security_rating,security_review_rating,sqale_index,sqale_debt_ratio,reliability_remediation_effort,security_remediation_effort"
90+
91+
URL="${SONAR_HOST}/api/measures/component?component=${KEY}&metricKeys=${METRICS}"
92+
RESP=$(curl -s -u "${SONAR_TOKEN}:" "${URL}")
93+
94+
# Mini-Diagnose im Log
95+
echo "Anfrage: ${URL}"
96+
echo "Response (erste 300 Zeichen):"
97+
echo "${RESP}" | head -c 300
98+
echo ""
99+
100+
# Hilfsfunktion: Metrik-Wert holen, "-" als Fallback
101+
get() {
102+
echo "${RESP}" | jq -r --arg k "$1" \
103+
'(.component.measures[]? | select(.metric==$k) | .value) // "-"' 2>/dev/null
104+
}
105+
106+
# Rating-Buchstabe (1.0..5.0 → A..E)
107+
rating() {
108+
case "$(get "$1")" in
109+
1.0) echo "A" ;; 2.0) echo "B" ;; 3.0) echo "C" ;;
110+
4.0) echo "D" ;; 5.0) echo "E" ;; *) echo "-" ;;
111+
esac
112+
}
113+
114+
# Minuten → Stunden + Minuten
115+
fmt_debt() {
116+
local m=$1
117+
if [[ "$m" =~ ^[0-9]+$ ]]; then
118+
local h=$((m / 60)); local r=$((m % 60))
119+
echo "${h}h ${r}min"
120+
else
121+
echo "-"
122+
fi
123+
}
124+
125+
# Quality-Gate-Icon
126+
if [ "${QG_STATUS}" = "PASSED" ] || [ "$(get alert_status)" = "OK" ]; then
127+
QG_ICON=":white_check_mark:"; QG_TXT="PASSED"
128+
else
129+
QG_ICON=":x:"; QG_TXT="FAILED"
130+
fi
131+
132+
DEBT_FMT=$(fmt_debt "$(get sqale_index)")
133+
REL_EFF_FMT=$(fmt_debt "$(get reliability_remediation_effort)")
134+
SEC_EFF_FMT=$(fmt_debt "$(get security_remediation_effort)")
135+
136+
# ===== Summary schreiben =====
137+
{
138+
echo "# SonarCloud – Voller Projekt-Report"
139+
echo ""
140+
echo "**Quality Gate:** ${QG_ICON} **${QG_TXT}** "
141+
echo "**Branch:** ${GITHUB_REF_NAME} "
142+
echo "**Commit:** ${GITHUB_SHA:0:7} "
143+
echo "**Dashboard:** [${SONAR_HOST}/project/overview?id=${KEY}](${SONAR_HOST}/project/overview?id=${KEY})"
144+
echo ""
145+
146+
# --- Übersicht ---
147+
echo "## Projekt-Übersicht"
148+
echo ""
149+
echo "| Kennzahl | Wert |"
150+
echo "|---|---:|"
151+
echo "| Lines of Code | $(get ncloc) |"
152+
echo "| Kommentar-Zeilen | $(get comment_lines) |"
153+
echo "| Kommentar-Anteil | $(get comment_lines_density)% |"
154+
echo "| Dateien | $(get files) |"
155+
echo "| Klassen | $(get classes) |"
156+
echo "| Funktionen | $(get functions) |"
157+
echo "| Statements | $(get statements) |"
158+
echo ""
159+
160+
# --- Coverage ---
161+
echo "## Test-Coverage"
162+
echo ""
163+
echo "| Metrik | Wert |"
164+
echo "|---|---:|"
165+
echo "| Coverage (gesamt) | $(get coverage)% |"
166+
echo "| Line Coverage | $(get line_coverage)% |"
167+
echo "| Branch Coverage | $(get branch_coverage)% |"
168+
echo "| Deckbare Zeilen | $(get lines_to_cover) |"
169+
echo "| Ungedeckte Zeilen | $(get uncovered_lines) |"
170+
echo ""
171+
172+
# --- Duplikate ---
173+
echo "## Duplikate"
174+
echo ""
175+
echo "| Metrik | Wert |"
176+
echo "|---|---:|"
177+
echo "| Duplizierte Zeilen (Rate) | $(get duplicated_lines_density)% |"
178+
echo "| Duplizierte Zeilen (absolut) | $(get duplicated_lines) |"
179+
echo "| Duplikat-Blöcke | $(get duplicated_blocks) |"
180+
echo "| Betroffene Dateien | $(get duplicated_files) |"
181+
echo ""
182+
183+
# --- Komplexität ---
184+
echo "## Komplexität"
185+
echo ""
186+
echo "| Metrik | Wert |"
187+
echo "|---|---:|"
188+
echo "| Zyklomatische Komplexität | $(get complexity) |"
189+
echo "| Cognitive Complexity | $(get cognitive_complexity) |"
190+
echo ""
191+
192+
# --- Issues & Ratings ---
193+
echo "## Issues & Bewertungen"
194+
echo ""
195+
echo "| Kategorie | Rating | Anzahl | Behebungs-Aufwand |"
196+
echo "|---|:---:|---:|---:|"
197+
echo "| Reliability (Bugs) | $(rating reliability_rating) | $(get bugs) | ${REL_EFF_FMT} |"
198+
echo "| Security (Vulnerabilities) | $(rating security_rating) | $(get vulnerabilities) | ${SEC_EFF_FMT} |"
199+
echo "| Maintainability (Code Smells) | $(rating sqale_rating) | $(get code_smells) | ${DEBT_FMT} |"
200+
echo "| Security Hotspots | $(rating security_review_rating) | $(get security_hotspots) | $(get security_hotspots_reviewed)% reviewed |"
201+
echo ""
202+
203+
# --- Technische Schuld ---
204+
echo "## Technische Schuld"
205+
echo ""
206+
echo "| Metrik | Wert |"
207+
echo "|---|---:|"
208+
echo "| Gesamte Schuld | ${DEBT_FMT} |"
209+
echo "| Debt Ratio | $(get sqale_debt_ratio)% |"
210+
echo ""
211+
} >> "$OUT"
212+
213+
# =====================================================
214+
# Top-10 Files: höchste Komplexität, schlechteste Coverage
215+
# =====================================================
216+
{
217+
echo "## Top-10 komplexeste Dateien"
218+
echo ""
219+
echo "| Datei | Komplexität | Cognitive | LoC |"
220+
echo "|---|---:|---:|---:|"
221+
} >> "$OUT"
222+
223+
curl -s -u "${SONAR_TOKEN}:" \
224+
"${SONAR_HOST}/api/measures/component_tree?component=${KEY}&metricKeys=complexity,cognitive_complexity,ncloc&qualifiers=FIL&ps=10&s=metric&metricSort=complexity&asc=false" \
225+
| jq -r '.components[]?
226+
| (.path // .key) as $p
227+
| ((.measures[]? | select(.metric=="complexity") | .value) // "-") as $c
228+
| ((.measures[]? | select(.metric=="cognitive_complexity")| .value) // "-") as $cog
229+
| ((.measures[]? | select(.metric=="ncloc") | .value) // "-") as $n
230+
| "| " + $p + " | " + $c + " | " + $cog + " | " + $n + " |"' \
231+
>> "$OUT"
232+
233+
{
234+
echo ""
235+
echo "## Top-10 Dateien mit schlechtester Coverage"
236+
echo ""
237+
echo "| Datei | Coverage | Ungedeckte Zeilen | LoC |"
238+
echo "|---|---:|---:|---:|"
239+
} >> "$OUT"
240+
241+
curl -s -u "${SONAR_TOKEN}:" \
242+
"${SONAR_HOST}/api/measures/component_tree?component=${KEY}&metricKeys=coverage,uncovered_lines,ncloc&qualifiers=FIL&ps=10&s=metric&metricSort=coverage&asc=true" \
243+
| jq -r '.components[]?
244+
| select(.measures[]? | select(.metric=="coverage"))
245+
| (.path // .key) as $p
246+
| ((.measures[]? | select(.metric=="coverage") | .value) // "-") as $cov
247+
| ((.measures[]? | select(.metric=="uncovered_lines") | .value) // "-") as $unc
248+
| ((.measures[]? | select(.metric=="ncloc") | .value) // "-") as $n
249+
| "| " + $p + " | " + $cov + "% | " + $unc + " | " + $n + " |"' \
250+
>> "$OUT"
251+
252+
{
253+
echo ""
254+
echo "## Top-10 Dateien mit den meisten Duplikat-Blöcken"
255+
echo ""
256+
echo "| Datei | Blöcke | Dupl. Zeilen | LoC |"
257+
echo "|---|---:|---:|---:|"
258+
} >> "$OUT"
259+
260+
curl -s -u "${SONAR_TOKEN}:" \
261+
"${SONAR_HOST}/api/measures/component_tree?component=${KEY}&metricKeys=duplicated_blocks,duplicated_lines,ncloc&qualifiers=FIL&ps=10&s=metric&metricSort=duplicated_blocks&asc=false" \
262+
| jq -r '.components[]?
263+
| (.path // .key) as $p
264+
| ((.measures[]? | select(.metric=="duplicated_blocks") | .value) // "0") as $b
265+
| ((.measures[]? | select(.metric=="duplicated_lines") | .value) // "0") as $l
266+
| ((.measures[]? | select(.metric=="ncloc") | .value) // "-") as $n
267+
| select(($b | tonumber) > 0)
268+
| "| " + $p + " | " + $b + " | " + $l + " | " + $n + " |"' \
269+
>> "$OUT"
270+
271+
{
272+
echo ""
273+
echo "---"
274+
echo "_Generiert von SonarCloud-Analyse aus Push auf \`${GITHUB_REF_NAME}\`._"
275+
} >> "$OUT"

.github/workflows/sonarqube.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
on:
44
push:
5-
branches: [main, master, develop]
5+
branches: [main, master, sonarqube]
66
pull_request:
7-
branches: [main, master, develop]
7+
branches: [main, master]
88
workflow_dispatch:
99

1010
permissions:

0 commit comments

Comments
 (0)