Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7469763
Merge pull request #13 from Komal362000/fix/codeql-update-misra-pack-…
Komal362000 Jun 12, 2026
2e24535
Merge branch 'eclipse-score:main' into main
Komal362000 Jun 12, 2026
90f8b95
Merge branch 'eclipse-score:main' into main
Komal362000 Jun 12, 2026
28e7045
Merge branch 'eclipse-score:main' into main
Komal362000 Jun 12, 2026
4e2de21
feat(quality): integrate CodeQL findings into dashboard and quality r…
Komal362000 Jun 15, 2026
8f10c94
Merge branch 'main' into feat/codeql-results-dashboard
Komal362000 Jun 15, 2026
08b3e43
Merge branch 'eclipse-score:main' into main
Komal362000 Jun 15, 2026
dac921e
Merge pull request #15 from Komal362000/feat/codeql-results-dashboard
Komal362000 Jun 15, 2026
b1e780d
Merge branch 'eclipse-score:main' into main
Komal362000 Jun 15, 2026
efcb1b5
Merge branch 'eclipse-score:main' into main
Komal362000 Jun 16, 2026
c4e9bf1
fix(quality): rename CodeQL title and stub ape dep for CI
Komal362000 Jun 16, 2026
23b9a4e
Merge pull request #16 from Komal362000/feat/codeql-results-dashboard
Komal362000 Jun 16, 2026
7029259
feat(quality): add CodeQL HTML report page (like coverage)
Komal362000 Jun 16, 2026
8b7e488
Merge pull request #17 from Komal362000/feat/codeql-results-dashboard
Komal362000 Jun 16, 2026
d52f2f9
fix(quality): add ape stub to deploy job in nightly_quality.yml
Komal362000 Jun 16, 2026
326631e
Merge pull request #18 from Komal362000/feat/codeql-results-dashboard
Komal362000 Jun 16, 2026
18a0965
fix(quality): add codeql_report.html.j2 to BUILD data deps
Komal362000 Jun 16, 2026
b309140
Merge pull request #19 from Komal362000/feat/codeql-results-dashboard
Komal362000 Jun 16, 2026
2ca3f5c
Merge branch 'eclipse-score:main' into feat/codeql-results-dashboard
Komal362000 Jun 16, 2026
8d98e1d
Fix: CodeQL dashboard now correctly displays 0 findings
Komal362000 Jun 16, 2026
b0ceb34
Merge branch 'main' into feat/codeql-results-dashboard
Komal362000 Jun 16, 2026
8057870
improve(quality): Better CodeQL CSV parsing with debug diagnostics
Komal362000 Jun 17, 2026
09b0b69
refactor(quality): Remove CodeQL HTML conversion, show CSV directly
Komal362000 Jun 17, 2026
994c0bf
fix(quality): Show CodeQL findings in browser, not download
Komal362000 Jun 17, 2026
b6662cd
fix(quality): Remove orphaned JavaScript from template
Komal362000 Jun 18, 2026
300a750
fix(workflow): Remove escaped quotes from bazel command
Komal362000 Jun 18, 2026
eadce98
404 error fix
Komal362000 Jun 18, 2026
9238e9a
Now coverage data shown on dashbord
Komal362000 Jun 18, 2026
8d40f2e
Merge branch 'eclipse-score:main' into feat/codeql-results-dashboard
Komal362000 Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ on:
schedule:
- cron: '0 2 * * *' # Nightly at 2 AM UTC
workflow_dispatch: # Allow maintainers to trigger manually when needed
workflow_call:
outputs:
artifact-name:
description: Name of the uploaded CSV artifact
value: codeql-csv-results
conclusion:
description: Job conclusion (success/failure)
value: ${{ jobs.run-codeql.result }}

permissions:
contents: read
Expand Down Expand Up @@ -50,6 +58,13 @@ jobs:
- name: Allow linux-sandbox
uses: ./actions/unblock_user_namespace_for_linux_sandbox

