1919name : " Scheduled legacy PROD image canary"
2020# The default PROD images are hardened and based on Debian trixie, and that is all that PR and canary
2121# builds test. The "legacy" flavor - Python compiled from sources on Debian bookworm - is still
22- # published for the 3.4.x line, so this checks once a week that it can still be built and passes the
23- # PROD image checks , instead of finding out only when a release is being prepared.
22+ # published for the 3.4.x line, so once a week this builds legacy bookworm PROD images and runs the
23+ # regular PROD image tests against them , instead of finding out only when a release is being prepared.
2424#
25- # The image is built the way release images are: with the Airflow version released to PyPI and its
26- # constraints, on top of the Dockerfile from the checked-out branch.
25+ # It reuses the PROD image workflows of the main CI build. The constraints those workflows normally get
26+ # from the CI image are taken from the constraints branch instead, so no CI image has to be built .
2727on : # yamllint disable-line rule:truthy
2828 schedule :
2929 - cron : ' 43 2 * * 0'
@@ -34,53 +34,149 @@ concurrency:
3434 group : scheduled-legacy-prod-image-canary-${{ github.ref }}
3535 cancel-in-progress : true
3636jobs :
37- python-versions :
38- name : " Python versions to test "
39- runs-on : ["ubuntu-slim "]
37+ build-info :
38+ name : " Build info "
39+ runs-on : ["ubuntu-22.04 "]
4040 if : github.repository == 'apache/airflow' || github.event_name == 'workflow_dispatch'
41- timeout-minutes : 10
41+ timeout-minutes : 15
4242 outputs :
43- python-versions : ${{ steps.versions.outputs.python-versions }}
44- airflow-version : ${{ steps.versions.outputs.airflow-version }}
43+ canary-run : ${{ steps.source-run-info.outputs.canary-run }}
44+ debug-resources : ${{ steps.selective-checks.outputs.debug-resources }}
45+ default-branch : ${{ steps.selective-checks.outputs.default-branch }}
46+ default-constraints-branch : ${{ steps.selective-checks.outputs.default-constraints-branch }}
47+ default-kubernetes-version : ${{ steps.selective-checks.outputs.default-kubernetes-version }}
48+ default-python-version : ${{ steps.selective-checks.outputs.default-python-version }}
49+ disable-airflow-repo-cache : ${{ steps.selective-checks.outputs.disable-airflow-repo-cache }}
50+ include-success-outputs : ${{ steps.selective-checks.outputs.include-success-outputs }}
51+ java-sdk-version : ${{ steps.selective-checks.outputs.java-sdk-version }}
52+ kubernetes-combos : ${{ steps.selective-checks.outputs.kubernetes-combos }}
53+ providers-compatibility-tests-matrix : >
54+ ${{ steps.selective-checks.outputs.providers-compatibility-tests-matrix }}
55+ python-versions : ${{ steps.selective-checks.outputs.python-versions }}
56+ python-versions-list-as-string : ${{ steps.selective-checks.outputs.python-versions-list-as-string }}
57+ run-airflow-ctl-integration-tests : >-
58+ ${{ steps.selective-checks.outputs.run-airflow-ctl-integration-tests }}
59+ run-event-driven-e2e-tests : ${{ steps.selective-checks.outputs.run-event-driven-e2e-tests }}
60+ run-go-sdk-e2e-tests : ${{ steps.selective-checks.outputs.run-go-sdk-e2e-tests }}
61+ run-java-sdk-e2e-tests : ${{ steps.selective-checks.outputs.run-java-sdk-e2e-tests }}
62+ run-openlineage-e2e-compat-tests : ${{ steps.selective-checks.outputs.run-openlineage-e2e-compat-tests }}
63+ run-openlineage-e2e-tests : ${{ steps.selective-checks.outputs.run-openlineage-e2e-tests }}
64+ run-remote-logging-elasticsearch-e2e-tests : >-
65+ ${{ steps.selective-checks.outputs.run-remote-logging-elasticsearch-e2e-tests }}
66+ run-remote-logging-opensearch-e2e-tests : >-
67+ ${{ steps.selective-checks.outputs.run-remote-logging-opensearch-e2e-tests }}
68+ run-remote-logging-s3-e2e-tests : ${{ steps.selective-checks.outputs.run-remote-logging-s3-e2e-tests }}
69+ run-task-sdk-integration-tests : ${{ steps.selective-checks.outputs.run-task-sdk-integration-tests }}
70+ run-ts-sdk-e2e-tests : ${{ steps.selective-checks.outputs.run-ts-sdk-e2e-tests }}
71+ run-ui-e2e-tests : ${{ steps.selective-checks.outputs.run-ui-e2e-tests }}
72+ use-uv : ${{ steps.selective-checks.outputs.force-pip == 'true' && 'false' || 'true' }}
4573 steps :
74+ - name : " Cleanup repo"
75+ shell : bash
76+ run : sudo rm -rf ${GITHUB_WORKSPACE}/*
4677 - name : " Checkout ${{ github.ref }} ( ${{ github.sha }} )"
4778 uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
4879 with :
80+ fetch-depth : 2
4981 persist-credentials : false
50- - name : " Install uv"
51- uses : astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
52- with :
53- version-file : uv.lock
54- - name : " Get Python versions and the latest released Airflow version"
55- id : versions
82+ - name : " Install Breeze"
83+ uses : ./.github/actions/breeze
84+ - name : " Save github context to file"
85+ # Same as in ci-amd.yml: a scheduled or dispatched run has no attacker-controlled context, and
86+ # the single-quoted heredoc disables every shell expansion of the JSON anyway.
87+ shell : bash
88+ run : | # zizmor: ignore[template-injection]
89+ cat > "${RUNNER_TEMP}/github_context.json" << '__GITHUB_CONTEXT_END__'
90+ ${{ toJson(github) }}
91+ __GITHUB_CONTEXT_END__
92+ - name : " Get information about the Workflow"
93+ id : source-run-info
94+ run : breeze ci get-workflow-info 2>> ${GITHUB_OUTPUT}
95+ env :
96+ SKIP_BREEZE_SELF_UPGRADE_CHECK : " true"
97+ GITHUB_CONTEXT_INPUT : " ${{ runner.temp }}/github_context.json"
98+ - name : " Selective checks"
99+ id : selective-checks
100+ env :
101+ COMMIT_REF : " ${{ github.sha }}"
102+ VERBOSE : " false"
103+ GITHUB_CONTEXT_INPUT : " ${{ runner.temp }}/github_context.json"
104+ PLATFORM : " linux/amd64"
105+ run : breeze ci selective-check 2>> ${GITHUB_OUTPUT}
106+
107+ constraints :
108+ name : " Constraints ${{ matrix.python-version }}"
109+ needs : [build-info]
110+ runs-on : ["ubuntu-slim"]
111+ timeout-minutes : 10
112+ strategy :
113+ matrix :
114+ python-version : ${{ fromJSON(needs.build-info.outputs.python-versions) }}
115+ env :
116+ PYTHON_MAJOR_MINOR_VERSION : ${{ matrix.python-version }}
117+ CONSTRAINTS_BRANCH : ${{ needs.build-info.outputs.default-constraints-branch }}
118+ steps :
119+ - name : " Download constraints from ${{ env.CONSTRAINTS_BRANCH }}"
56120 run : |
57- python_versions=$(uv run --project dev/breeze python -c "
58- import json
59- from airflow_breeze.global_constants import CURRENT_PYTHON_MAJOR_MINOR_VERSIONS
60- print(json.dumps(CURRENT_PYTHON_MAJOR_MINOR_VERSIONS))
61- ")
62- airflow_version=$(curl -fsSL --retry 3 https://pypi.org/pypi/apache-airflow/json \
63- | jq -r .info.version)
64- echo "python-versions=${python_versions}" >> "${GITHUB_OUTPUT}"
65- echo "airflow-version=${airflow_version}" >> "${GITHUB_OUTPUT}"
66- echo "Python versions: ${python_versions}, Airflow version: ${airflow_version}"
121+ base_url="https://raw.githubusercontent.com/apache/airflow/${CONSTRAINTS_BRANCH}"
122+ target_dir="files/constraints-${PYTHON_MAJOR_MINOR_VERSION}"
123+ mkdir -p "${target_dir}"
124+ for prefix in constraints constraints-no-providers constraints-source-providers; do
125+ file="${prefix}-${PYTHON_MAJOR_MINOR_VERSION}.txt"
126+ curl -fsSL --retry 5 "${base_url}/${file}" -o "${target_dir}/${file}"
127+ done
128+ ls -l "files/constraints-${PYTHON_MAJOR_MINOR_VERSION}"
129+ # Same artifact name and layout as generate-constraints.yml uploads, which is what the PROD image
130+ # build downloads.
131+ - name : " Upload constraint artifacts"
132+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
133+ with :
134+ name : constraints-${{ matrix.python-version }}
135+ path : ./files/constraints-${{ matrix.python-version }}/constraints-*.txt
136+ retention-days : 7
137+ if-no-files-found : error
67138
68- legacy-prod-image :
69- name : " Legacy bookworm PROD image ${{ matrix.python-version }}"
70- needs : [python-versions]
139+ build-prod-images :
140+ name : " Build legacy bookworm PROD images"
141+ needs : [build-info, constraints]
142+ uses : ./.github/workflows/prod-image-build.yml
143+ permissions :
144+ contents : read
145+ packages : read
146+ with :
147+ runners : ' ["ubuntu-22.04"]'
148+ platform : " linux/amd64"
149+ build-type : " Legacy"
150+ debian-version : " bookworm"
151+ image-flavor : " legacy"
152+ push-image : " false"
153+ upload-image-artifact : " true"
154+ upload-package-artifact : " true"
155+ python-versions : ${{ needs.build-info.outputs.python-versions }}
156+ default-python-version : " ${{ needs.build-info.outputs.default-python-version }}"
157+ branch : ${{ needs.build-info.outputs.default-branch }}
158+ use-uv : ${{ needs.build-info.outputs.use-uv }}
159+ upgrade-to-newer-dependencies : " false"
160+ constraints-branch : ${{ needs.build-info.outputs.default-constraints-branch }}
161+ # The cache in the registry is the one of the hardened images - it would not match anyway.
162+ docker-cache : " disabled"
163+ disable-airflow-repo-cache : ${{ needs.build-info.outputs.disable-airflow-repo-cache }}
164+ prod-image-build : " true"
165+
166+ verify-legacy-flavor :
167+ name : " Verify legacy bookworm flavor ${{ matrix.python-version }}"
168+ needs : [build-info, build-prod-images]
71169 runs-on : ["ubuntu-22.04"]
72- timeout-minutes : 90
170+ timeout-minutes : 20
73171 strategy :
74172 fail-fast : false
75173 matrix :
76- python-version : ${{ fromJSON(needs.python-versions .outputs.python-versions) }}
174+ python-version : ${{ fromJSON(needs.build-info .outputs.python-versions) }}
77175 env :
78176 PYTHON_MAJOR_MINOR_VERSION : ${{ matrix.python-version }}
79- AIRFLOW_VERSION : ${{ needs.python-versions.outputs.airflow-version }}
80177 GITHUB_REPOSITORY : ${{ github.repository }}
81178 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
82179 GITHUB_USERNAME : ${{ github.actor }}
83- VERBOSE : " true"
84180 steps :
85181 - name : " Cleanup repo"
86182 shell : bash
@@ -89,32 +185,78 @@ jobs:
89185 uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
90186 with :
91187 persist-credentials : false
92- - name : " Make /mnt writeable"
93- run : ./scripts/ci/make_mnt_writeable.sh
94- - name : " Move docker to /mnt"
95- run : ./scripts/ci/move_docker_to_mnt.sh
96- - name : " Install Breeze"
97- uses : ./.github/actions/breeze
98- - name : " Build legacy bookworm PROD image ${{ matrix.python-version }}"
99- run : >
100- breeze prod-image build
101- --python "${PYTHON_MAJOR_MINOR_VERSION}"
102- --image-flavor legacy
103- --debian-version bookworm
104- --installation-method apache-airflow
105- --install-airflow-version "${AIRFLOW_VERSION}"
106- --airflow-constraints-reference "constraints-${AIRFLOW_VERSION}"
107- --docker-cache disabled
188+ - name : " Prepare breeze & PROD image: ${{ env.PYTHON_MAJOR_MINOR_VERSION }}"
189+ uses : ./.github/actions/prepare_breeze_and_image
190+ with :
191+ platform : " linux/amd64"
192+ image-type : " prod"
193+ python : ${{ env.PYTHON_MAJOR_MINOR_VERSION }}
194+ use-uv : ${{ needs.build-info.outputs.use-uv }}
195+ make-mnt-writeable-and-cleanup : true
196+ # Guards against the canary silently testing the default flavor if the flavor or Debian version
197+ # stop being passed through to the build.
108198 - name : " Verify the image is the legacy bookworm flavor"
199+ env :
200+ DEFAULT_BRANCH : ${{ needs.build-info.outputs.default-branch }}
109201 run : |
110- image="ghcr.io/${GITHUB_REPOSITORY,,}/main /prod/python${PYTHON_MAJOR_MINOR_VERSION}"
202+ image="ghcr.io/${GITHUB_REPOSITORY,,}/${DEFAULT_BRANCH} /prod/python${PYTHON_MAJOR_MINOR_VERSION}"
111203 flavor=$(docker inspect "${image}" \
112204 --format '{{ index .Config.Labels "org.apache.airflow.image.flavor" }}')
113205 codename=$(docker run --rm --entrypoint /bin/bash "${image}" \
114206 -c '. /etc/os-release && echo "${VERSION_CODENAME}"')
115207 echo "Image flavor: ${flavor}, Debian: ${codename}"
116208 [[ "${flavor}" == "legacy" && "${codename}" == "bookworm" ]]
117- - name : " Verify PROD image ${{ matrix.python-version }}"
118- run : breeze prod-image verify --python "${PYTHON_MAJOR_MINOR_VERSION}"
119- - name : " Test docker-compose quick start ${{ matrix.python-version }}"
120- run : breeze testing docker-compose-tests --python "${PYTHON_MAJOR_MINOR_VERSION}"
209+
210+ additional-prod-image-tests :
211+ name : " PROD image tests"
212+ needs : [build-info, build-prod-images, constraints]
213+ uses : ./.github/workflows/additional-prod-image-tests.yml
214+ with :
215+ runners : ' ["ubuntu-22.04"]'
216+ platform : " linux/amd64"
217+ default-branch : ${{ needs.build-info.outputs.default-branch }}
218+ constraints-branch : ${{ needs.build-info.outputs.default-constraints-branch }}
219+ upgrade-to-newer-dependencies : " false"
220+ docker-cache : " disabled"
221+ disable-airflow-repo-cache : ${{ needs.build-info.outputs.disable-airflow-repo-cache }}
222+ default-python-version : " ${{ needs.build-info.outputs.default-python-version }}"
223+ run-task-sdk-integration-tests : ${{ needs.build-info.outputs.run-task-sdk-integration-tests }}
224+ canary-run : ${{ needs.build-info.outputs.canary-run }}
225+ run-remote-logging-elasticsearch-e2e-tests : >-
226+ ${{ needs.build-info.outputs.run-remote-logging-elasticsearch-e2e-tests }}
227+ run-remote-logging-opensearch-e2e-tests : >-
228+ ${{ needs.build-info.outputs.run-remote-logging-opensearch-e2e-tests }}
229+ run-remote-logging-s3-e2e-tests : ${{ needs.build-info.outputs.run-remote-logging-s3-e2e-tests }}
230+ run-event-driven-e2e-tests : ${{ needs.build-info.outputs.run-event-driven-e2e-tests }}
231+ run-java-sdk-e2e-tests : ${{ needs.build-info.outputs.run-java-sdk-e2e-tests }}
232+ java-sdk-version : ${{ needs.build-info.outputs.java-sdk-version }}
233+ run-go-sdk-e2e-tests : ${{ needs.build-info.outputs.run-go-sdk-e2e-tests }}
234+ run-openlineage-e2e-tests : ${{ needs.build-info.outputs.run-openlineage-e2e-tests }}
235+ run-openlineage-e2e-compat-tests : ${{ needs.build-info.outputs.run-openlineage-e2e-compat-tests }}
236+ providers-compatibility-tests-matrix : >
237+ ${{ needs.build-info.outputs.providers-compatibility-tests-matrix }}
238+ run-ts-sdk-e2e-tests : ${{ needs.build-info.outputs.run-ts-sdk-e2e-tests }}
239+ use-uv : ${{ needs.build-info.outputs.use-uv }}
240+ run-ui-e2e-tests : ${{ needs.build-info.outputs.run-ui-e2e-tests }}
241+ run-airflow-ctl-integration-tests : ${{ needs.build-info.outputs.run-airflow-ctl-integration-tests }}
242+
243+ tests-kubernetes :
244+ name : " Kubernetes tests"
245+ needs : [build-info, build-prod-images]
246+ uses : ./.github/workflows/k8s-tests.yml
247+ permissions :
248+ contents : read
249+ packages : read
250+ with :
251+ runners : ' ["ubuntu-22.04"]'
252+ platform : " linux/amd64"
253+ python-versions-list-as-string : ${{ needs.build-info.outputs.python-versions-list-as-string }}
254+ include-success-outputs : ${{ needs.build-info.outputs.include-success-outputs }}
255+ use-uv : ${{ needs.build-info.outputs.use-uv }}
256+ debug-resources : ${{ needs.build-info.outputs.debug-resources }}
257+ kubernetes-combos : ${{ needs.build-info.outputs.kubernetes-combos }}
258+ java-sdk-version : ${{ needs.build-info.outputs.java-sdk-version }}
259+ # yamllint disable rule:line-length
260+ lang-sdk-kubernetes-combo : >-
261+ ${{ needs.build-info.outputs.default-python-version }}-${{ needs.build-info.outputs.default-kubernetes-version }}
262+ # yamllint enable rule:line-length
0 commit comments