Skip to content

[v3-3-test] Resolve the constraints a release ships instead of taggin… - #71081

Merged
potiuk merged 2 commits into
apache:v3-3-testfrom
potiuk:backport-26d53bd-v3-3-test
Aug 4, 2026
Merged

[v3-3-test] Resolve the constraints a release ships instead of taggin…#71081
potiuk merged 2 commits into
apache:v3-3-testfrom
potiuk:backport-26d53bd-v3-3-test

Conversation

@potiuk

@potiuk potiuk commented Aug 4, 2026

Copy link
Copy Markdown
Member

…g whatever exists (#71040)

  • Resolve the constraints a release ships instead of tagging whatever exists

The constraints published with a version were whatever the constraints-X-Y branch happened to hold when the release ran - a resolution made by the last CI build, for the sources at that moment, rather than for the version being released. The candidate tagged that tip and the final release retagged the candidate, so no release ever resolved constraints of its own.

A candidate now resolves them allowing pre-releases: the providers of the wave being voted on exist on PyPI only as rc versions, so constraints that refuse pre-releases cannot describe what a tester is asked to install. They land on a branch of the candidate's own, leaving the branch every other build reads where it was. The final release cannot promote those by retagging - a released version must never pin an rc - so it resolves the same set again, without pre-releases, and commits onto constraints-X-Y, which is what makes the released constraints the baseline everything downstream reads.

Which of the two happens is derived from the version, so the stage cannot be set inconsistently with it. The work runs on CI runners rather than on the release manager's machine, which would otherwise need a CI image for every supported Python before it could cut a release, and is reachable on its own through breeze workflow-run release-constraints for redoing a candidate's constraints or producing them for a release cut before this existed.

  • Let only the providers answer with a pre-release

--pre applies to the whole resolution, so a candidate's constraints could pin a pre-release of any dependency - a beta of some third-party library would end up in what a release ships, which is not what allowing rc providers was meant to permit. uv considers a pre-release for a package only when a requirement for it mentions one, so naming the providers with a pre-release lower bound confines the allowance to them and leaves every other package on the default policy.

  • State the pre-release scoping rather than leaning on uv's default

The rc lower bounds already confined pre-releases to the providers, but only because uv's default strategy happens to permit them for explicitly marked packages. Naming explicit says that in the command instead of leaving it to a default that could change, and drops the if-necessary half of that default - the part that would let a package nobody marked resolve to a pre-release when no final version satisfies it.

  • Document what a release manager now sees at the constraints step

The candidate half was undocumented - the release notes described only what the final release does, leaving a release manager to infer why a candidate suddenly grows a branch and a tag of its own, and why its constraints pin rc providers when nothing else in them is a pre-release. Both stages and the scope of the pre-release allowance are stated where each is reached.

  • Register the new constraints command where the docs checks look for it

A command has to be grouped in its *_commands_config.py and embedded in one of the breeze docs, or the static checks reject it - --allow-pre-releases had no group and workflow-run release-constraints had a generated screenshot that nothing referenced. The two setup screenshots move because the command list they render is exactly what gained the new entry.
(cherry picked from commit 26d53bd)


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

…g whatever exists (apache#71040)

* Resolve the constraints a release ships instead of tagging whatever exists

The constraints published with a version were whatever the constraints-X-Y
branch happened to hold when the release ran - a resolution made by the last CI
build, for the sources at that moment, rather than for the version being
released. The candidate tagged that tip and the final release retagged the
candidate, so no release ever resolved constraints of its own.

A candidate now resolves them allowing pre-releases: the providers of the wave
being voted on exist on PyPI only as rc versions, so constraints that refuse
pre-releases cannot describe what a tester is asked to install. They land on a
branch of the candidate's own, leaving the branch every other build reads where
it was. The final release cannot promote those by retagging - a released version
must never pin an rc - so it resolves the same set again, without pre-releases,
and commits onto constraints-X-Y, which is what makes the released constraints
the baseline everything downstream reads.

Which of the two happens is derived from the version, so the stage cannot be set
inconsistently with it. The work runs on CI runners rather than on the release
manager's machine, which would otherwise need a CI image for every supported
Python before it could cut a release, and is reachable on its own through
`breeze workflow-run release-constraints` for redoing a candidate's constraints
or producing them for a release cut before this existed.

* Let only the providers answer with a pre-release

`--pre` applies to the whole resolution, so a candidate's constraints could pin
a pre-release of any dependency - a beta of some third-party library would end
up in what a release ships, which is not what allowing rc providers was meant to
permit. uv considers a pre-release for a package only when a requirement for it
mentions one, so naming the providers with a pre-release lower bound confines
the allowance to them and leaves every other package on the default policy.

* State the pre-release scoping rather than leaning on uv's default

The rc lower bounds already confined pre-releases to the providers, but only
because uv's default strategy happens to permit them for explicitly marked
packages. Naming `explicit` says that in the command instead of leaving it to a
default that could change, and drops the `if-necessary` half of that default -
the part that would let a package nobody marked resolve to a pre-release when no
final version satisfies it.

* Document what a release manager now sees at the constraints step

The candidate half was undocumented - the release notes described only what the
final release does, leaving a release manager to infer why a candidate suddenly
grows a branch and a tag of its own, and why its constraints pin rc providers
when nothing else in them is a pre-release. Both stages and the scope of the
pre-release allowance are stated where each is reached.

* Register the new constraints command where the docs checks look for it

A command has to be grouped in its `*_commands_config.py` and embedded in one of
the breeze docs, or the static checks reject it - `--allow-pre-releases` had no
group and `workflow-run release-constraints` had a generated screenshot that
nothing referenced. The two `setup` screenshots move because the command list
they render is exactly what gained the new entry.
(cherry picked from commit 26d53bd)

Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
The cherry-pick created the test file in full, including the cases for the
provider-downgrade check, which exists only on main - this branch has no
check_providers_not_downgraded for them to exercise, so seven of the nine
tests fail on an attribute that is not there. What the picked commit added
here is the pre-release requirement builder, and that is what the file is
left holding.
@potiuk
potiuk merged commit 5a9ce03 into apache:v3-3-test Aug 4, 2026
4 checks passed
@potiuk
potiuk deleted the backport-26d53bd-v3-3-test branch August 4, 2026 10:13
@vatsrahul1001 vatsrahul1001 added the changelog:skip Changes that should be skipped from the changelog (CI, tests, etc..) label Aug 4, 2026
@vatsrahul1001 vatsrahul1001 added this to the Airflow 3.3.1 milestone Aug 4, 2026
vatsrahul1001 pushed a commit that referenced this pull request Aug 5, 2026
#71081)

* [v3-3-test] Resolve the constraints a release ships instead of tagging whatever exists (#71040)

* Resolve the constraints a release ships instead of tagging whatever exists

The constraints published with a version were whatever the constraints-X-Y
branch happened to hold when the release ran - a resolution made by the last CI
build, for the sources at that moment, rather than for the version being
released. The candidate tagged that tip and the final release retagged the
candidate, so no release ever resolved constraints of its own.

A candidate now resolves them allowing pre-releases: the providers of the wave
being voted on exist on PyPI only as rc versions, so constraints that refuse
pre-releases cannot describe what a tester is asked to install. They land on a
branch of the candidate's own, leaving the branch every other build reads where
it was. The final release cannot promote those by retagging - a released version
must never pin an rc - so it resolves the same set again, without pre-releases,
and commits onto constraints-X-Y, which is what makes the released constraints
the baseline everything downstream reads.

Which of the two happens is derived from the version, so the stage cannot be set
inconsistently with it. The work runs on CI runners rather than on the release
manager's machine, which would otherwise need a CI image for every supported
Python before it could cut a release, and is reachable on its own through
`breeze workflow-run release-constraints` for redoing a candidate's constraints
or producing them for a release cut before this existed.

* Let only the providers answer with a pre-release

`--pre` applies to the whole resolution, so a candidate's constraints could pin
a pre-release of any dependency - a beta of some third-party library would end
up in what a release ships, which is not what allowing rc providers was meant to
permit. uv considers a pre-release for a package only when a requirement for it
mentions one, so naming the providers with a pre-release lower bound confines
the allowance to them and leaves every other package on the default policy.

* State the pre-release scoping rather than leaning on uv's default

The rc lower bounds already confined pre-releases to the providers, but only
because uv's default strategy happens to permit them for explicitly marked
packages. Naming `explicit` says that in the command instead of leaving it to a
default that could change, and drops the `if-necessary` half of that default -
the part that would let a package nobody marked resolve to a pre-release when no
final version satisfies it.

* Document what a release manager now sees at the constraints step

The candidate half was undocumented - the release notes described only what the
final release does, leaving a release manager to infer why a candidate suddenly
grows a branch and a tag of its own, and why its constraints pin rc providers
when nothing else in them is a pre-release. Both stages and the scope of the
pre-release allowance are stated where each is reached.

* Register the new constraints command where the docs checks look for it

A command has to be grouped in its `*_commands_config.py` and embedded in one of
the breeze docs, or the static checks reject it - `--allow-pre-releases` had no
group and `workflow-run release-constraints` had a generated screenshot that
nothing referenced. The two `setup` screenshots move because the command list
they render is exactly what gained the new entry.
(cherry picked from commit 26d53bd)

Co-authored-by: Jarek Potiuk <jarek@potiuk.com>

* Trim the backported constraints tests to what this branch implements

The cherry-pick created the test file in full, including the cases for the
provider-downgrade check, which exists only on main - this branch has no
check_providers_not_downgraded for them to exercise, so seven of the nine
tests fail on an attribute that is not there. What the picked commit added
here is the pre-release requirement builder, and that is what the file is
left holding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:dev-tools changelog:skip Changes that should be skipped from the changelog (CI, tests, etc..)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants