This is an automated email from the ASF dual-hosted git repository.
shahar1 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 8bdb287f7ee Build no images on the airflow-ctl release branches
(#75628)
8bdb287f7ee is described below
commit 8bdb287f7ee587a5ca6d642e59979bf4576c4a3e
Author: Jarek Potiuk <[email protected]>
AuthorDate: Mon Oct 26 04:48:35 2026 +0100
Build no images on the airflow-ctl release branches (#75628)
Backports to the airflow-ctl release branches only change airflow-ctl,
whose tests run in a local
virtualenv. Building the CI and PROD images there only served the
integration tests and the docs, and
made every small backport wait for the image builds.
Generated-by: Claude Opus 5
---
dev/breeze/doc/ci/04_selective_checks.md | 16 ++++++++-------
.../src/airflow_breeze/utils/selective_checks.py | 21 +++++++++++--------
dev/breeze/tests/test_selective_checks.py | 24 +++++++++++++++-------
...un_mypy_full_dist_local_venv_or_breeze_in_ci.py | 4 +++-
4 files changed, 42 insertions(+), 23 deletions(-)
diff --git a/dev/breeze/doc/ci/04_selective_checks.md
b/dev/breeze/doc/ci/04_selective_checks.md
index eaba2db9f35..4d0af1a220c 100644
--- a/dev/breeze/doc/ci/04_selective_checks.md
+++ b/dev/breeze/doc/ci/04_selective_checks.md
@@ -228,11 +228,13 @@ match one of those names: a feature branch named
`chart/...` is not a component
any push in a fork, which is selected against `main`. On such a branch every
output decorated with `_scoped_to_component_branch` is off, except those
`COMPONENT_BRANCH_OUTPUTS` lists
for the component: on `chart/`, Helm and Kubernetes tests always run
(kustomize overlays as usual) with
-the CI and PROD images they need; on `airflow-ctl/`, the airflow-ctl tests and
its integration tests run,
-with both images. The PROD image is built for those tests only, so
`run-generic-prod-image-tests` (Docker
+the CI and PROD images they need; on `airflow-ctl/`, only the airflow-ctl
tests run, in a local
+virtualenv, so no image is built there: static checks run on the host
(`basic-checks-only`), and the
+airflow-ctl integration tests, the docs and the dependency upgrade check,
which need an image, do not run. The PROD image is built for
+the chart's tests only, so `run-generic-prod-image-tests` (Docker
Compose, image-building examples, basic and canary end-to-end tests) is off,
and so is
-`run-generic-basic-tests` (the standalone Airflow and shared distributions
tests). Provider tests are skipped, and docs, when they changed, build only the
component's
-package. Static checks, scripts and Breeze integration tests, and the CodeQL
scans run as usual. A test
+`run-generic-basic-tests` (the standalone Airflow and shared distributions
tests). Provider tests are skipped, and on `chart/` docs, when they changed,
build only the
+chart's package. Static checks, scripts and Breeze integration tests, and the
CodeQL scans run as usual. A test
in `test_selective_checks.py` fails when a new `run_*` output is neither
scoped nor listed as a general
check, so a new job does not start running on these branches by accident.
@@ -503,8 +505,8 @@ together using `pytest-xdist` (pytest-xdist distributes the
tests among parallel
are enabled if any of the relevant files have been changed.
* `Helm` tests are run only if relevant files have been changed and if current
branch is `main`.
* On a component's release branch (`chart/...`, `airflow-ctl/...`) only that
component's tests run, always,
- with the images they need; other tests do not run, provider tests are
skipped, and docs build only the
- component's package. Static checks still run. See [Stage
2](#stage-2--decide-which-jobs-run).
+ with the images they need (none for airflow-ctl); other tests do not run,
provider tests are skipped,
+ and docs build only the chart's package. Static checks still run. See [Stage
2](#stage-2--decide-which-jobs-run).
* If no Source files are changed - no tests are run and no further rules below
are checked.
* `CI Image building` is enabled if either test are run, docs are build.
* `PROD Image building` is enabled when kubernetes tests are run.
@@ -719,7 +721,7 @@ GitHub Actions to pass the list of parameters to a command
to execute
| sqlite-exclude | Which versions of
Sqlite to exclude for tests as JSON array
| [] | |
| testable-core-integrations | List of core
integrations that are testable in the build as JSON array
| \['celery', 'kerberos'\] | |
| testable-providers-integrations | List of core
integrations that are testable in the build as JSON array
| \['mongo', 'kafka'\] | |
-| upgrade-to-newer-dependencies | Whether the image
build should attempt to upgrade all dependencies (true/false or commit hash)
| false | |
+| upgrade-to-newer-dependencies | Whether the image
build should attempt to upgrade all dependencies (true/false or commit hash);
false when no CI image is built | false |
|
## Self-hosted (RunsOn) vs. public runners
diff --git a/dev/breeze/src/airflow_breeze/utils/selective_checks.py
b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
index 39913be221a..f814662bd50 100644
--- a/dev/breeze/src/airflow_breeze/utils/selective_checks.py
+++ b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
@@ -902,8 +902,9 @@ def _get_test_list_as_json(list_of_list_of_types:
list[list[str]]) -> list[dict[
# The release branches of a single component (the Helm chart, airflow-ctl)
only ever get backports of that
# component, so CI there runs that component's tests, whatever changed, and
nothing else. Per branch prefix,
# the outputs decorated with `_scoped_to_component_branch` that run: True
forces one on, None leaves it to
-# its usual computation, and an output missing from the table is off. Static
checks and docs still run.
-# The PROD image is built for those tests alone:
`run_generic_prod_image_tests` stays off.
+# its usual computation, and an output missing from the table is off. Static
checks still run, and docs
+# too where the CI image is built. The PROD image is built for those tests
alone:
+# `run_generic_prod_image_tests` stays off.
COMPONENT_BRANCH_OUTPUTS: dict[str, dict[str, bool | None]] = {
"chart": {
"run_helm_tests": True,
@@ -913,16 +914,15 @@ COMPONENT_BRANCH_OUTPUTS: dict[str, dict[str, bool |
None]] = {
"ci_image_build": True,
"prod_image_build": True,
},
+ # The airflow-ctl tests run in a local virtualenv, so no image is built:
static checks run on the host
+ # and the integration tests, which need the PROD image, do not run.
"airflow-ctl": {
"run_airflow_ctl_tests": True,
- "run_airflow_ctl_integration_tests": True,
- # The airflow-ctl integration tests run against the PROD image, built
from the CI image.
- "ci_image_build": True,
- "prod_image_build": True,
},
}
-# The documentation built on a component's branch, when documentation changed.
-COMPONENT_BRANCH_DOCS = {"chart": "helm-chart", "airflow-ctl":
"apache-airflow-ctl"}
+# The documentation built on a component's branch, when documentation changed.
Docs build in the CI image,
+# so a component without an image builds none.
+COMPONENT_BRANCH_DOCS = {"chart": "helm-chart"}
# The release branches of each component, as in the pull_request branch
filters of ci-amd.yml. A feature
# branch named after a component, say chart/fix-ingress, is not one of them.
COMPONENT_BRANCH_PATTERNS = {
@@ -1546,6 +1546,8 @@ class SelectiveChecks:
@cached_property
def docs_build(self) -> bool:
+ if self._component_branch is not None and self._component_branch not
in COMPONENT_BRANCH_DOCS:
+ return False
return self._should_be_run(FileGroupForCi.DOC_FILES)
@cached_property
@@ -2037,6 +2039,9 @@ class SelectiveChecks:
@cached_property
def upgrade_to_newer_dependencies(self) -> bool:
+ # The dependency upgrade summary runs in the CI image.
+ if not self.ci_image_build:
+ return False
if len(self._matching_files(FileGroupForCi.ALL_PYPROJECT_TOML_FILES,
CI_FILE_GROUP_MATCHES)) > 0:
console_print("[warning]Upgrade to newer dependencies: Dependency
files changed[/]")
return True
diff --git a/dev/breeze/tests/test_selective_checks.py
b/dev/breeze/tests/test_selective_checks.py
index 83b0b971f5d..da53666267f 100644
--- a/dev/breeze/tests/test_selective_checks.py
+++ b/dev/breeze/tests/test_selective_checks.py
@@ -5516,13 +5516,8 @@ def _component_branch_checks(context: dict, files:
tuple[str, ...]) -> Selective
),
pytest.param(
{"base_ref": "airflow-ctl/v0-1-test"},
- {
- "run_airflow_ctl_tests",
- "run_airflow_ctl_integration_tests",
- "ci_image_build",
- "prod_image_build",
- },
- "apache-airflow-ctl",
+ {"run_airflow_ctl_tests"},
+ None,
id="pull-request-to-airflow-ctl-branch",
),
],
@@ -5542,6 +5537,21 @@ def
test_component_branch_runs_only_its_component(context, expected_on, expected
assert checks.skip_providers_tests is True
assert checks.has_migrations is False
assert checks.docs_list_as_string == expected_docs
+ assert checks.docs_build is (expected_docs is not None)
+ assert checks.basic_checks_only is ("ci_image_build" not in expected_on)
+
+
[email protected](
+ ("context", "expected"),
+ [
+ pytest.param({"base_ref": "chart/v1-2x-test"}, True,
id="chart-branch-builds-the-image"),
+ pytest.param({"base_ref": "airflow-ctl/v0-1-test"}, False,
id="airflow-ctl-branch-has-no-image"),
+ ],
+)
+def
test_component_branch_upgrades_dependencies_only_with_the_ci_image(context,
expected):
+ checks = _component_branch_checks(context, ("airflow-ctl/pyproject.toml",
"chart/pyproject.toml"))
+
+ assert checks.upgrade_to_newer_dependencies is expected
@pytest.mark.parametrize(
diff --git a/scripts/ci/prek/run_mypy_full_dist_local_venv_or_breeze_in_ci.py
b/scripts/ci/prek/run_mypy_full_dist_local_venv_or_breeze_in_ci.py
index 57284e07195..6e32154eca8 100755
--- a/scripts/ci/prek/run_mypy_full_dist_local_venv_or_breeze_in_ci.py
+++ b/scripts/ci/prek/run_mypy_full_dist_local_venv_or_breeze_in_ci.py
@@ -285,7 +285,9 @@ if console:
else:
print(f"Running mypy for folders: {mypy_folders}")
-if CI:
+# SKIP_BREEZE_PREK_HOOKS marks a CI run without the CI image (basic checks
only, e.g. on the airflow-ctl
+# release branches), where mypy runs in its local virtualenv rather than being
skipped with the image hooks.
+if CI and not os.environ.get("SKIP_BREEZE_PREK_HOOKS"):
# In CI, run inside the breeze Docker image to avoid needing a local
environment
# and to not change uv.lock or synchronize dependencies.
from common_prek_utils import (