mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-11-29 23:34:13 +01:00
Merge pull request #3320 from gilles-peskine-arm/check-files-changelog-development
Check changelog entries on CI
This commit is contained in:
commit
bd004e862d
@ -1,3 +1,4 @@
|
|||||||
Changes
|
Changes
|
||||||
* Fix warnings about signedness issues in format strings. The build is now
|
* Fix warnings about signedness issues in format strings. The build is now
|
||||||
clean of -Wformat-signedness warnings. Contributed by Kenneth Soerensen in #3153.
|
clean of -Wformat-signedness warnings. Contributed by Kenneth Soerensen
|
||||||
|
in #3153.
|
||||||
|
@ -625,6 +625,18 @@ component_check_files () {
|
|||||||
record_status tests/scripts/check-files.py
|
record_status tests/scripts/check-files.py
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component_check_changelog () {
|
||||||
|
msg "Check: changelog entries" # < 1s
|
||||||
|
rm -f ChangeLog.new
|
||||||
|
record_status scripts/assemble_changelog.py -o ChangeLog.new
|
||||||
|
if [ -e ChangeLog.new ]; then
|
||||||
|
# Show the diff for information. It isn't an error if the diff is
|
||||||
|
# non-empty.
|
||||||
|
diff -u ChangeLog ChangeLog.new || true
|
||||||
|
rm ChangeLog.new
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
component_check_names () {
|
component_check_names () {
|
||||||
msg "Check: declared and exported names (builds the library)" # < 3s
|
msg "Check: declared and exported names (builds the library)" # < 3s
|
||||||
record_status tests/scripts/check-names.sh -v
|
record_status tests/scripts/check-names.sh -v
|
||||||
|
@ -14,6 +14,8 @@ import os
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import codecs
|
import codecs
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
@ -23,28 +25,48 @@ class FileIssueTracker:
|
|||||||
To implement a checker that processes a file as a whole, inherit from
|
To implement a checker that processes a file as a whole, inherit from
|
||||||
this class and implement `check_file_for_issue` and define ``heading``.
|
this class and implement `check_file_for_issue` and define ``heading``.
|
||||||
|
|
||||||
``files_exemptions``: files whose name ends with a string in this set
|
``suffix_exemptions``: files whose name ends with a string in this set
|
||||||
will not be checked.
|
will not be checked.
|
||||||
|
|
||||||
|
``path_exemptions``: files whose path (relative to the root of the source
|
||||||
|
tree) matches this regular expression will not be checked. This can be
|
||||||
|
``None`` to match no path. Paths are normalized and converted to ``/``
|
||||||
|
separators before matching.
|
||||||
|
|
||||||
``heading``: human-readable description of the issue
|
``heading``: human-readable description of the issue
|
||||||
"""
|
"""
|
||||||
|
|
||||||
files_exemptions = frozenset()
|
suffix_exemptions = frozenset()
|
||||||
|
path_exemptions = None
|
||||||
# heading must be defined in derived classes.
|
# heading must be defined in derived classes.
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.files_with_issues = {}
|
self.files_with_issues = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normalize_path(filepath):
|
||||||
|
"""Normalize ``filepath`` with / as the directory separator."""
|
||||||
|
filepath = os.path.normpath(filepath)
|
||||||
|
# On Windows, we may have backslashes to separate directories.
|
||||||
|
# We need slashes to match exemption lists.
|
||||||
|
seps = os.path.sep
|
||||||
|
if os.path.altsep is not None:
|
||||||
|
seps += os.path.altsep
|
||||||
|
return '/'.join(filepath.split(seps))
|
||||||
|
|
||||||
def should_check_file(self, filepath):
|
def should_check_file(self, filepath):
|
||||||
"""Whether the given file name should be checked.
|
"""Whether the given file name should be checked.
|
||||||
|
|
||||||
Files whose name ends with a string listed in ``self.files_exemptions``
|
Files whose name ends with a string listed in ``self.suffix_exemptions``
|
||||||
will not be checked.
|
or whose path matches ``self.path_exemptions`` will not be checked.
|
||||||
"""
|
"""
|
||||||
for files_exemption in self.files_exemptions:
|
for files_exemption in self.suffix_exemptions:
|
||||||
if filepath.endswith(files_exemption):
|
if filepath.endswith(files_exemption):
|
||||||
return False
|
return False
|
||||||
|
if self.path_exemptions and \
|
||||||
|
re.match(self.path_exemptions, self.normalize_path(filepath)):
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def check_file_for_issue(self, filepath):
|
def check_file_for_issue(self, filepath):
|
||||||
@ -73,6 +95,17 @@ class FileIssueTracker:
|
|||||||
logger.info(filename)
|
logger.info(filename)
|
||||||
logger.info("")
|
logger.info("")
|
||||||
|
|
||||||
|
BINARY_FILE_PATH_RE_LIST = [
|
||||||
|
r'docs/.*\.pdf\Z',
|
||||||
|
r'programs/fuzz/corpuses/[^.]+\Z',
|
||||||
|
r'tests/data_files/[^.]+\Z',
|
||||||
|
r'tests/data_files/.*\.(crt|csr|db|der|key|pubkey)\Z',
|
||||||
|
r'tests/data_files/.*\.req\.[^/]+\Z',
|
||||||
|
r'tests/data_files/.*malformed[^/]+\Z',
|
||||||
|
r'tests/data_files/format_pkcs12\.fmt\Z',
|
||||||
|
]
|
||||||
|
BINARY_FILE_PATH_RE = re.compile('|'.join(BINARY_FILE_PATH_RE_LIST))
|
||||||
|
|
||||||
class LineIssueTracker(FileIssueTracker):
|
class LineIssueTracker(FileIssueTracker):
|
||||||
"""Base class for line-by-line issue tracking.
|
"""Base class for line-by-line issue tracking.
|
||||||
|
|
||||||
@ -80,6 +113,9 @@ class LineIssueTracker(FileIssueTracker):
|
|||||||
this class and implement `line_with_issue`.
|
this class and implement `line_with_issue`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Exclude binary files.
|
||||||
|
path_exemptions = BINARY_FILE_PATH_RE
|
||||||
|
|
||||||
def issue_with_line(self, line, filepath):
|
def issue_with_line(self, line, filepath):
|
||||||
"""Check the specified line for the issue that this class is for.
|
"""Check the specified line for the issue that this class is for.
|
||||||
|
|
||||||
@ -103,7 +139,7 @@ class LineIssueTracker(FileIssueTracker):
|
|||||||
|
|
||||||
def is_windows_file(filepath):
|
def is_windows_file(filepath):
|
||||||
_root, ext = os.path.splitext(filepath)
|
_root, ext = os.path.splitext(filepath)
|
||||||
return ext in ('.bat', '.dsp', '.sln', '.vcxproj')
|
return ext in ('.bat', '.dsp', '.dsw', '.sln', '.vcxproj')
|
||||||
|
|
||||||
|
|
||||||
class PermissionIssueTracker(FileIssueTracker):
|
class PermissionIssueTracker(FileIssueTracker):
|
||||||
@ -126,9 +162,18 @@ class EndOfFileNewlineIssueTracker(FileIssueTracker):
|
|||||||
|
|
||||||
heading = "Missing newline at end of file:"
|
heading = "Missing newline at end of file:"
|
||||||
|
|
||||||
|
path_exemptions = BINARY_FILE_PATH_RE
|
||||||
|
|
||||||
def check_file_for_issue(self, filepath):
|
def check_file_for_issue(self, filepath):
|
||||||
with open(filepath, "rb") as f:
|
with open(filepath, "rb") as f:
|
||||||
if not f.read().endswith(b"\n"):
|
try:
|
||||||
|
f.seek(-1, 2)
|
||||||
|
except OSError:
|
||||||
|
# This script only works on regular files. If we can't seek
|
||||||
|
# 1 before the end, it means that this position is before
|
||||||
|
# the beginning of the file, i.e. that the file is empty.
|
||||||
|
return
|
||||||
|
if f.read(1) != b"\n":
|
||||||
self.files_with_issues[filepath] = None
|
self.files_with_issues[filepath] = None
|
||||||
|
|
||||||
|
|
||||||
@ -138,7 +183,8 @@ class Utf8BomIssueTracker(FileIssueTracker):
|
|||||||
|
|
||||||
heading = "UTF-8 BOM present:"
|
heading = "UTF-8 BOM present:"
|
||||||
|
|
||||||
files_exemptions = frozenset([".vcxproj", ".sln"])
|
suffix_exemptions = frozenset([".vcxproj", ".sln"])
|
||||||
|
path_exemptions = BINARY_FILE_PATH_RE
|
||||||
|
|
||||||
def check_file_for_issue(self, filepath):
|
def check_file_for_issue(self, filepath):
|
||||||
with open(filepath, "rb") as f:
|
with open(filepath, "rb") as f:
|
||||||
@ -152,6 +198,8 @@ class UnixLineEndingIssueTracker(LineIssueTracker):
|
|||||||
heading = "Non-Unix line endings:"
|
heading = "Non-Unix line endings:"
|
||||||
|
|
||||||
def should_check_file(self, filepath):
|
def should_check_file(self, filepath):
|
||||||
|
if not super().should_check_file(filepath):
|
||||||
|
return False
|
||||||
return not is_windows_file(filepath)
|
return not is_windows_file(filepath)
|
||||||
|
|
||||||
def issue_with_line(self, line, _filepath):
|
def issue_with_line(self, line, _filepath):
|
||||||
@ -164,6 +212,8 @@ class WindowsLineEndingIssueTracker(LineIssueTracker):
|
|||||||
heading = "Non-Windows line endings:"
|
heading = "Non-Windows line endings:"
|
||||||
|
|
||||||
def should_check_file(self, filepath):
|
def should_check_file(self, filepath):
|
||||||
|
if not super().should_check_file(filepath):
|
||||||
|
return False
|
||||||
return is_windows_file(filepath)
|
return is_windows_file(filepath)
|
||||||
|
|
||||||
def issue_with_line(self, line, _filepath):
|
def issue_with_line(self, line, _filepath):
|
||||||
@ -174,7 +224,7 @@ class TrailingWhitespaceIssueTracker(LineIssueTracker):
|
|||||||
"""Track lines with trailing whitespace."""
|
"""Track lines with trailing whitespace."""
|
||||||
|
|
||||||
heading = "Trailing whitespace:"
|
heading = "Trailing whitespace:"
|
||||||
files_exemptions = frozenset([".dsp", ".md"])
|
suffix_exemptions = frozenset([".dsp", ".md"])
|
||||||
|
|
||||||
def issue_with_line(self, line, _filepath):
|
def issue_with_line(self, line, _filepath):
|
||||||
return line.rstrip(b"\r\n") != line.rstrip()
|
return line.rstrip(b"\r\n") != line.rstrip()
|
||||||
@ -184,7 +234,8 @@ class TabIssueTracker(LineIssueTracker):
|
|||||||
"""Track lines with tabs."""
|
"""Track lines with tabs."""
|
||||||
|
|
||||||
heading = "Tabs present:"
|
heading = "Tabs present:"
|
||||||
files_exemptions = frozenset([
|
suffix_exemptions = frozenset([
|
||||||
|
".pem", # some openssl dumps have tabs
|
||||||
".sln",
|
".sln",
|
||||||
"/Makefile",
|
"/Makefile",
|
||||||
"/Makefile.inc",
|
"/Makefile.inc",
|
||||||
@ -223,32 +274,6 @@ class IntegrityChecker:
|
|||||||
self.check_repo_path()
|
self.check_repo_path()
|
||||||
self.logger = None
|
self.logger = None
|
||||||
self.setup_logger(log_file)
|
self.setup_logger(log_file)
|
||||||
self.extensions_to_check = (
|
|
||||||
".bat",
|
|
||||||
".c",
|
|
||||||
".data",
|
|
||||||
".dsp",
|
|
||||||
".function",
|
|
||||||
".h",
|
|
||||||
".md",
|
|
||||||
".pl",
|
|
||||||
".py",
|
|
||||||
".sh",
|
|
||||||
".sln",
|
|
||||||
".vcxproj",
|
|
||||||
"/CMakeLists.txt",
|
|
||||||
"/ChangeLog",
|
|
||||||
"/Makefile",
|
|
||||||
"/Makefile.inc",
|
|
||||||
)
|
|
||||||
self.excluded_directories = [
|
|
||||||
'.git',
|
|
||||||
'mbed-os',
|
|
||||||
]
|
|
||||||
self.excluded_paths = list(map(os.path.normpath, [
|
|
||||||
'cov-int',
|
|
||||||
'examples',
|
|
||||||
]))
|
|
||||||
self.issues_to_check = [
|
self.issues_to_check = [
|
||||||
PermissionIssueTracker(),
|
PermissionIssueTracker(),
|
||||||
EndOfFileNewlineIssueTracker(),
|
EndOfFileNewlineIssueTracker(),
|
||||||
@ -275,21 +300,20 @@ class IntegrityChecker:
|
|||||||
console = logging.StreamHandler()
|
console = logging.StreamHandler()
|
||||||
self.logger.addHandler(console)
|
self.logger.addHandler(console)
|
||||||
|
|
||||||
def prune_branch(self, root, d):
|
@staticmethod
|
||||||
if d in self.excluded_directories:
|
def collect_files():
|
||||||
return True
|
bytes_output = subprocess.check_output(['git', 'ls-files', '-z'])
|
||||||
if os.path.normpath(os.path.join(root, d)) in self.excluded_paths:
|
bytes_filepaths = bytes_output.split(b'\0')[:-1]
|
||||||
return True
|
ascii_filepaths = map(lambda fp: fp.decode('ascii'), bytes_filepaths)
|
||||||
return False
|
# Prepend './' to files in the top-level directory so that
|
||||||
|
# something like `'/Makefile' in fp` matches in the top-level
|
||||||
|
# directory as well as in subdirectories.
|
||||||
|
return [fp if os.path.dirname(fp) else os.path.join(os.curdir, fp)
|
||||||
|
for fp in ascii_filepaths]
|
||||||
|
|
||||||
def check_files(self):
|
def check_files(self):
|
||||||
for root, dirs, files in os.walk("."):
|
|
||||||
dirs[:] = sorted(d for d in dirs if not self.prune_branch(root, d))
|
|
||||||
for filename in sorted(files):
|
|
||||||
filepath = os.path.join(root, filename)
|
|
||||||
if not filepath.endswith(self.extensions_to_check):
|
|
||||||
continue
|
|
||||||
for issue_to_check in self.issues_to_check:
|
for issue_to_check in self.issues_to_check:
|
||||||
|
for filepath in self.collect_files():
|
||||||
if issue_to_check.should_check_file(filepath):
|
if issue_to_check.should_check_file(filepath):
|
||||||
issue_to_check.check_file_for_issue(filepath)
|
issue_to_check.check_file_for_issue(filepath)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user