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

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new c79293ea4b9 Wait for a maintainer when a fork PR changes any 
CI-defining file (#75718)
c79293ea4b9 is described below

commit c79293ea4b998370e034284c159931e4edc40bdf
Author: Shahar Epstein <[email protected]>
AuthorDate: Tue Oct 27 10:50:35 2026 +0200

    Wait for a maintainer when a fork PR changes any CI-defining file (#75718)
    
    The project-CI rule of the workflow run auto-approval checked a shorter
    list of CI-defining paths than the fork CI reconciler. A PR changing a
    .pre-commit-config.yaml, which decides the static checks CI runs, had its
    runs approved without a maintainer's look. Changes to Dockerfile*,
    scripts/docker/ and scripts/in_container/ were held back only because
    selective checks currently run the full set of tests for them. Both
    rules now read the reconciler's list, so a path added there applies to
    both.
---
 contributing-docs/05_pull_requests.rst                  | 10 ++++++----
 dev/breeze/doc/ci/05_workflows.md                       | 14 +++++++-------
 .../src/airflow_breeze/utils/workflow_run_approval.py   | 14 ++++----------
 dev/breeze/tests/test_workflow_run_approval.py          | 17 +++++++++++++++++
 4 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/contributing-docs/05_pull_requests.rst 
b/contributing-docs/05_pull_requests.rst
index 56b0ea7825f..f3e32816dd7 100644
--- a/contributing-docs/05_pull_requests.rst
+++ b/contributing-docs/05_pull_requests.rst
@@ -252,8 +252,10 @@ and approves them automatically when all of these hold:
 
 * The PR targets ``main``. PRs to release branches, such as ``v3-4-test``, 
always wait for a
   maintainer.
-* The PR does not change anything under ``.github/``, ``dev/breeze/`` or 
``scripts/ci/``. Those
-  files define the CI workflows and choose the runners they use.
+* The PR does not change files that define CI: anything under ``.github/``, 
``dev/breeze/``,
+  ``scripts/ci/``, ``scripts/docker/`` or ``scripts/in_container/``, a 
top-level ``Dockerfile*``,
+  or a ``.pre-commit-config.yaml`` in any directory. Those files define the CI 
workflows, what
+  their jobs run and the runners they use.
 * The change does not need the full set of tests, does not change dependencies 
(``pyproject.toml``,
   lock files, ``package.json``, ``go.mod``, Gradle build files) and does not 
add a new provider.
 * The CI jobs your change selects are estimated to take at most 310 
job-minutes, about a quarter of
@@ -269,8 +271,8 @@ and approves them automatically when all of these hold:
 If your PR's CI runs in your fork (it carries the ``fork ci required`` label), 
the CI run in
 ``apache/airflow`` only checks that, so none of the rules above apply. Its 
runs are approved
 automatically unless the PR changes files that define CI: anything under 
``.github/``,
-``dev/breeze/``, ``scripts/ci/``, ``scripts/docker/`` or 
``scripts/in_container/``, a ``Dockerfile``
-or ``.pre-commit-config.yaml``. Then the runs wait for a maintainer and a 
comment on the PR explains
+``dev/breeze/``, ``scripts/ci/``, ``scripts/docker/`` or 
``scripts/in_container/``, a top-level
+``Dockerfile*``, or a ``.pre-commit-config.yaml`` in any directory. Then the 
runs wait for a maintainer and a comment on the PR explains
 why. CI in your fork runs either way.
 
 The runs of PRs opened from the repositories of trusted stakeholders 
(``astronomer/airflow``,
diff --git a/dev/breeze/doc/ci/05_workflows.md 
b/dev/breeze/doc/ci/05_workflows.md
index 4c323ab1bf3..a98d3a15861 100644
--- a/dev/breeze/doc/ci/05_workflows.md
+++ b/dev/breeze/doc/ci/05_workflows.md
@@ -107,8 +107,10 @@ them, for the contributors the repository's approval 
setting covers. The
 
 - the PR targets `main`; PRs to release branches (`v3-4-test`, 
`airflow-ctl/v0-1-test`, ...) run those
   branches' own workflows and always wait for a maintainer
-- the PR changes nothing under `.github/`, `dev/breeze/` or `scripts/ci/`, 
which define the workflows
-  and choose the runners
+- the PR changes no file the fork CI reconciler counts as CI-defining 
(`.github/`, `dev/breeze/`,
+  `scripts/ci/`, `scripts/docker/`, `scripts/in_container/`, a top-level 
`Dockerfile*`, a
+  `.pre-commit-config.yaml` in any directory),
+  which define the workflows, what their jobs run and the runners they use
 - the PR changes no dependency manifest or lock file (`pyproject.toml`, 
`uv.lock`, `package.json`,
   `pnpm-lock.yaml`, `go.mod`, Gradle build files, ...) and adds no new 
provider (selective checks
   run from `main`'s tree and do not know it)
@@ -121,11 +123,9 @@ them, for the contributors the repository's approval 
setting covers. The
 
 A PR to `main` whose CI runs in the contributor's fork (AIP-120: the `Fork CI 
gate` job would skip
 project CI for it) is decided by one rule instead, because its `Tests (AMD)` 
run only executes the
-gate: its runs are approved whatever its size, cost or dependency changes, 
unless it changes a file
-the fork CI reconciler counts as CI-defining (`.github/`, `dev/breeze/`, 
`scripts/ci/`,
-`scripts/docker/`, `scripts/in_container/`, `Dockerfile*`, 
`.pre-commit-config.yaml`). Such a PR gets
-the `need workflow approval` label and one comment telling the author that the 
CI change needs a
-maintainer; see
+gate: its runs are approved whatever its size, cost or dependency changes, 
unless it changes one of
+those CI-defining files. Such a PR gets the `need workflow approval` label and 
one comment telling
+the author that the CI change needs a maintainer; see
 [Approving gated 
runs](08_fork_ci_for_external_contributors.md#approving-gated-runs).
 
 The runs of PRs whose head repository belongs to a trusted stakeholder 
(`astronomer/airflow` for
diff --git a/dev/breeze/src/airflow_breeze/utils/workflow_run_approval.py 
b/dev/breeze/src/airflow_breeze/utils/workflow_run_approval.py
index f11760bb495..107fee1e4d8 100644
--- a/dev/breeze/src/airflow_breeze/utils/workflow_run_approval.py
+++ b/dev/breeze/src/airflow_breeze/utils/workflow_run_approval.py
@@ -81,11 +81,6 @@ AUTO_APPROVABLE_BASE_BRANCH = "main"
 
 MAX_ERROR_TEXT_LENGTH = 200
 
-# Changes here can change which runner a job uses (``runs-on:``, 
``runner-type`` computed by
-# selective checks, the scripts build-info runs) or what the workflows do, so 
they always need a
-# maintainer's look.
-CI_DEFINITION_PATH_PREFIXES = (".github/", "dev/breeze/", "scripts/ci/")
-
 # Dependency manifests and lock files. Selective checks only switch to 
dependency-upgrade mode for
 # pyproject.toml, but a changed lock file or JS / Go / Java manifest also 
changes what CI installs.
 DEPENDENCY_FILE_PATTERN = re.compile(
@@ -170,10 +165,6 @@ def count_source_lines(changed_files: list[ChangedFile]) 
-> int:
     return sum(file.changed_lines for file in changed_files if not 
NON_SOURCE_FILE_PATTERN.search(file.path))
 
 
-def find_ci_definition_files(files: list[str]) -> list[str]:
-    return [file for file in files if 
file.startswith(CI_DEFINITION_PATH_PREFIXES)]
-
-
 def find_dependency_files(files: list[str]) -> list[str]:
     return [file for file in files if DEPENDENCY_FILE_PATTERN.search(file)]
 
@@ -276,7 +267,10 @@ def decide_approval(
             estimate=estimate,
         )
     paths = [file.path for file in changed_files]
-    ci_files = find_ci_definition_files(paths)
+    # CI definition files can change which runner a job uses (``runs-on:``, 
``runner-type``
+    # computed by selective checks, the scripts build-info runs) or what the 
jobs run, so they
+    # always need a maintainer's look.
+    ci_files = find_fork_ci_definition_files(paths)
     if ci_files:
         return ApprovalDecision(
             approve=False,
diff --git a/dev/breeze/tests/test_workflow_run_approval.py 
b/dev/breeze/tests/test_workflow_run_approval.py
index 39e07a02123..d82a5aabe93 100644
--- a/dev/breeze/tests/test_workflow_run_approval.py
+++ b/dev/breeze/tests/test_workflow_run_approval.py
@@ -133,6 +133,23 @@ def mock_estimate():
             "CI definition files",
             id="selective-checks-change",
         ),
+        *(
+            pytest.param(
+                [ChangedFile(path, 1)],
+                _selective_checks(),
+                100,
+                False,
+                f"CI definition files: {path}",
+                id=f"fork-ci-defining-{path}",
+            )
+            for path in (
+                ".pre-commit-config.yaml",
+                "airflow-core/.pre-commit-config.yaml",
+                "Dockerfile.ci",
+                "scripts/docker/entrypoint_ci.sh",
+                "scripts/in_container/run_ci_tests.sh",
+            )
+        ),
         pytest.param(
             CORE_CHANGE,
             _selective_checks(full_tests_needed=True),

Reply via email to