diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index b71169bb..fbc1dd71 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -61,6 +61,13 @@ types: [text] stages: [pre-commit, pre-push, manual] minimum_pre_commit_version: 3.2.0 +- id: check-spdx + name: check SPDX line + description: checks for the presence of an SPDX-License-Identifier in the comments of source files. + entry: check-spdx + language: python + files: \.(py|js|java|c|cpp|go|sh|ps1)$ + types: [text] - id: pretty-format-json name: pretty format json description: sets a standard for formatting json files. diff --git a/README.md b/README.md index c0f678fd..f620b4dc 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ Check for files that contain merge conflict strings. #### `check-shebang-scripts-are-executable` Checks that scripts with shebangs are executable. +#### `check-spdx` +Checks for the presence of an SPDX-License-Identifier in the comments of source files. + #### `check-symlinks` Checks for symlinks which do not point to anything. diff --git a/pre_commit_hooks/check_spdx.py b/pre_commit_hooks/check_spdx.py new file mode 100755 index 00000000..994600e2 --- /dev/null +++ b/pre_commit_hooks/check_spdx.py @@ -0,0 +1,62 @@ +"""This script checks for the presence of an SPDX-License-Identifier in the comments of source files.""" +from __future__ import annotations + +import argparse +import re +from collections.abc import Sequence + + +def _load_file(file_path: str) -> str: + try: + with open(file_path, encoding='utf-8') as f: + return f.read() + except Exception as e: + print(f"Error loading file content of {file_path}: {e}") + + +def _check_spdx(file_content: str) -> bool: + for line in file_content: + stripped_line = line.strip() + if stripped_line.startswith('#') or stripped_line.startswith('//') or re.match(r'^\s*/\*', stripped_line): + if 'SPDX-License-Identifier:' in stripped_line: + return True + else: + break + + +def check_spdx(file_paths: list[str]) -> int: + """ + Check if the given files contain an SPDX license identifier. + + Args: + file_paths (list of str): List of file paths to check. + + Returns: + int: Returns 0 if all files contain an SPDX license identifier, + otherwise returns 1 if any file is missing the SPDX line. + """ + any_missing_spdx = False + for file_path in file_paths: + file_content = _load_file(file_path) + if not file_content: + return 1 + + if not _check_spdx(file_path): + print(f"Missing SPDX line in {file_path}") + any_missing_spdx = True + + if any_missing_spdx: + return 1 + return 0 + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('filenames', nargs='*') + args = parser.parse_args(argv) + + return check_spdx(args.filenames) + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/setup.cfg b/setup.cfg index 3b7e5eec..2e1eeb4e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,6 +40,7 @@ console_scripts = check-json = pre_commit_hooks.check_json:main check-merge-conflict = pre_commit_hooks.check_merge_conflict:main check-shebang-scripts-are-executable = pre_commit_hooks.check_shebang_scripts_are_executable:main + check-spdx = pre_commit_hooks.check_spdx:main check-symlinks = pre_commit_hooks.check_symlinks:main check-toml = pre_commit_hooks.check_toml:main check-vcs-permalinks = pre_commit_hooks.check_vcs_permalinks:main