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),