From 6b3d8a236668491ad29e885f2ae321c6e7b5dc75 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 29 Jan 2025 23:14:47 +1100 Subject: [PATCH] CI: add a regression test for output of clang-scan-build ratchet so we reduce these over time --- .github/workflows/test_clang_scan_build.yml | 206 ++++++++++++++++++++ Tools/autotest/process_scan_build_output.py | 72 +++++++ Tools/scripts/build_ci.sh | 9 + 3 files changed, 287 insertions(+) create mode 100644 .github/workflows/test_clang_scan_build.yml create mode 100755 Tools/autotest/process_scan_build_output.py diff --git a/.github/workflows/test_clang_scan_build.yml b/.github/workflows/test_clang_scan_build.yml new file mode 100644 index 00000000000000..7d0a849cca7223 --- /dev/null +++ b/.github/workflows/test_clang_scan_build.yml @@ -0,0 +1,206 @@ +name: test clang-scan-build + +on: + push: + paths-ignore: + # remove non SITL HAL + - 'libraries/AP_HAL_ChibiOS/**' + - 'libraries/AP_HAL_ESP32/**' + - 'libraries/AP_HAL_Linux/**' + - 'libraries/AP_HAL_QURT/**' + # remove non SITL directories + - 'Tools/AP_Bootloader/**' + - 'Tools/AP_Periph/**' + - 'Tools/bootloaders/**' + - 'Tools/CHDK-Script/**' + - 'Tools/CodeStyle/**' + - 'Tools/completion/**' + - 'Tools/CPUInfo/**' + - 'Tools/debug/**' + - 'Tools/environment_install/**' + - 'Tools/FilterTestTool/**' + - 'Tools/Frame_params/**' + - 'Tools/geotag/**' + - 'Tools/GIT_Test/**' + - 'Tools/gittools/**' + - 'Tools/Hello/**' + - 'Tools/IO_Firmware/**' + - 'Tools/Linux_HAL_Essentials/**' + - 'Tools/Pozyx/**' + - 'Tools/PrintVersion.py' + - 'Tools/Replay/**' + - 'Tools/simulink/**' + - 'Tools/UDP_Proxy/**' + - 'Tools/vagrant/**' + - 'Tools/Vicon/**' + # Discard python file from Tools/scripts as not used + - 'Tools/scripts/build_sizes/**' + - 'Tools/scripts/build_tests/**' + - 'Tools/scripts/CAN/**' + - 'Tools/scripts/signing/**' + # Remove autotest + - 'Tools/autotest/antennatracker.py' + - 'Tools/autotest/arducopter.py' + - 'Tools/autotest/arduplane.py' + - 'Tools/autotest/ardusub.py' + - 'Tools/autotest/helicopter.py' + - 'Tools/autotest/rover.py' + - 'Tools/autotest/location.txt' + - 'Tools/autotest/quadplane.py' + - 'Tools/autotest/swarminit.txt' + # Remove markdown files as irrelevant + - '**.md' + # Remove dotfile at root directory + - './.dir-locals.el' + - './.dockerignore' + - './.editorconfig' + - './.flake8' + - './.gitattributes' + - './.github' + - './.gitignore' + - './.pre-commit-config.yaml' + - './.pydevproject' + - './.valgrind-suppressions' + - './.valgrindrc' + - 'Dockerfile' + - 'Vagrantfile' + - 'Makefile' + # Remove some directories check + - '.vscode/**' + - '.github/ISSUE_TEMPLATE/**' + # Remove change on other workflows + - '.github/workflows/test_environment.yml' + + + pull_request: + paths-ignore: + # remove non SITL HAL + - 'libraries/AP_HAL_QURT/**' + - 'libraries/AP_HAL_Linux/**' + - 'libraries/AP_HAL_ChibiOS/**' + - 'libraries/AP_HAL_ESP32/**' + # remove non SITL directories + - 'Tools/AP_Bootloader/**' + - 'Tools/AP_Periph/**' + - 'Tools/bootloaders/**' + - 'Tools/CHDK-Script/**' + - 'Tools/CodeStyle/**' + - 'Tools/completion/**' + - 'Tools/CPUInfo/**' + - 'Tools/debug/**' + - 'Tools/environment_install/**' + - 'Tools/FilterTestTool/**' + - 'Tools/Frame_params/**' + - 'Tools/geotag/**' + - 'Tools/GIT_Test/**' + - 'Tools/gittools/**' + - 'Tools/Hello/**' + - 'Tools/IO_Firmware/**' + - 'Tools/Linux_HAL_Essentials/**' + - 'Tools/LogAnalyzer/**' + - 'Tools/Pozyx/**' + - 'Tools/PrintVersion.py' + - 'Tools/Replay/**' + - 'Tools/simulink/**' + - 'Tools/UDP_Proxy/**' + - 'Tools/vagrant/**' + - 'Tools/Vicon/**' + # Discard python file from Tools/scripts as not used + - 'Tools/scripts/build_sizes/**' + - 'Tools/scripts/build_tests/**' + - 'Tools/scripts/CAN/**' + - 'Tools/scripts/signing/**' + # Remove other vehicles autotest + - 'Tools/autotest/antennatracker.py' + - 'Tools/autotest/arducopter.py' + - 'Tools/autotest/arduplane.py' + - 'Tools/autotest/ardusub.py' + - 'Tools/autotest/helicopter.py' + - 'Tools/autotest/location.txt' + - 'Tools/autotest/quadplane.py' + - 'Tools/autotest/rover.py' + - 'Tools/autotest/swarminit.txt' + # Remove markdown files as irrelevant + - '**.md' + # Remove dotfile at root directory + - './.dir-locals.el' + - './.dockerignore' + - './.editorconfig' + - './.flake8' + - './.gitattributes' + - './.github' + - './.gitignore' + - './.pre-commit-config.yaml' + - './.pydevproject' + - './.valgrind-suppressions' + - './.valgrindrc' + - 'Dockerfile' + - 'Vagrantfile' + - 'Makefile' + # Remove some directories check + - '.vscode/**' + - '.github/ISSUE_TEMPLATE/**' + # Remove change on other workflows + - '.github/workflows/test_environment.yml' + + workflow_dispatch: + +concurrency: + group: ci-${{github.workflow}}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-22.04 + container: + image: ardupilot/ardupilot-dev-base:v0.1.3 + options: --privileged --cap-add=SYS_PTRACE --security-opt apparmor=unconfined --security-opt seccomp=unconfined + strategy: + fail-fast: false # don't cancel if a job from the matrix fails (get archives!) + steps: + # git checkout the PR + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + # Put ccache into github cache for faster build + - name: Prepare ccache timestamp + id: ccache_cache_timestamp + run: | + NOW=$(date -u +"%F-%T") + echo "timestamp=${NOW}" >> $GITHUB_OUTPUT + - name: ccache cache files + uses: actions/cache@v4 + with: + path: ~/.ccache + key: ${{github.workflow}}-ccache-clang-scan-build-${{steps.ccache_cache_timestamp.outputs.timestamp}} + restore-keys: ${{github.workflow}}-ccache-clang-scan-build- # restore ccache from either previous build on this branch or on master + - name: setup ccache + run: | + . .github/workflows/ccache.env + - name: run clang-scan-build + shell: bash + run: | + git config --global --add safe.directory ${GITHUB_WORKSPACE} + sudo apt update + sudo apt-get -y install clang-tools + ls /usr/bin/clang-scan* + mkdir -p $HOME/bin + ln -s /usr/bin/scan-build-py-18 $HOME/bin/scan-build + export PATH="$HOME/bin:/github/home/.local/bin:$PATH" + mkdir -p /__w/ardupilot/ardupilot/tmp + CI_BUILD_TARGET="clang_scan_build" Tools/scripts/build_ci.sh >$HOME/scan-build-stdout.txt + + ccache -s + ccache -z + + # this renames the scan-build output directory to a fixed + # name so we can archive it + ./Tools/autotest/process_scan_build_output.py $HOME/scan-build-stdout.txt + + - name: Archive artifacts + uses: actions/upload-artifact@v4 + with: + name: clang-scan-build + path: /__w/ardupilot/ardupilot/tmp/scan-build + retention-days: 7 + diff --git a/Tools/autotest/process_scan_build_output.py b/Tools/autotest/process_scan_build_output.py new file mode 100755 index 00000000000000..4e31a738012280 --- /dev/null +++ b/Tools/autotest/process_scan_build_output.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +''' +Tool to process stdout from clang_scan_build, and manipulate files for archiving + +AP_FLAKE8_CLEAN +''' + +import os +import pathlib +import re +import sys + + +class ProcessScanBuildOutput(): + def __init__(self, stdout_filepath): + self.stdout_filepath = stdout_filepath + + def progress(self, msg): + print(f"psbo: {msg}") + + def run(self): + t = pathlib.Path(self.stdout_filepath).read_text() + m_scan_build_dir = None + m_bug_count = None + for line in t.split("\n"): + # extract scan-build-dir + m = re.match(r".*Run 'scan-view (.+)'", line) + if m is not None: + m_scan_build_dir = m + # extract count of bugs + m = re.match(r".*?(\d+) bugs found", line) + if m is not None: + m_bug_count = m + if m_scan_build_dir is None: + raise ValueError("Did not find scan-build output directory in output") + if m_bug_count is None: + raise ValueError("Did not find bug count in output") + scan_build_dir = m_scan_build_dir.group(1) + bug_count = int(m_bug_count.group(1)) + + dest = "/__w/ardupilot/ardupilot/scan-build" + self.progress(f"Renaming {scan_build_dir} to {dest}") + os.rename(scan_build_dir, dest) + + new_stdout_filepath = os.path.join(dest, self.stdout_filepath) + self.progress(f"Renaming {self.stdout_filepath} to {new_stdout_filepath}") + os.rename(self.stdout_filepath, new_stdout_filepath) + + self.progress(f"Extracted Bug count is {bug_count}") + + if bug_count != self.expected_bug_count(): + self.progress(f"Bug count incorrect (want={self.expected_bug_count()} got={bug_count})") + if bug_count < self.expected_bug_count(): + self.progress("You have fixed bugs, please modify Tools/autotest/process_scan_build_output.py to reduce expected count") # noqa: E501 + else: + self.progress("clang-scan-build has found problems being introduced; see artifacts") + sys.exit(1) + + def expected_bug_count(self): + return 80 + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description='tool to post-process output from clang-scan-build in CI') + parser.add_argument('clang_scan_build_stdout', default=None, help='file containing stdout from clang-scan-build process') + + args = parser.parse_args() + + p = ProcessScanBuildOutput(args.clang_scan_build_stdout) + p.run() diff --git a/Tools/scripts/build_ci.sh b/Tools/scripts/build_ci.sh index 460d0db00f0f3e..60c7fb583cf2cf 100755 --- a/Tools/scripts/build_ci.sh +++ b/Tools/scripts/build_ci.sh @@ -444,6 +444,15 @@ for t in $CI_BUILD_TARGET; do continue fi + if [ "$t" == "clang_scan_build" ]; then + install_mavproxy + install_pymavlink + unset BUILDROOT + echo "Running SITL clang-scan-build test" + ./Tools/autotest/autotest.py clang-scan-build + continue + fi + if [ "$t" == "validate_board_list" ]; then echo "Validating board list" ./Tools/autotest/validate_board_list.py