Feat/sonarqube #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: SonarCloud Full Metrics (main branch) | |
| on: | |
| push: | |
| branches: [sonarqube] | |
| pull_request: | |
| branches: [main, master] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| full-metrics: | |
| name: Full Project Report | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # ===================================================== | |
| # Backend-Tests + Coverage | |
| # ===================================================== | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.10" | |
| - name: Install backend deps | |
| working-directory: project/backend | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install -r requirements.txt | |
| python -m pip install "pytest-cov>=5,<7" "coverage>=7" | |
| - name: Run backend tests with coverage | |
| working-directory: project | |
| run: | | |
| python -m pytest \ | |
| --cov=backend \ | |
| --cov-report=xml:backend/coverage.xml \ | |
| --cov-report=term-missing \ | |
| backend/tests/ | |
| continue-on-error: true | |
| # ===================================================== | |
| # SonarCloud Scan | |
| # ===================================================== | |
| - name: SonarQube Scan | |
| uses: SonarSource/sonarqube-scan-action@v3 | |
| with: | |
| projectBaseDir: project | |
| args: > | |
| -Dsonar.projectKey=GalacticCodeGambit_LazyCook | |
| -Dsonar.organization=galacticcodegambit | |
| -Dproject.settings=sonar-project.properties | |
| -Dsonar.python.coverage.reportPaths=backend/coverage.xml | |
| -Dsonar.python.version=3.10 | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| - name: Wait for analysis | |
| id: qg | |
| uses: SonarSource/sonarqube-quality-gate-action@master | |
| timeout-minutes: 5 | |
| continue-on-error: true | |
| with: | |
| scanMetadataReportFile: project/.scannerwork/report-task.txt | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| # ===================================================== | |
| # Voller Projekt-Report ins Job-Summary | |
| # ===================================================== | |
| - name: Render Full Metrics | |
| if: always() | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| SONAR_HOST: https://sonarcloud.io | |
| QG_STATUS: ${{ steps.qg.outputs.quality-gate-status }} | |
| run: | | |
| set +e | |
| KEY="GalacticCodeGambit_LazyCook" | |
| OUT="$GITHUB_STEP_SUMMARY" | |
| # Alle relevanten Branch-Metriken auf einen Schwung holen | |
| 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" | |
| URL="${SONAR_HOST}/api/measures/component?component=${KEY}&metricKeys=${METRICS}" | |
| RESP=$(curl -s -u "${SONAR_TOKEN}:" "${URL}") | |
| # Mini-Diagnose im Log | |
| echo "Anfrage: ${URL}" | |
| echo "Response (erste 300 Zeichen):" | |
| echo "${RESP}" | head -c 300 | |
| echo "" | |
| # Hilfsfunktion: Metrik-Wert holen, "-" als Fallback | |
| get() { | |
| echo "${RESP}" | jq -r --arg k "$1" \ | |
| '(.component.measures[]? | select(.metric==$k) | .value) // "-"' 2>/dev/null | |
| } | |
| # Rating-Buchstabe (1.0..5.0 → A..E) | |
| rating() { | |
| case "$(get "$1")" in | |
| 1.0) echo "A" ;; 2.0) echo "B" ;; 3.0) echo "C" ;; | |
| 4.0) echo "D" ;; 5.0) echo "E" ;; *) echo "-" ;; | |
| esac | |
| } | |
| # Minuten → Stunden + Minuten | |
| fmt_debt() { | |
| local m=$1 | |
| if [[ "$m" =~ ^[0-9]+$ ]]; then | |
| local h=$((m / 60)); local r=$((m % 60)) | |
| echo "${h}h ${r}min" | |
| else | |
| echo "-" | |
| fi | |
| } | |
| # Quality-Gate-Icon | |
| if [ "${QG_STATUS}" = "PASSED" ] || [ "$(get alert_status)" = "OK" ]; then | |
| QG_ICON=":white_check_mark:"; QG_TXT="PASSED" | |
| else | |
| QG_ICON=":x:"; QG_TXT="FAILED" | |
| fi | |
| DEBT_FMT=$(fmt_debt "$(get sqale_index)") | |
| REL_EFF_FMT=$(fmt_debt "$(get reliability_remediation_effort)") | |
| SEC_EFF_FMT=$(fmt_debt "$(get security_remediation_effort)") | |
| # ===== Summary schreiben ===== | |
| { | |
| echo "# SonarCloud – Voller Projekt-Report" | |
| echo "" | |
| echo "**Quality Gate:** ${QG_ICON} **${QG_TXT}** " | |
| echo "**Branch:** ${GITHUB_REF_NAME} " | |
| echo "**Commit:** ${GITHUB_SHA:0:7} " | |
| echo "**Dashboard:** [${SONAR_HOST}/project/overview?id=${KEY}](${SONAR_HOST}/project/overview?id=${KEY})" | |
| echo "" | |
| # --- Übersicht --- | |
| echo "## Projekt-Übersicht" | |
| echo "" | |
| echo "| Kennzahl | Wert |" | |
| echo "|---|---:|" | |
| echo "| Lines of Code | $(get ncloc) |" | |
| echo "| Kommentar-Zeilen | $(get comment_lines) |" | |
| echo "| Kommentar-Anteil | $(get comment_lines_density)% |" | |
| echo "| Dateien | $(get files) |" | |
| echo "| Klassen | $(get classes) |" | |
| echo "| Funktionen | $(get functions) |" | |
| echo "| Statements | $(get statements) |" | |
| echo "" | |
| # --- Coverage --- | |
| echo "## Test-Coverage" | |
| echo "" | |
| echo "| Metrik | Wert |" | |
| echo "|---|---:|" | |
| echo "| Coverage (gesamt) | $(get coverage)% |" | |
| echo "| Line Coverage | $(get line_coverage)% |" | |
| echo "| Branch Coverage | $(get branch_coverage)% |" | |
| echo "| Deckbare Zeilen | $(get lines_to_cover) |" | |
| echo "| Ungedeckte Zeilen | $(get uncovered_lines) |" | |
| echo "" | |
| # --- Duplikate --- | |
| echo "## Duplikate" | |
| echo "" | |
| echo "| Metrik | Wert |" | |
| echo "|---|---:|" | |
| echo "| Duplizierte Zeilen (Rate) | $(get duplicated_lines_density)% |" | |
| echo "| Duplizierte Zeilen (absolut) | $(get duplicated_lines) |" | |
| echo "| Duplikat-Blöcke | $(get duplicated_blocks) |" | |
| echo "| Betroffene Dateien | $(get duplicated_files) |" | |
| echo "" | |
| # --- Komplexität --- | |
| echo "## Komplexität" | |
| echo "" | |
| echo "| Metrik | Wert |" | |
| echo "|---|---:|" | |
| echo "| Zyklomatische Komplexität | $(get complexity) |" | |
| echo "| Cognitive Complexity | $(get cognitive_complexity) |" | |
| echo "" | |
| # --- Issues & Ratings --- | |
| echo "## Issues & Bewertungen" | |
| echo "" | |
| echo "| Kategorie | Rating | Anzahl | Behebungs-Aufwand |" | |
| echo "|---|:---:|---:|---:|" | |
| echo "| Reliability (Bugs) | $(rating reliability_rating) | $(get bugs) | ${REL_EFF_FMT} |" | |
| echo "| Security (Vulnerabilities) | $(rating security_rating) | $(get vulnerabilities) | ${SEC_EFF_FMT} |" | |
| echo "| Maintainability (Code Smells) | $(rating sqale_rating) | $(get code_smells) | ${DEBT_FMT} |" | |
| echo "| Security Hotspots | $(rating security_review_rating) | $(get security_hotspots) | $(get security_hotspots_reviewed)% reviewed |" | |
| echo "" | |
| # --- Technische Schuld --- | |
| echo "## Technische Schuld" | |
| echo "" | |
| echo "| Metrik | Wert |" | |
| echo "|---|---:|" | |
| echo "| Gesamte Schuld | ${DEBT_FMT} |" | |
| echo "| Debt Ratio | $(get sqale_debt_ratio)% |" | |
| echo "" | |
| } >> "$OUT" | |
| # ===================================================== | |
| # Top-10 Files: höchste Komplexität, schlechteste Coverage | |
| # ===================================================== | |
| { | |
| echo "## Top-10 komplexeste Dateien" | |
| echo "" | |
| echo "| Datei | Komplexität | Cognitive | LoC |" | |
| echo "|---|---:|---:|---:|" | |
| } >> "$OUT" | |
| curl -s -u "${SONAR_TOKEN}:" \ | |
| "${SONAR_HOST}/api/measures/component_tree?component=${KEY}&metricKeys=complexity,cognitive_complexity,ncloc&qualifiers=FIL&ps=10&s=metric&metricSort=complexity&asc=false" \ | |
| | jq -r '.components[]? | |
| | (.path // .key) as $p | |
| | ((.measures[]? | select(.metric=="complexity") | .value) // "-") as $c | |
| | ((.measures[]? | select(.metric=="cognitive_complexity")| .value) // "-") as $cog | |
| | ((.measures[]? | select(.metric=="ncloc") | .value) // "-") as $n | |
| | "| " + $p + " | " + $c + " | " + $cog + " | " + $n + " |"' \ | |
| >> "$OUT" | |
| { | |
| echo "" | |
| echo "## Top-10 Dateien mit schlechtester Coverage" | |
| echo "" | |
| echo "| Datei | Coverage | Ungedeckte Zeilen | LoC |" | |
| echo "|---|---:|---:|---:|" | |
| } >> "$OUT" | |
| curl -s -u "${SONAR_TOKEN}:" \ | |
| "${SONAR_HOST}/api/measures/component_tree?component=${KEY}&metricKeys=coverage,uncovered_lines,ncloc&qualifiers=FIL&ps=10&s=metric&metricSort=coverage&asc=true" \ | |
| | jq -r '.components[]? | |
| | select(.measures[]? | select(.metric=="coverage")) | |
| | (.path // .key) as $p | |
| | ((.measures[]? | select(.metric=="coverage") | .value) // "-") as $cov | |
| | ((.measures[]? | select(.metric=="uncovered_lines") | .value) // "-") as $unc | |
| | ((.measures[]? | select(.metric=="ncloc") | .value) // "-") as $n | |
| | "| " + $p + " | " + $cov + "% | " + $unc + " | " + $n + " |"' \ | |
| >> "$OUT" | |
| { | |
| echo "" | |
| echo "## Top-10 Dateien mit den meisten Duplikat-Blöcken" | |
| echo "" | |
| echo "| Datei | Blöcke | Dupl. Zeilen | LoC |" | |
| echo "|---|---:|---:|---:|" | |
| } >> "$OUT" | |
| curl -s -u "${SONAR_TOKEN}:" \ | |
| "${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" \ | |
| | jq -r '.components[]? | |
| | (.path // .key) as $p | |
| | ((.measures[]? | select(.metric=="duplicated_blocks") | .value) // "0") as $b | |
| | ((.measures[]? | select(.metric=="duplicated_lines") | .value) // "0") as $l | |
| | ((.measures[]? | select(.metric=="ncloc") | .value) // "-") as $n | |
| | select(($b | tonumber) > 0) | |
| | "| " + $p + " | " + $b + " | " + $l + " | " + $n + " |"' \ | |
| >> "$OUT" | |
| { | |
| echo "" | |
| echo "---" | |
| echo "_Generiert von SonarCloud-Analyse aus Push auf \`${GITHUB_REF_NAME}\`._" | |
| } >> "$OUT" |