diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index a59a29f5..ef1cef83 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -12,7 +12,7 @@ jobs: - name: "Install packages" run: sudo apt-get install libsdl1.2-dev libsdl-net1.2-dev libsdl-sound1.2-dev python3-setuptools - name: "Install scan-build (Python version)" - run: sudo pip3 install scan-build + run: sudo pip3 install scan-build beautifulsoup4 html5lib - name: Build run: | # build steps @@ -27,3 +27,9 @@ jobs: with: name: report path: report + - name: Summarize report + run: | + # summary + echo "Full report is included in build Artifacts" + echo + ./scripts/count-bugs.py report/*/index.html diff --git a/scripts/count-bugs.py b/scripts/count-bugs.py new file mode 100755 index 00000000..1b720b54 --- /dev/null +++ b/scripts/count-bugs.py @@ -0,0 +1,74 @@ +#!/usr/bin/python3 + +# Copyright (c) 2019 Patryk Obara +# SPDX-License-Identifier: GPL-2.0-or-later + +# This script prints a summary snippet of information out of reports created +# by scan-build or analyze-build for Clang's static code analysis. +# +# Usage: ./count-warnings.py path/to/report/index.html +# +# This script depends on BeautifulSoup module, if you're distribution is +# missing it, you can use pipenv to install it for virtualenv spanning only +# this repo: pipenv install beautifulsoup4 html5lib + +# pylint: disable=invalid-name +# pylint: disable=missing-docstring + +import sys + +from bs4 import BeautifulSoup + +# Maximum allowed number of issues; if report will include more bugs, +# then script will return with status 1. Simply change this line if you +# want to set a different limit. +# +MAX_ISSUES = 113 + + +def summary_values(summary_table): + if not summary_table: + return + for row in summary_table.find_all('tr'): + description = row.find('td', 'SUMM_DESC') + value = row.find('td', 'Q') + if description is None or value is None: + continue + yield description.get_text(), int(value.get_text()) + + +def read_soup(index_html): + with open(index_html) as index: + soup = BeautifulSoup(index, 'html5lib') + tables = soup.find_all('table') + summary = tables[1] + return {bug: count for bug, count in summary_values(summary)} + + +def find_longest_name_length(names): + return max(len(x) for x in names) + + +def print_summary(issues): + summary = list(issues.items()) + size = find_longest_name_length(issues.keys()) + 1 + for warning, count in sorted(summary, key=lambda x: -x[1]): + print(' {text:{field_size}s}: {count}'.format( + text=warning, count=count, field_size=size)) + print() + + +def main(): + bug_types = read_soup(sys.argv[1]) + total = bug_types.pop('All Bugs') + if bug_types: + print("Bugs grouped by type:\n") + print_summary(bug_types) + print('Total: {} bugs (out of {} allowed)\n'.format(total, MAX_ISSUES)) + if total > MAX_ISSUES: + print('Error: upper limit of allowed bugs is', MAX_ISSUES) + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/scripts/count-warnings.py b/scripts/count-warnings.py old mode 100644 new mode 100755 index 54aa06a8..6fa3a712 --- a/scripts/count-warnings.py +++ b/scripts/count-warnings.py @@ -1,8 +1,9 @@ #!/usr/bin/python3 -# Copyright (c) 2019 Patryk Obara +# Copyright (c) 2019 Patryk Obara +# SPDX-License-Identifier: GPL-2.0-or-later -# This script counts and all warnings and prints a summary. +# This script counts all compiler warnings and prints a summary. # # Usage: ./count-warnings.py build.log # Usage: cat "*.log" | ./count-warnings.py - @@ -18,11 +19,11 @@ import os import re import sys -# Maximum allowed number of warnings; if build will include more warnings, +# Maximum allowed number of issues; if build will include more warnings, # then script will return with status 1. Simply change this line if you # want to set a different limit. # -MAX_WARNINGS = 357 +MAX_ISSUES = 357 # For recognizing warnings in GCC format in stderr: # @@ -63,11 +64,16 @@ def get_input_lines(name): return logs.readlines() -def print_summary(warning_types): - print("Warnings grouped by type:\n") - summary = list(warning_types.items()) +def find_longest_name_length(names): + return max(len(x) for x in names) + + +def print_summary(issues): + summary = list(issues.items()) + size = find_longest_name_length(issues.keys()) + 1 for warning, count in sorted(summary, key=lambda x: -x[1]): - print(' {:28s}: {}'.format(warning, count)) + print(' {text:{field_size}s}: {count}'.format( + text=warning, count=count, field_size=size)) print() @@ -77,10 +83,11 @@ def main(): for line in get_input_lines(sys.argv[1]): total += count_warning(line, warning_types) if warning_types: + print("Warnings grouped by type:\n") print_summary(warning_types) - print('Total: {} warnings\n'.format(total)) - if total > MAX_WARNINGS: - print('Error: upper limit of warnings is', MAX_WARNINGS) + print('Total: {} warnings (out of {} allowed)\n'.format(total, MAX_ISSUES)) + if total > MAX_ISSUES: + print('Error: upper limit of allowed warnings is', MAX_ISSUES) sys.exit(1)