diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 2f284d8..9e0cfc8 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -3,7 +3,6 @@ # # 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 @@ -16,10 +15,20 @@ name: Static Code Analysis on: workflow_call: inputs: - bazel-target: - description: "Custom Bazel target to run (e.g.: 'run //:static-analysis')" + bazel-targets: + description: "Bazel targets to build (default: //...)" + required: false + default: "//..." + type: string + bazel-config: + description: "Bazel config to apply (default: lint). Set empty to disable." + required: false + default: "lint" + type: string + bazel-args: + description: "Extra Bazel args to pass to the build command" required: false - default: "run //:static-analysis" + default: "" type: string jobs: @@ -38,7 +47,83 @@ jobs: bazelisk-cache: true cache-save: ${{ github.event_name == 'push' }} - - name: Run Static Analysis via Bazel + - name: Run Clippy via Bazel build + id: bazel-build + continue-on-error: true run: | - echo "Running: bazel ${{ inputs.bazel-target }}" - bazel ${{ inputs.bazel-target }} \ No newline at end of file + set -uo pipefail + config_flag="" + if [ -n "${{ inputs.bazel-config }}" ]; then + config_flag="--config=${{ inputs.bazel-config }}" + fi + echo "Running: bazel build ${config_flag} ${{ inputs.bazel-args }} ${{ inputs.bazel-targets }}" + bazel build ${config_flag} ${{ inputs.bazel-args }} ${{ inputs.bazel-targets }} + exit_code=$? + echo "exit_code=${exit_code}" >> "$GITHUB_OUTPUT" + if [ "${exit_code}" != "0" ]; then + echo "Bazel build failed with exit code ${exit_code}" + fi + + - name: Collect Clippy reports + id: collect + if: always() + run: | + set -euo pipefail + mkdir -p clippy-reports + mapfile -d '' files < <(find -L bazel-bin -type f -name '*.AspectRulesLintClippy.out' -print0 || true) + if [ ${#files[@]} -eq 0 ]; then + echo "No Clippy reports found." + echo "clippy_report_count=0" >> "$GITHUB_OUTPUT" + echo "clippy_issue_count=0" >> "$GITHUB_OUTPUT" + exit 0 + fi + + for f in "${files[@]}"; do + dest="clippy-reports/${f#./}" + mkdir -p "$(dirname "$dest")" + cp "$f" "$dest" + done + + issues=$(find -L bazel-bin -type f -name '*.AspectRulesLintClippy.out' -size +0c | wc -l | tr -d ' ') + echo "clippy_report_count=${#files[@]}" >> "$GITHUB_OUTPUT" + echo "clippy_issue_count=${issues}" >> "$GITHUB_OUTPUT" + tar -czf clippy-reports.tar.gz -C clippy-reports . + + - name: Upload Clippy reports + if: always() + uses: actions/upload-artifact@v4.4.0 + with: + name: clippy-reports + path: | + clippy-reports.tar.gz + clippy-reports + if-no-files-found: warn + + - name: Clippy summary + if: always() + run: | + { + echo "### Clippy report summary" + echo "- Targets: ${{ inputs.bazel-targets }}" + echo "- Config: ${{ inputs.bazel-config }}" + echo "- Total report files: ${{ steps.collect.outputs.clippy_report_count }}" + echo "- Non-empty reports: ${{ steps.collect.outputs.clippy_issue_count }}" + echo "- Bazel exit code: ${{ steps.bazel-build.outputs.exit_code }}" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Fail if build or Clippy issues found + if: always() + run: | + exit_code="${{ steps.bazel-build.outputs.exit_code }}" + issues="${{ steps.collect.outputs.clippy_issue_count }}" + + if [ "${exit_code}" != "0" ]; then + echo "Bazel build failed with exit code ${exit_code}" + fi + if [ "${issues}" != "0" ]; then + echo "Clippy issues found: ${issues}" + fi + + if [ "${exit_code}" != "0" ] || [ "${issues}" != "0" ]; then + exit 1 + fi diff --git a/README.md b/README.md index bea930e..fbdb359 100644 --- a/README.md +++ b/README.md @@ -124,16 +124,21 @@ jobs: static-analysis: uses: eclipse-score/cicd-workflows/.github/workflows/static-analysis.yml@main with: - bazel-target: "run //:static-analysis" # optional, this is the default + bazel-targets: "//..." # optional, default + bazel-config: "lint" # optional, default + bazel-args: "--@aspect_rules_lint//lint:fail_on_violation=true" # optional ``` This workflow: -✅ Runs **Clang-Tidy** for C++ -✅ Runs **Rust Clippy, Cargo Audit, and Cargo Geiger** for Rust -✅ Runs **Pylint** for Python - -> ℹ️ **Note:** You can override the Bazel command using the `bazel-target` input. -> **Default:** `run //:static-analysis` +✅ Runs **Clippy** via Bazel on the selected targets +✅ Publishes **Clippy reports** as an artifact +✅ Fails the job if Bazel fails or if any Clippy report is non-empty +✅ Writes a summary to the GitHub job summary + +Inputs: +- `bazel-targets`: Bazel targets to build (default: `//...`) +- `bazel-config`: Bazel config to apply (default: `lint`, set empty to disable) +- `bazel-args`: Extra Bazel args (e.g., `--@aspect_rules_lint//lint:fail_on_violation=true`) ---