AutoRelease + Header Checker Upgrades (#482)

* Initial version where all deps are pylibs
* mechanism for undoing an autorelease
* misc refactor touchups
* +mechanism to baseline older commit into detached HEAD tag
* decouple kernel check configs + misc refactor improvements
* improved compatibility with git action
* Get pushes working in git action with release
* Fix header-check issue when same deletion occurs in parallel
* Add help message in case check fails
* Address PR feedback
This commit is contained in:
David Chalco
2020-12-20 17:03:37 -08:00
committed by GitHub
parent 1f9389c7c4
commit 0527a2a02a
9 changed files with 864 additions and 675 deletions

133
.github/scripts/common/header_checker.py vendored Executable file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env python3
import os, sys, re
from argparse import ArgumentParser
from difflib import unified_diff
from json import load
def dprint(msg):
print('[DEBUG]: %s' % str(msg))
class HeaderChecker:
def __init__(self, header, padding=1000, ignored_files=[], ignored_ext=[], ignored_patterns=[]):
self.padding = padding
self.header = header
self.ignorePatternList = ignored_patterns.copy()
self.ignoreFileList = ignored_files.copy()
self.ignoreExtList = ignored_ext.copy()
def checkJSONList(self, path_json):
'''
This is particularly useful when ingesting output from other programs, like git actions
'''
assert os.path.exists(path_json), 'No such file: ' + path_json
# Get list of files to check from JSON file
with open(path_json) as file_json:
file_checklist = load(file_json)
assert isinstance(file_checklist, list), 'Expected list for singular JSON List entry'
# Accrue how how files fail the check
n_failed = 0
for path_file in file_checklist:
assert isinstance(path_file, str), 'Unexpected JSON format for ' + path_json
if os.path.exists(path_file) and not self.isValidFile(path_file):
n_failed += 1
return n_failed
def isValidFile(self, path):
assert os.path.exists(path), 'No such file: ' + path
print('-------------------------------------------------------------------------------------')
print('Checking file: %s...' % path, end='')
if self.isIgnoredFile(path) or os.path.isdir(path):
print('SKIP')
print('-------------------------------------------------------------------------------------')
return True
# Don't need entire file. Read sufficiently large chunk of file that should contain the header
with open(path, encoding='utf-8', errors='ignore') as file:
chunk = file.read(len(''.join(self.header)) + self.padding)
lines = [('%s\n' % l) for l in chunk.strip().splitlines()][:len(self.header)]
if self.header == lines:
print('PASS')
print('-------------------------------------------------------------------------------------')
return True
else:
print('FAIL')
print('File Delta: %s' % path)
print(*unified_diff(lines[:len(self.header)], self.header))
print('-------------------------------------------------------------------------------------')
return False
def ignoreExtension(self, *args):
for ext in args:
self.ignoreExtList.append(ext)
def ignoreFile(self, *args):
for f in args:
self.ignoreFileList.append(f)
def ignorePattern(self, *args):
for p in args:
self.ignorePatternList.append(re.compile(p))
def isIgnoredFile(self, path):
'''
There are multiple ways a file can be ignored. This is a catch all
'''
assert os.path.exists(path), 'No such file: ' + path
# Try simpler checks first
filename = os.path.split(path)[-1]
extension = os.path.splitext(filename)[-1]
if extension in self.ignoreExtList or filename in self.ignoreFileList:
return True
# Then iterate against regex patterns. In future consider Trie
for pattern in self.ignorePatternList:
if pattern.match(path):
return True
return False
def showHelp(self, path_config):
print('\n\n'
"Please fix all highlighted diffs or add exceptions to '%s' as necessary.\n"
"Include your changes to '%s' in your PR. Git PR checks source this file from your PR.\n"
"\n"
"The FreeRTOS Header Check ensures all files that contain FreeRTOS Headers are up to date\n"
"with the latest version, copyright, and licensing info."
"\n\n" % (path_config, path_config))
@staticmethod
def configArgParser():
parser = ArgumentParser(description='FreeRTOS file header checker. We expect a consistent header across all '
'first party files. The header includes current version number, copyright, '
'and FreeRTOS license.')
parser.add_argument('files_checked',
nargs = '+',
metavar = 'FILE_LIST',
help = 'Space separated list of files to check.')
parser.add_argument('-j', '--json',
default = False,
action = 'store_true',
help = 'Treat arguments json files that store a list of files to check.')
return parser
def processArgs(self, args):
n_failed = 0
if args.json:
for path in args.files_checked:
n_failed += self.checkJSONList(path)
else:
for path in args.files_checked:
n_failed += not self.isValidFile(path)
return n_failed