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 34e7129cda4 Add staging-to-main sync step to the release docs process 
(#73653)
34e7129cda4 is described below

commit 34e7129cda4f37b0c46c8e9e1d9538ff00587ae6
Author: Jarek Potiuk <[email protected]>
AuthorDate: Thu Sep 24 12:49:51 2026 +0200

    Add staging-to-main sync step to the release docs process (#73653)
    
    * Add staging-to-main sync step to the release docs process
    
    The staging branch of airflow-site accumulates docs from earlier release
    candidates, so a new release's staging docs are built on top of stale
    content. Resetting staging to main first gives each vote a clean staging
    site. It must not happen while another release is being voted on, because
    that vote's staging docs would be wiped, so the command warns and asks
    for confirmation before triggering the workflow.
    
    Generated-by: Claude Opus 5
    
    * Also reset staging of airflow-site-archive in sync-staging-to-main
    
    Release candidate docs are staged on the staging branch of
    apache/airflow-site-archive as well as apache/airflow-site, so resetting
    only airflow-site left the archive's staging branch carrying docs from
    earlier release candidates. The command now triggers the reset-staging
    workflow in both repositories after the single confirmation. The archive
    workflow only moves the ref; it does not rebuild anything.
    
    Generated-by: Claude Opus 5
---
 dev/README_RELEASE_AIRFLOW.md                      |  23 +++++
 dev/README_RELEASE_AIRFLOWCTL.md                   |  23 +++++
 dev/README_RELEASE_HELM_CHART.md                   |  25 +++++
 dev/README_RELEASE_MYPY.md                         |  25 +++++
 dev/README_RELEASE_PROVIDERS.md                    |  25 +++++
 dev/breeze/doc/09_release_management_tasks.rst     |  22 +++++
 .../output_setup_check-all-params-in-groups.svg    |   2 +-
 .../output_setup_check-all-params-in-groups.txt    |   2 +-
 .../output_setup_regenerate-command-images.svg     |  28 +++---
 .../output_setup_regenerate-command-images.txt     |   2 +-
 dev/breeze/doc/images/output_workflow-run.svg      |  16 ++--
 dev/breeze/doc/images/output_workflow-run.txt      |   2 +-
 .../output_workflow-run_sync-staging-to-main.svg   | 104 +++++++++++++++++++++
 .../output_workflow-run_sync-staging-to-main.txt   |   1 +
 .../airflow_breeze/commands/workflow_commands.py   |  30 +++++-
 .../commands/workflow_commands_config.py           |  10 +-
 dev/breeze/tests/test_workflow_commands.py         |  34 ++++++-
 17 files changed, 348 insertions(+), 26 deletions(-)

diff --git a/dev/README_RELEASE_AIRFLOW.md b/dev/README_RELEASE_AIRFLOW.md
index 3fd3cf6e89f..7bb3fef3e3b 100644
--- a/dev/README_RELEASE_AIRFLOW.md
+++ b/dev/README_RELEASE_AIRFLOW.md
@@ -640,6 +640,29 @@ emergency cases.
 
 We have two options publishing the documentation 1. Using breeze commands 2. 
Manually using GitHub Actions.:
 
+### Sync staging with main (skip if another vote is in progress)
+
+Before publishing the staging docs, reset the `staging` branches of
+[`apache/airflow-site`](https://github.com/apache/airflow-site) and
+[`apache/airflow-site-archive`](https://github.com/apache/airflow-site-archive)
 to `main`, so the staging
+site starts from the current live site rather than from whatever an earlier 
release left there:
+
+```shell script
+breeze workflow-run sync-staging-to-main
+```
+
+It triggers the `Reset staging to main` workflow in
+[`airflow-site`](https://github.com/apache/airflow-site/actions/workflows/reset-staging.yml)
 and in
+[`airflow-site-archive`](https://github.com/apache/airflow-site-archive/actions/workflows/reset-staging.yml).
+Each force-updates its repository's `staging` branch to the current `main` 
commit (`main` itself is not
+changed); in `airflow-site` it also rebuilds the staging site.
+
+> [!WARNING]
+> **Skip this step if a vote for any other release (Airflow, Providers, Helm 
Chart, airflowctl, ...) is
+> in progress.** Its release candidate docs are on the `staging` branches, and 
resetting `staging` to `main`
+> would overwrite the staging docs prepared for that vote. The command asks 
for confirmation before it
+> does anything; answer `n` to skip it.
+
 ### Using breeze commands
 
 You can use the `breeze` command to publish the documentation.
diff --git a/dev/README_RELEASE_AIRFLOWCTL.md b/dev/README_RELEASE_AIRFLOWCTL.md
index ed6b4fff914..7e8b8fa2673 100644
--- a/dev/README_RELEASE_AIRFLOWCTL.md
+++ b/dev/README_RELEASE_AIRFLOWCTL.md
@@ -710,6 +710,29 @@ emergency cases.
 
 We have two options publishing the documentation 1. Using breeze commands 2. 
Manually using GitHub Actions.:
 
+### Sync staging with main (skip if another vote is in progress)
+
+Before publishing the staging docs, reset the `staging` branches of
+[`apache/airflow-site`](https://github.com/apache/airflow-site) and
+[`apache/airflow-site-archive`](https://github.com/apache/airflow-site-archive)
 to `main`, so the staging
+site starts from the current live site rather than from whatever an earlier 
release left there:
+
+```shell script
+breeze workflow-run sync-staging-to-main
+```
+
+It triggers the `Reset staging to main` workflow in
+[`airflow-site`](https://github.com/apache/airflow-site/actions/workflows/reset-staging.yml)
 and in
+[`airflow-site-archive`](https://github.com/apache/airflow-site-archive/actions/workflows/reset-staging.yml).
+Each force-updates its repository's `staging` branch to the current `main` 
commit (`main` itself is not
+changed); in `airflow-site` it also rebuilds the staging site.
+
+> [!WARNING]
+> **Skip this step if a vote for any other release (Airflow, Providers, Helm 
Chart, airflowctl, ...) is
+> in progress.** Its release candidate docs are on the `staging` branches, and 
resetting `staging` to `main`
+> would overwrite the staging docs prepared for that vote. The command asks 
for confirmation before it
+> does anything; answer `n` to skip it.
+
 ### Using breeze commands
 
 You can use the `breeze` command to publish the documentation.
diff --git a/dev/README_RELEASE_HELM_CHART.md b/dev/README_RELEASE_HELM_CHART.md
index 2a74527e956..46fdf6d81b9 100644
--- a/dev/README_RELEASE_HELM_CHART.md
+++ b/dev/README_RELEASE_HELM_CHART.md
@@ -377,6 +377,31 @@ you need to run several workflows to publish the 
documentation. More details abo
 emergency cases.
 
 
+### Sync staging with main (skip if another vote is in progress)
+
+Before publishing the staging docs, reset the `staging` branches of
+[`apache/airflow-site`](https://github.com/apache/airflow-site) and
+[`apache/airflow-site-archive`](https://github.com/apache/airflow-site-archive)
 to `main`, so the staging
+site starts from the current live site rather than from whatever an earlier 
release left there:
+
+```shell script
+breeze workflow-run sync-staging-to-main
+```
+
+It triggers the `Reset staging to main` workflow in
+[`airflow-site`](https://github.com/apache/airflow-site/actions/workflows/reset-staging.yml)
 and in
+[`airflow-site-archive`](https://github.com/apache/airflow-site-archive/actions/workflows/reset-staging.yml).
+Each force-updates its repository's `staging` branch to the current `main` 
commit (`main` itself is not
+changed); in `airflow-site` it also rebuilds the staging site.
+
+> [!WARNING]
+> **Skip this step if a vote for any other release (Airflow, Providers, Helm 
Chart, airflowctl, ...) is
+> in progress.** Its release candidate docs are on the `staging` branches, and 
resetting `staging` to `main`
+> would overwrite the staging docs prepared for that vote. The command asks 
for confirmation before it
+> does anything; answer `n` to skip it.
+
+### Publish the docs
+
 You should use the `breeze` command to publish the documentation.
 The command does the following:
 
diff --git a/dev/README_RELEASE_MYPY.md b/dev/README_RELEASE_MYPY.md
index 9df04a6d6a1..cd16851f263 100644
--- a/dev/README_RELEASE_MYPY.md
+++ b/dev/README_RELEASE_MYPY.md
@@ -170,6 +170,31 @@ Use a short-lived (throw-away) PyPI API token for the 
upload and delete it after
 
 ## Publish release candidate documentation
 
+### Sync staging with main (skip if another vote is in progress)
+
+Before publishing the staging docs, reset the `staging` branches of
+[`apache/airflow-site`](https://github.com/apache/airflow-site) and
+[`apache/airflow-site-archive`](https://github.com/apache/airflow-site-archive)
 to `main`, so the staging
+site starts from the current live site rather than from whatever an earlier 
release left there:
+
+```shell script
+breeze workflow-run sync-staging-to-main
+```
+
+It triggers the `Reset staging to main` workflow in
+[`airflow-site`](https://github.com/apache/airflow-site/actions/workflows/reset-staging.yml)
 and in
+[`airflow-site-archive`](https://github.com/apache/airflow-site-archive/actions/workflows/reset-staging.yml).
+Each force-updates its repository's `staging` branch to the current `main` 
commit (`main` itself is not
+changed); in `airflow-site` it also rebuilds the staging site.
+
+> [!WARNING]
+> **Skip this step if a vote for any other release (Airflow, Providers, Helm 
Chart, airflowctl, ...) is
+> in progress.** Its release candidate docs are on the `staging` branches, and 
resetting `staging` to `main`
+> would overwrite the staging docs prepared for that vote. The command asks 
for confirmation before it
+> does anything; answer `n` to skip it.
+
+### Publish the docs
+
 Run the `Publish Docs to S3` workflow from the `apache/airflow` repository 
with:
 
 - **ref**: `apache-airflow-mypy-<VERSION>rc<RC>`
diff --git a/dev/README_RELEASE_PROVIDERS.md b/dev/README_RELEASE_PROVIDERS.md
index eedaa88cbd8..680106bdac0 100644
--- a/dev/README_RELEASE_PROVIDERS.md
+++ b/dev/README_RELEASE_PROVIDERS.md
@@ -907,6 +907,31 @@ you need to run several workflows to publish the 
documentation. More details abo
 [Docs README](../docs/README.md) showing the architecture and workflows 
including manual workflows for
 emergency cases.
 
+### Sync staging with main (skip if another vote is in progress)
+
+Before publishing the staging docs, reset the `staging` branches of
+[`apache/airflow-site`](https://github.com/apache/airflow-site) and
+[`apache/airflow-site-archive`](https://github.com/apache/airflow-site-archive)
 to `main`, so the staging
+site starts from the current live site rather than from whatever an earlier 
release left there:
+
+```shell script
+breeze workflow-run sync-staging-to-main
+```
+
+It triggers the `Reset staging to main` workflow in
+[`airflow-site`](https://github.com/apache/airflow-site/actions/workflows/reset-staging.yml)
 and in
+[`airflow-site-archive`](https://github.com/apache/airflow-site-archive/actions/workflows/reset-staging.yml).
+Each force-updates its repository's `staging` branch to the current `main` 
commit (`main` itself is not
+changed); in `airflow-site` it also rebuilds the staging site.
+
+> [!WARNING]
+> **Skip this step if a vote for any other release (Airflow, Providers, Helm 
Chart, airflowctl, ...) is
+> in progress.** Its release candidate docs are on the `staging` branches, and 
resetting `staging` to `main`
+> would overwrite the staging docs prepared for that vote. The command asks 
for confirmation before it
+> does anything; answer `n` to skip it.
+
+### Publish the docs
+
 You usually use the `breeze` command to publish the documentation. The command 
does the following:
 
 1. Triggers [Publish Docs to 
S3](https://github.com/apache/airflow/actions/workflows/publish-docs-to-s3.yml).
diff --git a/dev/breeze/doc/09_release_management_tasks.rst 
b/dev/breeze/doc/09_release_management_tasks.rst
index 40694e437c6..52ec6559771 100644
--- a/dev/breeze/doc/09_release_management_tasks.rst
+++ b/dev/breeze/doc/09_release_management_tasks.rst
@@ -1080,6 +1080,28 @@ These are all available flags of ``workflow-run 
publish-docs`` command:
   :width: 100%
   :alt: Breeze workflow-run publish-docs
 
+Syncing the staging site with main
+""""""""""""""""""""""""""""""""""
+
+Before publishing release candidate docs to staging, reset the ``staging`` 
branches of
+``apache/airflow-site`` and ``apache/airflow-site-archive`` to ``main`` with 
the
+``breeze workflow-run sync-staging-to-main`` command. It triggers the 
``reset-staging.yml`` workflow in both
+repositories, which force-updates each ``staging`` branch to the current 
``main`` commit (``main`` itself is
+not changed); in ``apache/airflow-site`` it also rebuilds the staging site.
+
+.. warning::
+
+   Skip this step if a vote for any other release is in progress. The 
``staging`` branches hold the
+   docs prepared for that vote, and resetting them to ``main`` overwrites 
them. The command asks for
+   confirmation before triggering the workflow.
+
+These are all available flags of ``workflow-run sync-staging-to-main`` command:
+
+.. image:: ./images/output_workflow-run_sync-staging-to-main.svg
+  :target: 
https://raw.githubusercontent.com/apache/airflow/main/dev/breeze/doc/images/output_workflow-run_sync-staging-to-main.svg
+  :width: 100%
+  :alt: Breeze workflow-run sync-staging-to-main
+
 Resolving the constraints for a release
 """""""""""""""""""""""""""""""""""""""
 
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 938ff18d355..102ac89521a 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
@@ -247,7 +247,7 @@
 </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&#160;|&#160;testing:providers-tests&#160;|&#160;testing:python-api-client-tests&#160;|&#160;</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&#160;|&#160;testing:task-sdk-integration-tests&#160;|&#160;testing:task-sdk-tests&#160;|&#160;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="1281" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-42)">|&#160;ui&#160;|&#160;ui:check-translation-completeness&#160;|&#160;ui:compile-assets&#160;|&#160;workflow-run&#160;|&#160;workflow-run:publish-docs&#160;|</
 [...]
-</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="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="841.8" 
clip-path="url(#breeze-setup-check-all-params-in-groups-line-43)">workflow-run:release-constraints&#160;|&#160;workflow-run:sync-staging-to-main)</text><text
 class="breeze-setup-check-all-params-in-groups-r5" x="1451.8" y= [...]
 </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)">&#160;Common&#160;options&#160;</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 [...]
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 6987a59efd8..79fb51c84ed 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 @@
-b52151d5b1fb9ecfd92edf910750f0ee
+466e12cd92f255b4a2ea75d3fe6d2c6c
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 8b96e56ba30..9d2c56dd70a 100644
--- a/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
+++ b/dev/breeze/doc/images/output_setup_regenerate-command-images.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1367.6" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 1392.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-regenerate-command-images-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="1316.6" />
+      <rect x="0" y="0" width="1463.0" height="1341.0" />
     </clipPath>
     <clipPath id="breeze-setup-regenerate-command-images-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -204,9 +204,12 @@
 <clipPath id="breeze-setup-regenerate-command-images-line-52">
     <rect x="0" y="1270.3" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-setup-regenerate-command-images-line-53">
+    <rect x="0" y="1294.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="1365.6" rx="8"/><text 
class="breeze-setup-regenerate-command-images-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;setup&#160;regenerate-command-images</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1390" rx="8"/><text 
class="breeze-setup-regenerate-command-images-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;setup&#160;regenerate-command-images</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -261,15 +264,16 @@
 </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&#160;|&#160;testing:providers-integration-tests&#160;|&#160;testing:providers-tests&#160;|&#160;</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&#160;|&#160;testing:system-tests&#160;|&#160;testing:task-sdk-integration-tests&#160;|&#160;</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&#160;|&#160;testing:ui-e2e-tests&#160;|&#160;ui&#160;|&#160;ui:check-translation-completeness&#160;|&#160;</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="1171.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-45)">ui:compile-assets&#160;|&#160;workflow-run&#160;|&#160;workflow-run:publish-docs&#160;|&#160;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&#160;with&#160;</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)">
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1215.6" textLength="24.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-49)">╭─</text><text 
class="breeze-setup-regenerate-command-images-r5" x="24.4" y="1215.6" 
textLength="195.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-49)">&#160;Common&#160;options&#160;</text><text
 class="breeze-setup-regenerate-command-images-r5" x="219.6" y="1215.6" 
textLength="1220" clip-path="url(#breeze-setu [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="1240" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-50)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="1240" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-50)">--verbose</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="1240" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-images-l [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1264.4" textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-51)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="1264.4" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-51)">--dry-run</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="1264.4" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-im [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1288.8" textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-52)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="1288.8" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-52)">--help&#160;&#160;&#160;</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="1288.8" 
textLength="24.4" clip-path="url(#breeze-setup-regene [...]
-</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1313.2" textLength="1464" 
clip-path="url(#breeze-setup-regenerate-command-images-line-53)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-regenerate-command-images-r1" x="1464" y="1313.2" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-53)">
+</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="1195.6" 
clip-path="url(#breeze-setup-regenerate-command-images-line-45)">ui:compile-assets&#160;|&#160;workflow-run&#160;|&#160;workflow-run:publish-docs&#160;|&#160;workflow-run:release-constraints&#160;|&#160;</text><text
 class="breez [...]
+</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-r6" x="195.2" y="1142.4" 
textLength="414.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-46)">workflow-run:sync-staging-to-main)</text><text
 class="breeze-setup-regenerate-command-images-r5" x="1451.8" y="1142.4" 
textLength="12.2" clip-path="url(#breeze- [...]
+</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-r4" x="24.4" y="1166.8" 
textLength="146.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-47)">--check-only</text><text
 class="breeze-setup-regenerate-command-images-r1" x="195.2" y="1166.8" 
textLength="1244.4" clip-path="url(#breeze-setup-regenerate-comma [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1191.2" textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-48)">│</text><text 
class="breeze-setup-regenerate-command-images-r1" x="195.2" y="1191.2" 
textLength="170.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-48)">together&#160;with&#160;</text><text
 class="breeze-setup-regenerate-command-images-r4" x="366" y="1191.2" 
textLength="109.8" clip-path="url(#breeze-setup-regene [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1215.6" textLength="1464" 
clip-path="url(#breeze-setup-regenerate-command-images-line-49)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-regenerate-command-images-r1" x="1464" y="1215.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-49)">
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" y="1240" 
textLength="24.4" 
clip-path="url(#breeze-setup-regenerate-command-images-line-50)">╭─</text><text 
class="breeze-setup-regenerate-command-images-r5" x="24.4" y="1240" 
textLength="195.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-50)">&#160;Common&#160;options&#160;</text><text
 class="breeze-setup-regenerate-command-images-r5" x="219.6" y="1240" 
textLength="1220" clip-path="url(#breeze-setup-rege [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1264.4" textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-51)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="1264.4" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-51)">--verbose</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="1264.4" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-im [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1288.8" textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-52)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="1288.8" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-52)">--dry-run</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="1288.8" 
textLength="24.4" clip-path="url(#breeze-setup-regenerate-command-im [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1313.2" textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-53)">│</text><text 
class="breeze-setup-regenerate-command-images-r4" x="24.4" y="1313.2" 
textLength="109.8" 
clip-path="url(#breeze-setup-regenerate-command-images-line-53)">--help&#160;&#160;&#160;</text><text
 class="breeze-setup-regenerate-command-images-r7" x="158.6" y="1313.2" 
textLength="24.4" clip-path="url(#breeze-setup-regene [...]
+</text><text class="breeze-setup-regenerate-command-images-r5" x="0" 
y="1337.6" textLength="1464" 
clip-path="url(#breeze-setup-regenerate-command-images-line-54)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-setup-regenerate-command-images-r1" x="1464" y="1337.6" 
textLength="12.2" 
clip-path="url(#breeze-setup-regenerate-command-images-line-54)">
 </text>
     </g>
     </g>
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 ac7e52d52bf..8c6c5112178 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 @@
-fadc598c6c80132f76537b23c462e6ed
+4463e56c4d0363f78d210bc76e8613bb
diff --git a/dev/breeze/doc/images/output_workflow-run.svg 
b/dev/breeze/doc/images/output_workflow-run.svg
index f8f7cb779f0..855758dde0d 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 342.79999999999995" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 367.2" 
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="291.79999999999995" />
+      <rect x="0" y="0" width="1463.0" height="316.2" />
     </clipPath>
     <clipPath id="breeze-workflow-run-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -77,9 +77,12 @@
 <clipPath id="breeze-workflow-run-line-10">
     <rect x="0" y="245.5" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-workflow-run-line-11">
+    <rect x="0" y="269.9" 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="340.8" rx="8"/><text 
class="breeze-workflow-run-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;workflow-run</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="365.2" rx="8"/><text 
class="breeze-workflow-run-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;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"/>
@@ -98,9 +101,10 @@
 </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)">&#160;Airflow&#160;github&#160;actions&#160;workflow&#160;commands&#160;</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="256.2" 
clip-path="url(#breeze-workflow-run-line-9)">publish-docs&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-workflow-run-r1" x="305" y="239.6" textLength="1134.6" 
clip-path="url(#breeze-workflow-run-line-9)">Trigger&#160;publish&#160;docs&#160;to&#160;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&#160;&#160;</text><text
 class="breeze-workflow-run-r1" x="305" y="264" textLength="1134.6" 
clip-path="url(#breeze-workflow-run-line-10)">Trigger&#160;the&#160;workflow&#160;that&#160;resolves,&#160;publishes&#160;and&#160;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><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="268.4" 
clip-path="url(#breeze-workflow-run-line-9)">publish-docs&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-workflow-run-r1" x="317.2" y="239.6" textLength="1122.4" 
clip-path="url(#breeze-workflow-run-line-9)">Trigger&#160;publish&#160;docs&#160;to&#
 [...]
+</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="268.4" 
clip-path="url(#breeze-workflow-run-line-10)">sync-staging-to-main&#160;&#160;</text><text
 class="breeze-workflow-run-r1" x="317.2" y="264" textLength="1122.4" 
clip-path="url(#breeze-workflow-run-line-10)">Reset&#160;the&#160;staging&#160;branch&#160;of&#160;apache/airflow-site&#160;to&#1
 [...]
+</text><text class="breeze-workflow-run-r5" x="0" y="288.4" textLength="12.2" 
clip-path="url(#breeze-workflow-run-line-11)">│</text><text 
class="breeze-workflow-run-r4" x="24.4" y="288.4" textLength="268.4" 
clip-path="url(#breeze-workflow-run-line-11)">release-constraints&#160;&#160;&#160;</text><text
 class="breeze-workflow-run-r1" x="317.2" y="288.4" textLength="1122.4" 
clip-path="url(#breeze-workflow-run-line-11)">Trigger&#160;the&#160;workflow&#160;that&#160;resolves,&#160;publishes&#
 [...]
+</text><text class="breeze-workflow-run-r5" x="0" y="312.8" textLength="1464" 
clip-path="url(#breeze-workflow-run-line-12)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-workflow-run-r1" x="1464" y="312.8" textLength="12.2" 
clip-path="url(#breeze-workflow-run-line-12)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_workflow-run.txt 
b/dev/breeze/doc/images/output_workflow-run.txt
index 606ed71654d..af2826144c1 100644
--- a/dev/breeze/doc/images/output_workflow-run.txt
+++ b/dev/breeze/doc/images/output_workflow-run.txt
@@ -1 +1 @@
-cfbf0a5234b3a9689a01d164e3e91abf
+f43871d1a12e85d1d91ad7fbfe402524
diff --git a/dev/breeze/doc/images/output_workflow-run_sync-staging-to-main.svg 
b/dev/breeze/doc/images/output_workflow-run_sync-staging-to-main.svg
new file mode 100644
index 00000000000..da8afbd9d5b
--- /dev/null
+++ b/dev/breeze/doc/images/output_workflow-run_sync-staging-to-main.svg
@@ -0,0 +1,104 @@
+<svg class="rich-terminal" viewBox="0 0 1482 318.4" 
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-sync-staging-to-main-matrix {
+        font-family: Fira Code, monospace;
+        font-size: 20px;
+        line-height: 24.4px;
+        font-variant-east-asian: full-width;
+    }
+
+    .breeze-workflow-run-sync-staging-to-main-title {
+        font-size: 18px;
+        font-weight: bold;
+        font-family: arial;
+    }
+
+    .breeze-workflow-run-sync-staging-to-main-r1 { fill: #c5c8c6 }
+.breeze-workflow-run-sync-staging-to-main-r2 { fill: #d0b344 }
+.breeze-workflow-run-sync-staging-to-main-r3 { fill: #c5c8c6;font-weight: bold 
}
+.breeze-workflow-run-sync-staging-to-main-r4 { fill: #68a0b3;font-weight: bold 
}
+.breeze-workflow-run-sync-staging-to-main-r5 { fill: #868887 }
+.breeze-workflow-run-sync-staging-to-main-r6 { fill: #98a84b;font-weight: bold 
}
+.breeze-workflow-run-sync-staging-to-main-r7 { fill: #8d7b39 }
+    </style>
+
+    <defs>
+    <clipPath id="breeze-workflow-run-sync-staging-to-main-clip-terminal">
+      <rect x="0" y="0" width="1463.0" height="267.4" />
+    </clipPath>
+    <clipPath id="breeze-workflow-run-sync-staging-to-main-line-0">
+    <rect x="0" y="1.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-1">
+    <rect x="0" y="25.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-2">
+    <rect x="0" y="50.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-3">
+    <rect x="0" y="74.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-4">
+    <rect x="0" y="99.1" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-5">
+    <rect x="0" y="123.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-6">
+    <rect x="0" y="147.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-7">
+    <rect x="0" y="172.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-8">
+    <rect x="0" y="196.7" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath id="breeze-workflow-run-sync-staging-to-main-line-9">
+    <rect x="0" y="221.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="316.4" rx="8"/><text 
class="breeze-workflow-run-sync-staging-to-main-title" fill="#c5c8c6" 
text-anchor="middle" x="740" 
y="27">Command:&#160;workflow-run&#160;sync-staging-to-main</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-sync-staging-to-main-clip-terminal)">
+    
+    <g class="breeze-workflow-run-sync-staging-to-main-matrix">
+    <text class="breeze-workflow-run-sync-staging-to-main-r1" x="1464" y="20" 
textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-0)">
+</text><text class="breeze-workflow-run-sync-staging-to-main-r2" x="12.2" 
y="44.4" textLength="73.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-1)">Usage:</text><text
 class="breeze-workflow-run-sync-staging-to-main-r3" x="97.6" y="44.4" 
textLength="488" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-1)">breeze&#160;workflow-run&#160;sync-staging-to-main</text><text
 class="breeze-workflow-run-sync-staging-to-main-r1" x="597.8" y="44.4" 
textLength="12.2" c [...]
+</text><text class="breeze-workflow-run-sync-staging-to-main-r1" x="1464" 
y="68.8" textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-2)">
+</text><text class="breeze-workflow-run-sync-staging-to-main-r1" x="12.2" 
y="93.2" textLength="1037" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-3)">Reset&#160;the&#160;staging&#160;branch&#160;of&#160;apache/airflow-site&#160;to&#160;main&#160;and&#160;rebuild&#160;the&#160;staging&#160;site.</text><text
 class="breeze-workflow-run-sync-staging-to-main-r1" x="1464" y="93.2" 
textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-3)">
+</text><text class="breeze-workflow-run-sync-staging-to-main-r1" x="1464" 
y="117.6" textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-4)">
+</text><text class="breeze-workflow-run-sync-staging-to-main-r5" x="0" y="142" 
textLength="24.4" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-5)">╭─</text><text
 class="breeze-workflow-run-sync-staging-to-main-r5" x="24.4" y="142" 
textLength="170.8" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-5)">&#160;Confirmation&#160;</text><text
 class="breeze-workflow-run-sync-staging-to-main-r5" x="195.2" y="142" 
textLength="1244.4" clip-path="url(#breeze-workflow-r [...]
+</text><text class="breeze-workflow-run-sync-staging-to-main-r5" x="0" 
y="166.4" textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-6)">│</text><text 
class="breeze-workflow-run-sync-staging-to-main-r4" x="24.4" y="166.4" 
textLength="97.6" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-6)">--answer</text><text
 class="breeze-workflow-run-sync-staging-to-main-r6" x="146.4" y="166.4" 
textLength="24.4" clip-path="url(#breeze-workflow-run-sync-stagin [...]
+</text><text class="breeze-workflow-run-sync-staging-to-main-r5" x="0" 
y="190.8" textLength="1464" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-7)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-workflow-run-sync-staging-to-main-r1" x="1464" y="190.8" 
textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-7)">
+</text><text class="breeze-workflow-run-sync-staging-to-main-r5" x="0" 
y="215.2" textLength="24.4" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-8)">╭─</text><text
 class="breeze-workflow-run-sync-staging-to-main-r5" x="24.4" y="215.2" 
textLength="195.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-8)">&#160;Common&#160;options&#160;</text><text
 class="breeze-workflow-run-sync-staging-to-main-r5" x="219.6" y="215.2" 
textLength="1220" clip-path="url(#breeze [...]
+</text><text class="breeze-workflow-run-sync-staging-to-main-r5" x="0" 
y="239.6" textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-9)">│</text><text 
class="breeze-workflow-run-sync-staging-to-main-r4" x="24.4" y="239.6" 
textLength="73.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-9)">--help</text><text
 class="breeze-workflow-run-sync-staging-to-main-r6" x="122" y="239.6" 
textLength="24.4" clip-path="url(#breeze-workflow-run-sync-staging-to [...]
+</text><text class="breeze-workflow-run-sync-staging-to-main-r5" x="0" y="264" 
textLength="1464" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-10)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-workflow-run-sync-staging-to-main-r1" x="1464" y="264" 
textLength="12.2" 
clip-path="url(#breeze-workflow-run-sync-staging-to-main-line-10)">
+</text>
+    </g>
+    </g>
+</svg>
diff --git a/dev/breeze/doc/images/output_workflow-run_sync-staging-to-main.txt 
b/dev/breeze/doc/images/output_workflow-run_sync-staging-to-main.txt
new file mode 100644
index 00000000000..a43deb6eea7
--- /dev/null
+++ b/dev/breeze/doc/images/output_workflow-run_sync-staging-to-main.txt
@@ -0,0 +1 @@
+4d037ba710aed3e7859c778da2ffbcd7
diff --git a/dev/breeze/src/airflow_breeze/commands/workflow_commands.py 
b/dev/breeze/src/airflow_breeze/commands/workflow_commands.py
index d6c98827b42..acd13c2e763 100644
--- a/dev/breeze/src/airflow_breeze/commands/workflow_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/workflow_commands.py
@@ -23,8 +23,9 @@ import sys
 
 import click
 
-from airflow_breeze.commands.common_options import argument_doc_packages
+from airflow_breeze.commands.common_options import argument_doc_packages, 
option_answer
 from airflow_breeze.utils.click_utils import BreezeGroup
+from airflow_breeze.utils.confirm import Answer, user_confirm
 from airflow_breeze.utils.console import console_print
 from airflow_breeze.utils.custom_param_types import BetterChoice
 from airflow_breeze.utils.gh_workflow_utils import trigger_workflow_and_monitor
@@ -35,6 +36,7 @@ WORKFLOW_NAME_MAPS = {
     "airflow-refresh-site": "build.yml",
     "sync-s3-to-github": "s3-to-github.yml",
     "release-constraints": "release-constraints.yml",
+    "reset-staging": "reset-staging.yml",
 }
 
 # X.Y.Z or X.Y.ZrcN - the workflow derives the release stage from which of the 
two it is given,
@@ -316,3 +318,29 @@ def workflow_run_release_constraints(version: str, ref: 
str, workflow_branch: st
         version=version,
         ref=ref,
     )
+
+
+@workflow_run_group.command(
+    name="sync-staging-to-main",
+    help="Reset the staging branches of apache/airflow-site and 
apache/airflow-site-archive to main.",
+)
+@option_answer
+def workflow_run_sync_staging_to_main():
+    console_print(
+        f"[warning]This force-updates the `staging` branches of 
{APACHE_AIRFLOW_SITE_REPO} and "
+        f"{APACHE_AIRFLOW_SITE_ARCHIVE_REPO} to their current `main` commits, 
dropping everything that "
+        "is only on `staging`.[/warning]\n"
+        "[warning]If a vote for ANY other release is in progress, its staging 
docs live on those "
+        "branches - SKIP this step, or you will overwrite the docs prepared 
for that vote.[/warning]"
+    )
+    answer = user_confirm("Is no other release vote in progress, and should 
staging be reset to main?")
+    if answer != Answer.YES:
+        console_print("[info]Skipping the reset of staging to main.[/info]")
+        sys.exit(0 if answer == Answer.NO else 1)
+    for repo in (APACHE_AIRFLOW_SITE_REPO, APACHE_AIRFLOW_SITE_ARCHIVE_REPO):
+        console_print(f"[blue]Resetting staging to main in {repo}[/blue]")
+        trigger_workflow_and_monitor(
+            workflow_name=WORKFLOW_NAME_MAPS["reset-staging"],
+            repo=repo,
+            branch="main",
+        )
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 9c6d0c99277..6022fc3aaf8 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", "release-constraints"],
+    "commands": ["publish-docs", "sync-staging-to-main", 
"release-constraints"],
 }
 
 WORKFLOW_RUN_PARAMETERS: dict[str, list[dict[str, str | list[str]]]] = {
@@ -65,3 +65,11 @@ WORKFLOW_RUN_PARAMETERS["breeze workflow-run 
release-constraints"] = [
         ],
     },
 ]
+WORKFLOW_RUN_PARAMETERS["breeze workflow-run sync-staging-to-main"] = [
+    {
+        "name": "Confirmation",
+        "options": [
+            "--answer",
+        ],
+    },
+]
diff --git a/dev/breeze/tests/test_workflow_commands.py 
b/dev/breeze/tests/test_workflow_commands.py
index 8a30e2a40e4..dea188d19e4 100644
--- a/dev/breeze/tests/test_workflow_commands.py
+++ b/dev/breeze/tests/test_workflow_commands.py
@@ -18,12 +18,15 @@ from __future__ import annotations
 
 import json
 from subprocess import CompletedProcess
-from unittest.mock import MagicMock, patch
+from unittest.mock import MagicMock, call, patch
 
 import pytest
 from click.testing import CliRunner
 
-from airflow_breeze.commands.workflow_commands import workflow_run_publish
+from airflow_breeze.commands.workflow_commands import (
+    workflow_run_publish,
+    workflow_run_sync_staging_to_main,
+)
 
 
 def _make_gh_response(ref: str | None) -> CompletedProcess:
@@ -99,3 +102,30 @@ class TestPublishDocsTagValidation:
         assert result.exit_code == 0
         mock_run_gh_command.assert_not_called()
         mock_trigger.assert_called()
+
+
+class TestSyncStagingToMain:
+    @pytest.mark.parametrize(
+        ("answer", "expected_exit_code", "expected_triggered"),
+        [
+            pytest.param("y", 0, True, id="confirmed"),
+            pytest.param("n", 0, False, id="skipped"),
+            pytest.param("q", 1, False, id="quit"),
+        ],
+    )
+    
@patch("airflow_breeze.commands.workflow_commands.trigger_workflow_and_monitor")
+    def test_reset_staging_is_triggered_only_when_confirmed(
+        self, mock_trigger, answer, expected_exit_code, expected_triggered
+    ):
+        result = CliRunner().invoke(
+            workflow_run_sync_staging_to_main, ["--answer", answer], 
catch_exceptions=False
+        )
+
+        assert result.exit_code == expected_exit_code
+        if expected_triggered:
+            assert mock_trigger.call_args_list == [
+                call(workflow_name="reset-staging.yml", 
repo="apache/airflow-site", branch="main"),
+                call(workflow_name="reset-staging.yml", 
repo="apache/airflow-site-archive", branch="main"),
+            ]
+        else:
+            mock_trigger.assert_not_called()

Reply via email to