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 2025/08/01 14:53:10 UTC
(tooling-trusted-release) branch main updated: Add an overall check result for license header member checks
This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git
The following commit(s) were added to refs/heads/main by this push:
new 1765244 Add an overall check result for license header member checks
1765244 is described below
commit 1765244b6dc06758d0f09943fd403217e7021f9c
Author: Sean B. Palmer <se...@miscoranda.com>
AuthorDate: Fri Aug 1 15:52:41 2025 +0100
Add an overall check result for license header member checks
---
atr/tasks/checks/__init__.py | 5 +++++
atr/tasks/checks/license.py | 46 +++++++++++++++++++++++++++-----------------
atr/tasks/checks/paths.py | 22 ++++++++++++++++++++-
3 files changed, 54 insertions(+), 19 deletions(-)
diff --git a/atr/tasks/checks/__init__.py b/atr/tasks/checks/__init__.py
index c8a7a45..574c9ab 100644
--- a/atr/tasks/checks/__init__.py
+++ b/atr/tasks/checks/__init__.py
@@ -75,6 +75,7 @@ class Recorder:
self.member_rel_path = member_rel_path
self.afresh = afresh
self.constructed = False
+ self.member_problems: dict[sql.CheckResultStatus, int] = {}
self.project_name = project_name
self.version_name = version_name
@@ -114,6 +115,10 @@ class Recorder:
# # Clear inner path only if it's specified
# await self.clear(primary_rel_path=primary_rel_path, member_rel_path=member_rel_path)
+ if member_rel_path is not None:
+ if status != sql.CheckResultStatus.SUCCESS:
+ self.member_problems[status] = self.member_problems.get(status, 0) + 1
+
result = sql.CheckResult(
release_name=self.release_name,
revision_number=self.revision_number,
diff --git a/atr/tasks/checks/license.py b/atr/tasks/checks/license.py
index 47689bb..911aea1 100644
--- a/atr/tasks/checks/license.py
+++ b/atr/tasks/checks/license.py
@@ -170,20 +170,7 @@ async def headers(args: checks.FunctionArguments) -> results.Results | None:
if ignore_file.exists():
ignore_lines = ignore_file.read_text().splitlines()
- try:
- for result in await asyncio.to_thread(_headers_check_core_logic, str(artifact_abs_path), ignore_lines):
- match result:
- case ArtifactResult():
- await _record_artifact(recorder, result)
- case MemberResult():
- await _record_member(recorder, result)
- case MemberSkippedResult():
- pass
-
- except Exception as e:
- await recorder.exception("Error during license header check execution", {"error": str(e)})
-
- return None
+ return await _headers_core(recorder, str(artifact_abs_path), ignore_lines)
def headers_validate(content: bytes, _filename: str) -> tuple[bool, str | None]:
@@ -238,8 +225,8 @@ def _files_check_core_logic(artifact_path: str, is_podling: bool) -> Iterator[Re
elif filename in {"DISCLAIMER", "DISCLAIMER-WIP"}:
disclaimer_found = True
- yield from __license_results(license_results)
- yield from __notice_results(notice_results)
+ yield from _license_results(license_results)
+ yield from _notice_results(notice_results)
if is_podling and (not disclaimer_found):
yield ArtifactResult(
status=sql.CheckResultStatus.FAILURE,
@@ -302,7 +289,7 @@ def _files_check_core_logic_notice(archive: tarzip.Archive, member: tarzip.Membe
return len(issues) == 0, issues, preamble
-def __license_results(
+def _license_results(
license_results: dict[str, str | None],
) -> Iterator[Result]:
"""Build status messages for license file verification."""
@@ -339,7 +326,7 @@ def __license_results(
)
-def __notice_results(
+def _notice_results(
notice_results: dict[str, tuple[bool, list[str], str]],
) -> Iterator[Result]:
"""Build status messages for notice file verification."""
@@ -517,6 +504,29 @@ def _headers_check_core_logic_should_check(filepath: str) -> bool:
return False
+async def _headers_core(recorder: checks.Recorder, artifact_abs_path: str, ignore_lines: list[str]) -> None:
+ try:
+ for result in await asyncio.to_thread(_headers_check_core_logic, str(artifact_abs_path), ignore_lines):
+ match result:
+ case ArtifactResult():
+ await _record_artifact(recorder, result)
+ case MemberResult():
+ await _record_member(recorder, result)
+ case MemberSkippedResult():
+ pass
+ member_failures = recorder.member_problems.get(sql.CheckResultStatus.FAILURE, 0)
+ if member_failures > 0:
+ await recorder.failure(
+ f"Some files had invalid license headers ({member_failures} failures)",
+ None,
+ )
+
+ except Exception as e:
+ await recorder.exception("Error during license header check execution", {"error": str(e)})
+
+ return None
+
+
async def _record_artifact(recorder: checks.Recorder, result: ArtifactResult) -> None:
match result.status:
case sql.CheckResultStatus.SUCCESS:
diff --git a/atr/tasks/checks/paths.py b/atr/tasks/checks/paths.py
index f202d52..76b7fcf 100644
--- a/atr/tasks/checks/paths.py
+++ b/atr/tasks/checks/paths.py
@@ -186,7 +186,9 @@ async def _check_path_process_single(
# We should enquire as to whether such a policy should be instituted
# We're forbidding dotfiles to catch accidental uploads of e.g. .git or .htaccess
# Such cases are likely to be in error, and could carry security risks
- errors.append("Dotfiles are forbidden")
+ # We allow .atr/ files, e.g. .atr/license-headers-ignore
+ if relative_path.parts[0] != ".atr":
+ errors.append("Dotfiles are forbidden")
search = re.search(analysis.extension_pattern(), relative_path_str)
ext_artifact = search.group("artifact") if search else None
@@ -204,6 +206,24 @@ async def _check_path_process_single(
if (relative_path.parent == pathlib.Path(".")) and (relative_path.name not in allowed_top_level):
warnings.append(f"Unknown top level file: {relative_path.name}")
+ await _record(
+ recorder_errors,
+ recorder_warnings,
+ recorder_success,
+ relative_path_str,
+ errors,
+ warnings,
+ )
+
+
+async def _record(
+ recorder_errors: checks.Recorder,
+ recorder_warnings: checks.Recorder,
+ recorder_success: checks.Recorder,
+ relative_path_str: str,
+ errors: list[str],
+ warnings: list[str],
+) -> None:
for error in errors:
await recorder_errors.failure(error, {}, primary_rel_path=relative_path_str)
for warning in warnings:
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org