Skip to content
Open
Changes from all commits
Commits
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
153 changes: 153 additions & 0 deletions .github/workflows/clang_tidy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

# Workflow: Clang-Tidy PR check (voting).
#
# Runs clang-tidy on every pull_request and push to main.
# - Writes a job summary with error/warning counts.
# - Uploads findings as a downloadable artifact (clang-tidy-findings).
# - Fails the check if any clang-tidy *errors* are found.
#
# Cache is saved only on pushes to main (not on PRs) to avoid
# cache poisoning from unreviewed code.

name: Clang-Tidy Check

on:
pull_request:
types: [opened, reopened, synchronize]
push:
branches: [main]

permissions:
contents: read

concurrency:
group: clang-tidy-pr-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

env:
ANDROID_HOME: ""
ANDROID_SDK_ROOT: ""
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
clang-tidy:
runs-on: ubuntu-24.04

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Free Disk Space (Ubuntu)
uses: eclipse-score/more-disk-space@v1
with:
level: 4

- uses: castler/setup-bazel@cache-optimized
with:
bazelisk-cache: true
disk-cache: "clang_tidy"
repository-cache: true
cache-optimized: true
cache-save: ${{ github.ref == 'refs/heads/main' }}

- name: Allow linux-sandbox
uses: ./actions/unblock_user_namespace_for_linux_sandbox

- name: Run clang-tidy via Bazel
id: run-clang-tidy
# continue-on-error so we can collect findings and upload the artifact
# even when the Bazel invocation exits non-zero.
continue-on-error: true
run: |
bazel test --config=clang-tidy //... \
2>&1 | tee clang_tidy_raw.log

- name: Collect findings
id: findings
run: |
# aspect_rules_lint writes one .out file per target under bazel-bin.
# -L is needed because bazel-bin is a symlink.
ERRORS=$(find -L bazel-bin -name "*.AspectRulesLintClangTidy.out" 2>/dev/null \
| xargs cat 2>/dev/null \
| grep -c "error:" || true)
WARNINGS=$(find -L bazel-bin -name "*.AspectRulesLintClangTidy.out" 2>/dev/null \
| xargs cat 2>/dev/null \
| grep -c "warning:" || true)
TOTAL=$((ERRORS + WARNINGS))

echo "errors=${ERRORS}" >> $GITHUB_OUTPUT
echo "warnings=${WARNINGS}" >> $GITHUB_OUTPUT
echo "total=${TOTAL}" >> $GITHUB_OUTPUT

# ── Count errors only in C++ files changed by this PR ─────────────
# For push to main: all errors are blocking.
# For pull_request with no C++ changes: nothing to block on.
# For pull_request with C++ changes: only errors in changed files block.
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
CHANGED_CPP=$(git diff --name-only "origin/${GITHUB_BASE_REF}...HEAD" 2>/dev/null \
| grep -E '\.(cpp|h|cc|cxx|hpp)$' || true)
if [[ -z "$CHANGED_CPP" ]]; then
ERRORS_BLOCKING=0
else
PATTERN=$(echo "$CHANGED_CPP" | tr '\n' '|' | sed 's/|$//')
ERRORS_BLOCKING=$(find -L bazel-bin -name "*.AspectRulesLintClangTidy.out" 2>/dev/null \
| xargs cat 2>/dev/null \
| grep -E "(${PATTERN})" \
| grep -c "error:" || true)
fi
else
ERRORS_BLOCKING=$ERRORS
fi
echo "errors_blocking=${ERRORS_BLOCKING}" >> $GITHUB_OUTPUT

# ── Write findings to file for artifact ───────────────────────────
find -L bazel-bin -name "*.AspectRulesLintClangTidy.out" 2>/dev/null \
| xargs cat 2>/dev/null > clang_tidy_findings.txt || true

# ── Job summary ──────────────────────────────────────────────────
{
echo "## Clang-Tidy Results"
echo ""
echo "| Metric | Count |"
echo "|--------|------:|"
echo "| :x: Errors (total) | **${ERRORS}** |"
echo "| :x: Errors (in changed files) | **${ERRORS_BLOCKING}** |"
echo "| :warning: Warnings | **${WARNINGS}** |"
echo "| Total | **${TOTAL}** |"
if [[ "${ERRORS_BLOCKING}" -gt 0 ]]; then
echo ""
echo "> :x: **Check failed** — clang-tidy errors found in changed files. Fix before merging."
else
echo ""
echo "> :white_check_mark: **Check passed** — no errors in changed files."
fi
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload clang-tidy findings as artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: clang-tidy-findings
path: |
clang_tidy_findings.txt
clang_tidy_raw.log
if-no-files-found: ignore
retention-days: 7

- name: Fail check if clang-tidy errors found in changed files
if: steps.findings.outputs.errors_blocking != '0'
run: |
echo "::error::Clang-tidy found ${{ steps.findings.outputs.errors_blocking }} error(s) in changed files. See the 'clang-tidy-findings' artifact for details."
exit 1
Loading