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 c66d54075b9 Fix scheduled CI upgrade job: extract versions from
uv.lock + Slack alerts (#65211)
c66d54075b9 is described below
commit c66d54075b93b9e538d12bc4f536ec96c0e5fafb
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue Apr 14 15:27:38 2026 +0200
Fix scheduled CI upgrade job: extract versions from uv.lock + Slack alerts
(#65211)
Removes all hard-coded uv/prek version strings from GitHub Actions
workflows and composite actions and derives them at runtime from
'uv.lock' via a small sed snippet. Also adds Slack success and failure
notifications to the scheduled CI upgrade workflow.
Why: the scheduled '[v3-2-test] Scheduled CI upgrade check' job was
failing because 'breeze ci upgrade' kept rewriting version strings in
'.github/workflows/*.yml' files, which the default GITHUB_TOKEN (a
GitHub App token) is not permitted to push. Reading versions from
'uv.lock' (which gets refreshed by 'uv lock --upgrade' as part of the
upgrade run anyway) means the job no longer needs to touch any file
under '.github/workflows/' and its PR can be created using only the
standard GITHUB_TOKEN — no PAT or GitHub App required.
Notifications to '#internal-airflow-ci-cd' now fire on both success
(with PR link and Undraft -> Review -> Merge-once-CI-passes steps) and
failure (with a link to the failed run). The branch prefix
(e.g. '[main]' vs '[v3-2-test]') distinguishes notifications between
the schedules.
---
.github/actions/breeze/action.yml | 16 ++++---
.github/actions/install-prek/action.yml | 31 +++++++++-----
.github/workflows/basic-tests.yml | 43 +++++++++++++------
.github/workflows/ci-amd-arm.yml | 1 -
.github/workflows/release_dockerhub_image.yml | 3 --
.../scheduled-verify-release-calendar.yml | 13 ++++--
.github/workflows/update-constraints-on-push.yml | 2 +-
.github/workflows/upgrade-check.yml | 49 ++++++++++++++++++----
scripts/ci/prek/upgrade_important_versions.py | 6 ---
9 files changed, 112 insertions(+), 52 deletions(-)
diff --git a/.github/actions/breeze/action.yml
b/.github/actions/breeze/action.yml
index cc6005f3955..f9a4dc5a683 100644
--- a/.github/actions/breeze/action.yml
+++ b/.github/actions/breeze/action.yml
@@ -22,9 +22,6 @@ inputs:
python-version:
description: 'Python version to use'
default: "3.10"
- uv-version:
- description: 'uv version to use'
- default: "0.11.3" # Keep this comment to allow automatic replacement of
uv version
outputs:
host-python-version:
description: Python version used in host
@@ -38,9 +35,16 @@ runs:
python-version: ${{ inputs.python-version }}
- name: "Install uv"
shell: bash
- run: pip install "uv==${UV_VERSION}"
- env:
- UV_VERSION: ${{ inputs.uv-version }}
+ # Extract uv version from uv.lock. The format is stable: the line
+ # immediately after `name = "uv"` is `version = "<X.Y.Z>"`.
+ run: |
+ UV_VERSION=$(sed -n '/^name = "uv"$/{n;s/^version = "\(.*\)"$/\1/p;}'
uv.lock)
+ if [[ -z "${UV_VERSION}" ]]; then
+ echo "Failed to extract uv version from uv.lock" >&2
+ exit 1
+ fi
+ echo "Installing uv==${UV_VERSION}"
+ pip install "uv==${UV_VERSION}"
# NOTE! Installing Breeze without using cache is FASTER than when using
cache - uv is so fast and has
# so low overhead, that just running upload cache/restore cache is slower
than installing it from scratch
- name: "Install Breeze"
diff --git a/.github/actions/install-prek/action.yml
b/.github/actions/install-prek/action.yml
index 7e43c3245f4..998a1b186d3 100644
--- a/.github/actions/install-prek/action.yml
+++ b/.github/actions/install-prek/action.yml
@@ -22,12 +22,6 @@ inputs:
python-version:
description: 'Python version to use'
default: "3.10"
- uv-version:
- description: 'uv version to use'
- default: "0.11.3" # Keep this comment to allow automatic replacement of
uv version
- prek-version:
- description: 'prek version to use'
- default: "0.3.8" # Keep this comment to allow automatic replacement of
prek version
save-cache:
description: "Whether to save prek cache"
required: true
@@ -37,16 +31,31 @@ inputs:
runs:
using: "composite"
steps:
+ - name: "Extract uv and prek versions from uv.lock"
+ id: versions
+ shell: bash
+ # The uv.lock format is stable: the line immediately after `name =
"<pkg>"`
+ # is `version = "<X.Y.Z>"` for that package.
+ run: |
+ UV_VERSION=$(sed -n '/^name = "uv"$/{n;s/^version = "\(.*\)"$/\1/p;}'
uv.lock)
+ PREK_VERSION=$(sed -n '/^name = "prek"$/{n;s/^version =
"\(.*\)"$/\1/p;}' uv.lock)
+ if [[ -z "${UV_VERSION}" || -z "${PREK_VERSION}" ]]; then
+ echo "Failed to extract uv (${UV_VERSION}) or prek (${PREK_VERSION})
version from uv.lock" >&2
+ exit 1
+ fi
+ echo "Extracted uv==${UV_VERSION}, prek==${PREK_VERSION}"
+ echo "uv-version=${UV_VERSION}" >> "${GITHUB_OUTPUT}"
+ echo "prek-version=${PREK_VERSION}" >> "${GITHUB_OUTPUT}"
- name: "Install uv"
shell: bash
run: pip install "uv==${UV_VERSION}"
env:
- UV_VERSION: ${{ inputs.uv-version }}
+ UV_VERSION: ${{ steps.versions.outputs.uv-version }}
- name: Install prek
shell: bash
env:
- PREK_VERSION: ${{inputs.prek-version}}
- UV_VERSION: ${{ inputs.uv-version }}
+ UV_VERSION: ${{ steps.versions.outputs.uv-version }}
+ PREK_VERSION: ${{ steps.versions.outputs.prek-version }}
run: |
uv tool install prek==${PREK_VERSION} --with uv==${UV_VERSION}
working-directory: ${{ github.workspace }}
@@ -64,7 +73,7 @@ runs:
uses:
apache/infrastructure-actions/stash/restore@1c35b5ccf8fba5d4c3fdf25a045ca91aa0cbc468
with:
# yamllint disable rule:line-length
- key: cache-prek-v9-${{ inputs.platform }}-python${{
inputs.python-version }}-uv${{ inputs.uv-version }}-${{
hashFiles('**/.pre-commit-config.yaml') }}
+ key: cache-prek-v9-${{ inputs.platform }}-python${{
inputs.python-version }}-uv${{ steps.versions.outputs.uv-version }}-${{
hashFiles('**/.pre-commit-config.yaml') }}
path: /tmp/
id: restore-prek-cache
- name: "Restore .cache from the tar file"
@@ -113,7 +122,7 @@ runs:
uses:
apache/infrastructure-actions/stash/save@1c35b5ccf8fba5d4c3fdf25a045ca91aa0cbc468
with:
# yamllint disable rule:line-length
- key: cache-prek-v9-${{ inputs.platform }}-python${{
inputs.python-version }}-uv${{ inputs.uv-version }}-${{
hashFiles('**/.pre-commit-config.yaml') }}
+ key: cache-prek-v9-${{ inputs.platform }}-python${{
inputs.python-version }}-uv${{ steps.versions.outputs.uv-version }}-${{
hashFiles('**/.pre-commit-config.yaml') }}
path: /tmp/cache-prek.tar.gz
if-no-files-found: 'error'
retention-days: '2'
diff --git a/.github/workflows/basic-tests.yml
b/.github/workflows/basic-tests.yml
index 5f449ab2227..5bc1fc8905b 100644
--- a/.github/workflows/basic-tests.yml
+++ b/.github/workflows/basic-tests.yml
@@ -72,10 +72,6 @@ on: # yamllint disable-line rule:truthy
description: "Whether to use uv in the image"
required: true
type: string
- uv-version:
- description: 'uv version to use'
- default: "0.11.3" # Keep this comment to allow automatic replacement
of uv version
- type: string
platform:
description: 'Platform for the build - linux/amd64 or linux/arm64'
required: true
@@ -143,9 +139,16 @@ jobs:
fetch-depth: 1
persist-credentials: false
- name: "Install uv"
- run: pip install "uv==${UV_VERSION}"
- env:
- UV_VERSION: ${{ inputs.uv-version }}
+ # Extract uv version from uv.lock. The format is stable: the line
+ # immediately after `name = "uv"` is `version = "<X.Y.Z>"`.
+ run: |
+ UV_VERSION=$(sed -n '/^name = "uv"$/{n;s/^version =
"\(.*\)"$/\1/p;}' uv.lock)
+ if [[ -z "${UV_VERSION}" ]]; then
+ echo "Failed to extract uv version from uv.lock" >&2
+ exit 1
+ fi
+ echo "Installing uv==${UV_VERSION}"
+ pip install "uv==${UV_VERSION}"
- name: "Run shared ${{ matrix.shared-distribution }} tests"
run: uv run --group dev pytest --color=yes -n auto
working-directory: shared/${{ matrix.shared-distribution }}
@@ -161,9 +164,16 @@ jobs:
fetch-depth: 1
persist-credentials: false
- name: "Install uv"
- run: pip install "uv==${UV_VERSION}"
- env:
- UV_VERSION: ${{ inputs.uv-version }}
+ # Extract uv version from uv.lock. The format is stable: the line
+ # immediately after `name = "uv"` is `version = "<X.Y.Z>"`.
+ run: |
+ UV_VERSION=$(sed -n '/^name = "uv"$/{n;s/^version =
"\(.*\)"$/\1/p;}' uv.lock)
+ if [[ -z "${UV_VERSION}" ]]; then
+ echo "Failed to extract uv version from uv.lock" >&2
+ exit 1
+ fi
+ echo "Installing uv==${UV_VERSION}"
+ pip install "uv==${UV_VERSION}"
- name: "Run scripts tests"
run: uv run --project . pytest --color=yes -n auto
working-directory: ./scripts/
@@ -368,9 +378,16 @@ jobs:
with:
persist-credentials: false
- name: "Install uv"
- run: pip install "uv==${UV_VERSION}"
- env:
- UV_VERSION: ${{ inputs.uv-version }}
+ # Extract uv version from uv.lock. The format is stable: the line
+ # immediately after `name = "uv"` is `version = "<X.Y.Z>"`.
+ run: |
+ UV_VERSION=$(sed -n '/^name = "uv"$/{n;s/^version =
"\(.*\)"$/\1/p;}' uv.lock)
+ if [[ -z "${UV_VERSION}" ]]; then
+ echo "Failed to extract uv version from uv.lock" >&2
+ exit 1
+ fi
+ echo "Installing uv==${UV_VERSION}"
+ pip install "uv==${UV_VERSION}"
- name: "Set up Airflow home directory"
run: |
echo "Setting AIRFLOW_HOME to $AIRFLOW_HOME"
diff --git a/.github/workflows/ci-amd-arm.yml b/.github/workflows/ci-amd-arm.yml
index 035b4d53d74..da98b28b4d0 100644
--- a/.github/workflows/ci-amd-arm.yml
+++ b/.github/workflows/ci-amd-arm.yml
@@ -40,7 +40,6 @@ env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_USERNAME: ${{ github.actor }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
- UV_VERSION: "0.11.3" # Keep this comment to allow automatic replacement of
uv version
VERBOSE: "true"
concurrency:
diff --git a/.github/workflows/release_dockerhub_image.yml
b/.github/workflows/release_dockerhub_image.yml
index 3614f4c7eef..f3efcb67c2f 100644
--- a/.github/workflows/release_dockerhub_image.yml
+++ b/.github/workflows/release_dockerhub_image.yml
@@ -58,7 +58,6 @@ jobs:
AIRFLOW_VERSION: ${{ github.event.inputs.airflowVersion }}
AMD_ONLY: ${{ github.event.inputs.amdOnly }}
LIMIT_PYTHON_VERSIONS: ${{ github.event.inputs.limitPythonVersions }}
- UV_VERSION: "0.11.3" # Keep this comment to allow automatic replacement
of uv version
if: contains(fromJSON('[
"ashb",
"bugraoz93",
@@ -93,8 +92,6 @@ jobs:
persist-credentials: false
- name: "Install Breeze"
uses: ./.github/actions/breeze
- with:
- uv-version: ${{ env.UV_VERSION }}
- name: Selective checks
id: selective-checks
env:
diff --git a/.github/workflows/scheduled-verify-release-calendar.yml
b/.github/workflows/scheduled-verify-release-calendar.yml
index 75b5b8742dd..199ccfb72c1 100644
--- a/.github/workflows/scheduled-verify-release-calendar.yml
+++ b/.github/workflows/scheduled-verify-release-calendar.yml
@@ -24,8 +24,6 @@ on: # yamllint disable-line rule:truthy
workflow_dispatch:
permissions:
contents: read
-env:
- UV_VERSION: "0.11.3" # Keep this comment to allow automatic replacement of
uv version
jobs:
verify-release-calendar:
name: "Verify release calendar"
@@ -37,7 +35,16 @@ jobs:
with:
persist-credentials: false
- name: "Install uv"
- run: pip install "uv==${UV_VERSION}"
+ # Extract uv version from uv.lock. The format is stable: the line
+ # immediately after `name = "uv"` is `version = "<X.Y.Z>"`.
+ run: |
+ UV_VERSION=$(sed -n '/^name = "uv"$/{n;s/^version =
"\(.*\)"$/\1/p;}' uv.lock)
+ if [[ -z "${UV_VERSION}" ]]; then
+ echo "Failed to extract uv version from uv.lock" >&2
+ exit 1
+ fi
+ echo "Installing uv==${UV_VERSION}"
+ pip install "uv==${UV_VERSION}"
- name: "Verify release calendar"
run: uv run dev/verify_release_calendar.py
# yamllint disable rule:line-length
diff --git a/.github/workflows/update-constraints-on-push.yml
b/.github/workflows/update-constraints-on-push.yml
index 182ad7374e4..18042838cd1 100644
--- a/.github/workflows/update-constraints-on-push.yml
+++ b/.github/workflows/update-constraints-on-push.yml
@@ -22,6 +22,7 @@ on: # yamllint disable-line rule:truthy
branches:
- main
- v[0-9]+-[0-9]+-test
+ - v[0-9]+-[0-9]+-stable
paths:
- 'uv.lock'
permissions:
@@ -34,7 +35,6 @@ env:
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_USERNAME: ${{ github.actor }}
- UV_VERSION: "0.10.10" # Keep this comment to allow automatic replacement of
uv version
VERBOSE: "true"
jobs:
build-info:
diff --git a/.github/workflows/upgrade-check.yml
b/.github/workflows/upgrade-check.yml
index 55a7383665e..d4f23d57822 100644
--- a/.github/workflows/upgrade-check.yml
+++ b/.github/workflows/upgrade-check.yml
@@ -100,8 +100,8 @@ jobs:
--jq '.[0].url' 2>/dev/null || true)
echo "pr-url=${PR_URL}" >> "${GITHUB_OUTPUT}"
- name: >-
- [${{ inputs.target-branch }}] Notify Slack
- if: steps.find-pr.outputs.pr-url != ''
+ [${{ inputs.target-branch }}] Notify Slack on success
+ if: success() && steps.find-pr.outputs.pr-url != ''
uses: >-
slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95
with:
@@ -110,16 +110,49 @@ jobs:
payload: |
channel: "internal-airflow-ci-cd"
text: >-
- 🔧 [${{ inputs.target-branch }}] CI upgrade PR
- ready for review. Please undraft, review and
- merge: ${{ steps.find-pr.outputs.pr-url }}
+ 🔧 [${{ inputs.target-branch }}] Scheduled CI upgrade PR
+ ready: ${{ steps.find-pr.outputs.pr-url }}
blocks:
- type: section
text:
type: mrkdwn
text: >-
- 🔧 *[${{ inputs.target-branch }}] CI upgrade
- PR ready for review*
+ 🔧 *[${{ inputs.target-branch }}] Scheduled CI upgrade
+ PR ready*
+
+ A new CI upgrade PR has been created as a draft on the
+ `${{ inputs.target-branch }}` branch. Please:
+
+ 1. *Undraft* the PR to trigger CI
+ 2. *Review* the changes
+ 3. *Merge* it once CI passes
- Please undraft, review and merge:
<${{ steps.find-pr.outputs.pr-url }}|View PR>
+ - name: >-
+ [${{ inputs.target-branch }}] Notify Slack on failure
+ if: failure()
+ uses: >-
+ slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95
+ with:
+ method: chat.postMessage
+ token: ${{ env.SLACK_BOT_TOKEN }}
+ # yamllint disable rule:line-length
+ payload: |
+ channel: "internal-airflow-ci-cd"
+ text: >-
+ ⚠️ [${{ inputs.target-branch }}] Scheduled CI upgrade FAILED.
+ See: ${{ github.server_url }}/${{ github.repository
}}/actions/runs/${{ github.run_id }}
+ blocks:
+ - type: section
+ text:
+ type: mrkdwn
+ text: >-
+ ⚠️ *[${{ inputs.target-branch }}] Scheduled CI upgrade
+ FAILED*
+
+ The `breeze ci upgrade` job on the
+ `${{ inputs.target-branch }}` branch did not complete
+ successfully. Please investigate the failed run and
+ re-run the workflow if needed.
+
+ <${{ github.server_url }}/${{ github.repository
}}/actions/runs/${{ github.run_id }}|View failed run>
diff --git a/scripts/ci/prek/upgrade_important_versions.py
b/scripts/ci/prek/upgrade_important_versions.py
index 63975364b80..472abd81b89 100755
--- a/scripts/ci/prek/upgrade_important_versions.py
+++ b/scripts/ci/prek/upgrade_important_versions.py
@@ -67,7 +67,6 @@ FILES_TO_UPDATE: list[tuple[Path, bool]] = [
(AIRFLOW_ROOT_PATH / "scripts" / "docker" / "common.sh", False),
(AIRFLOW_ROOT_PATH / "scripts" / "tools" / "setup_breeze", False),
(AIRFLOW_ROOT_PATH / "pyproject.toml", False),
- (AIRFLOW_ROOT_PATH / ".github" / "workflows" /
"airflow-distributions-tests.yml", False),
(AIRFLOW_ROOT_PATH / "dev" / "breeze" / "pyproject.toml", False),
(AIRFLOW_ROOT_PATH / "dev" / "breeze" / "src" / "airflow_breeze" /
"global_constants.py", False),
(
@@ -80,11 +79,6 @@ FILES_TO_UPDATE: list[tuple[Path, bool]] = [
/ "release_management_commands.py",
False,
),
- (AIRFLOW_ROOT_PATH / ".github" / "workflows" /
"release_dockerhub_image.yml", False),
- (AIRFLOW_ROOT_PATH / ".github" / "actions" / "install-prek" /
"action.yml", False),
- (AIRFLOW_ROOT_PATH / ".github" / "actions" / "breeze" / "action.yml",
False),
- (AIRFLOW_ROOT_PATH / ".github" / "workflows" / "basic-tests.yml", False),
- (AIRFLOW_ROOT_PATH / ".github" / "workflows" / "ci-amd-arm.yml", False),
(AIRFLOW_ROOT_PATH / "dev" / "breeze" / "doc" / "ci" / "02_images.md",
True),
(AIRFLOW_ROOT_PATH / "docker-stack-docs" / "build-arg-ref.rst", True),
(AIRFLOW_ROOT_PATH / "devel-common" / "pyproject.toml", True),