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 (

Reply via email to