diff --git a/pontos/updateheader/_parser.py b/pontos/updateheader/_parser.py index 7315ae646..577f5d0c2 100644 --- a/pontos/updateheader/_parser.py +++ b/pontos/updateheader/_parser.py @@ -114,8 +114,8 @@ def parse_args(args: Optional[Sequence[str]] = None) -> Namespace: action="store_true", default=False, help=( - "If set, will not update license with from-to years format " - "(YYYY-YYYY) if it has single (only creation) year format (YYYY). " + "If set, will format license headers in from-to year format " + "into single (creation) year format. " "Default is %(default)s." ), ) diff --git a/pontos/updateheader/updateheader.py b/pontos/updateheader/updateheader.py index 5339436c9..9f70ede94 100644 --- a/pontos/updateheader/updateheader.py +++ b/pontos/updateheader/updateheader.py @@ -8,6 +8,7 @@ Also it appends a header if it is missing in the file. """ +import io import re import sys from dataclasses import dataclass @@ -208,39 +209,43 @@ def update_file( return # replace found header and write it to file - if copyright_match and ( - not copyright_match.modification_year - and copyright_match.creation_year < year - or copyright_match.modification_year - and copyright_match.modification_year < year - ): + if copyright_match: + + # use different target license formats depending on provided single_year argument if single_year: - # In case of single year updating the license with modification date doesn't make sense. - # Changing the existing license header with created-modified years to single year is not supported. - return - copyright_term = ( - f"SPDX-FileCopyrightText: " - f"{copyright_match.creation_year}" - f"-{year} {company}" - ) - new_line = re.sub(copyright_regex, copyright_term, line) - fp_write = fp.tell() - len(line) # save position to insert - rest_of_file = fp.read() - fp.seek(fp_write) - fp.write(new_line) - fp.write(rest_of_file) - # in some cases we replace "YYYY - YYYY" with "YYYY-YYYY" - # resulting in 2 characters left at the end of the file - # so we truncate the file, just in case! - fp.truncate() - print( - f"{file}: Changed License Header Copyright Year " - f"{copyright_match.modification_year} -> " - f"{year}" - ) + copyright_term = ( + f"SPDX-FileCopyrightText: " + f"{copyright_match.creation_year} " + f"{company}" + ) + else: + copyright_term = ( + f"SPDX-FileCopyrightText: " + f"{copyright_match.creation_year}" + f"-{year} {company}" + ) + + with_multi_year = copyright_match.creation_year and copyright_match.modification_year + with_single_year_outdated = not copyright_match.modification_year and copyright_match.creation_year < year + with_multi_year_outdated = with_multi_year and copyright_match.modification_year < year + + if single_year and with_multi_year: + _substitute_license_text(fp, line, copyright_regex, copyright_term) + print( + f"{file}: Changed License Header Copyright Year format to single year " + f"{copyright_match.creation_year}-{year} -> " + f"{copyright_match.creation_year}" + ) + elif not single_year and (with_multi_year_outdated or with_single_year_outdated): + _substitute_license_text(fp, line, copyright_regex, copyright_term) + print( + f"{file}: Changed License Header Copyright Year " + f"{copyright_match.modification_year} -> " + f"{year}" + ) + else: + print(f"{file}: License Header is ok.") - else: - print(f"{file}: License Header is ok.") except FileNotFoundError as e: print(f"{file}: File is not existing.") raise e @@ -258,6 +263,25 @@ def update_file( print(f"{file}: Cleaned up!") +def _substitute_license_text( + fp: io.TextIOWrapper, + line: str, + copyright_regex: re.Pattern, + copyright_term: str, +) -> None: + """Substitute the old license text in file fp, starting on provided line, with the new one provided in copyright_term""" + new_line = re.sub(copyright_regex, copyright_term, line) + fp_write = fp.tell() - len(line) # save position to insert + rest_of_file = fp.read() + fp.seek(fp_write) + fp.write(new_line) + fp.write(rest_of_file) + # in some cases we replace "YYYY - YYYY" with "YYYY-YYYY" + # resulting in 2 characters left at the end of the file + # so we truncate the file, just in case! + fp.truncate() + + def _get_exclude_list( exclude_file: Path, directories: list[Path] ) -> list[Path]: diff --git a/tests/updateheader/test_header.py b/tests/updateheader/test_header.py index e00b48bb4..59dfe8e7b 100644 --- a/tests/updateheader/test_header.py +++ b/tests/updateheader/test_header.py @@ -343,7 +343,7 @@ def test_update_header_in_file_single_year(self, mock_stdout): year = "2021" license_id = "AGPL-3.0-or-later" - header = HEADER.format(date="2020") + header = HEADER.format(date="2020-2021") with temp_file( content=header, name="test.py", change_into=True ) as test_file: @@ -355,6 +355,13 @@ def test_update_header_in_file_single_year(self, mock_stdout): single_year=True, ) + ret = mock_stdout.getvalue() + self.assertEqual( + ret, + f"{test_file}: Changed License Header Copyright Year format to single year " + "2020-2021 -> 2020\n", + ) + self.assertIn( "# SPDX-FileCopyrightText: 2020 Greenbone AG", test_file.read_text(encoding="utf-8"),