check_build_warnings.py
1 #!/usr/bin/env python 2 # coding=utf-8 3 # 4 # CI script to check build logs for warnings. 5 # Reads the list of builds, in the format produced by find_apps.py or build_apps.py, and finds warnings in the 6 # log files for every build. 7 # Exits with a non-zero exit code if any warning is found. 8 9 import argparse 10 import logging 11 import os 12 import re 13 import sys 14 15 try: 16 from find_build_apps import BuildItem, setup_logging 17 except ImportError: 18 sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) 19 from find_build_apps import BuildItem, setup_logging 20 21 WARNING_REGEX = re.compile(r"(?:error|warning)[^\w]", re.MULTILINE | re.IGNORECASE) 22 23 IGNORE_WARNS = [ 24 re.compile(r_str) for r_str in [ 25 r"library/error\.o", 26 r".*error.*\.c\.obj", 27 r"-Werror", 28 r"error\.d", 29 r"reassigning to symbol", 30 r"changes choice state", 31 r"crosstool_version_check\.cmake", 32 r"CryptographyDeprecationWarning", 33 ] 34 ] 35 36 37 def line_has_warnings(line): # type: (str) -> bool 38 if not WARNING_REGEX.search(line): 39 return False 40 41 has_warnings = True 42 for ignored in IGNORE_WARNS: 43 if re.search(ignored, line): 44 has_warnings = False 45 break 46 47 return has_warnings 48 49 50 def main(): 51 parser = argparse.ArgumentParser(description="ESP-IDF app builder") 52 parser.add_argument( 53 "-v", 54 "--verbose", 55 action="count", 56 help="Increase the logging level of the script. Can be specified multiple times.", 57 ) 58 parser.add_argument( 59 "--log-file", 60 type=argparse.FileType("w"), 61 help="Write the script log to the specified file, instead of stderr", 62 ) 63 parser.add_argument( 64 "build_list", 65 type=argparse.FileType("r"), 66 nargs="?", 67 default=sys.stdin, 68 help="Name of the file to read the list of builds from. If not specified, read from stdin.", 69 ) 70 args = parser.parse_args() 71 setup_logging(args) 72 73 build_items = [BuildItem.from_json(line) for line in args.build_list] 74 if not build_items: 75 logging.warning("Empty build list") 76 SystemExit(0) 77 78 found_warnings = 0 79 for build_item in build_items: 80 if not build_item.build_log_path: 81 logging.debug("No log file for {}".format(build_item.work_dir)) 82 continue 83 with open(build_item.build_log_path, "r") as log_file: 84 for line_no, line in enumerate(log_file): 85 if line_has_warnings(line): 86 logging.error("Issue in app {}, config {}:".format(build_item.app_dir, build_item.config_name)) 87 logging.error(line.rstrip("\n")) 88 logging.error("See {}:{} for details".format(os.path.basename(build_item.build_log_path), 89 line_no + 1)) 90 found_warnings += 1 91 break 92 93 if found_warnings: 94 logging.error("Checked {} builds, found {} warnings".format(len(build_items), found_warnings)) 95 raise SystemExit(1) 96 97 logging.info("No warnings found") 98 99 100 if __name__ == "__main__": 101 main()