hugovk commented on code in PR #62682:
URL: https://github.com/apache/airflow/pull/62682#discussion_r2872249145
##########
dev/breeze/src/airflow_breeze/utils/github.py:
##########
@@ -355,3 +356,205 @@ def download_artifact_from_pr(pr: str, output_file: Path,
github_repository: str
get_console().print(f"[info]Found run id {run_id} for PR {pr}")
download_artifact_from_run_id(str(run_id), output_file, github_repository,
github_token)
+
+
+_CONTRIBUTING_DOCS_URL =
"https://github.com/apache/airflow/blob/main/contributing-docs"
+_STATIC_CHECKS_URL = f"{_CONTRIBUTING_DOCS_URL}/08_static_code_checks.rst"
+_TESTING_URL = f"{_CONTRIBUTING_DOCS_URL}/09_testing.rst"
+
+# Patterns to categorize failing CI check names
+_CHECK_CATEGORIES: list[tuple[str, list[str], str, str]] = [
+ # (category, name_patterns, fix_instructions, doc_url)
+ (
+ "Pre-commit / static checks",
+ ["static checks", "pre-commit", "prek"],
+ "Run `prek run --ref-from main` locally to find and fix issues.",
+ _STATIC_CHECKS_URL,
+ ),
+ (
+ "Ruff (linting / formatting)",
+ ["ruff"],
+ "Run `prek run ruff --ref-from main` and `prek run ruff-format
--ref-from main` to fix.",
+ f"{_STATIC_CHECKS_URL}#using-prek",
+ ),
+ (
+ "mypy (type checking)",
+ ["mypy"],
+ "Run `prek run mypy --ref-from main --hook-stage pre-push` locally. "
+ "You need `breeze ci-image build --python 3.10` for Docker-based
mypy.",
+ f"{_STATIC_CHECKS_URL}#mypy-checks",
+ ),
+ (
+ "Unit tests",
+ ["unit test", "test-"],
+ "Run failing tests with `breeze run pytest <path> -xvs`.",
+ _TESTING_URL,
+ ),
+ (
+ "Build docs",
+ ["docs", "spellcheck-docs", "build-docs"],
+ "Run `breeze build-docs` locally to reproduce.",
+ f"{_CONTRIBUTING_DOCS_URL}/16_documentation.rst",
+ ),
+ (
+ "Helm tests",
+ ["helm"],
+ "Run Helm tests with `breeze k8s run-complete-tests`.",
+ _TESTING_URL,
+ ),
+ (
+ "Kubernetes tests",
+ ["k8s", "kubernetes"],
+ "See the K8s testing documentation.",
+ _TESTING_URL,
+ ),
+ (
+ "Image build",
+ ["build ci image", "build prod image", "ci-image", "prod-image"],
+ "Check that Dockerfiles and dependencies are correct.",
+ f"{_CONTRIBUTING_DOCS_URL}/03a_contributors_quick_start_beginners.rst",
+ ),
+ (
+ "Provider tests",
+ ["provider"],
+ "Run provider tests with `breeze run pytest <provider-test-path>
-xvs`.",
+ f"{_CONTRIBUTING_DOCS_URL}/12_provider_distributions.rst",
+ ),
+]
+
+
+@dataclass
+class Violation:
+ category: str
+ explanation: str # short description of the problem (shown in terminal)
+ severity: str # "error" or "warning"
+ details: str = "" # fix suggestions and doc links (included only in
GitHub comment)
+
+
+@dataclass
+class PRAssessment:
+ should_flag: bool
+ violations: list[Violation] = field(default_factory=list)
+ summary: str = ""
+ error: bool = False
+
+
+def _categorize_check(check_name: str) -> tuple[str, str, str] | None:
+ """Match a failing check name to a category. Returns (category, fix,
doc_url) or None."""
+ lower = check_name.lower()
+ for category, patterns, fix, url in _CHECK_CATEGORIES:
+ if any(p in lower for p in patterns):
+ return category, fix, url
+ return None
+
+
+def assess_pr_checks(pr_number: int, checks_state: str, failed_checks:
list[str]) -> PRAssessment | None:
+ """Deterministically flag a PR if CI checks are failing. Returns None if
checks pass.
+
+ Uses the statusCheckRollup.state as the authoritative signal.
+ failed_checks is a best-effort list of individual failing check names.
+ """
+ if checks_state != "FAILURE":
+ return None
+
+ violations: list[Violation] = []
+
+ if failed_checks:
+ # Group failing checks by category
+ categorized: dict[str, tuple[list[str], str, str]] = {}
+ uncategorized: list[str] = []
+
+ for check in failed_checks:
+ match = _categorize_check(check)
+ if match:
+ category, fix, url = match
+ if category not in categorized:
+ categorized[category] = ([], fix, url)
+ categorized[category][0].append(check)
+ else:
+ uncategorized.append(check)
+
+ for category, (checks, fix, url) in categorized.items():
+ checks_list = ", ".join(checks[:5])
+ if len(checks) > 5:
+ checks_list += f" (+{len(checks) - 5} more)"
+ violations.append(
+ Violation(
+ category=category,
+ explanation=f"Failing: {checks_list}.",
+ severity="error",
+ details=f"{fix} See [{category} docs]({url}).",
+ )
+ )
+
+ if uncategorized:
+ checks_list = ", ".join(uncategorized[:5])
+ if len(uncategorized) > 5:
+ checks_list += f" (+{len(uncategorized) - 5} more)"
+ violations.append(
+ Violation(
+ category="Other failing CI checks",
+ explanation=f"Failing: {checks_list}.",
+ severity="error",
+ details=(
+ f"Run `prek run --ref-from main` locally to reproduce.
"
+ f"See [static checks docs]({_STATIC_CHECKS_URL})."
+ ),
+ )
+ )
+
+ summary = f"PR #{pr_number} has {len(failed_checks)} failing CI
check(s)."
Review Comment:
```suggestion
s = "" if len(failed_checks) == 1 else "s"
summary = f"PR #{pr_number} has {len(failed_checks)} failing CI
check{s}"
```
And I'll leave the seven in `pr_commands.py` for the LLM to fix :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]