- name: Stub out ARM-only dependencies unavailable in CI
run: |
mkdir -p /tmp/ape_stub
touch /tmp/ape_stub/BUILD.bazel
touch /tmp/ape_stub/WORKSPACE
echo "common --override_repository=ape+=/tmp/ape_stub" >> user.bazelrc

- name: Create CodeQL database
run: |
bazel run //quality/static_analysis:codeql_lint -- \
Expand Down
47 changes: 44 additions & 3 deletions .github/workflows/nightly_quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@
# Runs every night at midnight UTC:
# - Coverage : full C++ test suite with gcov/lcov → HTML report
# - Clang-Tidy: static analysis across all C++ targets → findings text file
# - CodeQL : MISRA C++ compliance analysis → CSV findings
#
# After both jobs complete, deploy-quality-reports:
# 1. Downloads the coverage HTML artifact and the clang-tidy findings artifact
# After all jobs complete, deploy-quality-reports:
# 1. Downloads the coverage HTML artifact, clang-tidy findings, and CodeQL CSV
# 2. Runs `bazel run //quality/dashboard:generate_dashboard` to produce the KPI dashboard
# 3. Uploads everything as nightly-quality-reports artifact for docs.yml to deploy
#
# Deployed URL structure:
# https://eclipse-score.github.io/communication/latest/quality/index.html ← dashboard
# https://eclipse-score.github.io/communication/latest/quality/coverage/index.html ← lcov HTML
# https://eclipse-score.github.io/communication/latest/quality/clang_tidy_findings.txt ← raw findings
# https://eclipse-score.github.io/communication/latest/quality/codeql/index.html ← CodeQL report

name: Nightly Quality Jobs

Expand Down Expand Up @@ -59,11 +61,20 @@ jobs:
permissions:
contents: read

# --------------------------------------------------------------------
# Quality job 3: CodeQL
# --------------------------------------------------------------------
run-codeql:
uses: ./.github/workflows/codeql.yml
permissions:
contents: read
security-events: write

# --------------------------------------------------------------------
# Collect results, build the dashboard, upload artifact for docs.yml
# --------------------------------------------------------------------
deploy-quality-reports:
needs: [run-coverage, run-clang-tidy]
needs: [run-coverage, run-clang-tidy, run-codeql]
# Always run even if individual quality jobs fail, so the dashboard
# still reflects which jobs passed and which failed.
if: always()
Expand All @@ -88,6 +99,13 @@ jobs:
id: setup
uses: ./actions/unblock_user_namespace_for_linux_sandbox

- name: Stub out ARM-only dependencies unavailable in CI
run: |
mkdir -p /tmp/ape_stub
touch /tmp/ape_stub/BUILD.bazel
touch /tmp/ape_stub/WORKSPACE
echo "common --override_repository=ape+=/tmp/ape_stub" >> user.bazelrc

# ------------------------------------------------------------------
# Download Coverage artifacts (only if the upstream job succeeded)
# ------------------------------------------------------------------
Expand Down Expand Up @@ -131,6 +149,28 @@ jobs:
echo "::warning::clang_tidy_findings.txt not found in downloaded artifact; skipping copy."
fi

# ------------------------------------------------------------------
# Download CodeQL CSV artifact
# ------------------------------------------------------------------
- name: Download CodeQL CSV artifact
if: always()
continue-on-error: true
uses: actions/download-artifact@v4
with:
name: ${{ needs.run-codeql.outputs.artifact-name }}
path: /tmp/codeql

- name: Copy CodeQL CSV into quality output
if: always()
run: |
mkdir -p "${GITHUB_WORKSPACE}/_quality"
if [[ -f /tmp/codeql/codeql-nightly.csv ]]; then
cp /tmp/codeql/codeql-nightly.csv \
"${GITHUB_WORKSPACE}/_quality/codeql_findings.txt"
else
echo "::warning::codeql-nightly.csv not found; skipping copy."
fi

