diff --git a/.pylintrc b/.pylintrc index f906c45df..9fe8714c8 100644 --- a/.pylintrc +++ b/.pylintrc @@ -15,8 +15,8 @@ ignore-patterns= ignore-paths= # Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= +# pygtk.require(). Required for custom checkers. +init-hook='import sys; sys.path.append(".")' # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the # number of processors available to use. @@ -29,7 +29,7 @@ limit-inference-results=100 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. -load-plugins=pylint.extensions.no_self_use +load-plugins=pylint.extensions.no_self_use,checkers.file_header_checker # Pickle collected data for later comparisons. persistent=yes @@ -491,4 +491,4 @@ min-public-methods=2 # Exceptions that will emit a warning when being caught. Defaults to # "Exception". -overgeneral-exceptions=Exception +overgeneral-exceptions=builtins.Exception diff --git a/checkers/file_header_checker.py b/checkers/file_header_checker.py new file mode 100644 index 000000000..f2d1da65c --- /dev/null +++ b/checkers/file_header_checker.py @@ -0,0 +1,59 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +from pylint.checkers import BaseRawFileChecker + +COPYWRITE_STRING = ( + "# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n" +) +COPYWRITE_BYTES = bytes(COPYWRITE_STRING, "utf-8") +LICENSE_STRING = "# SPDX-License-Identifier: Apache-2.0" +LICENSE_BYTES = bytes(LICENSE_STRING, "utf-8") + + +class FileHeaderChecker(BaseRawFileChecker): + name = "file_header_checker" + msgs = { + "E1234": ( + "File has missing or malformed header", + "missing-header", + "All files must have required header: \n" + + COPYWRITE_STRING + + LICENSE_STRING, + ), + } + options = () + + def process_module(self, node): + """ + Check if the file has the required header in first and second lines of + the file. Some files may be scripts, which requires the first line to + be the shebang line, so handle that by ignoring the first line. + """ + first_line = 0 + second_line = 1 + with node.stream() as stream: + for line_num, line in enumerate(stream): + if line_num == first_line and line.startswith(b"#!"): + first_line += 1 + second_line += 1 + elif line_num == first_line and is_bad_copywrite_line(line): + self.add_message("missing-header", line=line_num) + break + elif line_num == second_line and is_bad_license_line(line): + self.add_message("missing-header", line=line_num) + break + elif line_num > second_line: + break + + +def is_bad_copywrite_line(line: bytes) -> bool: + return not line.startswith(COPYWRITE_BYTES) + + +def is_bad_license_line(line: bytes) -> bool: + return not line.startswith(LICENSE_BYTES) + + +def register(linter) -> None: + linter.register_checker(FileHeaderChecker(linter)) diff --git a/scripts/check_for_valid_readme.py b/scripts/check_for_valid_readme.py index 42446dd74..c84b309ae 100644 --- a/scripts/check_for_valid_readme.py +++ b/scripts/check_for_valid_readme.py @@ -1,3 +1,5 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 """Test script to check given paths for valid README.rst files.""" import argparse import sys diff --git a/scripts/eachdist.py b/scripts/eachdist.py index 068b42380..7dac44f54 100755 --- a/scripts/eachdist.py +++ b/scripts/eachdist.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 import argparse import os