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 e61640e2a1b Aggregate CI-image dependency groups so providers can 
register non-default extras with a one-line change (#67130)
e61640e2a1b is described below

commit e61640e2a1bceb3ee864d2dd552f623ac76bfb2d
Author: Bugra Ozturk <[email protected]>
AuthorDate: Tue May 19 00:07:21 2026 +0200

    Aggregate CI-image dependency groups so providers can register non-default 
extras with a one-line change (#67130)
---
 Dockerfile                                         | 12 +++---
 Dockerfile.ci                                      | 12 +++---
 contributing-docs/12_provider_distributions.rst    | 43 ++++++++++++++++++++++
 .../utils/constraints_version_check.py             |  8 ++--
 pyproject.toml                                     | 13 +++++++
 .../docker/install_airflow_when_building_images.sh | 12 +++---
 6 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 532dd9c6dc7..1afcd732052 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1228,8 +1228,8 @@ function install_from_sources() {
         # (binary lxml embeds its own libxml2, while xmlsec uses system one).
         # See https://bugs.launchpad.net/lxml/+bug/2110068
         set -x
-        uv sync --all-packages --resolution highest --group dev --group docs 
--group docs-gen \
-            --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+        uv sync --all-packages --resolution highest --group ci-image \
+            ${extra_sync_flags} --no-binary-package lxml --no-binary-package 
xmlsec \
             --no-python-downloads --no-managed-python
     else
         set +x
@@ -1241,8 +1241,8 @@ function install_from_sources() {
         # libxml2 (binary lxml embeds its own libxml2, while xmlsec uses 
system one).
         # See https://bugs.launchpad.net/lxml/+bug/2110068
         set -x
-        if ! uv sync --all-packages --frozen --group dev --group docs --group 
docs-gen \
-            --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+        if ! uv sync --all-packages --frozen --group ci-image \
+            ${extra_sync_flags} --no-binary-package lxml --no-binary-package 
xmlsec \
             --no-python-downloads --no-managed-python; then
             set +x
             if [[ ${AIRFLOW_FALLBACK_NO_CONSTRAINTS_INSTALLATION} != "true" 
]]; then
@@ -1257,8 +1257,8 @@ function install_from_sources() {
             echo "${COLOR_BLUE}Falling back to re-resolving dependencies (uv 
sync without --frozen).${COLOR_RESET}"
             echo
             set -x
-            uv sync --all-packages --group dev --group docs --group docs-gen \
-                --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+            uv sync --all-packages --group ci-image \
+                ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
                 --no-python-downloads --no-managed-python
             set +x
         fi
diff --git a/Dockerfile.ci b/Dockerfile.ci
index 0c4e7f5a7fc..c8d686aa0e3 100644
--- a/Dockerfile.ci
+++ b/Dockerfile.ci
@@ -933,8 +933,8 @@ function install_from_sources() {
         # (binary lxml embeds its own libxml2, while xmlsec uses system one).
         # See https://bugs.launchpad.net/lxml/+bug/2110068
         set -x
-        uv sync --all-packages --resolution highest --group dev --group docs 
--group docs-gen \
-            --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+        uv sync --all-packages --resolution highest --group ci-image \
+            ${extra_sync_flags} --no-binary-package lxml --no-binary-package 
xmlsec \
             --no-python-downloads --no-managed-python
     else
         set +x
@@ -946,8 +946,8 @@ function install_from_sources() {
         # libxml2 (binary lxml embeds its own libxml2, while xmlsec uses 
system one).
         # See https://bugs.launchpad.net/lxml/+bug/2110068
         set -x
-        if ! uv sync --all-packages --frozen --group dev --group docs --group 
docs-gen \
-            --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+        if ! uv sync --all-packages --frozen --group ci-image \
+            ${extra_sync_flags} --no-binary-package lxml --no-binary-package 
xmlsec \
             --no-python-downloads --no-managed-python; then
             set +x
             if [[ ${AIRFLOW_FALLBACK_NO_CONSTRAINTS_INSTALLATION} != "true" 
]]; then
@@ -962,8 +962,8 @@ function install_from_sources() {
             echo "${COLOR_BLUE}Falling back to re-resolving dependencies (uv 
sync without --frozen).${COLOR_RESET}"
             echo
             set -x
-            uv sync --all-packages --group dev --group docs --group docs-gen \
-                --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+            uv sync --all-packages --group ci-image \
+                ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
                 --no-python-downloads --no-managed-python
             set +x
         fi
diff --git a/contributing-docs/12_provider_distributions.rst 
b/contributing-docs/12_provider_distributions.rst
index 832d89128a8..49a987cba21 100644
--- a/contributing-docs/12_provider_distributions.rst
+++ b/contributing-docs/12_provider_distributions.rst
@@ -117,6 +117,49 @@ you should do it before you make a PR with such changed 
dependency changes
 Also, you should rebuild the image ``breeze ci-image build`` or answer ``y`` 
when you are asked to rebuild the
 image for the new dependencies to be used in the Breeze CI environment.
 
+Non-default provider extras
+---------------------------
+
+Some providers depend on packages that cannot be installed in CI by default — 
for example a
+proprietary client library (IBM MQ's ``ibmmq``) or a native library that 
requires system packages
+(Google's ``leveldb``/``plyvel`` needs ``libleveldb-dev``). Pulling these into 
the default
+``uv sync`` would break CI on every runner that doesn't have the prerequisite 
installed.
+
+For these cases, declare the dependency as an extra on the provider and 
register it as its own
+group at the root, without adding it to ``dev``:
+
+1. **In the provider's ``pyproject.toml``** — keep the package under 
``[project.optional-dependencies]``
+   so users can opt in with ``pip install 
apache-airflow-providers-<id>[<extra>]``.
+
+2. **In the root ``pyproject.toml``** — add a dedicated entry under 
``[dependency-groups]``,
+   then include it from the ``ci-image`` aggregate group. The ``ci-image`` 
group is the single
+   source of truth referenced by ``Dockerfile``, ``Dockerfile.ci``,
+   ``scripts/docker/install_airflow_when_building_images.sh``, and the breeze 
constraints
+   checker — adding your group there is the only change required for the CI 
image to pick it up:
+
+   .. code:: toml
+
+       [dependency-groups]
+       my-non-default-extra = [
+           "some-package>=1.2.3",
+       ]
+
+       ci-image = [
+           {include-group = "dev"},
+           {include-group = "docs"},
+           {include-group = "docs-gen"},
+           {include-group = "leveldb"},
+           {include-group = "my-non-default-extra"},
+       ]
+
+3. **If system libraries are required**, add them to 
``scripts/docker/install_os_dependencies.sh``
+   so the CI image has the prerequisites before ``uv sync`` runs.
+
+Because the new group is *not* part of ``dev``, a plain ``uv sync`` on a 
contributor's machine
+will not try to install it. The CI image installs it via ``ci-image``; 
provider unit tests that
+import the proprietary or hard-to-build module should mock it (see 
``providers/google/leveldb``
+for the established pattern).
+
 Provider's cross-dependencies
 -----------------------------
 
diff --git a/dev/breeze/src/airflow_breeze/utils/constraints_version_check.py 
b/dev/breeze/src/airflow_breeze/utils/constraints_version_check.py
index 75c5ee22af5..ced0564d855 100755
--- a/dev/breeze/src/airflow_breeze/utils/constraints_version_check.py
+++ b/dev/breeze/src/airflow_breeze/utils/constraints_version_check.py
@@ -593,10 +593,10 @@ def explain_package_upgrade(
     additional_args = []
     if airflow_constraints_mode == "constraints-source-providers":
         # In case of source constraints we also need to add all development 
dependencies
-        # to reflect exactly what is installed in the CI image by default
-        additional_args.extend(
-            ["--group", "dev", "--group", "docs", "--group", "docs-gen", 
"--group", "leveldb"]
-        )
+        # to reflect exactly what is installed in the CI image by default. The 
``ci-image``
+        # group aggregates dev/docs/docs-gen plus any hard-to-install provider 
extras
+        # (see root pyproject.toml).
+        additional_args.extend(["--group", "ci-image"])
     with (
         preserve_pyproject_file(AIRFLOW_ROOT_PATH / "pyproject.toml") as 
airflow_pyproject,
         preserve_pyproject_file(AIRFLOW_ROOT_PATH / "uv.lock"),
diff --git a/pyproject.toml b/pyproject.toml
index b09e1331701..77ec982702a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1371,6 +1371,19 @@ leveldb = [
     "plyvel>=1.5.1"
 ]
 
+# Aggregate of every group the CI image installs by default. Single source of
+# truth referenced from the Dockerfiles, the image install script, and the
+# breeze constraints checker. When a provider needs to register a
+# hard-to-install extra (proprietary client, needs system libs, etc.), add a
+# dedicated [dependency-groups] entry above and include it here — no Dockerfile
+# or breeze edits required. See 
contributing-docs/12_provider_distributions.rst.
+ci-image = [
+    {include-group = "dev"},
+    {include-group = "docs"},
+    {include-group = "docs-gen"},
+    {include-group = "leveldb"},
+]
+
 [tool.uv]
 # Bump this only when the project actually relies on a newer uv feature/fix. 
It is a
 # minimum contributors must install, NOT the uv CI pins to — keeping it in 
lockstep
diff --git a/scripts/docker/install_airflow_when_building_images.sh 
b/scripts/docker/install_airflow_when_building_images.sh
index 85f879786f3..772465678a8 100644
--- a/scripts/docker/install_airflow_when_building_images.sh
+++ b/scripts/docker/install_airflow_when_building_images.sh
@@ -57,8 +57,8 @@ function install_from_sources() {
         # (binary lxml embeds its own libxml2, while xmlsec uses system one).
         # See https://bugs.launchpad.net/lxml/+bug/2110068
         set -x
-        uv sync --all-packages --resolution highest --group dev --group docs 
--group docs-gen \
-            --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+        uv sync --all-packages --resolution highest --group ci-image \
+            ${extra_sync_flags} --no-binary-package lxml --no-binary-package 
xmlsec \
             --no-python-downloads --no-managed-python
     else
         set +x
@@ -70,8 +70,8 @@ function install_from_sources() {
         # libxml2 (binary lxml embeds its own libxml2, while xmlsec uses 
system one).
         # See https://bugs.launchpad.net/lxml/+bug/2110068
         set -x
-        if ! uv sync --all-packages --frozen --group dev --group docs --group 
docs-gen \
-            --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+        if ! uv sync --all-packages --frozen --group ci-image \
+            ${extra_sync_flags} --no-binary-package lxml --no-binary-package 
xmlsec \
             --no-python-downloads --no-managed-python; then
             set +x
             if [[ ${AIRFLOW_FALLBACK_NO_CONSTRAINTS_INSTALLATION} != "true" 
]]; then
@@ -86,8 +86,8 @@ function install_from_sources() {
             echo "${COLOR_BLUE}Falling back to re-resolving dependencies (uv 
sync without --frozen).${COLOR_RESET}"
             echo
             set -x
-            uv sync --all-packages --group dev --group docs --group docs-gen \
-                --group leveldb ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
+            uv sync --all-packages --group ci-image \
+                ${extra_sync_flags} --no-binary-package lxml 
--no-binary-package xmlsec \
                 --no-python-downloads --no-managed-python
             set +x
         fi

Reply via email to