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 66d751bfd22 Skip already-released providers in 
update-providers-next-version (#74098)
66d751bfd22 is described below

commit 66d751bfd2290db41f8f96757f58cdc0d8f04fae
Author: Shahar Epstein <[email protected]>
AuthorDate: Fri Oct 2 22:31:38 2026 +0300

    Skip already-released providers in update-providers-next-version (#74098)
    
    The command resolved every "# use next version" pin to the referenced
    provider's current version and dropped the marker, without checking
    whether that version is the one being released. That is only right while
    the version is still unreleased in the same release PR. In an ad-hoc
    release that does not include the referenced provider, the pin ended up
    at a floor that lacks the required code, and the marker was lost so later
    waves never corrected it.
    
    A final release tag now leaves the pin untouched. Release candidate tags
    alone are ambiguous (in vote, or re-cut in this release), so the pin is
    still resolved there, with a warning for the release manager.
---
 .../prepare-providers-documentation/SKILL.md       |  6 +++-
 dev/README_RELEASE_PROVIDERS.md                    |  5 ++-
 dev/breeze/src/airflow_breeze/utils/packages.py    | 26 ++++++++++++++++
 dev/breeze/tests/test_packages.py                  | 36 ++++++++++++++++++++++
 4 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/.agents/skills/prepare-providers-documentation/SKILL.md 
b/.agents/skills/prepare-providers-documentation/SKILL.md
index cfcfda85817..d51db0f3a4a 100644
--- a/.agents/skills/prepare-providers-documentation/SKILL.md
+++ b/.agents/skills/prepare-providers-documentation/SKILL.md
@@ -680,7 +680,11 @@ breeze release-management update-providers-next-version
 ```
 
 This rewrites every `# use next version` dependency to the just-bumped
-version of the referenced provider and removes the comment.
+version of the referenced provider and removes the comment. Pins whose
+referenced provider already has a final release tag are left alone (the
+"next version" is then a future release); when only release candidate tags
+exist the pin is updated with a warning, revert it if that provider is in
+vote rather than re-cut in this release.
 
 > [!IMPORTANT]
 > **Run this every time, before opening the PR — even when you believe no
diff --git a/dev/README_RELEASE_PROVIDERS.md b/dev/README_RELEASE_PROVIDERS.md
index 854f167aa9d..eb8097f93e0 100644
--- a/dev/README_RELEASE_PROVIDERS.md
+++ b/dev/README_RELEASE_PROVIDERS.md
@@ -498,7 +498,10 @@ doing it immediately in the code they can add a comment 
``# use next version``
 to the line of ``pyproject.toml`` file of the provider that refers to the 
provider, which next version
 should be used. This comment will be picked up by 
the``update-providers-next-version`` command and the
 version of the dependent provider will be updated to the next version and 
comment will be
-removed.
+removed. Pins of a provider whose current version already has a final release 
tag are left untouched,
+because the "next version" of that provider is then a future release. When 
only release candidate
+tags exist the pin is still updated with a warning: revert that update if the 
provider is in vote
+rather than re-cut in this release.
 
 ```shell script
 breeze release-management update-providers-next-version
diff --git a/dev/breeze/src/airflow_breeze/utils/packages.py 
b/dev/breeze/src/airflow_breeze/utils/packages.py
index 4a192bde196..18c54392224 100644
--- a/dev/breeze/src/airflow_breeze/utils/packages.py
+++ b/dev/breeze/src/airflow_breeze/utils/packages.py
@@ -1354,6 +1354,32 @@ def _process_line_with_next_version_comment(
     if not provider_version:
         return line, False
 
+    provider_id = provider_package_name.replace("apache-airflow-providers-", 
"").replace("-", ".")
+    version_tag = get_version_tag(provider_version, provider_id)
+    existing_tags = run_command(
+        ["git", "tag", "--list", f"{version_tag}*"],
+        cwd=AIRFLOW_PROVIDERS_ROOT_PATH,
+        capture_output=True,
+        text=True,
+        check=False,
+    ).stdout.split()
+    relative_pyproject = 
pyproject_file.relative_to(AIRFLOW_PROVIDERS_ROOT_PATH)
+    # A final tag means the version is immutable, so "next version" is a 
future release. An rc tag
+    # alone is ambiguous: the version is either in vote (pin must wait) or 
being re-cut in this
+    # release (pin must resolve), and only the release manager knows which.
+    if version_tag in existing_tags:
+        console_print(
+            f"[warning]Skipping {provider_package_name} in 
{relative_pyproject}: "
+            f"version {provider_version} is already released, leaving the pin 
for the next release"
+        )
+        return line, False
+    if existing_tags:
+        console_print(
+            f"[warning]{provider_package_name} {provider_version} has release 
candidate tags but no final "
+            f"release. Revert the update of {relative_pyproject} below if 
{provider_package_name} "
+            f"is not part of this release."
+        )
+
     # Update the line with the new version
     return _update_dependency_line_with_new_version(
         line, provider_package_name, current_min_version, provider_version, 
pyproject_file, updates_made
diff --git a/dev/breeze/tests/test_packages.py 
b/dev/breeze/tests/test_packages.py
index 27b197498ed..2db1df22eb6 100644
--- a/dev/breeze/tests/test_packages.py
+++ b/dev/breeze/tests/test_packages.py
@@ -18,12 +18,14 @@ from __future__ import annotations
 
 from collections.abc import Iterable
 from pathlib import Path
+from unittest import mock
 
 import pytest
 
 from airflow_breeze.global_constants import REGULAR_DOC_PACKAGES
 from airflow_breeze.utils.packages import (
     PipRequirements,
+    _process_line_with_next_version_comment,
     apply_version_suffix_to_non_provider_pyproject_tomls,
     apply_version_suffix_to_provider_pyproject_toml,
     convert_cross_package_dependencies_to_table,
@@ -588,3 +590,37 @@ def 
test_apply_version_suffix_to_non_provider_pyproject_tomls(
         _check_dependencies_modified_properly(
             original_toml, modified_toml, version_suffix, 
floored_version_suffix
         )
+
+
[email protected](
+    ("existing_tags", "expected_line", "expected_modified"),
+    [
+        pytest.param("", '    
"apache-airflow-providers-common-compat>=1.20.0",', True, id="unreleased"),
+        pytest.param(
+            "providers-common-compat/1.20.0\n",
+            '    "apache-airflow-providers-common-compat>=1.19.0",  # use next 
version',
+            False,
+            id="released",
+        ),
+        pytest.param(
+            
"providers-common-compat/1.20.0rc1\nproviders-common-compat/1.20.0rc2\n",
+            '    "apache-airflow-providers-common-compat>=1.20.0",',
+            True,
+            id="rc-only",
+        ),
+    ],
+)
[email protected]("airflow_breeze.utils.packages._get_provider_version_from_package_name",
 autospec=True)
[email protected]("airflow_breeze.utils.packages.run_command", autospec=True)
+def test_process_line_with_next_version_comment(
+    mock_run_command, mock_get_version, existing_tags, expected_line, 
expected_modified
+):
+    mock_get_version.return_value = "1.20.0"
+    mock_run_command.return_value.stdout = existing_tags
+    line = '    "apache-airflow-providers-common-compat>=1.19.0",  # use next 
version'
+    pyproject_file = AIRFLOW_ROOT_PATH / "providers" / "anthropic" / 
"pyproject.toml"
+
+    result = _process_line_with_next_version_comment(line, pyproject_file, {})
+
+    assert result == (expected_line, expected_modified)
+    assert mock_run_command.call_args.args[0] == ["git", "tag", "--list", 
"providers-common-compat/1.20.0*"]

Reply via email to