diff --git a/.github/tools/clean_lint_sarif.py b/.github/tools/clean_lint_sarif.py index f34272d762..e8f31d8acd 100755 --- a/.github/tools/clean_lint_sarif.py +++ b/.github/tools/clean_lint_sarif.py @@ -36,6 +36,7 @@ """ import argparse +import hashlib import json import os import re @@ -159,7 +160,11 @@ def main(): if result_count == 0: continue - out_name = path.replace(os.sep, "__") + ".sarif" + # Flattening a deeply-nested Bazel output path into one filename can + # exceed the filesystem's filename length limit; hash it instead. + # The name only needs to be unique, since the merge step globs + # every ".sarif" file in the tool's output directory. + out_name = hashlib.sha1(path.encode()).hexdigest() + ".sarif" with open(os.path.join(args.output_dir, out_name), "w", encoding="utf-8") as f: json.dump(report, f) written += 1 diff --git a/.github/tools/manual_lint_targets.sh b/.github/tools/manual_lint_targets.sh new file mode 100755 index 0000000000..7581f6966c --- /dev/null +++ b/.github/tools/manual_lint_targets.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# ******************************************************************************* +# 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 +# ******************************************************************************* +# Finds `manual`-tagged targets that a linter aspect would otherwise apply +# to, and prints their labels one per line. +# +# `manual` only excludes a target from wildcards like `//...`; rules_lint's +# aspects don't check for it. Building the target by name is the only way to +# lint it, so the lint workflow appends this script's output to its build. +# +# docs()/docs_bundle() wrapper targets are excluded: their srcs are external +# repo code, nothing here to lint. Platform-incompatible targets are excluded +# too, since naming one explicitly fails the build instead of being skipped. +# +# Usage: manual_lint_targets.sh +set -euo pipefail + +config="${1:?usage: manual_lint_targets.sh }" + +# Rule kinds each linter aspect visits: clang-tidy (cc_*), Ruff (py_*), +# Clippy (rust_*). +lintable_kinds='cc_binary|cc_library|cc_test|py_binary|py_library|py_test|rust_binary|rust_library|rust_shared_library|rust_test' + +# \b avoids matching tags that merely contain "manual", e.g. "manually". +query="attr(tags, '\bmanual\b', kind('${lintable_kinds}', //...))" +query+=" except attr(generator_function, '^docs', //...)" + +mapfile -t candidates < <(bazel query "${query}") + +if [ ${#candidates[@]} -eq 0 ]; then + exit 0 +fi + +# cquery, not query, since compatibility is only known after configuration. +# Prints the label if compatible, else a blank line, which gets dropped below. +print_label_if_compatible='( + "" if "IncompatiblePlatformProvider" in [str(type(p)) for p in providers(target).values()] + else "//{}:{}".format(target.label.package, target.label.name) +)' + +bazel cquery --config="${config}" "set(${candidates[*]})" \ + --output=starlark \ + --starlark:expr="${print_label_if_compatible}" \ + | sed '/^$/d' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 76f42ecf30..ed07d7c6b4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,6 +14,8 @@ # Runs clang-tidy, Clippy, and Ruff through rules_lint in one job. Each build # uses fail_on_violation=false so violating targets still produce SARIF; the # job fails at the end, once everything has been collected and uploaded. +# `manual` targets are built separately, by name, since `//...` skips them; +# see .github/tools/manual_lint_targets.sh. name: Linter checks permissions: contents: read @@ -46,6 +48,14 @@ jobs: bazel build --config=bl-x86_64-linux --config=lint --keep_going \ --output_groups=+rules_lint_machine --@aspect_rules_lint//lint:fail_on_violation=false \ -- //... + - name: Bazel build with linters (manual targets) + run: | + mapfile -t manual_targets < <(.github/tools/manual_lint_targets.sh bl-x86_64-linux) + if [ "${#manual_targets[@]}" -gt 0 ]; then + bazel build --config=bl-x86_64-linux --config=lint --keep_going \ + --output_groups=+rules_lint_machine --@aspect_rules_lint//lint:fail_on_violation=false \ + -- "${manual_targets[@]}" || true + fi - name: Collect human-readable lint reports if: always() run: |