# ------------------------------------------------------------------
# Generate coverage KPI dashboard via generate_dashboard py_binary
# ------------------------------------------------------------------
Expand All @@ -142,6 +182,7 @@ jobs:
bazel run //quality/dashboard:generate_dashboard -- \
--lcov /tmp/coverage_zip/extracted/artifacts/coverage_report.dat \
--clang-tidy /tmp/clang_tidy/clang_tidy_findings.txt \
--codeql-csv "${GITHUB_WORKSPACE}/_quality/codeql_findings.txt" \
--html "${GITHUB_WORKSPACE}/_quality/index.html" \
--github-summary

Expand Down
10 changes: 9 additions & 1 deletion bazel/rules/generate_quality_links.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def _generate_quality_links_impl(ctx):
coverage_ref = "`Coverage report <quality/coverage/index.html>`__"
dashboard_ref = "`Quality Dashboard <quality/index.html>`__"
clang_tidy_ref = "`Clang-Tidy report <quality/clang_tidy_findings.txt>`__"
codeql_ref = "`CodeQL findings <quality/codeql_findings.txt>`__"
elif docs_version and docs_base_url:
# versioned release — quality reports only live at latest/
latest = docs_base_url + "/latest"
Expand All @@ -50,6 +51,8 @@ def _generate_quality_links_impl(ctx):
"/quality/index.html>`__")
clang_tidy_ref = ("`Clang-Tidy report (latest) <" + latest +
"/quality/clang_tidy_findings.txt>`__")
codeql_ref = ("`CodeQL findings (latest) <" + latest +
"/quality/codeql_findings.txt>`__")
else:
# local build — no published reports; show the equivalent bazel command
coverage_ref = (
Expand All @@ -63,10 +66,15 @@ def _generate_quality_links_impl(ctx):
"*local build* — run " +
"``bazel test --config=clang-tidy //...``"
)
codeql_ref = (
"*local build* — run " +
"``bazel run //quality/static_analysis:codeql_lint``"
)
content = (
".. |coverage_report_link| replace:: " + coverage_ref + "\n" +
".. |quality_dashboard_link| replace:: " + dashboard_ref + "\n" +
".. |clang_tidy_report_link| replace:: " + clang_tidy_ref + "\n"
".. |clang_tidy_report_link| replace:: " + clang_tidy_ref + "\n" +
".. |codeql_report_link| replace:: " + codeql_ref + "\n"
)

output = ctx.actions.declare_file(ctx.label.name + ".rst")
Expand Down
1 change: 0 additions & 1 deletion coding-standards.yaml

This file was deleted.

