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 d9d8fdb3a19 Speed up docs publishes by reusing the previously built CI
image (#70650)
d9d8fdb3a19 is described below
commit d9d8fdb3a19390c8e047b274855af8a154843448
Author: Jarek Potiuk <[email protected]>
AuthorDate: Wed Jul 29 11:32:53 2026 +0200
Speed up docs publishes by reusing the previously built CI image (#70650)
Publishing docs for a ref cut before main pays for a from-scratch CI image
build. The registry cache the build reads is main's, and the first
Dockerfile.ci change made since the ref was cut breaks the cache chain at
the
third layer - #70285, which bakes Node.js and pnpm into the image, is by
itself enough to make the twenty-minute Python build run again. Nothing
caches those layers for the ref being documented except the image the
previous publish of that same ref already built.
That image could not serve as a cache until now. BuildKit imports the cache
manifest of an image loaded from a tarball and then discards every record
whose layers it cannot pull from a registry, so a docker load contributes
nothing at all; serving the image from a registry on localhost is what makes
its records usable. Recording those records in the first place needs inline
cache metadata, which no image carried before.
---
.github/workflows/ci-image-build.yml | 78 ++++++++++++++++
.github/workflows/publish-docs-to-s3.yml | 7 ++
dev/breeze/doc/images/output_ci-image_build.svg | 104 ++++++++++++---------
dev/breeze/doc/images/output_ci-image_build.txt | 2 +-
dev/breeze/doc/images/output_ci-image_load.svg | 22 +++--
dev/breeze/doc/images/output_ci-image_load.txt | 2 +-
.../airflow_breeze/commands/ci_image_commands.py | 16 ++++
.../commands/ci_image_commands_config.py | 2 +
.../commands/common_image_options.py | 11 +++
.../airflow_breeze/params/common_build_params.py | 10 ++
dev/breeze/tests/test_build_ci_params.py | 57 +++++++++++
11 files changed, 254 insertions(+), 57 deletions(-)
diff --git a/.github/workflows/ci-image-build.yml
b/.github/workflows/ci-image-build.yml
index f9aaa3aa473..df116423717 100644
--- a/.github/workflows/ci-image-build.yml
+++ b/.github/workflows/ci-image-build.yml
@@ -103,6 +103,25 @@ on: # yamllint disable-line rule:truthy
description: "Disable airflow repo cache read from main."
required: true
type: string
+ seed-cache-from-stashed-image:
+ description: >
+ Seed the build cache from the CI image an earlier run stashed
(true/false). Worth it
+ where the registry cache is built for a different branch than the
sources - the
+ previous image matches them layer for layer, the registry cache of
another branch may
+ match nothing.
+ required: false
+ default: "false"
+ type: string
+ image-stash-suffix:
+ description: >
+ Appended verbatim to the key of an extra copy of the image stash (so
it needs its own
+ leading separator). Callers that build many different refs from one
branch pass the ref
+ here to keep a copy per ref: they all share the plain per-branch
stash and would
+ otherwise seed each other's builds, and refs far enough apart make
poor caches for one
+ another. Seeding prefers this copy and falls back to the per-branch
one.
+ required: false
+ default: ""
+ type: string
permissions:
contents: read
jobs:
@@ -166,6 +185,44 @@ jobs:
breeze ci-image import-mount-cache
--cache-file
/tmp/ci-cache-mount-save-v3-${PYTHON_MAJOR_MINOR_VERSION}.tar.gz
if: steps.restore-cache-mount.outputs.stash-hit == 'true'
+ # BuildKit reads an image's recorded layer cache only when it can pull
that image's layers
+ # from a registry - one merely loaded into the docker engine contributes
nothing. So the
+ # image an earlier run stashed is served back to the build from a
registry on localhost.
+ - name: >
+ Restore CI docker image for this ref
+ ${{ inputs.platform }}:${{ env.PYTHON_MAJOR_MINOR_VERSION }}
+ uses:
apache/infrastructure-actions/stash/restore@49df447b39b18354895520e0a63731b7cad7cbec
+ with:
+ key: "ci-image-save-v3-${{ inputs.platform }}-${{
env.PYTHON_MAJOR_MINOR_VERSION }}\
+ ${{ inputs.image-stash-suffix }}"
+ path: "/mnt/"
+ only-current-branch: 'true'
+ id: restore-cache-image-for-ref
+ if: inputs.seed-cache-from-stashed-image == 'true' &&
inputs.image-stash-suffix != ''
+ - name: "Restore CI docker image ${{ inputs.platform }}:${{
env.PYTHON_MAJOR_MINOR_VERSION }}"
+ uses:
apache/infrastructure-actions/stash/restore@49df447b39b18354895520e0a63731b7cad7cbec
+ with:
+ key: "ci-image-save-v3-${{ inputs.platform }}-${{
env.PYTHON_MAJOR_MINOR_VERSION }}"
+ path: "/mnt/"
+ only-current-branch: 'true'
+ id: restore-cache-image
+ if: >
+ inputs.seed-cache-from-stashed-image == 'true' &&
+ steps.restore-cache-image-for-ref.outputs.stash-hit != 'true'
+ - name: "Serve stashed image as cache ${{ inputs.platform }}:${{
env.PYTHON_MAJOR_MINOR_VERSION }}"
+ env:
+ PLATFORM: ${{ inputs.platform }}
+ CACHE_IMAGE: "localhost:5000/ci-image-cache:${{
env.PYTHON_MAJOR_MINOR_VERSION }}"
+ run: |
+ docker run -d --name cache-registry -p 5000:5000 registry:2
+ breeze ci-image load --platform "${PLATFORM}" --python
"${PYTHON_MAJOR_MINOR_VERSION}" \
+ --image-file-dir "/mnt" --tag-as "${CACHE_IMAGE}"
+ docker push "${CACHE_IMAGE}"
+ echo "CACHE_FROM_IMAGE=${CACHE_IMAGE}" >> "${GITHUB_ENV}"
+ shell: bash
+ if: >
+ steps.restore-cache-image-for-ref.outputs.stash-hit == 'true' ||
+ steps.restore-cache-image.outputs.stash-hit == 'true'
- name: "Login to ghcr.io"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -203,6 +260,14 @@ jobs:
PUSH: ${{ inputs.push-image }}
VERBOSE: "true"
PLATFORM: ${{ inputs.platform }}
+ - name: "Stop serving the cache image"
+ # The registry holds a second copy of a multi-gigabyte image and the
export below needs
+ # the room.
+ run: |
+ docker rm -f cache-registry
+ docker rmi "${CACHE_FROM_IMAGE}"
+ shell: bash
+ if: always() && env.CACHE_FROM_IMAGE != ''
- name: "Export CI docker image ${{ env.PYTHON_MAJOR_MINOR_VERSION }}"
env:
PLATFORM: ${{ inputs.platform }}
@@ -216,6 +281,19 @@ jobs:
if-no-files-found: 'error'
retention-days: '2'
if: inputs.upload-image-artifact == 'true'
+ # Everything in this run reads the stash above; this copy exists only so
the next run
+ # built from the same ref can seed its cache from sources it actually
matches. It outlives
+ # that one by days - the same ref is rebuilt three days apart at the
very least, so the
+ # two-day retention the shared stash gets would expire it before it is
ever read.
+ - name: "Stash CI docker image for this ref ${{
env.PYTHON_MAJOR_MINOR_VERSION }}"
+ uses:
apache/infrastructure-actions/stash/save@49df447b39b18354895520e0a63731b7cad7cbec
+ with:
+ key: "ci-image-save-v3-${{ inputs.platform }}-${{
env.PYTHON_MAJOR_MINOR_VERSION }}\
+ ${{ inputs.image-stash-suffix }}"
+ path: "/mnt/ci-image-save-*-${{ env.PYTHON_MAJOR_MINOR_VERSION
}}.tar"
+ if-no-files-found: 'error'
+ retention-days: '6'
+ if: inputs.upload-image-artifact == 'true' &&
inputs.image-stash-suffix != ''
- name: "Export mount cache ${{ inputs.platform }}:${{
env.PYTHON_MAJOR_MINOR_VERSION }}"
env:
PYTHON_MAJOR_MINOR_VERSION: ${{ env.PYTHON_MAJOR_MINOR_VERSION }}
diff --git a/.github/workflows/publish-docs-to-s3.yml
b/.github/workflows/publish-docs-to-s3.yml
index 6345afa84b6..5f375004d1f 100644
--- a/.github/workflows/publish-docs-to-s3.yml
+++ b/.github/workflows/publish-docs-to-s3.yml
@@ -247,6 +247,13 @@ jobs:
# ci-image-build.yml always restores it, so consecutive publishes stop
re-downloading
# the whole dependency set.
upload-mount-cache-artifact: "true"
+ # Docs are published from refs cut days or weeks before main, and main's
registry cache
+ # stops matching at the first Dockerfile.ci change made since the cut -
#70285 alone
+ # costs a from-scratch Python build. The image the previous publish
stashed was built
+ # from these very sources, so it is the cache main's cannot be.
Publishes of different
+ # refs share one branch-scoped stash, hence the per-ref copy to prefer
over it.
+ seed-cache-from-stashed-image: "true"
+ image-stash-suffix: "-${{ inputs.ref }}"
python-versions: ${{ format('["{0}"]',
needs.build-info.outputs.default-python-version) }}
branch: "main"
constraints-branch: "constraints-main"
diff --git a/dev/breeze/doc/images/output_ci-image_build.svg
b/dev/breeze/doc/images/output_ci-image_build.svg
index f58ee2f3031..1f020988b46 100644
--- a/dev/breeze/doc/images/output_ci-image_build.svg
+++ b/dev/breeze/doc/images/output_ci-image_build.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1953.1999999999998"
xmlns="http://www.w3.org/2000/svg">
+<svg class="rich-terminal" viewBox="0 0 1482 2026.3999999999999"
xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -43,7 +43,7 @@
<defs>
<clipPath id="breeze-ci-image-build-clip-terminal">
- <rect x="0" y="0" width="1463.0" height="1902.1999999999998" />
+ <rect x="0" y="0" width="1463.0" height="1975.3999999999999" />
</clipPath>
<clipPath id="breeze-ci-image-build-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -276,9 +276,18 @@
<clipPath id="breeze-ci-image-build-line-76">
<rect x="0" y="1855.9" width="1464" height="24.65"/>
</clipPath>
+<clipPath id="breeze-ci-image-build-line-77">
+ <rect x="0" y="1880.3" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-ci-image-build-line-78">
+ <rect x="0" y="1904.7" width="1464" height="24.65"/>
+ </clipPath>
+<clipPath id="breeze-ci-image-build-line-79">
+ <rect x="0" y="1929.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="1951.2" rx="8"/><text
class="breeze-ci-image-build-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: ci-image build</text>
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="2024.4" rx="8"/><text
class="breeze-ci-image-build-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: ci-image build</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -323,49 +332,52 @@
</text><text class="breeze-ci-image-build-r5" x="0" y="800.8"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-32)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="800.8" textLength="512.4"
clip-path="url(#breeze-ci-image-build-line-32)"> Advanced build options (for power users) </text><text
class="breeze-ci-image-build-r5" x="536.8" y="800.8" textLength="902.8"
clip-path="url(#breeze-ci-image-build-line-32)">──────────────────── [...]
</text><text class="breeze-ci-image-build-r5" x="0" y="825.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-33)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="825.2" textLength="366"
clip-path="url(#breeze-ci-image-build-line-33)">--additional-pip-install-flags</text><text
class="breeze-ci-image-build-r1" x="414.8" y="825.2" textLength="1024.8"
clip-path="url(#breeze-ci-image-build-line-33)">Additional flags added to `pip install` 
[...]
</text><text class="breeze-ci-image-build-r5" x="0" y="849.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-34)">│</text><text
class="breeze-ci-image-build-r7" x="414.8" y="849.6" textLength="73.2"
clip-path="url(#breeze-ci-image-build-line-34)">(TEXT)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="849.6" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-34)">│</text><text
class="breeze-ci-image-build-r1" x="1464" y="849.6" textLength="12.2" clip-pat
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="874" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-35)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="874" textLength="366"
clip-path="url(#breeze-ci-image-build-line-35)">--commit-sha                  </text><text
class="breeze-ci-image-build-r1" x="414.8" y="874" textLength="549"
clip-path="url(#breeze-ci-image-buil [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="898.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-36)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="898.4" textLength="366"
clip-path="url(#breeze-ci-image-build-line-36)">--debian-version              </text><text
class="breeze-ci-image-build-r1" x="414.8" y="898.4" textLength="805.2"
clip-path="url(#breeze-ci-image-build-line-36)"> [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="922.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-37)">│</text><text
class="breeze-ci-image-build-r5" x="414.8" y="922.8" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-37)">bookworm]</text><text
class="breeze-ci-image-build-r7" x="536.8" y="922.8" textLength="122"
clip-path="url(#breeze-ci-image-build-line-37)">(bookworm)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="922.8" textLength="1 [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="947.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-38)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="947.2" textLength="366"
clip-path="url(#breeze-ci-image-build-line-38)">--disable-airflow-repo-cache  </text><text
class="breeze-ci-image-build-r1" x="414.8" y="947.2" textLength="658.8"
clip-path="url(#breeze-ci-image-build-line-38)">Disable cache from Airflow repository
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="971.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-39)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="971.6" textLength="366"
clip-path="url(#breeze-ci-image-build-line-39)">--install-mysql-client-type   </text><text
class="breeze-ci-image-build-r1" x="414.8" y="971.6" textLength="488"
clip-path="url(#breeze-ci-image-build-line-39)">Which client to choose when inst
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="996" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-40)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="996" textLength="366"
clip-path="url(#breeze-ci-image-build-line-40)">--python-image                </text><text
class="breeze-ci-image-build-r1" x="414.8" y="996" textLength="1024.8"
clip-path="url(#breeze-ci-image-build-line- [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1020.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-41)">│</text><text
class="breeze-ci-image-build-r1" x="414.8" y="1020.4" textLength="561.2"
clip-path="url(#breeze-ci-image-build-line-41)">something like: python:VERSION-slim-bookworm. </text><text
class="breeze-ci-image-build-r7" x="976" y="1020.4" textLength="73.2"
clip-path="url(#breeze-ci-image-build-line-41)">(TEXT)</text><text
class="breeze-ci- [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1044.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-42)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1044.8" textLength="97.6"
clip-path="url(#breeze-ci-image-build-line-42)">--use-uv</text><text
class="breeze-ci-image-build-r1" x="122" y="1044.8" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-42)">/</text><text
class="breeze-ci-image-build-r4" x="134.2" y="1044.8" textLength="134.2" clip
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1069.2"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-43)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1069.2" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-43)">
-</text><text class="breeze-ci-image-build-r5" x="0" y="1093.6"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-44)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1093.6" textLength="597.8"
clip-path="url(#breeze-ci-image-build-line-44)"> Selecting constraint location (for power users) </text><text
class="breeze-ci-image-build-r5" x="622.2" y="1093.6" textLength="817.4"
clip-path="url(#breeze-ci-image-build-line-44)">────────── [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1118" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-45)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1118" textLength="378.2"
clip-path="url(#breeze-ci-image-build-line-45)">--airflow-constraints-location </text><text
class="breeze-ci-image-build-r1" x="427" y="1118" textLength="915"
clip-path="url(#breeze-ci-image-build-line-45)">Location of airflow constraints to use 
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1142.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-46)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1142.4" textLength="378.2"
clip-path="url(#breeze-ci-image-build-line-46)">--airflow-constraints-mode     </text><text
class="breeze-ci-image-build-r1" x="427" y="1142.4" textLength="671"
clip-path="url(#breeze-ci-image-build-line-46)">Mode of constraints for 
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1166.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-47)">│</text><text
class="breeze-ci-image-build-r5" x="427" y="1166.8" textLength="353.8"
clip-path="url(#breeze-ci-image-build-line-47)">constraints-source-providers]</text><text
class="breeze-ci-image-build-r7" x="793" y="1166.8" textLength="561.2"
clip-path="url(#breeze-ci-image-build-line-47)">(constraints-source-providers | constraints | </t
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1191.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-48)">│</text><text
class="breeze-ci-image-build-r7" x="427" y="1191.2" textLength="305"
clip-path="url(#breeze-ci-image-build-line-48)">constraints-no-providers)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="1191.2" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-48)">│</text><text
class="breeze-ci-image-build-r1" x="1464" y="1191.2" textLe [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1215.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-49)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1215.6" textLength="378.2"
clip-path="url(#breeze-ci-image-build-line-49)">--airflow-constraints-reference</text><text
class="breeze-ci-image-build-r1" x="427" y="1215.6" textLength="646.6"
clip-path="url(#breeze-ci-image-build-line-49)">Constraint reference to use when building
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1240" textLength="1464"
clip-path="url(#breeze-ci-image-build-line-50)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1240" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-50)">
-</text><text class="breeze-ci-image-build-r5" x="0" y="1264.4"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-51)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1264.4" textLength="634.4"
clip-path="url(#breeze-ci-image-build-line-51)"> Choosing dependencies and extras (for power users) </text><text
class="breeze-ci-image-build-r5" x="658.8" y="1264.4" textLength="780.8"
clip-path="url(#breeze-ci-image-build-line-51)">── [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1288.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-52)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1288.8" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-52)">--additional-airflow-extras </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1288.8" textLength="780.8"
clip-path="url(#breeze-ci-image-build-line-52)">Additional extra package while installing&
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1313.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-53)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1313.2" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-53)">--additional-python-deps    </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1313.2" textLength="780.8"
clip-path="url(#breeze-ci-image-build-line-53)">Additional python dependencies t
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1337.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-54)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1337.6" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-54)">--dev-apt-deps              </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1337.6" textLength="658.8"
clip-path="url(#breeze-ci-image-build-line-54 [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1362" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-55)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1362" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-55)">--additional-dev-apt-deps   </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1362" textLength="793"
clip-path="url(#breeze-ci-image-build-line-55)">Additional apt dev dependencies to 
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1386.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-56)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1386.4" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-56)">--dev-apt-command           </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1386.4" textLength="634.4"
clip-path="url(#breeze-ci-image-build-line-56)">Command  [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1410.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-57)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1410.8" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-57)">--additional-dev-apt-command</text><text
class="breeze-ci-image-build-r1" x="390.4" y="1410.8" textLength="768.6"
clip-path="url(#breeze-ci-image-build-line-57)">Additional command executed before dev apt
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1435.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-58)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1435.2" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-58)">--additional-dev-apt-env    </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1435.2" textLength="817.4"
clip-path="url(#breeze-ci-image-build-line-58)">Additional environment variables 
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1459.6"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-59)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1459.6" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-59)">
-</text><text class="breeze-ci-image-build-r5" x="0" y="1484" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-60)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1484" textLength="622.2"
clip-path="url(#breeze-ci-image-build-line-60)"> Preparing cache and push (for maintainers and CI) </text><text
class="breeze-ci-image-build-r5" x="646.6" y="1484" textLength="793"
clip-path="url(#breeze-ci-image-build-line-60)">────── [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1508.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-61)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1508.4" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-61)">--builder             </text><text
class="breeze-ci-image-build-r1" x="317.2" y="1508.4" textLength="768.6"
clip-path="url(#breeze-ci-image-build-line-61)">Buildx&# [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1532.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-62)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1532.8" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-62)">--platform            </text><text
class="breeze-ci-image-build-r1" x="317.2" y="1532.8" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-62)">Platform  [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1557.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-63)">│</text><text
class="breeze-ci-image-build-r7" x="317.2" y="1557.2" textLength="292.8"
clip-path="url(#breeze-ci-image-build-line-63)">linux/amd64,linux/arm64)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="1557.2" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-63)">│</text><text
class="breeze-ci-image-build-r1" x="1464" y="1557.2" tex [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1581.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-64)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1581.6" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-64)">--push                </text><text
class="breeze-ci-image-build-r1" x="317.2" y="1581.6" textLength="353.8"
clip-path="url(#breeze-ci-image-build-lin [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1606" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-65)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1606" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-65)">--prepare-buildx-cache</text><text
class="breeze-ci-image-build-r1" x="317.2" y="1606" textLength="1122.4"
clip-path="url(#breeze-ci-image-build-line-65)">Prepares build cache (this is done as separ
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1630.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-66)">│</text><text
class="breeze-ci-image-build-r1" x="317.2" y="1630.4" textLength="1122.4"
clip-path="url(#breeze-ci-image-build-line-66)">image).                                    
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1654.8"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-67)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1654.8" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-67)">
-</text><text class="breeze-ci-image-build-r5" x="0" y="1679.2"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-68)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1679.2" textLength="280.6"
clip-path="url(#breeze-ci-image-build-line-68)"> GitHub authentication </text><text
class="breeze-ci-image-build-r5" x="305" y="1679.2" textLength="1134.6"
clip-path="url(#breeze-ci-image-build-line-68)">─────────────────────────────────────────────────────────
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1703.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-69)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1703.6" textLength="231.8"
clip-path="url(#breeze-ci-image-build-line-69)">--github-repository</text><text
class="breeze-ci-image-build-r6" x="280.6" y="1703.6" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-69)">-g</text><text
class="breeze-ci-image-build-r1" x="329.4" y="1703.6" textLeng [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1728" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-70)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1728" textLength="231.8"
clip-path="url(#breeze-ci-image-build-line-70)">--github-token     </text><text
class="breeze-ci-image-build-r1" x="329.4" y="1728" textLength="512.4"
clip-path="url(#breeze-ci-image-build-line-70)">The token used to authenticate t
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1752.4"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-71)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1752.4" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-71)">
-</text><text class="breeze-ci-image-build-r5" x="0" y="1776.8"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-72)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1776.8" textLength="195.2"
clip-path="url(#breeze-ci-image-build-line-72)"> Common options </text><text
class="breeze-ci-image-build-r5" x="219.6" y="1776.8" textLength="1220"
clip-path="url(#breeze-ci-image-build-line-72)">────────────────────────────────────────────────────────────────
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1801.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-73)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1801.2" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-73)">--answer </text><text
class="breeze-ci-image-build-r6" x="158.6" y="1801.2" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-73)">-a</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1801.2" textLength="3 [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1825.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-74)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1825.6" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-74)">--dry-run</text><text
class="breeze-ci-image-build-r6" x="158.6" y="1825.6" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-74)">-D</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1825.6" textLength="719.8" [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1850" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-75)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1850" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-75)">--verbose</text><text
class="breeze-ci-image-build-r6" x="158.6" y="1850" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-75)">-v</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1850" textLength="585.6" clip-pa
[...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1874.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-76)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1874.4" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-76)">--help   </text><text
class="breeze-ci-image-build-r6" x="158.6" y="1874.4" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-76)">-h</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1874.4" tex [...]
-</text><text class="breeze-ci-image-build-r5" x="0" y="1898.8"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-77)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1898.8" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-77)">
+</text><text class="breeze-ci-image-build-r5" x="0" y="874" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-35)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="874" textLength="366"
clip-path="url(#breeze-ci-image-build-line-35)">--cache-from-image            </text><text
class="breeze-ci-image-build-r1" x="414.8" y="874" textLength="1024.8"
clip-path="url(#breeze-ci-image-build-line-35)">Additional  [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="898.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-36)">│</text><text
class="breeze-ci-image-build-r1" x="414.8" y="898.4" textLength="1024.8"
clip-path="url(#breeze-ci-image-build-line-36)">registry, an image only present in the local docker engine contributes no cache.    </text><text
class="breeze-ci-image-build-r5" x="1451.8" y="898.4 [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="922.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-37)">│</text><text
class="breeze-ci-image-build-r7" x="414.8" y="922.8" textLength="73.2"
clip-path="url(#breeze-ci-image-build-line-37)">(TEXT)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="922.8" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-37)">│</text><text
class="breeze-ci-image-build-r1" x="1464" y="922.8" textLength="12.2" clip-pat
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="947.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-38)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="947.2" textLength="366"
clip-path="url(#breeze-ci-image-build-line-38)">--commit-sha                  </text><text
class="breeze-ci-image-build-r1" x="414.8" y="947.2" textLength="549"
clip-path="url(#breeze-ci-imag [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="971.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-39)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="971.6" textLength="366"
clip-path="url(#breeze-ci-image-build-line-39)">--debian-version              </text><text
class="breeze-ci-image-build-r1" x="414.8" y="971.6" textLength="805.2"
clip-path="url(#breeze-ci-image-build-line-39)"> [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="996" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-40)">│</text><text
class="breeze-ci-image-build-r5" x="414.8" y="996" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-40)">bookworm]</text><text
class="breeze-ci-image-build-r7" x="536.8" y="996" textLength="122"
clip-path="url(#breeze-ci-image-build-line-40)">(bookworm)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="996" textLength="12.2" cli [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1020.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-41)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1020.4" textLength="366"
clip-path="url(#breeze-ci-image-build-line-41)">--disable-airflow-repo-cache  </text><text
class="breeze-ci-image-build-r1" x="414.8" y="1020.4" textLength="658.8"
clip-path="url(#breeze-ci-image-build-line-41)">Disable cache from Airflow repository
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1044.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-42)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1044.8" textLength="366"
clip-path="url(#breeze-ci-image-build-line-42)">--install-mysql-client-type   </text><text
class="breeze-ci-image-build-r1" x="414.8" y="1044.8" textLength="488"
clip-path="url(#breeze-ci-image-build-line-42)">Which client to choose when i
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1069.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-43)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1069.2" textLength="366"
clip-path="url(#breeze-ci-image-build-line-43)">--python-image                </text><text
class="breeze-ci-image-build-r1" x="414.8" y="1069.2" textLength="1024.8"
clip-path="url(#breeze-ci-image-bu [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1093.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-44)">│</text><text
class="breeze-ci-image-build-r1" x="414.8" y="1093.6" textLength="561.2"
clip-path="url(#breeze-ci-image-build-line-44)">something like: python:VERSION-slim-bookworm. </text><text
class="breeze-ci-image-build-r7" x="976" y="1093.6" textLength="73.2"
clip-path="url(#breeze-ci-image-build-line-44)">(TEXT)</text><text
class="breeze-ci- [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1118" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-45)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1118" textLength="97.6"
clip-path="url(#breeze-ci-image-build-line-45)">--use-uv</text><text
class="breeze-ci-image-build-r1" x="122" y="1118" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-45)">/</text><text
class="breeze-ci-image-build-r4" x="134.2" y="1118" textLength="134.2"
clip-path="u [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1142.4"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-46)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1142.4" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-46)">
+</text><text class="breeze-ci-image-build-r5" x="0" y="1166.8"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-47)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1166.8" textLength="597.8"
clip-path="url(#breeze-ci-image-build-line-47)"> Selecting constraint location (for power users) </text><text
class="breeze-ci-image-build-r5" x="622.2" y="1166.8" textLength="817.4"
clip-path="url(#breeze-ci-image-build-line-47)">────────── [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1191.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-48)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1191.2" textLength="378.2"
clip-path="url(#breeze-ci-image-build-line-48)">--airflow-constraints-location </text><text
class="breeze-ci-image-build-r1" x="427" y="1191.2" textLength="915"
clip-path="url(#breeze-ci-image-build-line-48)">Location of airflow constraints to use
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1215.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-49)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1215.6" textLength="378.2"
clip-path="url(#breeze-ci-image-build-line-49)">--airflow-constraints-mode     </text><text
class="breeze-ci-image-build-r1" x="427" y="1215.6" textLength="671"
clip-path="url(#breeze-ci-image-build-line-49)">Mode of constraints for 
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1240" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-50)">│</text><text
class="breeze-ci-image-build-r5" x="427" y="1240" textLength="353.8"
clip-path="url(#breeze-ci-image-build-line-50)">constraints-source-providers]</text><text
class="breeze-ci-image-build-r7" x="793" y="1240" textLength="561.2"
clip-path="url(#breeze-ci-image-build-line-50)">(constraints-source-providers | constraints | </text><t
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1264.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-51)">│</text><text
class="breeze-ci-image-build-r7" x="427" y="1264.4" textLength="305"
clip-path="url(#breeze-ci-image-build-line-51)">constraints-no-providers)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="1264.4" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-51)">│</text><text
class="breeze-ci-image-build-r1" x="1464" y="1264.4" textLe [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1288.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-52)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1288.8" textLength="378.2"
clip-path="url(#breeze-ci-image-build-line-52)">--airflow-constraints-reference</text><text
class="breeze-ci-image-build-r1" x="427" y="1288.8" textLength="646.6"
clip-path="url(#breeze-ci-image-build-line-52)">Constraint reference to use when building
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1313.2"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-53)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1313.2" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-53)">
+</text><text class="breeze-ci-image-build-r5" x="0" y="1337.6"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-54)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1337.6" textLength="634.4"
clip-path="url(#breeze-ci-image-build-line-54)"> Choosing dependencies and extras (for power users) </text><text
class="breeze-ci-image-build-r5" x="658.8" y="1337.6" textLength="780.8"
clip-path="url(#breeze-ci-image-build-line-54)">── [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1362" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-55)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1362" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-55)">--additional-airflow-extras </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1362" textLength="780.8"
clip-path="url(#breeze-ci-image-build-line-55)">Additional extra package while installing A
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1386.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-56)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1386.4" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-56)">--additional-python-deps    </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1386.4" textLength="780.8"
clip-path="url(#breeze-ci-image-build-line-56)">Additional python dependencies t
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1410.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-57)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1410.8" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-57)">--dev-apt-deps              </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1410.8" textLength="658.8"
clip-path="url(#breeze-ci-image-build-line-57 [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1435.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-58)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1435.2" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-58)">--additional-dev-apt-deps   </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1435.2" textLength="793"
clip-path="url(#breeze-ci-image-build-line-58)">Additional apt dev dependencies to
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1459.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-59)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1459.6" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-59)">--dev-apt-command           </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1459.6" textLength="634.4"
clip-path="url(#breeze-ci-image-build-line-59)">Command  [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1484" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-60)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1484" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-60)">--additional-dev-apt-command</text><text
class="breeze-ci-image-build-r1" x="390.4" y="1484" textLength="768.6"
clip-path="url(#breeze-ci-image-build-line-60)">Additional command executed before dev apt 
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1508.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-61)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1508.4" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-61)">--additional-dev-apt-env    </text><text
class="breeze-ci-image-build-r1" x="390.4" y="1508.4" textLength="817.4"
clip-path="url(#breeze-ci-image-build-line-61)">Additional environment variables 
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1532.8"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-62)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1532.8" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-62)">
+</text><text class="breeze-ci-image-build-r5" x="0" y="1557.2"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-63)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1557.2" textLength="622.2"
clip-path="url(#breeze-ci-image-build-line-63)"> Preparing cache and push (for maintainers and CI) </text><text
class="breeze-ci-image-build-r5" x="646.6" y="1557.2" textLength="793"
clip-path="url(#breeze-ci-image-build-line-63)"> [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1581.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-64)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1581.6" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-64)">--builder             </text><text
class="breeze-ci-image-build-r1" x="317.2" y="1581.6" textLength="768.6"
clip-path="url(#breeze-ci-image-build-line-64)">Buildx&# [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1606" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-65)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1606" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-65)">--platform            </text><text
class="breeze-ci-image-build-r1" x="317.2" y="1606" textLength="341.6"
clip-path="url(#breeze-ci-image-build-line-65)">Platform for&# [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1630.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-66)">│</text><text
class="breeze-ci-image-build-r7" x="317.2" y="1630.4" textLength="292.8"
clip-path="url(#breeze-ci-image-build-line-66)">linux/amd64,linux/arm64)</text><text
class="breeze-ci-image-build-r5" x="1451.8" y="1630.4" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-66)">│</text><text
class="breeze-ci-image-build-r1" x="1464" y="1630.4" tex [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1654.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-67)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1654.8" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-67)">--push                </text><text
class="breeze-ci-image-build-r1" x="317.2" y="1654.8" textLength="353.8"
clip-path="url(#breeze-ci-image-build-lin [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1679.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-68)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1679.2" textLength="268.4"
clip-path="url(#breeze-ci-image-build-line-68)">--prepare-buildx-cache</text><text
class="breeze-ci-image-build-r1" x="317.2" y="1679.2" textLength="1122.4"
clip-path="url(#breeze-ci-image-build-line-68)">Prepares build cache (this is done as 
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1703.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-69)">│</text><text
class="breeze-ci-image-build-r1" x="317.2" y="1703.6" textLength="1122.4"
clip-path="url(#breeze-ci-image-build-line-69)">image).                                    
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1728" textLength="1464"
clip-path="url(#breeze-ci-image-build-line-70)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1728" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-70)">
+</text><text class="breeze-ci-image-build-r5" x="0" y="1752.4"
textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-71)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1752.4" textLength="280.6"
clip-path="url(#breeze-ci-image-build-line-71)"> GitHub authentication </text><text
class="breeze-ci-image-build-r5" x="305" y="1752.4" textLength="1134.6"
clip-path="url(#breeze-ci-image-build-line-71)">─────────────────────────────────────────────────────────
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1776.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-72)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1776.8" textLength="231.8"
clip-path="url(#breeze-ci-image-build-line-72)">--github-repository</text><text
class="breeze-ci-image-build-r6" x="280.6" y="1776.8" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-72)">-g</text><text
class="breeze-ci-image-build-r1" x="329.4" y="1776.8" textLeng [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1801.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-73)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1801.2" textLength="231.8"
clip-path="url(#breeze-ci-image-build-line-73)">--github-token     </text><text
class="breeze-ci-image-build-r1" x="329.4" y="1801.2" textLength="512.4"
clip-path="url(#breeze-ci-image-build-line-73)">The token used to authenticate&
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1825.6"
textLength="1464"
clip-path="url(#breeze-ci-image-build-line-74)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1825.6" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-74)">
+</text><text class="breeze-ci-image-build-r5" x="0" y="1850" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-75)">╭─</text><text
class="breeze-ci-image-build-r5" x="24.4" y="1850" textLength="195.2"
clip-path="url(#breeze-ci-image-build-line-75)"> Common options </text><text
class="breeze-ci-image-build-r5" x="219.6" y="1850" textLength="1220"
clip-path="url(#breeze-ci-image-build-line-75)">──────────────────────────────────────────────────────────────────────
[...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1874.4"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-76)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1874.4" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-76)">--answer </text><text
class="breeze-ci-image-build-r6" x="158.6" y="1874.4" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-76)">-a</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1874.4" textLength="3 [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1898.8"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-77)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1898.8" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-77)">--dry-run</text><text
class="breeze-ci-image-build-r6" x="158.6" y="1898.8" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-77)">-D</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1898.8" textLength="719.8" [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1923.2"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-78)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1923.2" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-78)">--verbose</text><text
class="breeze-ci-image-build-r6" x="158.6" y="1923.2" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-78)">-v</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1923.2" textLength="585.6" [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1947.6"
textLength="12.2" clip-path="url(#breeze-ci-image-build-line-79)">│</text><text
class="breeze-ci-image-build-r4" x="24.4" y="1947.6" textLength="109.8"
clip-path="url(#breeze-ci-image-build-line-79)">--help   </text><text
class="breeze-ci-image-build-r6" x="158.6" y="1947.6" textLength="24.4"
clip-path="url(#breeze-ci-image-build-line-79)">-h</text><text
class="breeze-ci-image-build-r1" x="207.4" y="1947.6" tex [...]
+</text><text class="breeze-ci-image-build-r5" x="0" y="1972" textLength="1464"
clip-path="url(#breeze-ci-image-build-line-80)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-build-r1" x="1464" y="1972" textLength="12.2"
clip-path="url(#breeze-ci-image-build-line-80)">
</text>
</g>
</g>
diff --git a/dev/breeze/doc/images/output_ci-image_build.txt
b/dev/breeze/doc/images/output_ci-image_build.txt
index a1bafba4172..f0c4db66c4a 100644
--- a/dev/breeze/doc/images/output_ci-image_build.txt
+++ b/dev/breeze/doc/images/output_ci-image_build.txt
@@ -1 +1 @@
-52f338c973e63396bbffd450b229d6c9
+12742b1b784b6e3a33582d4fe5f90d1f
diff --git a/dev/breeze/doc/images/output_ci-image_load.svg
b/dev/breeze/doc/images/output_ci-image_load.svg
index d6c510fd5e2..5972fb23a4d 100644
--- a/dev/breeze/doc/images/output_ci-image_load.svg
+++ b/dev/breeze/doc/images/output_ci-image_load.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 806.4"
xmlns="http://www.w3.org/2000/svg">
+<svg class="rich-terminal" viewBox="0 0 1482 830.8"
xmlns="http://www.w3.org/2000/svg">
<!-- Generated with Rich https://www.textualize.io -->
<style>
@@ -43,7 +43,7 @@
<defs>
<clipPath id="breeze-ci-image-load-clip-terminal">
- <rect x="0" y="0" width="1463.0" height="755.4" />
+ <rect x="0" y="0" width="1463.0" height="779.8" />
</clipPath>
<clipPath id="breeze-ci-image-load-line-0">
<rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -135,9 +135,12 @@
<clipPath id="breeze-ci-image-load-line-29">
<rect x="0" y="709.1" width="1464" height="24.65"/>
</clipPath>
+<clipPath id="breeze-ci-image-load-line-30">
+ <rect x="0" y="733.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="804.4" rx="8"/><text
class="breeze-ci-image-load-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: ci-image load</text>
+ <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1"
x="1" y="1" width="1480" height="828.8" rx="8"/><text
class="breeze-ci-image-load-title" fill="#c5c8c6" text-anchor="middle" x="740"
y="27">Command: ci-image load</text>
<g transform="translate(26,22)">
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -172,12 +175,13 @@
</text><text class="breeze-ci-image-load-r5" x="0" y="556.8" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-22)">│</text><text
class="breeze-ci-image-load-r1" x="414.8" y="556.8" textLength="256.2"
clip-path="url(#breeze-ci-image-load-line-22)">from the latest job. </text><text
class="breeze-ci-image-load-r7" x="671" y="556.8" textLength="73.2"
clip-path="url(#breeze-ci-image-load-line-22)">(TEXT)</text><text
class="breeze-ci-image-load-r5" x="1451.8" y=" [...]
</text><text class="breeze-ci-image-load-r5" x="0" y="581.2" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-23)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="581.2" textLength="317.2"
clip-path="url(#breeze-ci-image-load-line-23)">--from-run                </text><text
class="breeze-ci-image-load-r1" x="414.8" y="581.2" textLength="793"
clip-path="url(#breeze-ci-image-load-line-23)"> [...]
</text><text class="breeze-ci-image-load-r5" x="0" y="605.6" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-24)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="605.6" textLength="317.2"
clip-path="url(#breeze-ci-image-load-line-24)">--skip-image-file-deletion</text><text
class="breeze-ci-image-load-r1" x="414.8" y="605.6" textLength="414.8"
clip-path="url(#breeze-ci-image-load-line-24)">Skip image deletion after loading.</text><text
class="bree [...]
-</text><text class="breeze-ci-image-load-r5" x="0" y="630" textLength="1464"
clip-path="url(#breeze-ci-image-load-line-25)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-load-r1" x="1464" y="630" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-25)">
-</text><text class="breeze-ci-image-load-r5" x="0" y="654.4" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-26)">╭─</text><text
class="breeze-ci-image-load-r5" x="24.4" y="654.4" textLength="195.2"
clip-path="url(#breeze-ci-image-load-line-26)"> Common options </text><text
class="breeze-ci-image-load-r5" x="219.6" y="654.4" textLength="1220"
clip-path="url(#breeze-ci-image-load-line-26)">─────────────────────────────────────────────────────────────────────────
[...]
-</text><text class="breeze-ci-image-load-r5" x="0" y="678.8" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-27)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="678.8" textLength="109.8"
clip-path="url(#breeze-ci-image-load-line-27)">--dry-run</text><text
class="breeze-ci-image-load-r6" x="158.6" y="678.8" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-27)">-D</text><text
class="breeze-ci-image-load-r1" x="207.4" y="678.8" textLength="719.8"
clip-path= [...]
-</text><text class="breeze-ci-image-load-r5" x="0" y="703.2" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-28)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="703.2" textLength="109.8"
clip-path="url(#breeze-ci-image-load-line-28)">--verbose</text><text
class="breeze-ci-image-load-r6" x="158.6" y="703.2" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-28)">-v</text><text
class="breeze-ci-image-load-r1" x="207.4" y="703.2" textLength="585.6"
clip-path= [...]
-</text><text class="breeze-ci-image-load-r5" x="0" y="727.6" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-29)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="727.6" textLength="109.8"
clip-path="url(#breeze-ci-image-load-line-29)">--help   </text><text
class="breeze-ci-image-load-r6" x="158.6" y="727.6" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-29)">-h</text><text
class="breeze-ci-image-load-r1" x="207.4" y="727.6" textLength="32 [...]
-</text><text class="breeze-ci-image-load-r5" x="0" y="752" textLength="1464"
clip-path="url(#breeze-ci-image-load-line-30)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-load-r1" x="1464" y="752" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-30)">
+</text><text class="breeze-ci-image-load-r5" x="0" y="630" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-25)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="630" textLength="317.2"
clip-path="url(#breeze-ci-image-load-line-25)">--tag-as                  </text><text
class="breeze-ci-image-load-r1" x="414.8" y="630" textLength="671"
clip-path="url(#breeze-ci-image-load-line-2 [...]
+</text><text class="breeze-ci-image-load-r5" x="0" y="654.4" textLength="1464"
clip-path="url(#breeze-ci-image-load-line-26)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-load-r1" x="1464" y="654.4" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-26)">
+</text><text class="breeze-ci-image-load-r5" x="0" y="678.8" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-27)">╭─</text><text
class="breeze-ci-image-load-r5" x="24.4" y="678.8" textLength="195.2"
clip-path="url(#breeze-ci-image-load-line-27)"> Common options </text><text
class="breeze-ci-image-load-r5" x="219.6" y="678.8" textLength="1220"
clip-path="url(#breeze-ci-image-load-line-27)">─────────────────────────────────────────────────────────────────────────
[...]
+</text><text class="breeze-ci-image-load-r5" x="0" y="703.2" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-28)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="703.2" textLength="109.8"
clip-path="url(#breeze-ci-image-load-line-28)">--dry-run</text><text
class="breeze-ci-image-load-r6" x="158.6" y="703.2" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-28)">-D</text><text
class="breeze-ci-image-load-r1" x="207.4" y="703.2" textLength="719.8"
clip-path= [...]
+</text><text class="breeze-ci-image-load-r5" x="0" y="727.6" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-29)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="727.6" textLength="109.8"
clip-path="url(#breeze-ci-image-load-line-29)">--verbose</text><text
class="breeze-ci-image-load-r6" x="158.6" y="727.6" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-29)">-v</text><text
class="breeze-ci-image-load-r1" x="207.4" y="727.6" textLength="585.6"
clip-path= [...]
+</text><text class="breeze-ci-image-load-r5" x="0" y="752" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-30)">│</text><text
class="breeze-ci-image-load-r4" x="24.4" y="752" textLength="109.8"
clip-path="url(#breeze-ci-image-load-line-30)">--help   </text><text
class="breeze-ci-image-load-r6" x="158.6" y="752" textLength="24.4"
clip-path="url(#breeze-ci-image-load-line-30)">-h</text><text
class="breeze-ci-image-load-r1" x="207.4" y="752" textLength="329.4" cli [...]
+</text><text class="breeze-ci-image-load-r5" x="0" y="776.4" textLength="1464"
clip-path="url(#breeze-ci-image-load-line-31)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
class="breeze-ci-image-load-r1" x="1464" y="776.4" textLength="12.2"
clip-path="url(#breeze-ci-image-load-line-31)">
</text>
</g>
</g>
diff --git a/dev/breeze/doc/images/output_ci-image_load.txt
b/dev/breeze/doc/images/output_ci-image_load.txt
index 2f2f4d04205..8a10a0f9d11 100644
--- a/dev/breeze/doc/images/output_ci-image_load.txt
+++ b/dev/breeze/doc/images/output_ci-image_load.txt
@@ -1 +1 @@
-baf0bfe0e270b6982bbfbfd97707a1ba
+9585cbea5c5cf55ef6b49273f4523fed
diff --git a/dev/breeze/src/airflow_breeze/commands/ci_image_commands.py
b/dev/breeze/src/airflow_breeze/commands/ci_image_commands.py
index e9b34bfd164..ad1c38e30c4 100644
--- a/dev/breeze/src/airflow_breeze/commands/ci_image_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/ci_image_commands.py
@@ -36,6 +36,7 @@ from airflow_breeze.commands.common_image_options import (
option_additional_python_deps,
option_airflow_constraints_reference_build,
option_build_progress,
+ option_cache_from_image,
option_debian_version,
option_dev_apt_command,
option_dev_apt_deps,
@@ -52,6 +53,7 @@ from airflow_breeze.commands.common_image_options import (
option_push,
option_python_image,
option_skip_image_file_deletion,
+ option_tag_as,
option_verify,
option_wait_for_image,
)
@@ -247,6 +249,7 @@ option_ci_image_file_to_load = click.option(
@option_answer
@option_build_progress
@option_builder
+@option_cache_from_image
@option_commit_sha
@option_debian_version
@option_debug_resources
@@ -286,6 +289,7 @@ def build(
airflow_constraints_reference: str,
build_progress: str,
builder: str,
+ cache_from_image: str | None,
commit_sha: str | None,
debian_version: str,
debug_resources: bool,
@@ -338,6 +342,7 @@ def build(
airflow_constraints_reference=airflow_constraints_reference,
build_progress=build_progress,
builder=builder,
+ cache_from_image=cache_from_image,
commit_sha=commit_sha,
debian_version=debian_version,
dev_apt_command=dev_apt_command,
@@ -558,6 +563,7 @@ def save(
@option_platform_single
@option_python
@option_skip_image_file_deletion
+@option_tag_as
@option_verbose
def load(
from_run: str | None,
@@ -569,6 +575,7 @@ def load(
platform: str,
python: str,
skip_image_file_deletion: bool,
+ tag_as: str | None,
):
"""Load CI image from a file."""
perform_environment_checks()
@@ -618,6 +625,15 @@ def load(
if result.returncode != 0:
console_print(f"[error]Error when loading image: {result.stdout}[/]")
sys.exit(result.returncode)
+ if tag_as:
+ console_print(f"[info]Tagging {build_ci_params.airflow_image_name} as
{tag_as}[/]")
+ result = run_command(
+ ["docker", "tag", build_ci_params.airflow_image_name, tag_as],
+ check=False,
+ )
+ if result.returncode != 0:
+ console_print(f"[error]Error when tagging image:
{result.stdout}[/]")
+ sys.exit(result.returncode)
if not skip_image_file_deletion:
console_print(f"[info]Deleting image file {image_file_to_load}[/]")
image_file_to_load.unlink()
diff --git a/dev/breeze/src/airflow_breeze/commands/ci_image_commands_config.py
b/dev/breeze/src/airflow_breeze/commands/ci_image_commands_config.py
index b9e0cf161a9..dd60ef4f2bf 100644
--- a/dev/breeze/src/airflow_breeze/commands/ci_image_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/ci_image_commands_config.py
@@ -57,6 +57,7 @@ CI_IMAGE_TOOLS_PARAMETERS: dict[str, list[dict[str, str |
list[str]]]] = {
"name": "Advanced build options (for power users)",
"options": [
"--additional-pip-install-flags",
+ "--cache-from-image",
"--commit-sha",
"--debian-version",
"--disable-airflow-repo-cache",
@@ -183,6 +184,7 @@ CI_IMAGE_TOOLS_PARAMETERS: dict[str, list[dict[str, str |
list[str]]]] = {
"--from-pr",
"--from-run",
"--skip-image-file-deletion",
+ "--tag-as",
],
},
],
diff --git a/dev/breeze/src/airflow_breeze/commands/common_image_options.py
b/dev/breeze/src/airflow_breeze/commands/common_image_options.py
index 5c545fbfbeb..696b1d93146 100644
--- a/dev/breeze/src/airflow_breeze/commands/common_image_options.py
+++ b/dev/breeze/src/airflow_breeze/commands/common_image_options.py
@@ -101,6 +101,12 @@ option_build_progress = click.option(
show_default=True,
default=ALLOWED_BUILD_PROGRESS[0],
)
+option_cache_from_image = click.option(
+ "--cache-from-image",
+ help="Additional image to read the build cache from - it has to be
pullable from a registry, "
+ "an image only present in the local docker engine contributes no cache.",
+ envvar="CACHE_FROM_IMAGE",
+)
option_debian_version = click.option(
"--debian-version",
type=BetterChoice(ALLOWED_DEBIAN_VERSIONS),
@@ -200,6 +206,11 @@ option_skip_image_file_deletion = click.option(
is_flag=True,
envvar="SKIP_IMAGE_FILE_DELETION",
)
+option_tag_as = click.option(
+ "--tag-as",
+ help="Additionally tag the loaded image with this reference.",
+ envvar="TAG_AS",
+)
option_from_run = click.option(
"--from-run",
required=False,
diff --git a/dev/breeze/src/airflow_breeze/params/common_build_params.py
b/dev/breeze/src/airflow_breeze/params/common_build_params.py
index 60f6034f925..01fc0d54061 100644
--- a/dev/breeze/src/airflow_breeze/params/common_build_params.py
+++ b/dev/breeze/src/airflow_breeze/params/common_build_params.py
@@ -51,6 +51,7 @@ class CommonBuildParams:
airflow_constraints_location: str | None = None
builder: str = "autodetect"
build_progress: str = ALLOWED_BUILD_PROGRESS[0]
+ cache_from_image: str | None = None
constraints_github_repository: str = APACHE_AIRFLOW_GITHUB_REPOSITORY
commit_sha: str | None = None
dev_apt_command: str | None = None
@@ -107,6 +108,15 @@ class CommonBuildParams:
extra_flags.append(f"--cache-from={self.get_cache(self.platform)}")
elif self.docker_cache == "disabled":
extra_flags.append("--no-cache")
+ if self.cache_from_image:
+ extra_flags.append(f"--cache-from={self.cache_from_image}")
+ if self.docker_cache != "disabled":
+ # Records the layer cache keys in the image config, which is what
lets an image
+ # built by an earlier run serve as `--cache-from` for a later one.
BuildKit only
+ # honours those records when it can pull the layers from a
registry, so an image
+ # that travelled as a saved tarball has to be pushed to one (even
a throw-away
+ # local registry) before it can be passed as `--cache-from-image`.
+ extra_flags.append("--build-arg=BUILDKIT_INLINE_CACHE=1")
return extra_flags
@property
diff --git a/dev/breeze/tests/test_build_ci_params.py
b/dev/breeze/tests/test_build_ci_params.py
new file mode 100644
index 00000000000..f652ca2f613
--- /dev/null
+++ b/dev/breeze/tests/test_build_ci_params.py
@@ -0,0 +1,57 @@
+# 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.params.build_ci_params import BuildCiParams
+
+INLINE_CACHE_FLAG = "--build-arg=BUILDKIT_INLINE_CACHE=1"
+
+
[email protected](
+ ("docker_cache", "inline_cache_expected"),
+ [
+ pytest.param("registry", True, id="registry"),
+ pytest.param("local", True, id="local"),
+ pytest.param("disabled", False, id="disabled"),
+ ],
+)
+def test_inline_cache_recorded_unless_cache_disabled(docker_cache: str,
inline_cache_expected: bool):
+ flags = BuildCiParams(docker_cache=docker_cache).common_docker_build_flags
+ assert (INLINE_CACHE_FLAG in flags) is inline_cache_expected
+
+
+def test_cache_from_image_added_next_to_registry_cache():
+ params = BuildCiParams(docker_cache="registry",
cache_from_image="localhost:5000/ci-image-cache:3.12")
+ flags = params.common_docker_build_flags
+ assert f"--cache-from={params.get_cache(params.platform)}" in flags
+ assert "--cache-from=localhost:5000/ci-image-cache:3.12" in flags
+
+
+def test_cache_from_image_added_when_registry_cache_is_not_used():
+ flags = BuildCiParams(
+ docker_cache="disabled",
cache_from_image="localhost:5000/ci-image-cache:3.12"
+ ).common_docker_build_flags
+ assert "--cache-from=localhost:5000/ci-image-cache:3.12" in flags
+ assert "--no-cache" in flags
+
+
+def test_no_cache_from_image_flag_when_unset():
+ flags = BuildCiParams(docker_cache="registry").common_docker_build_flags
+ assert not any(flag.startswith("--cache-from=localhost") for flag in flags)