Skip to content

Commit b1584e9

Browse files
[CI] Added feature to filter out files to file_check.py that do not require cppcheck (#7499)
Co-authored-by: supperthomas <[email protected]>
1 parent 01d1bbe commit b1584e9

File tree

3 files changed

+150
-9
lines changed

3 files changed

+150
-9
lines changed

.github/workflows/static_code_analysis.yml

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Static code analysis
22

3-
on:
3+
on:
44
pull_request:
55
branches:
66
- master
@@ -21,16 +21,10 @@ jobs:
2121
run: |
2222
sudo apt-get update
2323
sudo apt-get -qq install cppcheck
24+
pip install click PyYaml
2425
git remote -v
2526
git fetch origin
2627
cppcheck --version
2728
ls
2829
git branch -a
29-
changed_files=$(git diff --name-only HEAD origin/master | grep -E '\.(c|cpp|cc|cxx)$' || true)
30-
if [ -n "$changed_files" ];then
31-
cppcheck --enable=warning,performance,portability --inline-suppr --error-exitcode=1 --force $changed_files
32-
err=$?
33-
if [ $err -ne 0 ]; then
34-
echo "CPPCHECK REPORT, PLEASE CHECK THE WARNING !!!!!!!!!"
35-
fi
36-
fi
30+
python tools/ci/cpp_check.py check

tools/ci/cpp_check.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#
2+
# Copyright (c) 2006-2023, RT-Thread Development Team
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Change Logs:
7+
# Date Author Notes
8+
# 2023-05-16 dejavudwh the first version
9+
#
10+
11+
import click
12+
import logging
13+
import subprocess
14+
import sys
15+
import format_ignore
16+
17+
class CPPCheck:
18+
def __init__(self, file_list):
19+
self.file_list = file_list
20+
21+
def check(self):
22+
file_list_filtered = [file for file in self.file_list if file.endswith(('.c', '.cpp', '.cc', '.cxx'))]
23+
logging.info("Start to static code analysis.")
24+
check_result = True
25+
for file in file_list_filtered:
26+
result = subprocess.run(['cppcheck', '--enable=warning', 'performance', 'portability', '--inline-suppr', '--error-exitcode=1', '--force', file], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
27+
logging.info(result.stdout.decode())
28+
logging.info(result.stderr.decode())
29+
if result.stderr:
30+
check_result = False
31+
return check_result
32+
33+
@click.group()
34+
@click.pass_context
35+
def cli(ctx):
36+
pass
37+
38+
@cli.command()
39+
def check():
40+
"""
41+
static code analysis(cppcheck).
42+
"""
43+
format_ignore.init_logger()
44+
# get modified files list
45+
checkout = format_ignore.CheckOut()
46+
file_list = checkout.get_new_file()
47+
if file_list is None:
48+
logging.error("checkout files fail")
49+
sys.exit(1)
50+
51+
# use cppcheck
52+
cpp_check = CPPCheck(file_list)
53+
cpp_check_result = cpp_check.check()
54+
55+
if not cpp_check_result:
56+
logging.error("static code analysis(cppcheck) fail.")
57+
sys.exit(1)
58+
logging.info("check success.")
59+
sys.exit(0)
60+
61+
62+
if __name__ == '__main__':
63+
cli()

tools/ci/format_ignore.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#
2+
# Copyright (c) 2006-2023, RT-Thread Development Team
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Change Logs:
7+
# Date Author Notes
8+
# 2023-05-16 dejavudwh the first version
9+
#
10+
11+
import yaml
12+
import logging
13+
import os
14+
import subprocess
15+
16+
def init_logger():
17+
log_format = "[%(filename)s %(lineno)d %(levelname)s] %(message)s "
18+
date_format = '%Y-%m-%d %H:%M:%S %a '
19+
logging.basicConfig(level=logging.INFO,
20+
format=log_format,
21+
datefmt=date_format,
22+
)
23+
24+
class CheckOut:
25+
def __init__(self):
26+
pass
27+
28+
def __exclude_file(self, file_path):
29+
dir_number = file_path.split('/')
30+
ignore_path = file_path
31+
32+
# gets the file path depth.
33+
for i in dir_number:
34+
# current directory.
35+
dir_name = os.path.dirname(ignore_path)
36+
ignore_path = dir_name
37+
# judge the ignore file exists in the current directory.
38+
ignore_file_path = os.path.join(dir_name, ".ignore_format.yml")
39+
if not os.path.exists(ignore_file_path):
40+
continue
41+
try:
42+
with open(ignore_file_path) as f:
43+
ignore_config = yaml.safe_load(f.read())
44+
file_ignore = ignore_config.get("file_path", [])
45+
dir_ignore = ignore_config.get("dir_path", [])
46+
except Exception as e:
47+
logging.error(e)
48+
continue
49+
logging.debug("ignore file path: {}".format(ignore_file_path))
50+
logging.debug("file_ignore: {}".format(file_ignore))
51+
logging.debug("dir_ignore: {}".format(dir_ignore))
52+
try:
53+
# judge file_path in the ignore file.
54+
for file in file_ignore:
55+
if file is not None:
56+
file_real_path = os.path.join(dir_name, file)
57+
if file_real_path == file_path:
58+
logging.info("ignore file path: {}".format(file_real_path))
59+
return 0
60+
61+
file_dir_path = os.path.dirname(file_path)
62+
for _dir in dir_ignore:
63+
if _dir is not None:
64+
dir_real_path = os.path.join(dir_name, _dir)
65+
if file_dir_path.startswith(dir_real_path):
66+
logging.info("ignore dir path: {}".format(dir_real_path))
67+
return 0
68+
except Exception as e:
69+
logging.error(e)
70+
continue
71+
72+
return 1
73+
74+
def get_new_file(self):
75+
result = subprocess.run(['git', 'diff', '--name-only', 'HEAD', 'origin/master', '--diff-filter=ACMR', '--no-renames', '--full-index'], stdout = subprocess.PIPE)
76+
file_list = result.stdout.decode().strip().split('\n')
77+
new_files = []
78+
for line in file_list:
79+
logging.info("modified file -> {}".format(line))
80+
result = self.__exclude_file(line)
81+
if result != 0:
82+
new_files.append(line)
83+
84+
return new_files

0 commit comments

Comments
 (0)