You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by sb...@apache.org on 2026/05/06 15:40:19 UTC

(tooling-trusted-releases) branch sbp updated: Allow https URLs in Apache License 2.0 text, per ASF policy

This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch sbp
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git


The following commit(s) were added to refs/heads/sbp by this push:
     new ef9c4393 Allow https URLs in Apache License 2.0 text, per ASF policy
ef9c4393 is described below

commit ef9c4393c3d90461cfe6ffa93816a73e25bd39f0
Author: Sean B. Palmer <se...@miscoranda.com>
AuthorDate: Wed May 6 16:39:36 2026 +0100

    Allow https URLs in Apache License 2.0 text, per ASF policy
---
 atr/docs/checks.md                |  2 +-
 atr/tasks/checks/license.py       | 14 +++++++++++---
 tests/unit/test_checks_license.py | 13 +++++++++++++
 3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/atr/docs/checks.md b/atr/docs/checks.md
index ce9e9510..3f7521c2 100644
--- a/atr/docs/checks.md
+++ b/atr/docs/checks.md
@@ -76,7 +76,7 @@ The checker key for tar based structure checks is `atr.tasks.checks.targz.struct
 
 ### License files in archives
 
-ATR checks for `LICENSE` and `NOTICE` files at the top level of the root directory each archive. It requires exactly one of each. The `LICENSE` content must match the Apache License text with only whitespace differences. The `NOTICE` file must be valid UTF-8 text and must include a product line, an ASF copyright statement, and the standard ASF attribution line. For podling projects ATR also requires a `DISCLAIMER` or `DISCLAIMER-WIP` file at the same level. These lightweight license chec [...]
+ATR checks for `LICENSE` and `NOTICE` files at the top level of the root directory each archive. It requires exactly one of each. The `LICENSE` content must match the Apache License text with only whitespace differences, though `https` may be used in place of `http` for Apache license URLs. The `NOTICE` file must be valid UTF-8 text and must include a product line, an ASF copyright statement, and the standard ASF attribution line. For podling projects ATR also requires a `DISCLAIMER` or  [...]
 
 The checker key is `atr.tasks.checks.license.files`.
 
diff --git a/atr/tasks/checks/license.py b/atr/tasks/checks/license.py
index 71d6020c..5309546b 100644
--- a/atr/tasks/checks/license.py
+++ b/atr/tasks/checks/license.py
@@ -82,12 +82,16 @@ INCLUDED_PATTERNS: Final[list[str]] = [
 # Release policy fields which this check relies on - used for result caching
 INPUT_POLICY_KEYS: Final[list[str]] = ["license_check_mode", "source_excludes_lightweight"]
 INPUT_EXTRA_ARGS: Final[list[str]] = ["is_podling"]
-CHECK_VERSION_FILES: Final[str] = "4"
+CHECK_VERSION_FILES: Final[str] = "5"
 CHECK_VERSION_HEADERS: Final[str] = "3"
 
 _BINARY_LICENSE_FILENAMES: Final[frozenset[str]] = frozenset({"LICENSE", "LICENSE.txt"})
 _BINARY_NOTICE_FILENAMES: Final[frozenset[str]] = frozenset({"NOTICE", "NOTICE.txt"})
 _MAX_LICENSE_NOTICE_SIZE: Final[int] = 1024 * 1024
+_APACHE_LICENSE_URLS: Final[dict[str, str]] = {
+    "https://www.apache.org/licenses/": "http://www.apache.org/licenses/",
+    "https://www.apache.org/licenses/LICENSE-2.0": "http://www.apache.org/licenses/LICENSE-2.0",
+}
 
 # Types
 
@@ -359,8 +363,8 @@ def _files_check_core_logic_license(file_path: pathlib.Path) -> str | None:
     expected_lines = constants.APACHE_LICENSE_2_0.splitlines()
     actual_lines = package_license.splitlines()
 
-    expected_lines = _normal_whitespace(expected_lines)
-    actual_lines = _normal_whitespace(actual_lines)
+    expected_lines = _normal_license_lines(expected_lines)
+    actual_lines = _normal_license_lines(actual_lines)
     # Allow extra lines at the bottom of the license
     # This could invalidate the license, but we cannot check that automatically
     # if len(actual_lines) > len(expected_lines):
@@ -648,6 +652,10 @@ def _license_results(
             )
 
 
+def _normal_license_lines(lines: list[str]) -> list[str]:
+    return [_APACHE_LICENSE_URLS.get(line, line) for line in _normal_whitespace(lines)]
+
+
 def _normal_whitespace(lines: list[str]) -> list[str]:
     result = []
     for line in lines:
diff --git a/tests/unit/test_checks_license.py b/tests/unit/test_checks_license.py
index 8a524113..94671d09 100644
--- a/tests/unit/test_checks_license.py
+++ b/tests/unit/test_checks_license.py
@@ -95,6 +95,19 @@ def test_files_binary_multiple_license_no_failure(tmp_path):
     assert all(r.status == sql.CheckResultStatus.SUCCESS for r in artifact_results)
 
 
+def test_files_license_accepts_https_urls(tmp_path):
+    cache_dir = _cache_with_root(tmp_path)
+    root = cache_dir / "apache-test-0.2"
+    license_text = constants.APACHE_LICENSE_2_0.replace(
+        "http://www.apache.org/licenses/", "https://www.apache.org/licenses/"
+    )
+    (root / "LICENSE").path.write_text(license_text)
+    (root / "NOTICE").path.write_text(NOTICE_VALID)
+    results = list(license._files_check_core_logic(cache_dir, is_podling=False, is_binary=False))
+    artifact_results = [r for r in results if isinstance(r, license.ArtifactResult)]
+    assert all(r.status == sql.CheckResultStatus.SUCCESS for r in artifact_results)
+
+
 def test_files_missing_cache_dir():
     results = list(
         license._files_check_core_logic(safe.StatePath(pathlib.Path("/nonexistent")), is_podling=False, is_binary=False)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org