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*"]