mirror of
https://github.com/apache/airflow.git
synced 2026-11-04 07:12:48 +00:00
* Size CI test jobs on RunsOn runners to the parallelism they can use Jobs that run tests with --run-in-parallel start one serial pytest per test type, so they never use more CPUs than they have test types. On RunsOn, splitting core test types into two jobs only doubles the jobs: each half still lasts as long as its slowest test type, and the out-of-memory risk the split guards against on public runners does not apply to the larger RunsOn runners. The lowest-dependencies provider jobs left their 32 CPUs partly idle, and the integration-core and system tests ran a single pytest on 32-CPU runners. Generated-by: Claude Opus 5 * Run provider tests one provider per test type on RunsOn runners Grouping all providers but the long-running ones into one test type left the provider jobs waiting on that group's single serial pytest while the other CPUs idled. The Non-DB jobs run every provider in one xdist pytest, where splitting test types only adds entries, so they get the providers unsplit. Generated-by: Claude Opus 5 * Give docker on RunsOn runners enough address pools for parallel test runs Each test type of a parallel test run is a docker compose project with its own network. Docker's default address pools fit about 30 networks, so provider jobs running a test type per CPU on 32-CPU and larger runners failed with "all predefined address pools have been fully subnetted". Generated-by: Claude Opus 5 * Split the longest-running provider tests into several test types on RunsOn Once every provider runs as its own test type, a job lasts as long as its slowest provider, and amazon, google and standard each take far longer than the rest as a single serial pytest. Splitting them lets the large RunsOn runners work on their parts at once. Lowest-dependencies jobs are sized by test-type count, so a change touching a few providers keeps one job. Generated-by: Claude Opus 5 * Keep split provider test types out of compose project and artifact names Docker Compose project names and GitHub artifact names reject the colon that names a part of a split provider. Generated-by: Claude Opus 5 * Skip split provider test types whose provider is ignored A split provider part selects a folder inside the provider's tests, and pytest runs an explicitly selected path even when its provider folder is ignored, so a skipped or excluded provider's parts would still run. Generated-by: Claude Opus 5 * Fit RunsOn runner sizes to the work of each job and record their CPU and memory use Several jobs ran a single process, or a minute or two of work, on 32-CPU or 8-CPU runners, and fourteen Helm unit test jobs each spent more time preparing the image than running their tests. Charting each job's CPU and memory use lets the size classes be set from measurements rather than from how the jobs are expected to behave. Generated-by: Claude Opus 5 * Skip ignored test selections by the paths the test type selects The check for an empty run treated the first remaining argument, or any path-like argument, as a test selection, so option values such as the "8" of "-n 8" or a path passed to --rootdir decided whether tests ran. It now compares the ignored folders with the paths the test type itself selects, and passes paths the user names explicitly to pytest as they are. Generated-by: Claude Opus 5 * Reject split provider test types where all test types share one pytest Under xdist every test type runs in one pytest process, where the --ignore arguments of a provider's other part would silently be dropped or would remove its sibling parts, so the wrong tests would run. Generated-by: Claude Opus 5 * Count only test folders as the selections of a test type Test suites such as All-Postgres add pytest options with values, which were taken for selected test paths, so a run whose every test folder was ignored still started pytest with nothing selected. Generated-by: Claude Opus 5 * Run only its own test type in each worker of a parallel test run Each worker kept the whole list of test types, so with --skip-db-tests every worker selected the folders of all of them. Generated-by: Claude Opus 5 * Raise the AIO limit on RunsOn runners for parallel MySQL tests A few dozen MySQL servers running at once exhaust the default fs.aio-max-nr, and InnoDB then fails with "io_setup() failed with EAGAIN". Generated-by: Claude Opus 5 * Keep the provider compatibility tests on the grouped provider test types Each test type of a compatibility test installs an Airflow version and the providers before running, so listing every provider as its own test type multiplied those installs and the jobs ran out of time. Generated-by: Claude Opus 5
473 lines
19 KiB
YAML
473 lines
19 KiB
YAML
# 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.
|
|
#
|
|
---
|
|
name: Basic tests
|
|
on: # yamllint disable-line rule:truthy
|
|
workflow_call:
|
|
inputs:
|
|
newsfragment-pr-number:
|
|
description: "Pull request the newsfragments are checked against; empty to accept any number"
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
runners:
|
|
description: "The array of labels (in json form) determining runners."
|
|
required: true
|
|
type: string
|
|
run-ui-tests:
|
|
description: "Whether to run UI tests (true/false)"
|
|
required: true
|
|
type: string
|
|
run-www-tests:
|
|
description: "Whether to run WWW tests (true/false)"
|
|
required: true
|
|
type: string
|
|
run-api-codegen:
|
|
description: "Whether to run API codegen (true/false)"
|
|
required: true
|
|
type: string
|
|
run-breeze-integration-tests:
|
|
description: "Whether to run breeze integration tests (true/false)"
|
|
required: true
|
|
type: string
|
|
run-scripts-tests:
|
|
description: "Whether to run scripts tests (true/false)"
|
|
required: true
|
|
type: string
|
|
run-generic-basic-tests:
|
|
description: >-
|
|
Whether to run the standalone Airflow and shared distributions tests (true/false): not on the
|
|
release branch of a single component
|
|
required: true
|
|
type: string
|
|
basic-checks-only:
|
|
description: "Whether to run only basic checks (true/false)"
|
|
required: true
|
|
type: string
|
|
skip-prek-hooks:
|
|
description: "Whether to skip prek hooks (true/false)"
|
|
required: true
|
|
type: string
|
|
default-python-version:
|
|
description: "Which version of python should be used by default"
|
|
required: true
|
|
type: string
|
|
shared-distributions-as-json:
|
|
description: "Json array of shared distributions to run tests for"
|
|
required: true
|
|
type: string
|
|
canary-run:
|
|
description: "Whether to run canary tests (true/false)"
|
|
required: true
|
|
type: string
|
|
latest-versions-only:
|
|
description: "Whether to run only latest version checks (true/false)"
|
|
required: true
|
|
type: string
|
|
use-uv:
|
|
description: "Whether to use uv in the image"
|
|
required: true
|
|
type: string
|
|
platform:
|
|
description: 'Platform for the build - linux/amd64 or linux/arm64'
|
|
required: true
|
|
type: string
|
|
push-base-commit:
|
|
description: "For a push: the last successfully tested commit of the branch (empty otherwise)"
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
permissions:
|
|
contents: read
|
|
jobs:
|
|
run-breeze-tests:
|
|
timeout-minutes: 10
|
|
name: Breeze unit tests
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '4+8', '16+32') }}
|
|
steps:
|
|
- name: "Cleanup repo"
|
|
shell: bash
|
|
run: sudo rm -rf ${GITHUB_WORKSPACE}/*
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
# Need to fetch all history for selective checks tests
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- name: "Install Breeze"
|
|
uses: ./.github/actions/breeze
|
|
- name: "Run unit tests"
|
|
run: uv run --locked pytest -n auto --color=yes
|
|
working-directory: ./dev/breeze/
|
|
run-breeze-integration-tests:
|
|
timeout-minutes: 120
|
|
name: Breeze integration tests
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '4+8', '16+32') }}
|
|
if: inputs.run-breeze-integration-tests == 'true'
|
|
steps:
|
|
- name: "Cleanup repo"
|
|
shell: bash
|
|
run: sudo rm -rf ${GITHUB_WORKSPACE}/*
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- name: "Install Breeze"
|
|
uses: ./.github/actions/breeze
|
|
- name: "Install SVN"
|
|
run: sudo apt-get update && sudo apt-get install -y subversion
|
|
- name: "Install Java (for Apache RAT)"
|
|
uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0
|
|
with:
|
|
distribution: 'temurin'
|
|
java-version: '17'
|
|
- name: "Install hatch"
|
|
run: uv tool install hatch
|
|
- name: "Run integration tests"
|
|
run: uv run --locked pytest -v --color=yes -m integration_tests
|
|
working-directory: ./dev/breeze/
|
|
tests-shared-distributions:
|
|
timeout-minutes: 10
|
|
name: Shared distributions tests
|
|
if: inputs.run-generic-basic-tests == 'true'
|
|
env:
|
|
# Without a pin uv picks the runner's system Python, which can be older than Airflow supports.
|
|
UV_PYTHON: "${{ inputs.default-python-version }}"
|
|
SHARED_DISTRIBUTIONS: ${{ join(fromJSON(inputs.shared-distributions-as-json), ' ') }}
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '4+8', '16+32') }}
|
|
steps:
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 1
|
|
persist-credentials: false
|
|
- name: "RunsOn cost summary"
|
|
uses: ./.github/actions/runs-on-cost-summary
|
|
- name: "Install uv"
|
|
# 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 distributions tests"
|
|
run: |
|
|
failed=()
|
|
for dist in ${SHARED_DISTRIBUTIONS}; do
|
|
echo "::group::Shared ${dist} tests"
|
|
if ! (cd "shared/${dist}" && uv run --exact --group dev pytest --color=yes -n auto); then
|
|
failed+=("${dist}")
|
|
fi
|
|
echo "::endgroup::"
|
|
done
|
|
if (( ${#failed[@]} )); then
|
|
echo "::error::Shared distribution tests failed: ${failed[*]}"
|
|
exit 1
|
|
fi
|
|
tests-scripts:
|
|
timeout-minutes: 10
|
|
name: Scripts tests
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '4+8', '16+32') }}
|
|
if: inputs.run-scripts-tests == 'true'
|
|
env:
|
|
# Without a pin uv picks the runner's system Python, which can be older than Airflow supports.
|
|
UV_PYTHON: "${{ inputs.default-python-version }}"
|
|
steps:
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 1
|
|
persist-credentials: false
|
|
- name: "RunsOn cost summary"
|
|
uses: ./.github/actions/runs-on-cost-summary
|
|
- name: "Install uv"
|
|
# 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/
|
|
|
|
tests-ui:
|
|
timeout-minutes: 15
|
|
name: React UI tests
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '8+16', '32+64') }}
|
|
if: inputs.run-ui-tests == 'true'
|
|
steps:
|
|
- name: "Cleanup repo"
|
|
shell: bash
|
|
run: sudo rm -rf ${GITHUB_WORKSPACE}/*
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
- name: "RunsOn cost summary"
|
|
uses: ./.github/actions/runs-on-cost-summary
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
|
with:
|
|
version: 9
|
|
run_install: false
|
|
- name: "Setup node"
|
|
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
|
with:
|
|
node-version: 24
|
|
cache: 'pnpm'
|
|
cache-dependency-path: |
|
|
airflow-core/src/airflow/ui/pnpm-lock.yaml
|
|
airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui/pnpm-lock.yaml
|
|
# setup-node already caches pnpm's package store. Recreate node_modules rather than
|
|
# transferring another archive that excludes pnpm's hidden .pnpm directory by default.
|
|
- run: cd airflow-core/src/airflow/ui && pnpm install --frozen-lockfile
|
|
- run: cd airflow-core/src/airflow/ui && pnpm test
|
|
env:
|
|
FORCE_COLOR: 2
|
|
- run: cd airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui && pnpm install --frozen-lockfile
|
|
- run: cd airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui && pnpm test
|
|
env:
|
|
FORCE_COLOR: 2
|
|
|
|
check-translation-completness:
|
|
timeout-minutes: 15
|
|
name: "Check translation completeness"
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '4+8', '16+32') }}
|
|
steps:
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
- name: "Install Breeze"
|
|
uses: ./.github/actions/breeze
|
|
- name: "Check translation completeness"
|
|
run: breeze ui check-translation-completeness || true
|
|
|
|
# Those checks are run if no image needs to be built for checks. This is for simple changes that
|
|
# Do not touch any of the python code or any of the important files that might require building
|
|
# The CI Docker image and they can be run entirely using the prek virtual environments on host
|
|
static-checks-basic-checks-only:
|
|
timeout-minutes: 30
|
|
name: "Static checks: basic checks only"
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '8+16', '32+64') }}
|
|
if: inputs.basic-checks-only == 'true'
|
|
steps:
|
|
- name: "Cleanup repo"
|
|
shell: bash
|
|
run: sudo rm -rf ${GITHUB_WORKSPACE}/*
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
- name: "Install Breeze"
|
|
uses: ./.github/actions/breeze
|
|
id: breeze
|
|
- name: "Install prek"
|
|
uses: ./.github/actions/install-prek
|
|
id: prek
|
|
with:
|
|
platform: ${{ inputs.platform }}
|
|
save-cache: true
|
|
- name: Fetch incoming commit ${{ github.sha }} with its parent
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ github.sha }}
|
|
fetch-depth: 2
|
|
persist-credentials: false
|
|
- name: "Fetch the last tested push commit"
|
|
if: inputs.push-base-commit != ''
|
|
shell: bash
|
|
env:
|
|
PUSH_BASE_COMMIT: ${{ inputs.push-base-commit }}
|
|
run: |
|
|
git fetch --no-tags --depth=1 origin "${PUSH_BASE_COMMIT}" \
|
|
|| echo "::warning::Could not fetch ${PUSH_BASE_COMMIT}, all files will be checked"
|
|
- name: "Static checks: basic checks only"
|
|
# A push is checked from the last tested commit of the branch, like its test selection: the
|
|
# commits of earlier failed or cancelled push runs are checked again. `--from-ref` needs the
|
|
# merge base, which the shallow fetch does not have, so the changed files are listed here.
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
prek_args=(--show-diff-on-failure --color always)
|
|
if [[ -z "${PUSH_BASE_COMMIT}" ]]; then
|
|
prek "${prek_args[@]}" --from-ref "${GITHUB_SHA}^" --to-ref "${GITHUB_SHA}"
|
|
elif git cat-file -e "${PUSH_BASE_COMMIT}^{commit}"; then
|
|
mapfile -t files < <(git diff --name-only --no-renames --diff-filter=d \
|
|
"${PUSH_BASE_COMMIT}" "${GITHUB_SHA}")
|
|
if (( ${#files[@]} > 0 )); then
|
|
prek "${prek_args[@]}" --files "${files[@]}"
|
|
fi
|
|
else
|
|
prek "${prek_args[@]}" --all-files
|
|
fi
|
|
env:
|
|
PUSH_BASE_COMMIT: ${{ inputs.push-base-commit }}
|
|
VERBOSE: "false"
|
|
SKIP_BREEZE_PREK_HOOKS: "true"
|
|
PR_NUMBER: ${{ inputs.newsfragment-pr-number }}
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
SKIP: ${{ inputs.skip-prek-hooks }}
|
|
COLUMNS: "202"
|
|
- name: "Fail if static checks modified tracked files"
|
|
# prek does not report files that a nested-project hook modifies outside its own project,
|
|
# so check the tree independently.
|
|
shell: bash
|
|
run: |
|
|
if ! git diff --quiet; then
|
|
echo "::error::Static checks passed but modified tracked files. Commit the changes below."
|
|
git diff --stat
|
|
git diff | head -n 500 || true
|
|
exit 1
|
|
fi
|
|
|
|
test-git-clone-on-windows:
|
|
timeout-minutes: 5
|
|
name: "Test git clone on Windows"
|
|
runs-on: ["windows-2025"]
|
|
steps:
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 2
|
|
persist-credentials: false
|
|
|
|
test-airflow-release-commands:
|
|
timeout-minutes: 80
|
|
name: "Test Airflow release commands"
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '8+16', '32+64') }}
|
|
env:
|
|
PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}"
|
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
GITHUB_USERNAME: ${{ github.actor }}
|
|
VERBOSE: "true"
|
|
if: inputs.canary-run == 'true'
|
|
steps:
|
|
- name: "Cleanup repo"
|
|
shell: bash
|
|
run: sudo rm -rf ${GITHUB_WORKSPACE}/*
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
- name: "Install Breeze"
|
|
uses: ./.github/actions/breeze
|
|
- name: "Cleanup dist files"
|
|
run: rm -fv ./dist/*
|
|
- name: Setup git for tagging
|
|
run: |
|
|
git config --global user.email "bot@airflow.apache.org"
|
|
git config --global user.name "Your friendly bot"
|
|
- name: Install twine
|
|
run: pip install twine
|
|
- name: "Check Airflow create minor branch command"
|
|
run: breeze release-management create-minor-branch --version-branch 3-2 --answer yes --dry-run
|
|
- name: "Check Airflow RC process command"
|
|
run: >
|
|
breeze release-management start-rc-process --version 3.2.0rc1 --previous-version 3.1.0
|
|
--task-sdk-version 1.1.0rc1 --sync-branch v3-2-test --answer yes --dry-run
|
|
- name: "Check Airflow release process command"
|
|
run: >
|
|
breeze release-management start-release --version 3.2.7
|
|
--answer yes --dry-run
|
|
- name: "Test providers metadata generation"
|
|
run: |
|
|
git remote add upstream https://github.com/apache/airflow.git
|
|
git fetch upstream --tags
|
|
breeze release-management generate-providers-metadata --refresh-constraints-and-airflow-releases
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
- name: "Fetch all git tags for origin"
|
|
run: git fetch --tags >/dev/null 2>&1 || true
|
|
- name: "Test airflow core issue generation automatically"
|
|
run: |
|
|
breeze release-management generate-issue-content-core \
|
|
--limit-pr-count 2 --previous-release 3.0.1 --current-release 3.0.2 --verbose
|
|
|
|
|
|
test-airflow-standalone:
|
|
timeout-minutes: 30
|
|
name: "Test Airflow standalone commands"
|
|
if: inputs.run-generic-basic-tests == 'true'
|
|
runs-on: ${{ format(fromJSON(inputs.runners)[0], '4+8', '16+32') }}
|
|
env:
|
|
AIRFLOW_HOME: ~/airflow
|
|
FORCE_COLOR: 1
|
|
steps:
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
- name: "RunsOn cost summary"
|
|
uses: ./.github/actions/runs-on-cost-summary
|
|
- name: "Install uv"
|
|
# 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"
|
|
mkdir -p $AIRFLOW_HOME
|
|
- name: "Install Airflow from current repo (simulating user installation)"
|
|
run: |
|
|
uv venv
|
|
set -x
|
|
uv pip install -e ./airflow-core
|
|
- name: "Test airflow standalone command"
|
|
run: |
|
|
uv run --no-sync airflow standalone 2>&1 | tee airflow_startup.log &
|
|
AIRFLOW_PID=$!
|
|
|
|
# Wait for ready message till timeout (10 minutes)
|
|
for i in {1..600}; do
|
|
if ! kill -0 $AIRFLOW_PID 2>/dev/null; then
|
|
wait $AIRFLOW_PID
|
|
EXIT_CODE=$?
|
|
echo "FAILED: Airflow standalone exited with code $EXIT_CODE"
|
|
exit $EXIT_CODE
|
|
fi
|
|
|
|
if grep -q "Airflow is ready" airflow_startup.log; then
|
|
echo "SUCCESS: Airflow standalone is ready!"
|
|
kill $AIRFLOW_PID
|
|
exit 0
|
|
fi
|
|
|
|
sleep 1
|
|
done
|
|
|
|
echo "FAILED: Airflow standalone did not become ready in time"
|
|
kill $AIRFLOW_PID 2>/dev/null || true
|
|
exit 1
|