From 40ddb9caa413e50fe57e606faae5d195e238409f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 24 Jul 2026 16:43:09 +0200 Subject: [PATCH] Simplify file header updates (#836) --- actions/__init__.py | 2 +- actions/update_file_headers.py | 16 +- tests/test_file_headers.py | 259 --------------------------------- 3 files changed, 6 insertions(+), 271 deletions(-) delete mode 100644 tests/test_file_headers.py diff --git a/actions/__init__.py b/actions/__init__.py index 0ade891..22d88b2 100644 --- a/actions/__init__.py +++ b/actions/__init__.py @@ -28,4 +28,4 @@ # ├── test_summarize_pr.py # └── ... -__version__ = "0.2.37" +__version__ = "0.2.38" diff --git a/actions/update_file_headers.py b/actions/update_file_headers.py index fec0f9a..d6e1743 100644 --- a/actions/update_file_headers.py +++ b/actions/update_file_headers.py @@ -120,13 +120,9 @@ def update_file(file_path, prefix, block_start, block_end, base_header): # Check for special first line special_line_index = -1 - first_line = lines[0].lstrip("\ufeff") if lines else "" + first_line = lines[0].lstrip("\ufeff").lower() if lines else "" encoding_cookie = r"^[ \t\f]*#.*?coding[:=][ \t]*[-_.a-zA-Z0-9]+" - if lines and ( - first_line.startswith(("#!", " 1 and re.match(encoding_cookie, lines[1]): @@ -136,14 +132,12 @@ def update_file(file_path, prefix, block_start, block_end, base_header): start_idx = special_line_index + 1 if special_line_index >= 0 else 0 end_idx = min(start_idx + 5, len(lines)) # Look in first few lines - # An existing header must be the first non-empty line and use the file's comment syntax. candidate_index = next((i for i in range(start_idx, end_idx) if lines[i].strip()), -1) candidate = lines[candidate_index].strip() if candidate_index >= 0 else "" comment_start = (prefix or block_start or "# ").strip() - known_header = candidate.startswith(comment_start) and re.search( - r"AGPL-3\.0 License|CONFIDENTIAL: Unauthorized use|©\s*2014[–-]\d{4}\s+Ultralytics Inc\.|" - r"Ultralytics Inc\..*Copyright ©\s*2014[–-]\d{4}\s*-\s*CONFIDENTIAL\s*-", - candidate, + header = candidate[len(comment_start) :].strip() if candidate.startswith(comment_start) else "" + known_header = header.startswith(("Ultralytics 🚀 AGPL-3.0 License", "Ultralytics Inc. 🚀 Copyright")) or ( + header.startswith("© 2014-") and " Ultralytics Inc." in header ) header_index = candidate_index if candidate == formatted_header.strip() or known_header else -1 diff --git a/tests/test_file_headers.py b/tests/test_file_headers.py deleted file mode 100644 index f306386..0000000 --- a/tests/test_file_headers.py +++ /dev/null @@ -1,259 +0,0 @@ -# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license -"""Tests for the file headers update functionality.""" - -from pathlib import Path -from tempfile import TemporaryDirectory -from unittest.mock import patch - -from actions.update_file_headers import COMMENT_MAP, IGNORE_PATHS, main, update_file - - -def test_update_file_python(): - """Test updating Python file headers.""" - with TemporaryDirectory() as tmp_dir: - # Create a test Python file - test_file = Path(tmp_dir) / "test.py" - test_file.write_text("print('Hello World')\n") - - # Update file - result = update_file(test_file, "# ", None, None, "Ultralytics 🚀 Test Header") - - # Check results - assert result is True - content = test_file.read_text() - assert content.startswith("# Ultralytics 🚀 Test Header\n\n") - assert "print('Hello World')" in content - - -def test_update_file_cpp(): - """Test updating C++ file headers.""" - with TemporaryDirectory() as tmp_dir: - # Create a test C++ file - test_file = Path(tmp_dir) / "test.cpp" - test_file.write_text("#include \n\nint main() {\n return 0;\n}\n") - - # Update file - result = update_file(test_file, "// ", "/* ", " */", "Ultralytics 🚀 Test Header") - - # Check results - assert result is True - content = test_file.read_text() - assert content.startswith("// Ultralytics 🚀 Test Header\n\n") - assert "#include " in content - - -def test_update_file_with_existing_header(): - """Test updating file with existing header.""" - with TemporaryDirectory() as tmp_dir: - # Create a test file with existing header - test_file = Path(tmp_dir) / "test.py" - test_file.write_text("# Ultralytics 🚀 AGPL-3.0 License\n\ndef main():\n pass\n") - - # Update file - result = update_file(test_file, "# ", None, None, "Ultralytics 🚀 Test Header") - - # Check results - assert result is True - content = test_file.read_text() - assert content.startswith("# Ultralytics 🚀 Test Header\n\n") - assert "def main():" in content - - -def test_update_file_with_shebang(): - """Test updating file with shebang.""" - with TemporaryDirectory() as tmp_dir: - # Create a test file with shebang - test_file = Path(tmp_dir) / "test.py" - test_file.write_text("#!/usr/bin/env python3\n\nprint('Hello World')\n") - - # Update file - result = update_file(test_file, "# ", None, None, "Ultralytics 🚀 Test Header") - - # Check results - assert result is True - content = test_file.read_text() - assert content.startswith("#!/usr/bin/env python3\n# Ultralytics 🚀 Test Header\n\n") - assert "print('Hello World')" in content - - -def test_update_file_preserves_early_ultralytics_source(): - """Test that Ultralytics references in source code are not mistaken for headers.""" - with TemporaryDirectory() as tmp_dir: - tmp_path = Path(tmp_dir) - docstring_file = tmp_path / "api.py" - docstring_file.write_text('"""Ultralytics Platform API client."""\n\nVALUE = 1\n') - import_file = tmp_path / "__init__.py" - import_file.write_text("from ultralytics import YOLO\n") - - for test_file, spacing in ((docstring_file, ""), (import_file, "\n")): - original = test_file.read_text() - assert update_file(test_file, "# ", None, None, "Ultralytics 🚀 Test Header") is True - assert test_file.read_text() == f"# Ultralytics 🚀 Test Header\n{spacing}{original}" - - -def test_update_file_with_lowercase_doctype(): - """Test that Prettier's lowercase HTML doctype remains first.""" - with TemporaryDirectory() as tmp_dir: - test_file = Path(tmp_dir) / "index.html" - test_file.write_text("\n\n") - - assert update_file(test_file, None, "", "Ultralytics 🚀 Test Header") is True - assert test_file.read_text().startswith("\n\n\n") - - -def test_update_file_with_bom_xml_declaration(): - """Test that a BOM-prefixed XML declaration remains first.""" - with TemporaryDirectory() as tmp_dir: - test_file = Path(tmp_dir) / "layout.xml" - test_file.write_text('\ufeff\n\n') - - assert update_file(test_file, None, "", "Ultralytics 🚀 Test Header") is True - assert test_file.read_text().startswith( - '\ufeff\n\n\n' - ) - - -def test_update_file_with_shebang_and_encoding_cookie(): - """Test that a Python encoding cookie remains on line two and the header stays idempotent.""" - with TemporaryDirectory() as tmp_dir: - test_file = Path(tmp_dir) / "script.py" - test_file.write_text( - "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# Ultralytics 🚀 AGPL-3.0 License\n\nprint('hello')\n" - ) - - assert update_file(test_file, "# ", None, None, "Ultralytics 🚀 Test Header") is True - assert test_file.read_text().startswith( - "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n# Ultralytics 🚀 Test Header\n\n" - ) - assert update_file(test_file, "# ", None, None, "Ultralytics 🚀 Test Header") is False - - -def test_update_file_replaces_legacy_private_header(): - """Test that the previously emitted private header is replaced rather than duplicated.""" - with TemporaryDirectory() as tmp_dir: - test_file = Path(tmp_dir) / "app.py" - test_file.write_text( - "# Ultralytics Inc. 🚀 Copyright © 2014-2025 - CONFIDENTIAL - " - "https://ultralytics.com - All Rights Reserved\n\n" - "print('hello')\n" - ) - - assert update_file(test_file, "# ", None, None, "© 2014-2026 Ultralytics Inc. CONFIDENTIAL") is True - assert test_file.read_text().startswith("# © 2014-2026 Ultralytics Inc. CONFIDENTIAL\n\n") - assert "Copyright" not in test_file.read_text() - - -def test_update_file_no_changes(): - """Test updating file with no changes needed.""" - with TemporaryDirectory() as tmp_dir: - # Create a test file with correct header - test_file = Path(tmp_dir) / "test.py" - test_file.write_text("# Ultralytics 🚀 Test Header\n\nprint('Hello World')\n") - - # Update file - result = update_file(test_file, "# ", None, None, "Ultralytics 🚀 Test Header") - - # Check results - assert result is False # No changes made - - -def test_update_file_edge_cases(): - """Test header handling for empty, unreadable, and block-comment files.""" - with TemporaryDirectory() as tmp_dir: - tmp_path = Path(tmp_dir) - empty_file = tmp_path / "empty.py" - empty_file.write_text("") - assert update_file(empty_file, "# ", None, None, "Ultralytics 🚀 Test Header") is False - assert update_file(tmp_path, "# ", None, None, "Ultralytics 🚀 Test Header") is False - - css_file = tmp_path / "style.css" - css_file.write_text("body { color: black; }\n") - assert update_file(css_file, None, "/* ", " */", "Ultralytics 🚀 Test Header") is True - assert css_file.read_text().startswith("/* Ultralytics 🚀 Test Header */\n\n") - - -def test_comment_map_coverage(): - """Test that all supported file extensions have defined comment styles.""" - # Check for a few key extensions - assert ".py" in COMMENT_MAP - assert ".cpp" in COMMENT_MAP - assert ".js" in COMMENT_MAP - assert ".html" in COMMENT_MAP - - # Check comment style format - for ext, (prefix, block_start, block_end) in COMMENT_MAP.items(): - assert isinstance(ext, str) - assert prefix is None or isinstance(prefix, str) - assert block_start is None or isinstance(block_start, str) - assert block_end is None or isinstance(block_end, str) - - -def test_ignore_paths(): - """Test that the ignore paths list exists and contains expected entries.""" - assert isinstance(IGNORE_PATHS, set) - assert ".git" in IGNORE_PATHS - assert "__pycache__" in IGNORE_PATHS - - -def test_main_real_files(): - """Test main function on actual repository files.""" - with patch("actions.update_file_headers.update_file", return_value=False) as mock_update, patch( - "actions.update_file_headers.Action" - ) as mock_action: - mock_action.return_value.repository = "ultralytics/actions" - mock_action.return_value.is_repo_private.return_value = False - main() - assert mock_update.call_count > 0 - - -def test_main_with_custom_header(): - """Test main function with custom header environment variable.""" - with patch("actions.update_file_headers.update_file", return_value=False), patch( - "actions.update_file_headers.HEADER", "Custom Test Header" - ), patch("actions.update_file_headers.Action") as mock_action: - mock_event = mock_action.return_value - mock_event.repository = "test/repo" - main() - mock_action.assert_called_once() - - -def test_main_private_and_skipped_repos(): - """Test main selects private headers and skips repos without a header source.""" - with TemporaryDirectory() as tmp_dir: - tmp_path = Path(tmp_dir) - (tmp_path / "app.py").write_text("print('hello')\n") - - with patch("actions.update_file_headers.Path.cwd", return_value=tmp_path), patch( - "actions.update_file_headers.update_file", return_value=False - ) as mock_update, patch("actions.update_file_headers.Action") as mock_action: - mock_event = mock_action.return_value - mock_event.repository = "ultralytics/private" - mock_event.is_repo_private.return_value = True - main() - assert any("CONFIDENTIAL" in call.args[4] for call in mock_update.call_args_list) - - with patch("actions.update_file_headers.update_file", return_value=False) as mock_update, patch( - "actions.update_file_headers.HEADER", None - ), patch("actions.update_file_headers.Action") as mock_action: - mock_action.return_value.repository = "other/repo" - main() - mock_action.return_value.is_repo_private.assert_not_called() - mock_update.assert_not_called() - - -def test_main_updates_files_in_current_directory(): - """Test main updates supported files under the current directory.""" - with TemporaryDirectory() as tmp_dir: - tmp_path = Path(tmp_dir) - test_file = tmp_path / "app.py" - test_file.write_text("print('hello')\n") - - with patch("actions.update_file_headers.Path.cwd", return_value=tmp_path), patch( - "actions.update_file_headers.Action" - ) as mock_action: - mock_event = mock_action.return_value - mock_event.repository = "ultralytics/actions" - mock_event.is_repo_private.return_value = False - main() - - assert test_file.read_text().startswith("# Ultralytics 🚀 AGPL-3.0 License")