100 changes: 100 additions & 0 deletions dashboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Quality Dashboard</title>
<style>
:root { --bg:#0d1117; --surface:#161b22; --border:#30363d; --text:#e6edf3; --muted:#8b949e; --accent:#58a6ff; }
* { box-sizing:border-box; margin:0; padding:0; }
body { background:var(--bg); color:var(--text); font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; padding:2rem; }
h1 { font-size:1.6rem; margin-bottom:.25rem; }
h2 { font-size:1.1rem; color:var(--muted); text-transform:uppercase; letter-spacing:.05em; margin:2rem 0 .75rem; font-weight:600; }
.meta { color:var(--muted); font-size:.85rem; margin-bottom:1.5rem; }
.cards { display:flex; gap:.75rem; flex-wrap:wrap; margin-bottom:1.5rem; }
.card { background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:.9rem 1.25rem; min-width:120px; text-align:center; }
.card .num { font-size:1.8rem; font-weight:700; }
.card .label { color:var(--muted); font-size:.75rem; text-transform:uppercase; margin-top:4px; }
.card .delta { font-size:.8rem; min-height:1.1em; margin-top:2px; }
.cov-bar-wrap { display:inline-block; background:var(--border); border-radius:4px; height:6px; width:80px; vertical-align:middle; margin-right:6px; }
.cov-bar { height:6px; border-radius:4px; }
table { width:100%; border-collapse:collapse; font-size:.88rem; }
thead th { background:var(--surface); border-bottom:2px solid var(--border); padding:.6rem .8rem; text-align:left; color:var(--muted); text-transform:uppercase; font-size:.75rem; cursor:pointer; user-select:none; white-space:nowrap; }
thead th:hover { color:var(--accent); }
tbody tr { border-bottom:1px solid var(--border); }
tbody tr:hover { background:var(--surface); }
td { padding:.5rem .8rem; vertical-align:top; }
.mono { font-family:monospace; font-size:.82rem; }
.muted { color:var(--muted); }
.empty-msg { text-align:center; padding:3rem; color:var(--muted); }
.trend-up { color:#e74c3c; font-weight:700; font-size:.75rem; margin-left:2px; }
.trend-dn { color:#27ae60; font-weight:700; font-size:.75rem; margin-left:2px; }
.trend-eq { color:#8b949e; font-weight:700; font-size:.75rem; margin-left:2px; }
.spark-wrap { display:flex; align-items:flex-end; gap:3px; height:32px; background:var(--surface); padding:4px 6px; border-radius:4px; }
.spark-bar { width:10px; border-radius:2px 2px 0 0; min-height:2px; cursor:default; transition:opacity .15s; }
.spark-bar:hover { opacity:.7; }
</style>
</head>
<body>
<h1>Quality Dashboard</h1>
<p class="meta">Generated: 2026-06-17 05:32 UTC</p>



<p class="muted" style="margin-bottom:1.5rem">No coverage data available.</p>



<h2>Clang-Tidy</h2>

<p class="muted" style="margin-bottom:1.5rem">No clang-tidy data available.</p>



<h2>CodeQL</h2>

<div class="cards">
<div class="card">
<div class="num" style="color:#27ae60">0</div>

<div class="label">Errors</div>
</div>
<div class="card">
<div class="num" style="color:#27ae60">0</div>

<div class="label">Warnings</div>
</div>
<div class="card">
<div class="num" style="color:var(--muted)">6411</div>

<div class="label">Recommendations</div>
</div>
<div class="card">
<div class="num" style="color:var(--muted)">6411</div>

<div class="label">Total Findings</div>
</div>
</div>



<h2>Per-File Coverage</h2>

<p class="empty-msg">No per-file coverage data available.</p>





<script>
let cvDir = 1;
function cvSort(c) {
const tb = document.getElementById('cv-tbody');
[...tb.querySelectorAll('tr')]
.sort((a, b) => (parseFloat(a.cells[c]?.dataset.val || 0) - parseFloat(b.cells[c]?.dataset.val || 0)) * cvDir)
.forEach(r => tb.appendChild(r));
cvDir *= -1;
}
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions docs/sphinx/quality_reports.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ nightly run of the `Nightly Quality Jobs`_ workflow.
* - Clang-Tidy
- Static analysis findings (errors and warnings) across all C++ targets
- |clang_tidy_report_link|
* - CodeQL
- MISRA C++ compliance findings via CodeQL (codeql/misra-cpp-coding-standards)
- |codeql_report_link|

|quality_dashboard_link|

Expand Down
Binary file not shown.
78 changes: 32 additions & 46 deletions quality/dashboard/dashboard.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -77,44 +77,32 @@
<p class="muted" style="margin-bottom:1.5rem">No clang-tidy data available.</p>
{% endif %}

{# ── Per-file coverage table ── #}
<h2>Per-File Coverage</h2>
{% if cov_files %}
<table>
<thead>
<tr>
<th>File</th>
<th onclick="cvSort(1)">Lines &#8597;</th>
<th onclick="cvSort(2)">Functions &#8597;</th>
<th onclick="cvSort(3)">Branches &#8597;</th>
<th>Lines (hit/total)</th>
</tr>
</thead>
<tbody id="cv-tbody">
{% for f in cov_files %}
<tr>
<td class="mono">{{ f.file|basename }}</td>
<td data-val="{{ f.line_pct }}">
<div class="cov-bar-wrap"><div class="cov-bar" style="width:{{ [f.line_pct,100]|min }}%;background:{{ cov_colour(f.line_pct) }}"></div></div>
<span style="color:{{ cov_colour(f.line_pct) }};font-weight:600">{{ '%.1f'|format(f.line_pct) }}%</span>
</td>
<td data-val="{{ f.func_pct }}">
<div class="cov-bar-wrap"><div class="cov-bar" style="width:{{ [f.func_pct,100]|min }}%;background:{{ cov_colour(f.func_pct) }}"></div></div>
<span style="color:{{ cov_colour(f.func_pct) }};font-weight:600">{{ '%.1f'|format(f.func_pct) }}%</span>
</td>
<td data-val="{{ f.branch_pct }}">
<div class="cov-bar-wrap"><div class="cov-bar" style="width:{{ [f.branch_pct,100]|min }}%;background:{{ cov_colour(f.branch_pct) }}"></div></div>
<span style="color:{{ cov_colour(f.branch_pct) }};font-weight:600">{{ '%.1f'|format(f.branch_pct) }}%</span>
</td>
<td class="mono muted">{{ f.lh }}/{{ f.lf }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{# ── CodeQL summary cards ── #}
<h2>CodeQL</h2>
{% if codeql %}
<div class="cards">
<div class="card">
<div class="num" style="color:{% if (codeql.errors + codeql.recommendations) == 0 %}#27ae60{% else %}#e74c3c{% endif %}">{{ codeql.errors + codeql.recommendations }}</div>
{% if prev and prev.codeql_errors is not none %}<div class="delta">{{ delta(codeql.errors + codeql.recommendations, prev.codeql_errors, false) }}</div>{% endif %}
<div class="label">Errors</div>
</div>
<div class="card">
<div class="num" style="color:{% if codeql.warnings == 0 %}#27ae60{% else %}#e67e22{% endif %}">{{ codeql.warnings }}</div>
{% if prev and prev.codeql_warnings is not none %}<div class="delta">{{ delta(codeql.warnings, prev.codeql_warnings, false) }}</div>{% endif %}
<div class="label">Warnings</div>
</div>
<div class="card">
<div class="num" style="color:var(--muted)">{{ codeql.total }}</div>
{% if prev and prev.codeql_total is not none %}<div class="delta">{{ delta(codeql.total, prev.codeql_total, false) }}</div>{% endif %}
<div class="label">Total Findings</div>
</div>
</div>
{% else %}
<p class="empty-msg">No per-file coverage data available.</p>
<p class="muted" style="margin-bottom:1.5rem">No CodeQL data available.</p>
{% endif %}



{# ── KPI Trends ── #}
{% if history|length >= 2 %}
<h2>Coverage Trend</h2>
Expand Down Expand Up @@ -149,7 +137,7 @@
<h2>Run History</h2>
<table>
<thead>
<tr><th>Date</th><th>Line Cov</th><th>Function Cov</th><th>Branch Cov</th><th>CT Errors</th><th>CT Warnings</th></tr>
<tr><th>Date</th><th>Line Cov</th><th>Function Cov</th><th>Branch Cov</th><th>CT Errors</th><th>CT Warnings</th><th>CQ Errors</th><th>CQ Warnings</th><th>CQ Total</th></tr>
</thead>
<tbody>
{% for snap in history|reverse %}
Expand All @@ -174,21 +162,19 @@
{% else %}N/A{% endif %}
</td>
{% endfor %}
{% for key, higher_better in [('codeql_errors', false), ('codeql_warnings', false), ('codeql_total', false)] %}
<td>
{% if snap[key] is not none %}
<span style="color:{% if snap[key] == 0 %}#27ae60{% else %}#e74c3c{% endif %}">{{ snap[key] }}</span>
{% if ps and ps[key] is not none %} {{ delta(snap[key], ps[key], higher_better) }}{% endif %}
{% else %}N/A{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}

<script>
let cvDir = 1;
function cvSort(c) {
const tb = document.getElementById('cv-tbody');
[...tb.querySelectorAll('tr')]
.sort((a, b) => (parseFloat(a.cells[c]?.dataset.val || 0) - parseFloat(b.cells[c]?.dataset.val || 0)) * cvDir)
.forEach(r => tb.appendChild(r));
cvDir *= -1;
}
</script>
</body>
</html>
Loading
Loading