From 37a7fa07a3557e97a13ac2ff313c4288171739b5 Mon Sep 17 00:00:00 2001 From: Jordan Layfield Date: Mon, 19 Oct 2026 11:46:14 +0100 Subject: [PATCH 1/2] Add support for headers within leading region wrappers in licence header checks NO_JIRA --- main/licence_headers.py | 26 +++++++++++++++++++++++++- test/test_licence_headers.py | 8 ++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/main/licence_headers.py b/main/licence_headers.py index bc0b053..03f4415 100644 --- a/main/licence_headers.py +++ b/main/licence_headers.py @@ -109,6 +109,27 @@ def _header_line_matches(actual, expected): return actual == expected +def _strip_leading_region_wrapper(text): + lines = text.splitlines() + for idx, line in enumerate(lines): + stripped = line.strip() + if not stripped: + continue + if not stripped.startswith('#region'): + return lines + depth = 0 + for region_idx in range(idx, len(lines)): + region_line = lines[region_idx].strip() + if region_line.startswith('#region'): + depth += 1 + elif region_line.startswith('#endregion'): + depth -= 1 + if depth == 0: + return lines[idx + 1:region_idx] + return lines[idx + 1:] + return lines + + def _known_header_prefix_end(text, offset, expected): actual_lines = [] position = offset @@ -201,7 +222,10 @@ def _has_valid_header(text, offset, expected): '''Check if text starting at offset contains a valid compliant header (accepting any valid year).''' if text.startswith(expected, offset): return True - actual_lines = [line.strip() for line in text[offset:].splitlines()] + + body_lines = text[offset:].splitlines() + stripped_body = _strip_leading_region_wrapper('\n'.join(body_lines)) + actual_lines = [line.strip() for line in stripped_body] expected_lines = [line.strip() for line in expected.splitlines()] if len(actual_lines) < len(expected_lines): return False diff --git a/test/test_licence_headers.py b/test/test_licence_headers.py index 7b96484..ab30d96 100644 --- a/test/test_licence_headers.py +++ b/test/test_licence_headers.py @@ -21,6 +21,14 @@ def test_existing_file_with_earlier_year_passes_and_is_not_modified(): assert 'Copyright (C) 2020' in fixed +def test_header_inside_leading_region_wrapper_passes_without_duplication(): + header = licence_headers._render_header('hash', year=2026) + content = '#region Licence\n' + header + '#endregion\nprint("ok")\n' + assert licence_headers.check_content('example.py', content, 2026) is None + fixed = licence_headers.fix_content('example.py', content, 2026) + assert fixed == content + + def test_literal_year_token_fails(): header = licence_headers._render_header('hash', year=2026).replace('2026', '{{ .Year }}') assert licence_headers.check_content('example.py', header, 2026) is not None From 68cfb5cd6a4a555708d1e55ee743f088a89260a5 Mon Sep 17 00:00:00 2001 From: Jordan Layfield Date: Mon, 19 Oct 2026 11:58:29 +0100 Subject: [PATCH 2/2] Enhance region directive handling in licence header checks and add corresponding tests NO_JIRA --- main/licence_headers.py | 48 +++++++++++++++++++++++++++++------- test/test_licence_headers.py | 17 +++++++++++++ 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/main/licence_headers.py b/main/licence_headers.py index 03f4415..93cba62 100644 --- a/main/licence_headers.py +++ b/main/licence_headers.py @@ -109,25 +109,41 @@ def _header_line_matches(actual, expected): return actual == expected -def _strip_leading_region_wrapper(text): - lines = text.splitlines() +def _is_region_directive(line): + return bool(re.match(r'^#region(?:\s|$)', line.strip())) + + +def _is_end_region_directive(line): + return bool(re.match(r'^#endregion(?:\s|$)', line.strip())) + + +def _find_leading_region_block(lines): for idx, line in enumerate(lines): stripped = line.strip() if not stripped: continue - if not stripped.startswith('#region'): - return lines + if not _is_region_directive(stripped): + return None depth = 0 for region_idx in range(idx, len(lines)): region_line = lines[region_idx].strip() - if region_line.startswith('#region'): + if _is_region_directive(region_line): depth += 1 - elif region_line.startswith('#endregion'): + elif _is_end_region_directive(region_line): depth -= 1 if depth == 0: - return lines[idx + 1:region_idx] - return lines[idx + 1:] - return lines + return idx, region_idx + return None + return None + + +def _strip_leading_region_wrapper(text): + lines = text.splitlines() + region_block = _find_leading_region_block(lines) + if region_block is None: + return lines + idx, region_end = region_block + return lines[idx + 1:region_end] def _known_header_prefix_end(text, offset, expected): @@ -208,6 +224,8 @@ def _damaged_full_header_end(text, offset, style): def _existing_header_end(text, offset, style, expected): lines = text[offset:].splitlines(keepends=True) + if lines and _is_region_directive(lines[0].strip()): + return offset if lines and LEGACY_HEADER_PATTERN.match(lines[0]): if len(lines) > 1 and lines[1].strip() == '': return offset + len(lines[0]) + len(lines[1]) @@ -266,6 +284,18 @@ def fix_content(filename, data, year=None): if _has_valid_header(text, offset, expected): return data + lines = text.splitlines(keepends=True) + region_block = _find_leading_region_block(lines) + if region_block is not None: + region_start, region_end = region_block + inner = ''.join(lines[region_start + 1:region_end]) + if _has_valid_header(inner, 0, expected): + return data + header_end = _existing_header_end(inner, 0, style, expected) + fixed_inner = expected + inner[header_end:] + fixed = ''.join(lines[:region_start + 1]) + fixed_inner + ''.join(lines[region_end:]) + return fixed.encode(encoding) if encoding else fixed + header_end = _existing_header_end(text, offset, style, expected) prefix = text[:offset] if prefix and not prefix.endswith(('\n', '\r')): diff --git a/test/test_licence_headers.py b/test/test_licence_headers.py index ab30d96..d4a8b27 100644 --- a/test/test_licence_headers.py +++ b/test/test_licence_headers.py @@ -29,6 +29,23 @@ def test_header_inside_leading_region_wrapper_passes_without_duplication(): assert fixed == content +def test_regional_keyword_is_not_treated_as_region_directive(): + header = licence_headers._render_header('hash', year=2026) + content = '#regional\n' + header + 'print("ok")\n' + assert licence_headers.check_content('example.py', content, 2026) is not None + fixed = licence_headers.fix_content('example.py', content, 2026) + assert fixed.startswith(header) + + +def test_wrapped_header_is_repaired_in_place_without_double_insert(): + header = licence_headers._render_header('hash', year=2026) + broken = header.replace('# copied, except in accordance with a valid licence agreement with CCDC and\n', '') + content = '#region Licence\n' + broken + '#endregion\nprint("ok")\n' + fixed = licence_headers.fix_content('example.py', content, 2026) + assert fixed == '#region Licence\n' + header + '#endregion\nprint("ok")\n' + assert licence_headers.check_content('example.py', fixed, 2026) is None + + def test_literal_year_token_fails(): header = licence_headers._render_header('hash', year=2026).replace('2026', '{{ .Year }}') assert licence_headers.check_content('example.py', header, 2026) is not None