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 26d53bd1e84 Resolve the constraints a release ships instead of tagging
whatever exists (#71040)
26d53bd1e84 is described below
commit 26d53bd1e84088bf7cb7ab11dcfde3d8e6b99048
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue Aug 4 11:51:57 2026 +0200
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.
---
.github/workflows/generate-constraints.yml | 16 +-
.github/workflows/release-constraints.yml | 248 +++++++++++++++++++++
dev/README_RELEASE_AIRFLOW.md | 50 ++++-
dev/breeze/doc/09_release_management_tasks.rst | 21 ++
...put_release-management_generate-constraints.svg | 54 +++--
...put_release-management_generate-constraints.txt | 2 +-
.../output_setup_check-all-params-in-groups.svg | 24 +-
.../output_setup_check-all-params-in-groups.txt | 2 +-
.../output_setup_regenerate-command-images.svg | 2 +-
.../output_setup_regenerate-command-images.txt | 2 +-
dev/breeze/doc/images/output_workflow-run.svg | 14 +-
dev/breeze/doc/images/output_workflow-run.txt | 2 +-
.../output_workflow-run_release-constraints.svg | 138 ++++++++++++
.../output_workflow-run_release-constraints.txt | 1 +
.../commands/release_candidate_command.py | 31 +--
.../src/airflow_breeze/commands/release_command.py | 48 +---
.../commands/release_management_commands.py | 4 +
.../commands/release_management_commands_config.py | 1 +
.../airflow_breeze/commands/workflow_commands.py | 44 ++++
.../commands/workflow_commands_config.py | 12 +-
.../airflow_breeze/utils/release_constraints.py | 61 +++++
dev/breeze/tests/test_release_command.py | 57 ++---
dev/breeze/tests/test_release_constraints.py | 91 ++++++++
scripts/in_container/run_generate_constraints.py | 48 ++++
.../in_container/test_run_generate_constraints.py | 39 ++++
25 files changed, 851 insertions(+), 161 deletions(-)
diff --git a/.github/workflows/generate-constraints.yml
b/.github/workflows/generate-constraints.yml
index 28c078a3563..8178cde09e0 100644
--- a/.github/workflows/generate-constraints.yml
+++ b/.github/workflows/generate-constraints.yml
@@ -44,6 +44,15 @@ on: # yamllint disable-line rule:truthy
description: "Whether to generate PyPI constraints (true/false)"
required: true
type: string
+ allow-pre-releases:
+ description: >
+ Whether the PyPI constraints may pin pre-release providers
(true/false). Set when
+ constraints are cut for a release candidate, whose providers are on
PyPI only as rc
+ versions. Scoped to apache-airflow-providers-* - no other package
can resolve to a
+ pre-release.
+ required: false
+ default: "false"
+ type: string
debug-resources:
description: "Whether to run in debug mode (true/false)"
required: true
@@ -137,9 +146,14 @@ jobs:
- name: "PyPI constraints"
shell: bash
timeout-minutes: 25
+ env:
+ # Deliberately not named ALLOW_PRE_RELEASES: that is the option's
own envvar, and having
+ # both paths set it would make it unclear which one is in force.
Empty on a normal run,
+ # so the unquoted expansion below contributes no argument at all.
+ PRE_RELEASE_FLAG: ${{ inputs.allow-pre-releases == 'true' &&
'--allow-pre-releases' || '' }}
run: |
breeze release-management generate-constraints
--airflow-constraints-mode constraints \
- --answer yes --python "${PYTHON_VERSION}"
+ --answer yes --python "${PYTHON_VERSION}" ${PRE_RELEASE_FLAG}
if: inputs.generate-pypi-constraints == 'true'
- name: "Check for provider downgrade alert"
id: downgrade-alert
diff --git a/.github/workflows/release-constraints.yml
b/.github/workflows/release-constraints.yml
new file mode 100644
index 00000000000..268abf83341
--- /dev/null
+++ b/.github/workflows/release-constraints.yml
@@ -0,0 +1,248 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# Resolves the constraints that a release ships, rather than tagging whatever
the
+# `constraints-X-Y` branch happened to hold when the release ran.
+#
+# The stage is derived from the version, so the two cannot be mismatched by
hand:
+#
+# * a candidate (`3.1.3rc1`) resolves with pre-releases allowed - the
providers of the wave
+# being voted on exist on PyPI only as rc versions - and lands on a branch
of its own, so a
+# candidate never moves the branch every other build reads;
+# * a final (`3.1.3`) resolves without them, against the providers now
published as finals, and
+# commits onto `constraints-X-Y` itself, which is what makes the released
constraints the
+# baseline everything downstream reads.
+#
+# A final therefore cannot be produced by retagging a candidate: a released
version must never
+# pin an rc.
+---
+name: Release constraints
+on: # yamllint disable-line rule:truthy
+ workflow_dispatch:
+ inputs:
+ version:
+ description: "Version the constraints belong to, e.g. 3.1.3rc1 or
3.1.3"
+ required: true
+ type: string
+ ref:
+ description: "Ref the constraints are resolved from, e.g. v3-1-stable
or the release tag"
+ required: true
+ type: string
+permissions:
+ contents: read
+concurrency:
+ group: release-constraints-${{ inputs.version }}
+ cancel-in-progress: false
+jobs:
+ build-info:
+ timeout-minutes: 10
+ name: "Build info"
+ runs-on: ["ubuntu-22.04"]
+ if: contains(fromJSON('[
+ "ashb",
+ "eladkal",
+ "ephraimbuddy",
+ "jedcunningham",
+ "kaxil",
+ "pierrejeambrun",
+ "potiuk",
+ "utkarsharma2",
+ "vincbeck",
+ ]'), github.event.sender.login)
+ outputs:
+ python-versions: ${{ steps.selective-checks.outputs.python-versions }}
+ python-versions-list-as-string: ${{
steps.selective-checks.outputs.python-versions-list-as-string }}
+ default-branch: ${{ steps.selective-checks.outputs.default-branch }}
+ default-constraints-branch: ${{
steps.selective-checks.outputs.default-constraints-branch }}
+ constraints-branch: ${{ steps.stage.outputs.constraints-branch }}
+ target-branch: ${{ steps.stage.outputs.target-branch }}
+ allow-pre-releases: ${{ steps.stage.outputs.allow-pre-releases }}
+ steps:
+ - name: "Cleanup repo"
+ shell: bash
+ run: sudo rm -rf ${GITHUB_WORKSPACE}/*
+ - name: "Checkout ${{ inputs.ref }}"
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #
v7.0.1
+ with:
+ ref: ${{ inputs.ref }}
+ fetch-depth: 2
+ persist-credentials: false
+ - name: "Install Breeze"
+ uses: ./.github/actions/breeze
+ id: breeze
+ - name: "Save github context to file"
+ # See ci-amd.yml for the full rationale: avoids ARG_MAX on big PRs by
writing the
+ # github context to a file, and the single-quoted heredoc makes the
zizmor
+ # template-injection finding a false positive (no bash expansion
happens inside it).
+ shell: bash
+ run: | # zizmor: ignore[template-injection]
+ cat > "${RUNNER_TEMP}/github_context.json" <<
'__GITHUB_CONTEXT_END__'
+ ${{ toJson(github) }}
+ __GITHUB_CONTEXT_END__
+ - name: Selective checks
+ id: selective-checks
+ env:
+ PR_LABELS: "[]"
+ COMMIT_REF: "${{ inputs.ref }}"
+ VERBOSE: "false"
+ GITHUB_CONTEXT_INPUT: "${{ runner.temp }}/github_context.json"
+ run: breeze ci selective-check 2>> ${GITHUB_OUTPUT}
+ - name: "Derive the release stage from the version"
+ id: stage
+ shell: bash
+ env:
+ VERSION: ${{ inputs.version }}
+ run: |
+ if [[ ! "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(rc[0-9]+)?$ ]]; then
+ echo "'${VERSION}' is not a release version - expected X.Y.Z or
X.Y.ZrcN." >&2
+ exit 1
+ fi
+ major="$(echo "${VERSION}" | cut -d. -f1)"
+ minor="$(echo "${VERSION}" | cut -d. -f2)"
+ constraints_branch="constraints-${major}-${minor}"
+ echo "constraints-branch=${constraints_branch}" >> "${GITHUB_OUTPUT}"
+ if [[ "${VERSION}" == *rc* ]]; then
+ echo "allow-pre-releases=true" >> "${GITHUB_OUTPUT}"
+ echo "target-branch=constraints-${VERSION}" >> "${GITHUB_OUTPUT}"
+ else
+ echo "allow-pre-releases=false" >> "${GITHUB_OUTPUT}"
+ echo "target-branch=${constraints_branch}" >> "${GITHUB_OUTPUT}"
+ fi
+ - name: "Parameters summary"
+ shell: bash
+ env:
+ VERSION: ${{ inputs.version }}
+ REF: ${{ inputs.ref }}
+ CONSTRAINTS_BRANCH: ${{ steps.stage.outputs.constraints-branch }}
+ TARGET_BRANCH: ${{ steps.stage.outputs.target-branch }}
+ ALLOW_PRE_RELEASES: ${{ steps.stage.outputs.allow-pre-releases }}
+ run: |
+ {
+ echo "## Release constraints"
+ echo ""
+ echo "| Parameter | Value |"
+ echo "|---|---|"
+ echo "| Version | \`${VERSION}\` |"
+ echo "| Resolved from ref | \`${REF}\` |"
+ echo "| Branched off | \`${CONSTRAINTS_BRANCH}\` |"
+ echo "| Committed to | \`${TARGET_BRANCH}\` |"
+ echo "| Pre-releases allowed | \`${ALLOW_PRE_RELEASES}\` |"
+ echo "| Tagged | \`constraints-${VERSION}\` |"
+ } | tee -a "${GITHUB_STEP_SUMMARY}"
+
+ build-ci-images:
+ name: "Build CI images"
+ needs: [build-info]
+ uses: ./.github/workflows/ci-image-build.yml
+ permissions:
+ contents: read
+ packages: write
+ with:
+ runners: '["ubuntu-22.04"]'
+ platform: "linux/amd64"
+ push-image: "false"
+ upload-image-artifact: "true"
+ upload-mount-cache-artifact: "false"
+ python-versions: ${{ needs.build-info.outputs.python-versions }}
+ branch: ${{ needs.build-info.outputs.default-branch }}
+ constraints-branch: ${{
needs.build-info.outputs.default-constraints-branch }}
+ checkout-ref: ${{ inputs.ref }}
+ use-uv: "true"
+ upgrade-to-newer-dependencies: "false"
+ docker-cache: "registry"
+ disable-airflow-repo-cache: "false"
+
+ generate-constraints:
+ name: "Generate constraints"
+ needs: [build-info, build-ci-images]
+ uses: ./.github/workflows/generate-constraints.yml
+ with:
+ runners: '["ubuntu-22.04"]'
+ platform: "linux/amd64"
+ python-versions-list-as-string: ${{
needs.build-info.outputs.python-versions-list-as-string }}
+ python-versions: ${{ needs.build-info.outputs.python-versions }}
+ generate-pypi-constraints: "true"
+ # Only the PyPI constraints are what a release ships; the other modes
serve CI, and
+ # regenerating them here would move them for reasons unrelated to the
release.
+ generate-no-providers-constraints: "false"
+ allow-pre-releases: ${{ needs.build-info.outputs.allow-pre-releases }}
+ debug-resources: "false"
+ checkout-ref: ${{ inputs.ref }}
+ use-uv: "true"
+ secrets:
+ SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
+
+ publish-constraints:
+ runs-on: ["ubuntu-22.04"]
+ timeout-minutes: 20
+ name: "Publish and tag constraints"
+ needs: [build-info, generate-constraints]
+ permissions:
+ contents: write
+ packages: read
+ env:
+ VERSION: ${{ inputs.version }}
+ CONSTRAINTS_BRANCH: ${{ needs.build-info.outputs.constraints-branch }}
+ TARGET_BRANCH: ${{ needs.build-info.outputs.target-branch }}
+ steps:
+ - name: "Cleanup repo"
+ shell: bash
+ run: sudo rm -rf ${GITHUB_WORKSPACE}/*
+ - name: "Checkout ${{ inputs.ref }}"
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #
v7.0.1
+ with:
+ ref: ${{ inputs.ref }}
+ persist-credentials: false
+ # Branched off the shared constraints branch in both cases; what differs
is where the commit
+ # ends up, which the checkout below decides.
+ - name: "Checkout ${{ needs.build-info.outputs.constraints-branch }}"
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #
v7.0.1
+ with:
+ path: "constraints"
+ ref: ${{ needs.build-info.outputs.constraints-branch }}
+ persist-credentials: true
+ fetch-depth: 0
+ - name: "Download constraints from the generate-constraints job"
+ uses:
actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ pattern: constraints-*
+ path: ./files
+ - name: "Switch to ${{ needs.build-info.outputs.target-branch }}"
+ working-directory: "constraints"
+ shell: bash
+ run: git switch -c "${TARGET_BRANCH}" 2>/dev/null || git switch
"${TARGET_BRANCH}"
+ - name: "Diff in constraints for Python: ${{
needs.build-info.outputs.python-versions-list-as-string }}"
+ run: ./scripts/ci/constraints/ci_diff_constraints.sh
+ - name: "Commit changed constraint files"
+ run: ./scripts/ci/constraints/ci_commit_constraints.sh
+ - name: "Push ${{ needs.build-info.outputs.target-branch }}"
+ working-directory: "constraints"
+ shell: bash
+ run: git push origin "${TARGET_BRANCH}"
+ - name: "Tag constraints-${{ inputs.version }}"
+ working-directory: "constraints"
+ shell: bash
+ run: |
+ git tag -a "constraints-${VERSION}" -m "Constraints for Apache
Airflow ${VERSION}"
+ git push origin "constraints-${VERSION}"
+ - name: "Summary"
+ shell: bash
+ run: |
+ {
+ echo "Constraints for \`${VERSION}\` are on \`${TARGET_BRANCH}\`,"
+ echo "tagged \`constraints-${VERSION}\`."
+ } | tee -a "${GITHUB_STEP_SUMMARY}"
diff --git a/dev/README_RELEASE_AIRFLOW.md b/dev/README_RELEASE_AIRFLOW.md
index 33881515df9..0841475566c 100644
--- a/dev/README_RELEASE_AIRFLOW.md
+++ b/dev/README_RELEASE_AIRFLOW.md
@@ -588,6 +588,18 @@ still works but is no longer recommended.
--sync-branch ${SYNC_BRANCH}
```
+ Note: when it reaches the constraints step, `start-rc-process` triggers the
`Release
+ constraints` workflow and waits. The candidate resolves constraints of its
own rather than
+ tagging the `constraints-X-Y` branch tip, and it resolves them **allowing
pre-releases for the
+ providers** — the providers of the wave being voted on exist on PyPI only
as `rcN` versions, so
+ constraints that refused them could not describe what a tester is asked to
install. The
+ allowance is scoped to `apache-airflow-providers-*`; no other package can
resolve to a
+ pre-release, so a beta of some third-party library cannot slip into what
the candidate ships.
+
+ The result lands on a branch of its own (`constraints-${VERSION_RC}`) and
is tagged
+ `constraints-${VERSION_RC}`. The shared `constraints-X-Y` branch is left
where it was — only
+ the final release moves it.
+
**Testing the start-rc-process command:**
Before running the actual release command, you can safely test it using:
@@ -1372,15 +1384,37 @@ breeze release-management start-release \
Note: The `--task-sdk-version` parameter is optional. If you are releasing
Airflow without a corresponding Task SDK release, you can omit this parameter.
-Note: When it reaches the constraints step, `start-release` asks whether to
base the final
-`constraints-${VERSION}` tag on the latest `constraints-X-Y` branch tip
instead of the RC
-constraints tag. The RC constraints are frozen when the RC is cut, so if any
providers were
-released (or constraints were otherwise refreshed - see
+Note: When it reaches the constraints step, `start-release` resolves the
constraints again rather
+than promoting the ones the RC was cut with. The RC constraints deliberately
pin pre-releases -
+that wave's providers exist on PyPI only as `rcN` versions at candidate time -
so they can never
+become the released constraints by retagging. The regeneration runs without
pre-releases against
+the same providers now published as finals, commits the result onto the
`constraints-X-Y` branch,
+pushes it, and tags it `constraints-${VERSION}`. That commit is what makes the
released
+constraints the new baseline, so refreshing the branch beforehand (see
[MANUALLY_GENERATING_IMAGE_CACHE_AND_CONSTRAINTS.md](MANUALLY_GENERATING_IMAGE_CACHE_AND_CONSTRAINTS.md))
-after the last RC and you want the released constraints to reflect that,
answer **yes** to tag the
-`constraints-X-Y` branch tip. Otherwise (the default) the final tag matches
the RC exactly. If you
-do refresh, run the `Update constraints` workflow from `main` with `ref` set
to the ref you are
-releasing (typically `v3-*-stable`) **before** running `start-release`.
+is no longer necessary.
+
+The resolution runs on CI runners through the `Release constraints` workflow,
so the release
+manager's machine does not need a CI image for every supported Python.
`start-release` triggers it
+and waits. You can also run it on its own - to redo a candidate's constraints,
or to produce them
+for a release cut before this existed:
+
+```shell script
+breeze workflow-run release-constraints --version ${VERSION} --ref v3-1-stable
+```
+
+The workflow derives the stage from `--version` alone, so there is no separate
switch that could
+disagree with the version:
+
+| `--version` | Pre-releases | Lands on | Tagged |
+|---|---|---|---|
+| `3.1.3rc1` | providers only | `constraints-3.1.3rc1`, branched off
`constraints-3-1` | `constraints-3.1.3rc1` |
+| `3.1.3` | none | `constraints-3-1` (commit) | `constraints-3.1.3` |
+
+"Providers only" is literal: the resolution names every
`apache-airflow-providers-*` with a
+pre-release lower bound and runs under uv's `explicit` strategy, which permits
a pre-release solely
+for a package marked that way. Nothing else in the dependency graph can
resolve to one — which is
+why `--pre` is not used, since it would apply to the whole resolution.
4. Make sure to update Airflow version in ``v3-*-test`` branch after
cherry-picking to X.Y.1 in
diff --git a/dev/breeze/doc/09_release_management_tasks.rst
b/dev/breeze/doc/09_release_management_tasks.rst
index 70453de37db..40694e437c6 100644
--- a/dev/breeze/doc/09_release_management_tasks.rst
+++ b/dev/breeze/doc/09_release_management_tasks.rst
@@ -1080,6 +1080,27 @@ These are all available flags of ``workflow-run
publish-docs`` command:
:width: 100%
:alt: Breeze workflow-run publish-docs
+Resolving the constraints for a release
+"""""""""""""""""""""""""""""""""""""""
+
+To trigger the GitHub Actions workflow that resolves, publishes and tags the
constraints belonging to a
+release, you can use the ``breeze workflow-run release-constraints`` command.
The release commands trigger
+it themselves, so this is for redoing a candidate's constraints or producing
them for a release cut before
+the workflow existed.
+
+The stage is derived from ``--version`` alone, so it cannot be set
inconsistently with it. A candidate
+(``3.1.3rc1``) resolves allowing pre-releases for
``apache-airflow-providers-*`` — the providers of the wave
+being voted on are on PyPI only as ``rcN`` versions — and lands on a branch of
its own, leaving the shared
+``constraints-X-Y`` branch where it was. A final (``3.1.3``) resolves without
them and commits onto
+``constraints-X-Y``, which is what makes the released constraints the baseline
everything downstream reads.
+
+These are all available flags of ``workflow-run release-constraints`` command:
+
+.. image:: ./images/output_workflow-run_release-constraints.svg
+ :target:
https://raw.githubusercontent.com/apache/airflow/main/dev/breeze/doc/images/output_workflow-run_release-constraints.svg
+ :width: 100%
+ :alt: Breeze workflow-run release-constraints
+
Publishing the schema files to S3
"""""""""""""""""""""""""""""""""
diff --git
a/dev/breeze/doc/images/output_release-management_generate-constraints.svg
b/dev/breeze/doc/images/output_release-management_generate-constraints.svg
index 9a2a1328ea1..07e3538c1ce 100644
--- a/dev/breeze/doc/images/output_release-management_generate-constraints.svg
+++ b/dev/breeze/doc/images/output_release-management_generate-constraints.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 757.5999999999999"
xmlns="http://www.w3.org/2000/svg">
+<svg class="rich-terminal" viewBox="0 0 1482 806.4"
xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -43,7 +43,7 @@
<defs>
<clipPath
id="breeze-release-management-generate-constraints-clip-terminal">
- <rect x="0" y="0" width="1463.0" height="706.5999999999999" />
+ <rect x="0" y="0" width="1463.0" height="755.4" />
</clipPath>
<clipPath id="breeze-release-management-generate-constraints-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -129,9 +129,15 @@
<clipPath id="breeze-release-management-generate-constraints-line-27">
<rect x="0" y="660.3" width="1464" height="24.65"/>
</clipPath>
+<clipPath id="breeze-release-management-generate-constraints-line-28">
+ <rect x="0" y="684.7" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-release-management-generate-constraints-line-29">
+ <rect x="0" y="709.1" width="1464" height="24.65"/>
+ </clipPath>
</defs>
- <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="755.6" rx="8"/><text
class="breeze-release-management-generate-constraints-title" fill="#c5c8c6"
text-anchor="middle" x="740"
y="27">Command: release-management generate-constraints</text>
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="804.4" rx="8"/><text
class="breeze-release-management-generate-constraints-title" fill="#c5c8c6"
text-anchor="middle" x="740"
y="27">Command: release-management generate-constraints</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -150,26 +156,28 @@
</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="166.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-6)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="166.4"
textLength="317.2"
clip-path="url(#breeze-release-management-generate-constraints-line-6)">--airflow-constraints-mode</text><text
class="breeze-release-management-generate-constraints-r1" x="414.8" y="166.4"
textLength="671" [...]
</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="190.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-7)">│</text><text
class="breeze-release-management-generate-constraints-r5" x="414.8" y="190.8"
textLength="353.8"
clip-path="url(#breeze-release-management-generate-constraints-line-7)">constraints-source-providers]</text><text
class="breeze-release-management-generate-constraints-r6" x="780.8" y="190.8"
textLength=" [...]
</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="215.2" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-8)">│</text><text
class="breeze-release-management-generate-constraints-r6" x="414.8" y="215.2"
textLength="305"
clip-path="url(#breeze-release-management-generate-constraints-line-8)">constraints-no-providers)</text><text
class="breeze-release-management-generate-constraints-r5" x="1451.8" y="215.2"
textLength="12.2" [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="239.6" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-9)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="239.6"
textLength="317.2"
clip-path="url(#breeze-release-management-generate-constraints-line-9)">--github-repository       </text><text
class="breeze-release-management-generate-constraints-r7" x [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="264" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-10)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="264"
textLength="317.2"
clip-path="url(#breeze-release-management-generate-constraints-line-10)">--python                  </text><text
class= [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="288.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-11)">│</text><text
class="breeze-release-management-generate-constraints-r6" x="414.8" y="288.4"
textLength="341.6"
clip-path="url(#breeze-release-management-generate-constraints-line-11)">| 3.11 | 3.12 | 3.13 | 3.14)</text><text
class="breeze-release-management-generate-constraints- [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="312.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-12)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="312.8"
textLength="97.6"
clip-path="url(#breeze-release-management-generate-constraints-line-12)">--use-uv</text><text
class="breeze-release-management-generate-constraints-r1" x="122" y="312.8"
textLength="12.2" clip-path="url(#b [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="337.2" textLength="1464"
clip-path="url(#breeze-release-management-generate-constraints-line-13)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-release-management-generate-constraints-r1" x="1464" y="337.2"
textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-13)">
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="361.6" textLength="24.4"
clip-path="url(#breeze-release-management-generate-constraints-line-14)">╭─</text><text
class="breeze-release-management-generate-constraints-r5" x="24.4" y="361.6"
textLength="219.6"
clip-path="url(#breeze-release-management-generate-constraints-line-14)"> Parallel running </text><text
class="breeze-release-management-generate-constraints-r5" x="244" y="361.6"
textLeng [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="386" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-15)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="386"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-15)">--debug-resources</text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="386"
textLength="768.6" clip-path= [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="410.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-16)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="410.4"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-16)">--parallelism    </text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="410.4"
tex [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="434.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-17)">│</text><text
class="breeze-release-management-generate-constraints-r6" x="256.2" y="434.8"
textLength="170.8"
clip-path="url(#breeze-release-management-generate-constraints-line-17)">RANGE 1<=x<=8)</text><text
class="breeze-release-management-generate-constraints-r5" x="1451.8" y="434.8"
textLength="1 [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="459.2" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-18)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="459.2"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-18)">--python-versions</text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="459.2"
textLength="963.8" clip [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="483.6" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-19)">│</text><text
class="breeze-release-management-generate-constraints-r5" x="256.2" y="483.6"
textLength="244"
clip-path="url(#breeze-release-management-generate-constraints-line-19)">3.11 3.12 3.13 3.14]</text><text
class="breeze-release-management-generate-constraints-r6" x="512.4" y="483.6"
textLe [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="508" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-20)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="508"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-20)">--run-in-parallel</text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="508"
textLength="854" clip-path="u [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="532.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-21)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="532.4"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-21)">--skip-cleanup   </text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="532.4"
textLeng [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="556.8" textLength="1464"
clip-path="url(#breeze-release-management-generate-constraints-line-22)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-release-management-generate-constraints-r1" x="1464" y="556.8"
textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-22)">
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="581.2" textLength="24.4"
clip-path="url(#breeze-release-management-generate-constraints-line-23)">╭─</text><text
class="breeze-release-management-generate-constraints-r5" x="24.4" y="581.2"
textLength="195.2"
clip-path="url(#breeze-release-management-generate-constraints-line-23)"> Common options </text><text
class="breeze-release-management-generate-constraints-r5" x="219.6" y="581.2"
textLeng [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="605.6" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-24)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="605.6"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-24)">--verbose</text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="605.6"
textLength="24.4" clip-path="ur [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="630" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-25)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="630"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-25)">--dry-run</text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="630"
textLength="24.4" clip-path="url(#bre [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="654.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-26)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="654.4"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-26)">--answer </text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="654.4"
textLength="24.4" clip-pat [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="678.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-27)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="678.8"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-27)">--help   </text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="678.8"
textLength="24.4 [...]
-</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="703.2" textLength="1464"
clip-path="url(#breeze-release-management-generate-constraints-line-28)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-release-management-generate-constraints-r1" x="1464" y="703.2"
textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-28)">
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="239.6" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-9)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="239.6"
textLength="317.2"
clip-path="url(#breeze-release-management-generate-constraints-line-9)">--allow-pre-releases      </text><text
class="breeze-release-management-generate-constraints-r1" x="414 [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="264" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-10)">│</text><text
class="breeze-release-management-generate-constraints-r1" x="414.8" y="264"
textLength="512.4"
clip-path="url(#breeze-release-management-generate-constraints-line-10)">Set to true automatically for pre-release </text><text
class="breeze-release-management-generate-constra [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="288.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-11)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="288.4"
textLength="317.2"
clip-path="url(#breeze-release-management-generate-constraints-line-11)">--github-repository       </text><text
class="breeze-release-management-generate-constraints-r7" [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="312.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-12)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="312.8"
textLength="317.2"
clip-path="url(#breeze-release-management-generate-constraints-line-12)">--python                  </text><text
cl [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="337.2" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-13)">│</text><text
class="breeze-release-management-generate-constraints-r6" x="414.8" y="337.2"
textLength="341.6"
clip-path="url(#breeze-release-management-generate-constraints-line-13)">| 3.11 | 3.12 | 3.13 | 3.14)</text><text
class="breeze-release-management-generate-constraints- [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="361.6" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-14)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="361.6"
textLength="97.6"
clip-path="url(#breeze-release-management-generate-constraints-line-14)">--use-uv</text><text
class="breeze-release-management-generate-constraints-r1" x="122" y="361.6"
textLength="12.2" clip-path="url(#b [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="386" textLength="1464"
clip-path="url(#breeze-release-management-generate-constraints-line-15)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-release-management-generate-constraints-r1" x="1464" y="386"
textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-15)">
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="410.4" textLength="24.4"
clip-path="url(#breeze-release-management-generate-constraints-line-16)">╭─</text><text
class="breeze-release-management-generate-constraints-r5" x="24.4" y="410.4"
textLength="219.6"
clip-path="url(#breeze-release-management-generate-constraints-line-16)"> Parallel running </text><text
class="breeze-release-management-generate-constraints-r5" x="244" y="410.4"
textLeng [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="434.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-17)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="434.8"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-17)">--debug-resources</text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="434.8"
textLength="768.6" clip [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="459.2" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-18)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="459.2"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-18)">--parallelism    </text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="459.2"
tex [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="483.6" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-19)">│</text><text
class="breeze-release-management-generate-constraints-r6" x="256.2" y="483.6"
textLength="170.8"
clip-path="url(#breeze-release-management-generate-constraints-line-19)">RANGE 1<=x<=8)</text><text
class="breeze-release-management-generate-constraints-r5" x="1451.8" y="483.6"
textLength="1 [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="508" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-20)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="508"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-20)">--python-versions</text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="508"
textLength="963.8" clip-path= [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="532.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-21)">│</text><text
class="breeze-release-management-generate-constraints-r5" x="256.2" y="532.4"
textLength="244"
clip-path="url(#breeze-release-management-generate-constraints-line-21)">3.11 3.12 3.13 3.14]</text><text
class="breeze-release-management-generate-constraints-r6" x="512.4" y="532.4"
textLe [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="556.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-22)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="556.8"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-22)">--run-in-parallel</text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="556.8"
textLength="854" clip-p [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="581.2" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-23)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="581.2"
textLength="207.4"
clip-path="url(#breeze-release-management-generate-constraints-line-23)">--skip-cleanup   </text><text
class="breeze-release-management-generate-constraints-r1" x="256.2" y="581.2"
textLeng [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="605.6" textLength="1464"
clip-path="url(#breeze-release-management-generate-constraints-line-24)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-release-management-generate-constraints-r1" x="1464" y="605.6"
textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-24)">
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="630" textLength="24.4"
clip-path="url(#breeze-release-management-generate-constraints-line-25)">╭─</text><text
class="breeze-release-management-generate-constraints-r5" x="24.4" y="630"
textLength="195.2"
clip-path="url(#breeze-release-management-generate-constraints-line-25)"> Common options </text><text
class="breeze-release-management-generate-constraints-r5" x="219.6" y="630"
textLength="12 [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="654.4" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-26)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="654.4"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-26)">--verbose</text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="654.4"
textLength="24.4" clip-path="ur [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="678.8" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-27)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="678.8"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-27)">--dry-run</text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="678.8"
textLength="24.4" clip-path="ur [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="703.2" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-28)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="703.2"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-28)">--answer </text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="703.2"
textLength="24.4" clip-pat [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="727.6" textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-29)">│</text><text
class="breeze-release-management-generate-constraints-r4" x="24.4" y="727.6"
textLength="109.8"
clip-path="url(#breeze-release-management-generate-constraints-line-29)">--help   </text><text
class="breeze-release-management-generate-constraints-r7" x="158.6" y="727.6"
textLength="24.4 [...]
+</text><text class="breeze-release-management-generate-constraints-r5" x="0"
y="752" textLength="1464"
clip-path="url(#breeze-release-management-generate-constraints-line-30)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-release-management-generate-constraints-r1" x="1464" y="752"
textLength="12.2"
clip-path="url(#breeze-release-management-generate-constraints-line-30)">
</text>
</g>
</g>
diff --git
a/dev/breeze/doc/images/output_release-management_generate-constraints.txt
b/dev/breeze/doc/images/output_release-management_generate-constraints.txt
index 6b4ef06da4a..6328985d0ee 100644
--- a/dev/breeze/doc/images/output_release-management_generate-constraints.txt
+++ b/dev/breeze/doc/images/output_release-management_generate-constraints.txt
@@ -1 +1 @@
-8f5434ddc6564b1a2b026a63424eecea
+ab2a920a9c7ec445e7edd70051af73e1
diff --git a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg
b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg
index 202eba652be..938ff18d355 100644
--- a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg
+++ b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1245.6"
xmlns="http://www.w3.org/2000/svg">
+<svg class="rich-terminal" viewBox="0 0 1482 1270.0"
xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -43,7 +43,7 @@
<defs>
<clipPath id="breeze-setup-check-all-params-in-groups-clip-terminal">
- <rect x="0" y="0" width="1463.0" height="1194.6" />
+ <rect x="0" y="0" width="1463.0" height="1219.0" />
</clipPath>
<clipPath id="breeze-setup-check-all-params-in-groups-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -189,9 +189,12 @@
<clipPath id="breeze-setup-check-all-params-in-groups-line-47">
<rect x="0" y="1148.3" width="1464" height="24.65"/>
</clipPath>
+<clipPath id="breeze-setup-check-all-params-in-groups-line-48">
+ <rect x="0" y="1172.7" width="1464" height="24.65"/>
+ </clipPath>
</defs>
- <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="1243.6" rx="8"/><text
class="breeze-setup-check-all-params-in-groups-title" fill="#c5c8c6"
text-anchor="middle" x="740"
y="27">Command: setup check-all-params-in-groups</text>
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="1268" rx="8"/><text
class="breeze-setup-check-all-params-in-groups-title" fill="#c5c8c6"
text-anchor="middle" x="740"
y="27">Command: setup check-all-params-in-groups</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -243,13 +246,14 @@
</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="971.6" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-39)">│</text><text
class="breeze-setup-check-all-params-in-groups-r6" x="158.6" y="971.6"
textLength="890.6"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-39)">testing:core-tests | testing:docker-compose-tests | testing:helm-tests | </text><text
class="breeze-setup-check-all-params-in-gr [...]
</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="996"
textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-40)">│</text><text
class="breeze-setup-check-all-params-in-groups-r6" x="158.6" y="996"
textLength="1195.6"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-40)">testing:providers-integration-tests | testing:providers-tests | testing:python-api-client-tests | </text><text
class="breeze-setup- [...]
</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1020.4" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-41)">│</text><text
class="breeze-setup-check-all-params-in-groups-r6" x="158.6" y="1020.4"
textLength="1281"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-41)">testing:system-tests | testing:task-sdk-integration-tests | testing:task-sdk-tests | testing:ui-e2e-tests</text><text
class="br [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1044.8" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-42)">│</text><text
class="breeze-setup-check-all-params-in-groups-r6" x="158.6" y="1044.8"
textLength="1268.8"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-42)">| ui | ui:check-translation-completeness | ui:compile-assets | workflow-run | workflow-run:publish-docs)</text
[...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1069.2" textLength="1464"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-43)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="1069.2"
textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-43)">
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1093.6" textLength="24.4"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-44)">╭─</text><text
class="breeze-setup-check-all-params-in-groups-r5" x="24.4" y="1093.6"
textLength="195.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-44)"> Common options </text><text
class="breeze-setup-check-all-params-in-groups-r5" x="219.6" y="1093.6"
textLength="1220" clip-path="url(#breeze [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="1118"
textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-45)">│</text><text
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="1118"
textLength="109.8"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-45)">--verbose</text><text
class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="1118"
textLength="24.4" clip-path="url(#breeze-setup-check-all-params-in-gr [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1142.4" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-46)">│</text><text
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="1142.4"
textLength="109.8"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-46)">--dry-run</text><text
class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="1142.4"
textLength="24.4" clip-path="url(#breeze-setup-check-all-params [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1166.8" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-47)">│</text><text
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="1166.8"
textLength="109.8"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-47)">--help   </text><text
class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="1166.8"
textLength="24.4" clip-path="url(#breeze-setup-c [...]
-</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1191.2" textLength="1464"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-48)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="1191.2"
textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-48)">
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1044.8" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-42)">│</text><text
class="breeze-setup-check-all-params-in-groups-r6" x="158.6" y="1044.8"
textLength="1281"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-42)">| ui | ui:check-translation-completeness | ui:compile-assets | workflow-run | workflow-run:publish-docs |</
[...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1069.2" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-43)">│</text><text
class="breeze-setup-check-all-params-in-groups-r6" x="158.6" y="1069.2"
textLength="402.6"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-43)">workflow-run:release-constraints)</text><text
class="breeze-setup-check-all-params-in-groups-r5" x="1451.8" y="1069.2"
textLength="12.2" clip-path="url(#bre [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1093.6" textLength="1464"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-44)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="1093.6"
textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-44)">
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0" y="1118"
textLength="24.4"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-45)">╭─</text><text
class="breeze-setup-check-all-params-in-groups-r5" x="24.4" y="1118"
textLength="195.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-45)"> Common options </text><text
class="breeze-setup-check-all-params-in-groups-r5" x="219.6" y="1118"
textLength="1220" clip-path="url(#breeze-setup [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1142.4" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-46)">│</text><text
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="1142.4"
textLength="109.8"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-46)">--verbose</text><text
class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="1142.4"
textLength="24.4" clip-path="url(#breeze-setup-check-all-params [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1166.8" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-47)">│</text><text
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="1166.8"
textLength="109.8"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-47)">--dry-run</text><text
class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="1166.8"
textLength="24.4" clip-path="url(#breeze-setup-check-all-params [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1191.2" textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-48)">│</text><text
class="breeze-setup-check-all-params-in-groups-r4" x="24.4" y="1191.2"
textLength="109.8"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-48)">--help   </text><text
class="breeze-setup-check-all-params-in-groups-r7" x="158.6" y="1191.2"
textLength="24.4" clip-path="url(#breeze-setup-c [...]
+</text><text class="breeze-setup-check-all-params-in-groups-r5" x="0"
y="1215.6" textLength="1464"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-49)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-setup-check-all-params-in-groups-r1" x="1464" y="1215.6"
textLength="12.2"
clip-path="url(#breeze-setup-check-all-params-in-groups-line-49)">
</text>
</g>
</g>
diff --git a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt
b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt
index 92e75f17fd4..6987a59efd8 100644
--- a/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt
+++ b/dev/breeze/doc/images/output_setup_check-all-params-in-groups.txt
@@ -1 +1 @@
-fc5f65d76377357873c6b3ea200f2ec8
+b52151d5b1fb9ecfd92edf910750f0ee
diff --git a/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
b/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
index de56522e818..8b96e56ba30 100644
--- a/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
+++ b/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
@@ -261,7 +261,7 @@
</text><text class="breeze-setup-regenerate-command-images-r5" x="0"
y="1044.8" textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-42)">│</text><text
class="breeze-setup-regenerate-command-images-r6" x="195.2" y="1044.8"
textLength="1037"
clip-path="url(#breeze-setup-regenerate-command-images-line-42)">testing:helm-tests | testing:providers-integration-tests | testing:providers-tests | </text><text
class="breeze-setup-regenerate-co [...]
</text><text class="breeze-setup-regenerate-command-images-r5" x="0"
y="1069.2" textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-43)">│</text><text
class="breeze-setup-regenerate-command-images-r6" x="195.2" y="1069.2"
textLength="1146.8"
clip-path="url(#breeze-setup-regenerate-command-images-line-43)">testing:python-api-client-tests | testing:system-tests | testing:task-sdk-integration-tests | </text><text
class="breeze-setup-re [...]
</text><text class="breeze-setup-regenerate-command-images-r5" x="0"
y="1093.6" textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-44)">│</text><text
class="breeze-setup-regenerate-command-images-r6" x="195.2" y="1093.6"
textLength="1085.8"
clip-path="url(#breeze-setup-regenerate-command-images-line-44)">testing:task-sdk-tests | testing:ui-e2e-tests | ui | ui:check-translation-completeness | </text><text
class="breeze-set [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="1118"
textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-45)">│</text><text
class="breeze-setup-regenerate-command-images-r6" x="195.2" y="1118"
textLength="744.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-45)">ui:compile-assets | workflow-run | workflow-run:publish-docs)</text><text
class="breeze-setup-regenerate-command-images-r5" x="1451.8" y="1118" [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="1118"
textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-45)">│</text><text
class="breeze-setup-regenerate-command-images-r6" x="195.2" y="1118"
textLength="1171.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-45)">ui:compile-assets | workflow-run | workflow-run:publish-docs | workflow-run:release-constraints)</text><text
class="breeze-setup-rege [...]
</text><text class="breeze-setup-regenerate-command-images-r5" x="0"
y="1142.4" textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-46)">│</text><text
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="1142.4"
textLength="146.4"
clip-path="url(#breeze-setup-regenerate-command-images-line-46)">--check-only</text><text
class="breeze-setup-regenerate-command-images-r1" x="195.2" y="1142.4"
textLength="1244.4" clip-path="url(#breeze-setup-regenerate-comma [...]
</text><text class="breeze-setup-regenerate-command-images-r5" x="0"
y="1166.8" textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-47)">│</text><text
class="breeze-setup-regenerate-command-images-r1" x="195.2" y="1166.8"
textLength="170.8"
clip-path="url(#breeze-setup-regenerate-command-images-line-47)">together with </text><text
class="breeze-setup-regenerate-command-images-r4" x="366" y="1166.8"
textLength="109.8" clip-path="url(#breeze-setup-regene [...]
</text><text class="breeze-setup-regenerate-command-images-r5" x="0"
y="1191.2" textLength="1464"
clip-path="url(#breeze-setup-regenerate-command-images-line-48)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-setup-regenerate-command-images-r1" x="1464" y="1191.2"
textLength="12.2"
clip-path="url(#breeze-setup-regenerate-command-images-line-48)">
diff --git a/dev/breeze/doc/images/output_setup_regenerate-command-images.txt
b/dev/breeze/doc/images/output_setup_regenerate-command-images.txt
index fe2e502097d..ac7e52d52bf 100644
--- a/dev/breeze/doc/images/output_setup_regenerate-command-images.txt
+++ b/dev/breeze/doc/images/output_setup_regenerate-command-images.txt
@@ -1 +1 @@
-141b4bc2fbf13eddd1301de1064bf9fe
+fadc598c6c80132f76537b23c462e6ed
diff --git a/dev/breeze/doc/images/output_workflow-run.svg
b/dev/breeze/doc/images/output_workflow-run.svg
index af211f19a8e..f8f7cb779f0 100644
--- a/dev/breeze/doc/images/output_workflow-run.svg
+++ b/dev/breeze/doc/images/output_workflow-run.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 318.4"
xmlns="http://www.w3.org/2000/svg">
+<svg class="rich-terminal" viewBox="0 0 1482 342.79999999999995"
xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -42,7 +42,7 @@
<defs>
<clipPath id="breeze-workflow-run-clip-terminal">
- <rect x="0" y="0" width="1463.0" height="267.4" />
+ <rect x="0" y="0" width="1463.0" height="291.79999999999995" />
</clipPath>
<clipPath id="breeze-workflow-run-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -74,9 +74,12 @@
<clipPath id="breeze-workflow-run-line-9">
<rect x="0" y="221.1" width="1464" height="24.65"/>
</clipPath>
+<clipPath id="breeze-workflow-run-line-10">
+ <rect x="0" y="245.5" width="1464" height="24.65"/>
+ </clipPath>
</defs>
- <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="316.4" rx="8"/><text
class="breeze-workflow-run-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: workflow-run</text>
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="340.8" rx="8"/><text
class="breeze-workflow-run-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: workflow-run</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -95,8 +98,9 @@
</text><text class="breeze-workflow-run-r5" x="0" y="166.4" textLength="12.2"
clip-path="url(#breeze-workflow-run-line-6)">│</text><text
class="breeze-workflow-run-r4" x="24.4" y="166.4" textLength="73.2"
clip-path="url(#breeze-workflow-run-line-6)">--help</text><text
class="breeze-workflow-run-r6" x="122" y="166.4" textLength="24.4"
clip-path="url(#breeze-workflow-run-line-6)">-h</text><text
class="breeze-workflow-run-r1" x="170.8" y="166.4" textLength="329.4"
clip-path="url(#breeze-wor [...]
</text><text class="breeze-workflow-run-r5" x="0" y="190.8" textLength="1464"
clip-path="url(#breeze-workflow-run-line-7)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-workflow-run-r1" x="1464" y="190.8" textLength="12.2"
clip-path="url(#breeze-workflow-run-line-7)">
</text><text class="breeze-workflow-run-r5" x="0" y="215.2" textLength="24.4"
clip-path="url(#breeze-workflow-run-line-8)">╭─</text><text
class="breeze-workflow-run-r5" x="24.4" y="215.2" textLength="512.4"
clip-path="url(#breeze-workflow-run-line-8)"> Airflow github actions workflow commands </text><text
class="breeze-workflow-run-r5" x="536.8" y="215.2" textLength="902.8"
clip-path="url(#breeze-workflow-run-line-8)">────────────────────────────────────────
[...]
-</text><text class="breeze-workflow-run-r5" x="0" y="239.6" textLength="12.2"
clip-path="url(#breeze-workflow-run-line-9)">│</text><text
class="breeze-workflow-run-r4" x="24.4" y="239.6" textLength="366"
clip-path="url(#breeze-workflow-run-line-9)">publish-docs                  </text><text
class="breeze-workflow-run-r1" x="414.8" y="239.6" textLength="1024.8"
clip-path="url(#breeze-workflow-run-lin [...]
-</text><text class="breeze-workflow-run-r5" x="0" y="264" textLength="1464"
clip-path="url(#breeze-workflow-run-line-10)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-workflow-run-r1" x="1464" y="264" textLength="12.2"
clip-path="url(#breeze-workflow-run-line-10)">
+</text><text class="breeze-workflow-run-r5" x="0" y="239.6" textLength="12.2"
clip-path="url(#breeze-workflow-run-line-9)">│</text><text
class="breeze-workflow-run-r4" x="24.4" y="239.6" textLength="256.2"
clip-path="url(#breeze-workflow-run-line-9)">publish-docs         </text><text
class="breeze-workflow-run-r1" x="305" y="239.6" textLength="1134.6"
clip-path="url(#breeze-workflow-run-line-9)">Trigger publish docs to S3&#
[...]
+</text><text class="breeze-workflow-run-r5" x="0" y="264" textLength="12.2"
clip-path="url(#breeze-workflow-run-line-10)">│</text><text
class="breeze-workflow-run-r4" x="24.4" y="264" textLength="256.2"
clip-path="url(#breeze-workflow-run-line-10)">release-constraints  </text><text
class="breeze-workflow-run-r1" x="305" y="264" textLength="1134.6"
clip-path="url(#breeze-workflow-run-line-10)">Trigger the workflow that resolves, publishes and t
[...]
+</text><text class="breeze-workflow-run-r5" x="0" y="288.4" textLength="1464"
clip-path="url(#breeze-workflow-run-line-11)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-workflow-run-r1" x="1464" y="288.4" textLength="12.2"
clip-path="url(#breeze-workflow-run-line-11)">
</text>
</g>
</g>
diff --git a/dev/breeze/doc/images/output_workflow-run.txt
b/dev/breeze/doc/images/output_workflow-run.txt
index 096f1b4e226..606ed71654d 100644
--- a/dev/breeze/doc/images/output_workflow-run.txt
+++ b/dev/breeze/doc/images/output_workflow-run.txt
@@ -1 +1 @@
-348e7af5d380b4c7dd9452e48dfc4abf
+cfbf0a5234b3a9689a01d164e3e91abf
diff --git a/dev/breeze/doc/images/output_workflow-run_release-constraints.svg
b/dev/breeze/doc/images/output_workflow-run_release-constraints.svg
new file mode 100644
index 00000000000..e20e2d2696b
--- /dev/null
+++ b/dev/breeze/doc/images/output_workflow-run_release-constraints.svg
@@ -0,0 +1,138 @@
+<svg class="rich-terminal" viewBox="0 0 1482 513.5999999999999"
xmlns="http://www.w3.org/2000/svg">
+ <!-- Generated with Rich https://www.textualize.io -->
+ <style>
+
+ @font-face {
+ font-family: "Fira Code";
+ src: local("FiraCode-Regular"),
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2")
format("woff2"),
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff")
format("woff");
+ font-style: normal;
+ font-weight: 400;
+ }
+ @font-face {
+ font-family: "Fira Code";
+ src: local("FiraCode-Bold"),
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2")
format("woff2"),
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff")
format("woff");
+ font-style: bold;
+ font-weight: 700;
+ }
+
+ .breeze-workflow-run-release-constraints-matrix {
+ font-family: Fira Code, monospace;
+ font-size: 20px;
+ line-height: 24.4px;
+ font-variant-east-asian: full-width;
+ }
+
+ .breeze-workflow-run-release-constraints-title {
+ font-size: 18px;
+ font-weight: bold;
+ font-family: arial;
+ }
+
+ .breeze-workflow-run-release-constraints-r1 { fill: #c5c8c6 }
+.breeze-workflow-run-release-constraints-r2 { fill: #d0b344 }
+.breeze-workflow-run-release-constraints-r3 { fill: #c5c8c6;font-weight: bold }
+.breeze-workflow-run-release-constraints-r4 { fill: #68a0b3;font-weight: bold }
+.breeze-workflow-run-release-constraints-r5 { fill: #868887 }
+.breeze-workflow-run-release-constraints-r6 { fill: #cc555a }
+.breeze-workflow-run-release-constraints-r7 { fill: #8a4346 }
+.breeze-workflow-run-release-constraints-r8 { fill: #8d7b39 }
+.breeze-workflow-run-release-constraints-r9 { fill: #98a84b;font-weight: bold }
+ </style>
+
+ <defs>
+ <clipPath id="breeze-workflow-run-release-constraints-clip-terminal">
+ <rect x="0" y="0" width="1463.0" height="462.59999999999997" />
+ </clipPath>
+ <clipPath id="breeze-workflow-run-release-constraints-line-0">
+ <rect x="0" y="1.5" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-1">
+ <rect x="0" y="25.9" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-2">
+ <rect x="0" y="50.3" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-3">
+ <rect x="0" y="74.7" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-4">
+ <rect x="0" y="99.1" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-5">
+ <rect x="0" y="123.5" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-6">
+ <rect x="0" y="147.9" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-7">
+ <rect x="0" y="172.3" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-8">
+ <rect x="0" y="196.7" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-9">
+ <rect x="0" y="221.1" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-10">
+ <rect x="0" y="245.5" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-11">
+ <rect x="0" y="269.9" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-12">
+ <rect x="0" y="294.3" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-13">
+ <rect x="0" y="318.7" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-14">
+ <rect x="0" y="343.1" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-15">
+ <rect x="0" y="367.5" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-16">
+ <rect x="0" y="391.9" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-workflow-run-release-constraints-line-17">
+ <rect x="0" y="416.3" width="1464" height="24.65"/>
+ </clipPath>
+ </defs>
+
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="511.6" rx="8"/><text
class="breeze-workflow-run-release-constraints-title" fill="#c5c8c6"
text-anchor="middle" x="740"
y="27">Command: workflow-run release-constraints</text>
+ <g transform="translate(26,22)">
+ <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
+ <circle cx="22" cy="0" r="7" fill="#febc2e"/>
+ <circle cx="44" cy="0" r="7" fill="#28c840"/>
+ </g>
+
+ <g transform="translate(9, 41)"
clip-path="url(#breeze-workflow-run-release-constraints-clip-terminal)">
+
+ <g class="breeze-workflow-run-release-constraints-matrix">
+ <text class="breeze-workflow-run-release-constraints-r1" x="1464" y="20"
textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-0)">
+</text><text class="breeze-workflow-run-release-constraints-r2" x="12.2"
y="44.4" textLength="73.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-1)">Usage:</text><text
class="breeze-workflow-run-release-constraints-r3" x="97.6" y="44.4"
textLength="475.8"
clip-path="url(#breeze-workflow-run-release-constraints-line-1)">breeze workflow-run release-constraints</text><text
class="breeze-workflow-run-release-constraints-r1" x="585.6" y="44.4"
textLength="12.2" clip- [...]
+</text><text class="breeze-workflow-run-release-constraints-r1" x="1464"
y="68.8" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-2)">
+</text><text class="breeze-workflow-run-release-constraints-r1" x="12.2"
y="93.2" textLength="1037"
clip-path="url(#breeze-workflow-run-release-constraints-line-3)">Trigger the workflow that resolves, publishes and tags the constraints for a release.</text><text
class="breeze-workflow-run-release-constraints-r1" x="1464" y="93.2"
textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-3)">
+</text><text class="breeze-workflow-run-release-constraints-r1" x="1464"
y="117.6" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-4)">
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0" y="142"
textLength="24.4"
clip-path="url(#breeze-workflow-run-release-constraints-line-5)">╭─</text><text
class="breeze-workflow-run-release-constraints-r5" x="24.4" y="142"
textLength="292.8"
clip-path="url(#breeze-workflow-run-release-constraints-line-5)"> Constraints to resolve </text><text
class="breeze-workflow-run-release-constraints-r5" x="317.2" y="142"
textLength="1122.4" clip-path="url(#br [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="166.4" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-6)">│</text><text
class="breeze-workflow-run-release-constraints-r6" x="24.4" y="166.4"
textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-6)">*</text><text
class="breeze-workflow-run-release-constraints-r4" x="61" y="166.4"
textLength="207.4"
clip-path="url(#breeze-workflow-run-release-constraints-line- [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="190.8" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-7)">│</text><text
class="breeze-workflow-run-release-constraints-r1" x="292.8" y="190.8"
textLength="1146.8"
clip-path="url(#breeze-workflow-run-release-constraints-line-7)">and lands on a branch of its own; a final (3.1.3) resolves without them and commits&
[...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="215.2" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-8)">│</text><text
class="breeze-workflow-run-release-constraints-r1" x="292.8" y="215.2"
textLength="1146.8"
clip-path="url(#breeze-workflow-run-release-constraints-line-8)">constraints-X-Y. The stage is derived from this, so it cannot be set inconsistently.  
[...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="239.6" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-9)">│</text><text
class="breeze-workflow-run-release-constraints-r7" x="292.8" y="239.6"
textLength="122"
clip-path="url(#breeze-workflow-run-release-constraints-line-9)">[required]</text><text
class="breeze-workflow-run-release-constraints-r8" x="427" y="239.6"
textLength="73.2" clip-path="url(#breeze-workflow-run-release-constrai [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0" y="264"
textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-10)">│</text><text
class="breeze-workflow-run-release-constraints-r6" x="24.4" y="264"
textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-10)">*</text><text
class="breeze-workflow-run-release-constraints-r4" x="61" y="264"
textLength="207.4"
clip-path="url(#breeze-workflow-run-release-constraints-line-10)" [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="288.4" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-11)">│</text><text
class="breeze-workflow-run-release-constraints-r8" x="292.8" y="288.4"
textLength="73.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-11)">(TEXT)</text><text
class="breeze-workflow-run-release-constraints-r5" x="1451.8" y="288.4"
textLength="12.2" clip-path="url(#breeze-workflow-run-release-constr [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="312.8" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-12)">│</text><text
class="breeze-workflow-run-release-constraints-r4" x="61" y="312.8"
textLength="207.4"
clip-path="url(#breeze-workflow-run-release-constraints-line-12)">--workflow-branch</text><text
class="breeze-workflow-run-release-constraints-r1" x="292.8" y="312.8"
textLength="1146.8" clip-path="url(#breeze-workflow-run-rele [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="337.2" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-13)">│</text><text
class="breeze-workflow-run-release-constraints-r1" x="292.8" y="337.2"
textLength="1146.8"
clip-path="url(#breeze-workflow-run-release-constraints-line-13)">want: unlike the docs build, the constraints do not have to be produced by the wor
[...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="361.6" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-14)">│</text><text
class="breeze-workflow-run-release-constraints-r1" x="292.8" y="361.6"
textLength="402.6"
clip-path="url(#breeze-workflow-run-release-constraints-line-14)">stood at the ref being released. </text><text
class="breeze-workflow-run-release-constraints-r5" x="695.4" y="361.6"
textLength= [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0" y="386"
textLength="1464"
clip-path="url(#breeze-workflow-run-release-constraints-line-15)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-workflow-run-release-constraints-r1" x="1464" y="386"
textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-15)">
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="410.4" textLength="24.4"
clip-path="url(#breeze-workflow-run-release-constraints-line-16)">╭─</text><text
class="breeze-workflow-run-release-constraints-r5" x="24.4" y="410.4"
textLength="195.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-16)"> Common options </text><text
class="breeze-workflow-run-release-constraints-r5" x="219.6" y="410.4"
textLength="1220" clip-path="url(#breeze-wo [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="434.8" textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-17)">│</text><text
class="breeze-workflow-run-release-constraints-r4" x="24.4" y="434.8"
textLength="73.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-17)">--help</text><text
class="breeze-workflow-run-release-constraints-r9" x="122" y="434.8"
textLength="24.4" clip-path="url(#breeze-workflow-run-release-constraint [...]
+</text><text class="breeze-workflow-run-release-constraints-r5" x="0"
y="459.2" textLength="1464"
clip-path="url(#breeze-workflow-run-release-constraints-line-18)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-workflow-run-release-constraints-r1" x="1464" y="459.2"
textLength="12.2"
clip-path="url(#breeze-workflow-run-release-constraints-line-18)">
+</text>
+ </g>
+ </g>
+</svg>
diff --git a/dev/breeze/doc/images/output_workflow-run_release-constraints.txt
b/dev/breeze/doc/images/output_workflow-run_release-constraints.txt
new file mode 100644
index 00000000000..871ae3667b4
--- /dev/null
+++ b/dev/breeze/doc/images/output_workflow-run_release-constraints.txt
@@ -0,0 +1 @@
+14273c8c9c667e0004c0a1379d53da58
diff --git
a/dev/breeze/src/airflow_breeze/commands/release_candidate_command.py
b/dev/breeze/src/airflow_breeze/commands/release_candidate_command.py
index 5175e6e40ce..f6ac278bb35 100644
--- a/dev/breeze/src/airflow_breeze/commands/release_candidate_command.py
+++ b/dev/breeze/src/airflow_breeze/commands/release_candidate_command.py
@@ -49,6 +49,7 @@ from airflow_breeze.utils.path_utils import (
AIRFLOW_ROOT_PATH,
OUT_PATH,
)
+from airflow_breeze.utils.release_constraints import publish_constraints
from airflow_breeze.utils.reproducible import get_source_date_epoch,
repack_deterministically
from airflow_breeze.utils.run_utils import run_command
from airflow_breeze.utils.shared_options import get_dry_run
@@ -442,28 +443,10 @@ def sign_the_release(repo_root):
console_print("[success]Release signed")
-def tag_and_push_constraints(version, version_branch, remote_name):
- if confirm_action("Do you want to tag and push constraints?"):
- run_command(
- ["git", "checkout", f"{remote_name}/constraints-{version_branch}"],
- check=True,
- )
- run_command(
- [
- "git",
- "tag",
- "-s",
- f"constraints-{version}",
- "-m",
- f"Constraints for Apache Airflow {version}",
- ],
- check=True,
- )
- run_command(
- ["git", "push", remote_name, "tag", f"constraints-{version}"],
- check=True,
- )
- console_print("[success]Constraints tagged and pushed")
+def generate_and_push_constraints(version, version_branch):
+ # Resolved from the stable branch the candidate was cut from, so the
constraints describe the
+ # sources being voted on. The workflow reads "rcN" and allows pre-releases
accordingly.
+ publish_constraints(version=version, ref=f"v{version_branch}-stable")
def clone_asf_repo(version, repo_root):
@@ -845,8 +828,8 @@ def publish_release_candidate(
test_airflow()
# Sign the release
sign_the_release(airflow_repo_root)
- # Tag and push constraints
- tag_and_push_constraints(version, version_branch, remote_name)
+ # Generate, publish and tag the constraints for this candidate
+ generate_and_push_constraints(version, version_branch)
# Clone the asf repo
clone_asf_repo(version, airflow_repo_root)
# Move artifacts to SVN
diff --git a/dev/breeze/src/airflow_breeze/commands/release_command.py
b/dev/breeze/src/airflow_breeze/commands/release_command.py
index 1b93f9c28ac..ffa97a01f63 100644
--- a/dev/breeze/src/airflow_breeze/commands/release_command.py
+++ b/dev/breeze/src/airflow_breeze/commands/release_command.py
@@ -29,6 +29,7 @@ from airflow_breeze.utils.confirm import confirm_action
from airflow_breeze.utils.console import console_print
from airflow_breeze.utils.environment_check import is_ci_environment
from airflow_breeze.utils.path_utils import AIRFLOW_ROOT_PATH
+from airflow_breeze.utils.release_constraints import publish_constraints
from airflow_breeze.utils.run_utils import run_command
# Pattern to match Airflow release versions (e.g., "3.0.5")
@@ -343,45 +344,12 @@ def upload_to_pypi(version, task_sdk_version=None):
)
-def get_constraints_branch_for_version(version: str) -> str:
+def regenerate_constraints(version):
+ # The candidate's constraints pinned pre-releases, so they cannot be
promoted by retagging - a
+ # released version must never point at rc pins. The workflow reads a
version without "rcN" and
+ # resolves again without them, against the providers now published as
finals.
major, minor = version.split(".")[:2]
- return f"constraints-{major}-{minor}"
-
-
-def retag_constraints(release_candidate, version):
- # By default the final ``constraints-<version>`` tag is created from the
RC constraints tag.
- # If the constraints were refreshed after the last RC (e.g. to pick up
newly released
- # providers - see dev/MANUALLY_GENERATING_IMAGE_CACHE_AND_CONSTRAINTS.md)
the tip of the
- # ``constraints-X-Y`` branch is newer than the RC tag and should be tagged
instead.
- constraints_branch = get_constraints_branch_for_version(version)
- source_ref = f"constraints-{release_candidate}"
- if confirm_action(
- f"Base the final constraints on the latest '{constraints_branch}'
branch tip instead of the "
- f"'{source_ref}' tag? Choose yes if you refreshed constraints after
{release_candidate}."
- ):
- run_command(["git", "fetch", "origin", constraints_branch], check=True)
- source_ref = f"origin/{constraints_branch}"
- if confirm_action(f"Retag constraints from {source_ref} as {version}?"):
- run_command(
- ["git", "checkout", source_ref],
- check=True,
- )
- run_command(
- [
- "git",
- "tag",
- "-s",
- f"constraints-{version}",
- "-m",
- f"Constraints for Apache Airflow {version}",
- ],
- check=True,
- )
- if confirm_action(f"Push constraints-{version} tag to GitHub?"):
- run_command(
- ["git", "push", "origin", "tag", f"constraints-{version}"],
- check=True,
- )
+ publish_constraints(version=version, ref=f"v{major}-{minor}-stable")
def tag_and_push_latest_constraint(version):
@@ -567,8 +535,8 @@ def airflow_release(version, task_sdk_version):
# Change Directory to airflow
os.chdir(airflow_repo_root)
- # Retag and push the constraint file
- retag_constraints(release_candidate, version)
+ # Regenerate, publish and tag the constraints for the final version
+ regenerate_constraints(version)
tag_and_push_latest_constraint(version)
# Push tag for final version
diff --git
a/dev/breeze/src/airflow_breeze/commands/release_management_commands.py
b/dev/breeze/src/airflow_breeze/commands/release_management_commands.py
index c7efa5a2fd3..52ed5a6001a 100644
--- a/dev/breeze/src/airflow_breeze/commands/release_management_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/release_management_commands.py
@@ -1548,6 +1548,7 @@ def tag_providers(
@option_debug_resources
@option_python_versions
@option_airflow_constraints_mode_ci
+@option_allow_pre_releases
@option_github_repository
@option_use_uv
@option_verbose
@@ -1555,6 +1556,7 @@ def tag_providers(
@option_answer
def generate_constraints(
airflow_constraints_mode: str,
+ allow_pre_releases: bool,
debug_resources: bool,
github_repository: str,
parallelism: int,
@@ -1599,6 +1601,7 @@ def generate_constraints(
shell_params_list = [
ShellParams(
airflow_constraints_mode=airflow_constraints_mode,
+ allow_pre_releases=allow_pre_releases,
github_repository=github_repository,
python=python,
use_uv=use_uv,
@@ -1617,6 +1620,7 @@ def generate_constraints(
else:
shell_params = ShellParams(
airflow_constraints_mode=airflow_constraints_mode,
+ allow_pre_releases=allow_pre_releases,
github_repository=github_repository,
python=python,
use_uv=use_uv,
diff --git
a/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py
b/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py
index 2acad7f44f8..ac59513cdfb 100644
---
a/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py
+++
b/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py
@@ -339,6 +339,7 @@ RELEASE_MANAGEMENT_PARAMETERS: dict[str, list[dict[str, str
| list[str]]]] = {
"name": "Generate constraints flags",
"options": [
"--airflow-constraints-mode",
+ "--allow-pre-releases",
"--github-repository",
"--python",
"--use-uv",
diff --git a/dev/breeze/src/airflow_breeze/commands/workflow_commands.py
b/dev/breeze/src/airflow_breeze/commands/workflow_commands.py
index 2330edfcba6..d6c98827b42 100644
--- a/dev/breeze/src/airflow_breeze/commands/workflow_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/workflow_commands.py
@@ -34,8 +34,13 @@ WORKFLOW_NAME_MAPS = {
"publish-docs": "publish-docs-to-s3.yml",
"airflow-refresh-site": "build.yml",
"sync-s3-to-github": "s3-to-github.yml",
+ "release-constraints": "release-constraints.yml",
}
+# X.Y.Z or X.Y.ZrcN - the workflow derives the release stage from which of the
two it is given,
+# so there is no separate switch that could disagree with the version.
+RELEASE_VERSION_PATTERN = re.compile(r"^\d+\.\d+\.\d+(rc\d+)?$")
+
APACHE_AIRFLOW_REPO = "apache/airflow"
APACHE_AIRFLOW_SITE_REPO = "apache/airflow-site"
APACHE_AIRFLOW_SITE_ARCHIVE_REPO = "apache/airflow-site-archive"
@@ -272,3 +277,42 @@ def workflow_run_publish(
**workflow_fields,
monitor=False,
)
+
+
+@workflow_run_group.command(
+ name="release-constraints",
+ help="Trigger the workflow that resolves, publishes and tags the
constraints for a release.",
+)
[email protected](
+ "--version",
+ help="Version the constraints belong to. A candidate (3.1.3rc1) resolves
with pre-releases "
+ "allowed and lands on a branch of its own; a final (3.1.3) resolves
without them and commits "
+ "onto constraints-X-Y. The stage is derived from this, so it cannot be set
inconsistently.",
+ required=True,
+)
[email protected](
+ "--ref",
+ help="Git ref the constraints are resolved from, e.g. 'v3-1-stable' or the
release tag.",
+ required=True,
+)
[email protected](
+ "--workflow-branch",
+ help="Git ref the workflow DEFINITION runs from. Defaults to 'main', which
is normally what "
+ "you want: unlike the docs build, the constraints do not have to be
produced by the workflow "
+ "as it stood at the ref being released.",
+ default="main",
+ show_default=True,
+)
+def workflow_run_release_constraints(version: str, ref: str, workflow_branch:
str):
+ if not RELEASE_VERSION_PATTERN.match(version):
+ console_print(f"[red]Error: '{version}' is not a release version -
expected X.Y.Z or X.Y.ZrcN.[/red]")
+ sys.exit(1)
+ stage = "candidate" if "rc" in version else "final"
+ console_print(f"[blue]Triggering constraints generation for the {stage}
{version} from {ref}[/blue]")
+ trigger_workflow_and_monitor(
+ workflow_name=WORKFLOW_NAME_MAPS["release-constraints"],
+ repo=APACHE_AIRFLOW_REPO,
+ branch=workflow_branch,
+ version=version,
+ ref=ref,
+ )
diff --git a/dev/breeze/src/airflow_breeze/commands/workflow_commands_config.py
b/dev/breeze/src/airflow_breeze/commands/workflow_commands_config.py
index 239a5e46a6a..9c6d0c99277 100644
--- a/dev/breeze/src/airflow_breeze/commands/workflow_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/workflow_commands_config.py
@@ -18,7 +18,7 @@ from __future__ import annotations
WORKFLOW_RUN_COMMANDS: dict[str, str | list[str]] = {
"name": "Airflow github actions workflow commands",
- "commands": ["publish-docs"],
+ "commands": ["publish-docs", "release-constraints"],
}
WORKFLOW_RUN_PARAMETERS: dict[str, list[dict[str, str | list[str]]]] = {
@@ -55,3 +55,13 @@ WORKFLOW_RUN_PARAMETERS: dict[str, list[dict[str, str |
list[str]]]] = {
},
],
}
+WORKFLOW_RUN_PARAMETERS["breeze workflow-run release-constraints"] = [
+ {
+ "name": "Constraints to resolve",
+ "options": [
+ "--version",
+ "--ref",
+ "--workflow-branch",
+ ],
+ },
+]
diff --git a/dev/breeze/src/airflow_breeze/utils/release_constraints.py
b/dev/breeze/src/airflow_breeze/utils/release_constraints.py
new file mode 100644
index 00000000000..466ab689120
--- /dev/null
+++ b/dev/breeze/src/airflow_breeze/utils/release_constraints.py
@@ -0,0 +1,61 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""Handing the constraints of a release over to the workflow that resolves
them.
+
+A release used to tag whatever the ``constraints-X-Y`` branch happened to
hold, so the constraints
+shipped with a version were a resolution made by the last CI build rather than
one made for that
+version. They are resolved per release now, by the ``release-constraints``
workflow - on 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.
+
+The workflow derives the stage from the version it is given, so nothing here
has to pass a
+separate switch that could disagree with it.
+"""
+
+from __future__ import annotations
+
+from airflow_breeze.utils.confirm import confirm_action
+from airflow_breeze.utils.console import console_print
+from airflow_breeze.utils.gh_workflow_utils import trigger_workflow_and_monitor
+
+RELEASE_CONSTRAINTS_WORKFLOW = "release-constraints.yml"
+APACHE_AIRFLOW_REPO = "apache/airflow"
+
+
+def publish_constraints(*, version: str, ref: str, workflow_branch: str =
"main") -> None:
+ """Resolve, publish and tag the constraints belonging to ``version``.
+
+ ``version`` alone decides what happens: a candidate (``3.1.3rc1``)
resolves with pre-releases
+ allowed - the providers of the wave being voted on are on PyPI only as rc
versions - and lands
+ on a branch of its own, leaving the branch every other build reads where
it was. A final
+ (``3.1.3``) resolves without them and commits onto ``constraints-X-Y``,
which is what makes the
+ released constraints the baseline everything downstream reads.
+ """
+ stage = "candidate" if "rc" in version else "final"
+ if not confirm_action(
+ f"Trigger the release-constraints workflow for the {stage} {version}
(resolved from {ref})?"
+ ):
+ return
+ console_print(f"[info]Resolving constraints for {version} from {ref} -
this runs on CI runners.")
+ trigger_workflow_and_monitor(
+ workflow_name=RELEASE_CONSTRAINTS_WORKFLOW,
+ repo=APACHE_AIRFLOW_REPO,
+ branch=workflow_branch,
+ version=version,
+ ref=ref,
+ )
+ console_print(f"[success]Constraints for {version} published and tagged
'constraints-{version}'")
diff --git a/dev/breeze/tests/test_release_command.py
b/dev/breeze/tests/test_release_command.py
index 1e023e6bf5b..c1d89193e4f 100644
--- a/dev/breeze/tests/test_release_command.py
+++ b/dev/breeze/tests/test_release_command.py
@@ -540,53 +540,22 @@ def
test_remove_old_release_no_task_sdk_version(monkeypatch, release_cmd):
assert chdir_calls == [svn_release_repo, "/original/dir"]
[email protected](
- ("version", "expected_branch"),
- [
- ("3.3.0", "constraints-3-3"),
- ("3.0.5", "constraints-3-0"),
- ("3.12.10", "constraints-3-12"),
- ],
-)
-def test_get_constraints_branch_for_version(release_cmd, version,
expected_branch):
- assert release_cmd.get_constraints_branch_for_version(version) ==
expected_branch
-
-
-def test_retag_constraints_from_rc_tag_by_default(monkeypatch, release_cmd):
- run_command_calls: list[list[str]] = []
-
- def fake_confirm_action(prompt: str, **_kwargs) -> bool:
- # Decline basing on the branch tip; accept the retag and the push.
- return not prompt.startswith("Base the final constraints on the
latest")
-
- monkeypatch.setattr(release_cmd, "confirm_action", fake_confirm_action)
- monkeypatch.setattr(release_cmd, "run_command", lambda cmd, **_kwargs:
run_command_calls.append(cmd))
-
- release_cmd.retag_constraints("3.3.0rc2", "3.3.0")
+def test_regenerate_constraints_resolves_from_the_stable_branch(monkeypatch,
release_cmd):
+ """The final release resolves from the branch it is cut from, not from
main."""
+ calls: dict[str, object] = {}
+ monkeypatch.setattr(release_cmd, "publish_constraints", lambda **kw:
calls.update(kw))
- assert ["git", "checkout", "constraints-3.3.0rc2"] in run_command_calls
- assert ["git", "tag", "-s", "constraints-3.3.0", "-m", "Constraints for
Apache Airflow 3.3.0"] in (
- run_command_calls
- )
- assert ["git", "push", "origin", "tag", "constraints-3.3.0"] in
run_command_calls
- # The branch tip is not fetched when basing on the RC tag.
- assert not any(cmd[:2] == ["git", "fetch"] for cmd in run_command_calls)
+ release_cmd.regenerate_constraints("3.3.0")
+ assert calls == {"version": "3.3.0", "ref": "v3-3-stable"}
-def test_retag_constraints_from_branch_tip_when_confirmed(monkeypatch,
release_cmd):
- run_command_calls: list[list[str]] = []
- def fake_confirm_action(prompt: str, **_kwargs) -> bool:
- return True
+def test_regenerate_constraints_passes_a_final_version(monkeypatch,
release_cmd):
+ """No rc suffix reaches the workflow, which is what makes it refuse
pre-releases."""
+ calls: dict[str, object] = {}
+ monkeypatch.setattr(release_cmd, "publish_constraints", lambda **kw:
calls.update(kw))
- monkeypatch.setattr(release_cmd, "confirm_action", fake_confirm_action)
- monkeypatch.setattr(release_cmd, "run_command", lambda cmd, **_kwargs:
run_command_calls.append(cmd))
-
- release_cmd.retag_constraints("3.3.0rc2", "3.3.0")
+ release_cmd.regenerate_constraints("3.0.5")
- assert ["git", "fetch", "origin", "constraints-3-3"] in run_command_calls
- assert ["git", "checkout", "origin/constraints-3-3"] in run_command_calls
- assert ["git", "checkout", "constraints-3.3.0rc2"] not in run_command_calls
- assert ["git", "tag", "-s", "constraints-3.3.0", "-m", "Constraints for
Apache Airflow 3.3.0"] in (
- run_command_calls
- )
+ assert "rc" not in str(calls["version"])
+ assert calls["ref"] == "v3-0-stable"
diff --git a/dev/breeze/tests/test_release_constraints.py
b/dev/breeze/tests/test_release_constraints.py
new file mode 100644
index 00000000000..db914d97722
--- /dev/null
+++ b/dev/breeze/tests/test_release_constraints.py
@@ -0,0 +1,91 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+import pytest
+
+from airflow_breeze.utils import release_constraints
+
+
[email protected]
+def triggered(monkeypatch):
+ """Capture what would have been dispatched, with the prompt answered
yes."""
+ calls: list[dict] = []
+ monkeypatch.setattr(release_constraints, "confirm_action", lambda *a,
**kw: True)
+ monkeypatch.setattr(
+ release_constraints, "trigger_workflow_and_monitor", lambda **kwargs:
calls.append(kwargs)
+ )
+ return calls
+
+
[email protected](
+ ("version", "ref"),
+ [
+ pytest.param("3.1.3rc1", "v3-1-stable", id="candidate"),
+ pytest.param("3.1.3", "v3-1-stable", id="final"),
+ ],
+)
+def test_version_and_ref_are_passed_through(triggered, version, ref):
+ release_constraints.publish_constraints(version=version, ref=ref)
+
+ assert len(triggered) == 1
+ assert triggered[0]["version"] == version
+ assert triggered[0]["ref"] == ref
+ assert triggered[0]["workflow_name"] == "release-constraints.yml"
+ assert triggered[0]["repo"] == "apache/airflow"
+
+
+def test_workflow_definition_defaults_to_main(triggered):
+ # Unlike the docs build, constraints need not be produced by the workflow
as it stood at the
+ # ref being released - so this defaults to main rather than to the ref.
+ release_constraints.publish_constraints(version="3.1.3", ref="v3-1-stable")
+
+ assert triggered[0]["branch"] == "main"
+
+
+def test_workflow_definition_can_be_overridden(triggered):
+ release_constraints.publish_constraints(
+ version="3.1.3", ref="v3-1-stable", workflow_branch="my-fix-branch"
+ )
+
+ assert triggered[0]["branch"] == "my-fix-branch"
+
+
+def test_nothing_is_dispatched_when_declined(monkeypatch, triggered):
+ monkeypatch.setattr(release_constraints, "confirm_action", lambda *a,
**kw: False)
+
+ release_constraints.publish_constraints(version="3.1.3", ref="v3-1-stable")
+
+ assert triggered == []
+
+
[email protected](
+ ("version", "expected_stage"),
+ [
+ pytest.param("3.1.3rc2", "candidate", id="rc-is-a-candidate"),
+ pytest.param("3.1.3", "final", id="plain-version-is-final"),
+ ],
+)
+def test_the_prompt_names_the_stage_the_version_implies(monkeypatch, version,
expected_stage):
+ """The stage is never passed separately, so the operator sees what the
version implies."""
+ prompts: list[str] = []
+ monkeypatch.setattr(release_constraints, "confirm_action", lambda prompt,
**kw: prompts.append(prompt))
+ monkeypatch.setattr(release_constraints, "trigger_workflow_and_monitor",
lambda **kw: None)
+
+ release_constraints.publish_constraints(version=version, ref="v3-1-stable")
+
+ assert expected_stage in prompts[0]
diff --git a/scripts/in_container/run_generate_constraints.py
b/scripts/in_container/run_generate_constraints.py
index 6310ec1a052..1089739c4be 100755
--- a/scripts/in_container/run_generate_constraints.py
+++ b/scripts/in_container/run_generate_constraints.py
@@ -130,6 +130,7 @@ PYPI_PROVIDERS_CONSTRAINTS_PREFIX = f"""
@dataclass
class ConfigParams:
airflow_constraints_mode: str
+ allow_pre_releases: bool
constraints_github_repository: str
default_constraints_branch: str
github_actions: bool
@@ -458,6 +459,19 @@ def get_all_active_provider_distributions(python_version:
str | None = None) ->
]
+def build_provider_pre_release_requirements(python_version: str) -> list[str]:
+ """Requirements that let only the providers resolve to a pre-release.
+
+ uv considers a pre-release for a package only when some requirement for it
mentions one, so a
+ pre-release lower bound on each provider confines the allowance to them.
`--pre` would apply to
+ the whole resolution and could put a pre-release of any third-party
dependency into the
+ constraints a release ships.
+ """
+ return [
+ f"{distribution}>=0.0.0rc0" for distribution in
get_all_active_provider_distributions(python_version)
+ ]
+
+
def generate_constraints_source_providers(config_params: ConfigParams) -> None:
"""
Generates constraints with provider dependencies used from current
sources. This might be different
@@ -521,6 +535,28 @@ def generate_constraints_pypi_providers(config_params:
ConfigParams) -> None:
"gremlinpython>=3.8.0",
]
+ # Constraints cut for a release candidate have to pin the candidates
themselves - the providers
+ # for that wave exist on PyPI only as rcN versions, and uv will not
resolve to a pre-release
+ # unless asked. The final release regenerates these without it, so a
released constraints file
+ # can never carry an rc pin.
+ #
+ # Scoped to the providers rather than passing `--pre`, which applies to
the whole resolution
+ # and would let any dependency answer with a pre-release - putting, say, a
beta of a
+ # third-party library into the constraints a release ships. uv has no
per-package pre-release
+ # flag, so the scoping is expressed the way it does support: `explicit`
permits a pre-release
+ # only for a package some requirement marks as such, and the rc lower
bound below is that mark.
+ # `explicit` rather than the default `if-necessary-or-explicit` also drops
the fallback that
+ # would otherwise let an unmarked package resolve to a pre-release when no
final satisfies.
+ pre_release_requirements: list[str] = []
+ pre_release_strategy: list[str] = []
+ if config_params.allow_pre_releases:
+ pre_release_requirements =
build_provider_pre_release_requirements(config_params.python)
+ pre_release_strategy = ["--prerelease", "explicit"]
+ console.print(
+ f"[bright_blue]Allowing pre-releases for
{len(pre_release_requirements)} provider "
+ "distributions - no other package can resolve to one."
+ )
+
result = run_command(
cmd=[
"uv",
@@ -534,6 +570,8 @@ def generate_constraints_pypi_providers(config_params:
ConfigParams) -> None:
f"apache-airflow-task-sdk=={AIRFLOW_TASK_SDK_VERSION}",
"./airflow-ctl",
*additional_constraints_for_highest_resolution,
+ *pre_release_requirements,
+ *pre_release_strategy,
"--reinstall", # We need to pull the provider distributions from
PyPI or dist, not the local ones
"--resolution",
"highest",
@@ -632,8 +670,17 @@ ALLOWED_CONSTRAINTS_MODES = ["constraints",
"constraints-source-providers", "con
help="Use uv instead of pip as packaging tool.",
envvar="USE_UV",
)
[email protected](
+ "--allow-pre-releases",
+ is_flag=True,
+ default=False,
+ help="Allow pre-release versions of Airflow and providers to be pinned.
Used when constraints "
+ "are generated for a release candidate, whose providers are only on PyPI
as rc versions.",
+ envvar="ALLOW_PRE_RELEASES",
+)
def generate_constraints(
airflow_constraints_mode: str,
+ allow_pre_releases: bool,
constraints_github_repository: str,
default_constraints_branch: str,
github_actions: bool,
@@ -642,6 +689,7 @@ def generate_constraints(
) -> None:
config_params = ConfigParams(
airflow_constraints_mode=airflow_constraints_mode,
+ allow_pre_releases=allow_pre_releases,
constraints_github_repository=constraints_github_repository,
default_constraints_branch=default_constraints_branch,
github_actions=github_actions,
diff --git a/scripts/tests/in_container/test_run_generate_constraints.py
b/scripts/tests/in_container/test_run_generate_constraints.py
index b2bd467faa3..88af9e84102 100644
--- a/scripts/tests/in_container/test_run_generate_constraints.py
+++ b/scripts/tests/in_container/test_run_generate_constraints.py
@@ -109,3 +109,42 @@ class TestCheckProvidersNotDowngraded:
latest.write_text("apache-airflow-providers-amazon==not-a-version\n")
current.write_text("apache-airflow-providers-amazon==also-bad\n")
m.check_providers_not_downgraded(_config(latest, current))
+
+
+class TestBuildProviderPreReleaseRequirements:
+ """Pre-releases are allowed for the providers only, never for the whole
resolution."""
+
+ def
test_every_requirement_names_a_provider_and_permits_a_pre_release(self,
monkeypatch):
+ monkeypatch.setattr(
+ m,
+ "get_all_active_provider_distributions",
+ lambda python_version=None: [
+ "apache-airflow-providers-amazon",
+ "apache-airflow-providers-cncf-kubernetes",
+ ],
+ )
+
+ requirements = m.build_provider_pre_release_requirements("3.10")
+
+ assert requirements == [
+ "apache-airflow-providers-amazon>=0.0.0rc0",
+ "apache-airflow-providers-cncf-kubernetes>=0.0.0rc0",
+ ]
+ # The rc lower bound is what marks the package as explicit to uv;
without it the
+ # requirement would not permit a pre-release at all.
+ assert all(requirement.endswith(">=0.0.0rc0") for requirement in
requirements)
+ assert all(requirement.startswith("apache-airflow-providers-") for
requirement in requirements)
+
+ def test_the_python_version_is_passed_through(self, monkeypatch):
+ """Providers excluded on a Python version must not be named for it."""
+ seen: list[str | None] = []
+
+ def fake_distributions(python_version=None):
+ seen.append(python_version)
+ return []
+
+ monkeypatch.setattr(m, "get_all_active_provider_distributions",
fake_distributions)
+
+ m.build_provider_pre_release_requirements("3.14")
+
+ assert seen == ["3.14"]