diff --git a/.asf.yaml b/.asf.yaml index 3130630e80c6b..59dfd3c401ac4 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -134,6 +134,11 @@ github: required_linear_history: true required_conversation_resolution: true required_signatures: false + v3-0-stable: + required_pull_request_reviews: + required_approving_review_count: 1 + required_linear_history: true + required_signatures: false providers-fab/v1-5: required_pull_request_reviews: required_approving_review_count: 1 diff --git a/.github/.pre-commit-config.yaml b/.github/.pre-commit-config.yaml new file mode 100644 index 0000000000000..909f0c1cdca3c --- /dev/null +++ b/.github/.pre-commit-config.yaml @@ -0,0 +1,28 @@ +# 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. +--- +default_stages: [manual] +default_language_version: + python: python311 +minimum_pre_commit_version: '3.2.0' +repos: + - repo: https://github.com/eclipse-csi/octopin + rev: 21360742e352e87450f99e180fdfc2cf774a72a3 + hooks: + - id: pin-versions + name: Pin versions of dependencies in CI workflows (manual) + stages: ['manual'] diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7a97a52539cac..69f10c58301a7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -23,7 +23,7 @@ # API /airflow-core/src/airflow/api/ @ephraimbuddy @pierrejeambrun @rawwar @jason810496 -/airflow-core/src/airflow/api_fastapi/ @ephraimbuddy @pierrejeambrun @rawwar @jason810496 @bugraoz93 +/airflow-core/src/airflow/api_fastapi/ @ephraimbuddy @pierrejeambrun @rawwar @jason810496 @bugraoz93 @shubhamraj-git /airflow-core/src/airflow/api_fastapi/execution_api/ @ashb @kaxil @amoghrajesh # Airflow CTL @@ -33,7 +33,18 @@ /airflow-core/src/airflow/api_fastapi/auth/ @vincbeck # UI -/airflow-core/src/airflow/ui/ @bbovenzi @pierrejeambrun @ryanahamilton @jscheffl +/airflow-core/src/airflow/ui/ @bbovenzi @pierrejeambrun @ryanahamilton @jscheffl @shubhamraj-git + +# Translation Owners (i18n) +# Note: Non committer engaged translators are listed in comments prevent making file syntax invalid +# See: https://github.com/apache/airflow/blob/main/airflow-core/src/airflow/ui/public/i18n/README.md#43-engaged-translator +airflow-core/src/airflow/ui/public/i18n/locales/ar/ @shahar1 @hussein-awala # + @ahmadtfarhan +airflow-core/src/airflow/ui/public/i18n/locales/de/ @jscheffl # + @TJaniF @m1racoli +airflow-core/src/airflow/ui/public/i18n/locales/he/ @eladkal @shahar1 @romsharon98 # +@Dev-iL +airflow-core/src/airflow/ui/public/i18n/locales/nl/ @BasPH # + @DjVinnii +airflow-core/src/airflow/ui/public/i18n/locales/pl/ @potiuk @mobuchowski # + @kacpermuda +airflow-core/src/airflow/ui/public/i18n/locales/zh-TW/ @Lee-W @jason810496 # + @RoyLee1224 @guan404ming +airflow-core/src/airflow/ui/public/i18n/locales/fr/ @pierrejeambrun @vincbeck # Security/Permissions /airflow-core/src/airflow/security/permissions.py @vincbeck @@ -69,6 +80,7 @@ /providers/edge3/ @jscheffl /providers/fab/ @vincbeck /providers/hashicorp/ @hussein-awala +/providers/keycloak/ @vincbeck /providers/openlineage/ @mobuchowski /providers/slack/ @eladkal /providers/smtp/ @hussein-awala @@ -77,7 +89,7 @@ # Dev tools /.github/workflows/ @potiuk @ashb @gopidesupavan -/dev/ @potiuk @ashb @jedcunningham @gopidesupavan +/dev/ @potiuk @ashb @jedcunningham @gopidesupavan @amoghrajesh /docker-tests/ @potiuk @ashb @gopidesupavan @jason810496 /kubernetes-tests/ @potiuk @ashb @gopidesupavan @jason810496 /helm-tests/ @dstandish @jedcunningham @@ -109,4 +121,8 @@ ISSUE_TRIAGE_PROCESS.rst @eladkal /providers/fab/src/airflow-core/src/airflow/providers/fab/migrations/ @ephraimbuddy # AIP-72 - Task SDK +# Python SDK /task-sdk/ @ashb @kaxil @amoghrajesh + +# Golang SDK +/go-sdk/ @ashb @kaxil @amoghrajesh diff --git a/.github/ISSUE_TEMPLATE/airflow_bug_report.yml b/.github/ISSUE_TEMPLATE/1-airflow_bug_report.yml similarity index 99% rename from .github/ISSUE_TEMPLATE/airflow_bug_report.yml rename to .github/ISSUE_TEMPLATE/1-airflow_bug_report.yml index 25fb14cba10e4..862037f29bac9 100644 --- a/.github/ISSUE_TEMPLATE/airflow_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1-airflow_bug_report.yml @@ -25,8 +25,8 @@ body: the latest release or main to see if the issue is fixed before reporting it. multiple: false options: - - "2.10.5" - - "3.0.0" + - "3.0.2" + - "2.11.0" - "main (development)" - "Other Airflow 2 version (please specify below)" validations: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/2-feature_request.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/feature_request.yml rename to .github/ISSUE_TEMPLATE/2-feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/airflow_providers_bug_report.yml b/.github/ISSUE_TEMPLATE/3-airflow_providers_bug_report.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/airflow_providers_bug_report.yml rename to .github/ISSUE_TEMPLATE/3-airflow_providers_bug_report.yml diff --git a/.github/ISSUE_TEMPLATE/airflow_helmchart_bug_report.yml b/.github/ISSUE_TEMPLATE/4-airflow_helmchart_bug_report.yml similarity index 99% rename from .github/ISSUE_TEMPLATE/airflow_helmchart_bug_report.yml rename to .github/ISSUE_TEMPLATE/4-airflow_helmchart_bug_report.yml index 3c8b7e68a82bf..bb8abfe40a9ee 100644 --- a/.github/ISSUE_TEMPLATE/airflow_helmchart_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/4-airflow_helmchart_bug_report.yml @@ -28,7 +28,8 @@ body: What Apache Airflow Helm Chart version are you using? multiple: false options: - - "1.16.0 (latest released)" + - "1.17.0 (latest released)" + - "1.16.0" - "1.15.0" - "1.14.0" - "1.13.1" diff --git a/.github/ISSUE_TEMPLATE/airflow_doc_issue_report.yml b/.github/ISSUE_TEMPLATE/5-airflow_doc_issue_report.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/airflow_doc_issue_report.yml rename to .github/ISSUE_TEMPLATE/5-airflow_doc_issue_report.yml diff --git a/.github/ISSUE_TEMPLATE/~free_form.yml b/.github/ISSUE_TEMPLATE/6-free_form.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/~free_form.yml rename to .github/ISSUE_TEMPLATE/6-free_form.yml diff --git a/.github/actions/breeze/action.yml b/.github/actions/breeze/action.yml index 39e87cd7d8b52..40f683c5a6fd4 100644 --- a/.github/actions/breeze/action.yml +++ b/.github/actions/breeze/action.yml @@ -41,6 +41,8 @@ runs: - name: "Install Breeze" shell: bash run: ./scripts/ci/install_breeze.sh + env: + PYTHON_VERSION: "${{ inputs.python-version }}" - name: "Free space" shell: bash run: breeze ci free-space diff --git a/.github/actions/install-pre-commit/action.yml b/.github/actions/install-pre-commit/action.yml index dd7944841510a..8a68bc00363ba 100644 --- a/.github/actions/install-pre-commit/action.yml +++ b/.github/actions/install-pre-commit/action.yml @@ -24,13 +24,16 @@ inputs: default: "3.9" uv-version: description: 'uv version to use' - default: "0.6.13" # Keep this comment to allow automatic replacement of uv version + default: "0.7.19" # Keep this comment to allow automatic replacement of uv version pre-commit-version: description: 'pre-commit version to use' default: "4.2.0" # Keep this comment to allow automatic replacement of pre-commit version pre-commit-uv-version: description: 'pre-commit-uv version to use' default: "4.1.4" # Keep this comment to allow automatic replacement of pre-commit-uv version + skip-pre-commits: + description: "Skip some pre-commits from installation" + default: "" runs: using: "composite" steps: @@ -40,6 +43,7 @@ runs: UV_VERSION: ${{inputs.uv-version}} PRE_COMMIT_VERSION: ${{inputs.pre-commit-version}} PRE_COMMIT_UV_VERSION: ${{inputs.pre-commit-uv-version}} + SKIP: ${{ inputs.skip-pre-commits }} run: | pip install uv==${UV_VERSION} || true uv tool install pre-commit==${PRE_COMMIT_VERSION} --with uv==${UV_VERSION} \ @@ -61,6 +65,16 @@ runs: key: cache-pre-commit-v4-${{ inputs.python-version }}-${{ hashFiles('.pre-commit-config.yaml') }} path: /tmp/ id: restore-pre-commit-cache + - name: "Check if pre-commit cache tarball exists" + shell: bash + run: | + if [ -f /tmp/cache-pre-commit.tar.gz ]; then + echo "✅ Cache tarball found: /tmp/cache-pre-commit.tar.gz" + else + echo "❌ Cache tarball missing. Expected /tmp/cache-pre-commit.tar.gz" + exit 1 + fi + if: steps.restore-pre-commit-cache.outputs.stash-hit == 'true' - name: "Restore .cache from the tar file" run: tar -C ~ -xzf /tmp/cache-pre-commit.tar.gz shell: bash @@ -76,3 +90,5 @@ runs: shell: bash run: pre-commit install-hooks || (cat ~/.cache/pre-commit/pre-commit.log && exit 1) working-directory: ${{ github.workspace }} + env: + SKIP: ${{ inputs.skip-pre-commits }} diff --git a/.github/actions/migration_tests/action.yml b/.github/actions/migration_tests/action.yml index ed71e21407d10..0198cbf472b0b 100644 --- a/.github/actions/migration_tests/action.yml +++ b/.github/actions/migration_tests/action.yml @@ -24,12 +24,13 @@ runs: - name: "Test migration file 2 to 3 migration: ${{env.BACKEND}}" shell: bash run: | - breeze shell "${{ env.AIRFLOW_2_CMD }}" --use-airflow-version 2.10.5 --answer y && - breeze shell "${{ env.AIRFLOW_3_CMD }}" --no-db-cleanup + breeze shell "${{ env.AIRFLOW_2_CMD }}" --use-airflow-version 2.11.0 --answer y && + breeze shell "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${{env.DB_MANGERS}} + ${{ env.AIRFLOW_3_CMD }}" --no-db-cleanup env: COMPOSE_PROJECT_NAME: "docker-compose" - AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" DB_RESET: "false" + DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" AIRFLOW_2_CMD: >- airflow db reset --skip-init -y && airflow db migrate --to-revision heads @@ -46,12 +47,13 @@ runs: - name: "Test ORM migration 2 to 3: ${{env.BACKEND}}" shell: bash run: > - breeze shell "${{ env.AIRFLOW_2_CMD }}" --use-airflow-version 2.10.5 --answer y && - breeze shell "${{ env.AIRFLOW_3_CMD }}" --no-db-cleanup + breeze shell "${{ env.AIRFLOW_2_CMD }}" --use-airflow-version 2.11.0 --answer y && + breeze shell "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${{env.DB_MANGERS}} + ${{ env.AIRFLOW_3_CMD }}" --no-db-cleanup env: COMPOSE_PROJECT_NAME: "docker-compose" - AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" DB_RESET: "false" + DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" AIRFLOW_2_CMD: >- airflow db reset -y AIRFLOW_3_CMD: >- @@ -67,13 +69,14 @@ runs: - name: "Test ORM migration ${{env.BACKEND}}" shell: bash run: > - breeze shell "airflow db reset -y && + breeze shell "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${{env.DB_MANAGERS}} && + airflow db reset -y && airflow db migrate --to-revision heads && airflow db downgrade -n 2.7.0 -y && airflow db migrate" env: COMPOSE_PROJECT_NAME: "docker-compose" - AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" + DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" - name: "Bring compose down again" shell: bash run: breeze down @@ -82,12 +85,14 @@ runs: - name: "Test offline migration ${{env.BACKEND}}" shell: bash run: > - breeze shell "airflow db reset -y && + breeze shell + "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${{env.DB_MANAGERS}} && + airflow db reset -y && airflow db downgrade -n 2.7.0 -y && airflow db migrate -s" env: COMPOSE_PROJECT_NAME: "docker-compose" - AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" + DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager" if: env.BACKEND != 'sqlite' - name: "Bring any containers left down" shell: bash diff --git a/.github/actions/post_tests_success/action.yml b/.github/actions/post_tests_success/action.yml index b7b00a6fc0df3..36ee429477733 100644 --- a/.github/actions/post_tests_success/action.yml +++ b/.github/actions/post_tests_success/action.yml @@ -44,7 +44,7 @@ runs: mkdir ./files/coverage-reports mv ./files/coverage*.xml ./files/coverage-reports/ || true - name: "Upload all coverage reports to codecov" - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 env: CODECOV_TOKEN: ${{ inputs.codecov-token }} if: env.ENABLE_COVERAGE == 'true' && env.TEST_TYPES != 'Helm' && inputs.python-version != '3.12' diff --git a/.github/actions/prepare_breeze_and_image/action.yml b/.github/actions/prepare_breeze_and_image/action.yml index 3254254a86516..4a2685cc4ebd8 100644 --- a/.github/actions/prepare_breeze_and_image/action.yml +++ b/.github/actions/prepare_breeze_and_image/action.yml @@ -38,14 +38,19 @@ outputs: runs: using: "composite" steps: - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh shell: bash - name: "Install Breeze" uses: ./.github/actions/breeze with: use-uv: ${{ inputs.use-uv }} id: breeze + - name: "Check free space" + shell: bash + run: | + echo "Checking free space!" + df -H - name: "Restore ${{ inputs.image-type }} docker image ${{ inputs.platform }}:${{ inputs.python }}" uses: apache/infrastructure-actions/stash/restore@1c35b5ccf8fba5d4c3fdf25a045ca91aa0cbc468 with: diff --git a/.github/boring-cyborg.yml b/.github/boring-cyborg.yml index cff760ad9dc38..7cf001621d3c6 100644 --- a/.github/boring-cyborg.yml +++ b/.github/boring-cyborg.yml @@ -108,9 +108,6 @@ labelPRBasedOnFilePath: provider:common-sql: - providers/common/sql/** - provider:standard: - - providers/standard/** - provider:databricks: - providers/databricks/** @@ -216,7 +213,7 @@ labelPRBasedOnFilePath: provider:opsgenie: - providers/opsgenie/** - provider:Oracle: + provider:oracle: - providers/oracle/** provider:pagerduty: @@ -276,6 +273,9 @@ labelPRBasedOnFilePath: provider:ssh: - providers/ssh/** + provider:standard: + - providers/standard/** + provider:tableau: - providers/tableau/** @@ -326,6 +326,26 @@ labelPRBasedOnFilePath: - .rat-excludes - .readthedocs.yml + # This should not be enabled on the v3-0-test branch, it adds circular backport when PR open PR created + # from the v3-0-test branch + # This should be copy of the "area:dev-tools" above and should be updated when we switch maintenance branch + # backport-to-v3-0-test: + # - scripts/**/* + # - dev/**/* + # - .github/**/* + # - Dockerfile.ci + # - CONTRIBUTING.rst + # - contributing-docs/**/* + # - yamllint-config.yml + # - .asf.yaml + # - .bash_completion + # - .dockerignore + # - .hadolint.yaml + # - .pre-commit-config.yaml + # - .rat-excludes + # - .readthedocs.yml + + kind:documentation: - airflow-core/docs/**/* - chart/docs/**/* @@ -353,11 +373,16 @@ labelPRBasedOnFilePath: - airflow-core/docs/administration-and-deployment/lineage.rst area:Logging: + - airflow-core/src/airflow/config_templates/airflow_local_settings.py + - airflow-core/tests/unit/core/test_logging_config.py - airflow-core/src/airflow/utils/log/**/* - airflow-core/docs/administration-and-deployment/logging-monitoring/logging-*.rst - airflow-core/tests/unit/utils/log/**/* - providers/**/log/* + area:ConfigTemplates: + - airflow-core/src/airflow/config_templates/* + area:Plugins: - airflow-core/src/airflow/cli/commands/plugins_command.py - airflow-core/src/airflow/plugins_manager.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml index adefbb9f478f7..a0404b811674e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -33,7 +33,6 @@ updates: - package-ecosystem: npm directories: - - /airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui - /airflow-core/src/airflow/ui schedule: interval: daily @@ -41,6 +40,16 @@ updates: core-ui-package-updates: patterns: - "*" + + - package-ecosystem: npm + directories: + - /airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui + schedule: + interval: daily + groups: + core-ui-package-updates: + patterns: + - "*" - package-ecosystem: npm directories: - /providers/fab/src/airflow/providers/fab/www @@ -51,7 +60,7 @@ updates: patterns: - "*" - # Repeat dependency updates on 2.10 branch as well + # Repeat dependency updates on 2.11 branch as well - package-ecosystem: pip directories: - /clients/python @@ -60,14 +69,14 @@ updates: - / schedule: interval: daily - target-branch: v2-10-test + target-branch: v2-11-test - package-ecosystem: npm directories: - /airflow/www/ schedule: interval: daily - target-branch: v2-10-test + target-branch: v2-11-test groups: core-ui-package-updates: patterns: diff --git a/.github/workflows/additional-ci-image-checks.yml b/.github/workflows/additional-ci-image-checks.yml index e9529bd0d08d2..024f4a4ea0a93 100644 --- a/.github/workflows/additional-ci-image-checks.yml +++ b/.github/workflows/additional-ci-image-checks.yml @@ -20,16 +20,12 @@ name: Additional CI image checks on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." - required: true - type: string - runs-on-as-json-self-hosted: - description: "The array of labels (in json form) determining self-hosted runners." + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string python-versions: @@ -37,7 +33,7 @@ on: # yamllint disable-line rule:truthy required: true type: string branch: - description: "Branch used to run the CI jobs in (main/v2_*_test)." + description: "Branch used to run the CI jobs in (main/v*_*_test)." required: true type: string constraints-branch: @@ -103,12 +99,11 @@ jobs: # from forks. This is to prevent malicious PRs from creating images in the "apache/airflow" repo. packages: write with: - runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} - runs-on-as-json-self-hosted: ${{ inputs.runs-on-as-json-self-hosted }} + runners: ${{ inputs.runners }} cache-type: "Early" include-prod-images: "false" push-latest-images: "false" - platform: "linux/amd64" + platform: ${{ inputs.platform }} python-versions: ${{ inputs.python-versions }} branch: ${{ inputs.branch }} constraints-branch: ${{ inputs.constraints-branch }} @@ -116,32 +111,35 @@ jobs: include-success-outputs: ${{ inputs.include-success-outputs }} docker-cache: ${{ inputs.docker-cache }} disable-airflow-repo-cache: ${{ inputs.disable-airflow-repo-cache }} - if: inputs.branch == 'main' + if: > + inputs.canary-run == 'true' && + (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') # Check that after earlier cache push, breeze command will build quickly check-that-image-builds-quickly: timeout-minutes: 11 name: Check that image builds quickly - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: UPGRADE_TO_NEWER_DEPENDENCIES: false - PYTHON_MAJOR_MINOR_VERSION: ${{ inputs.default-python-version }} - PYTHON_VERSION: ${{ inputs.default-python-version }} + PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" + PYTHON_VERSION: "${{ inputs.default-python-version }}" GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_USERNAME: ${{ github.actor }} VERBOSE: "true" + PLATFORM: ${{ inputs.platform }} if: inputs.branch == 'main' steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -152,30 +150,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$actor" --password-stdin - name: "Check that image builds quickly" - run: breeze shell --max-time 600 --platform "linux/amd64" - -# # This is only a check if ARM images are successfully building when committer runs PR from -# # Apache repository. This is needed in case you want to fix failing cache job in "canary" run -# # There is no point in running this one in "canary" run, because the above step is doing the -# # same build anyway. -# build-ci-arm-images: -# name: Build CI ARM images -# uses: ./.github/workflows/ci-image-build.yml -# permissions: -# contents: read -# packages: write -# with: -# platform: "linux/arm64" -# push-image: "false" -# upload-image-artifact: "true" -# upload-mount-cache-artifact: ${{ inputs.canary-run }} -# runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} -# runs-on-as-json-self-hosted: ${{ inputs.runs-on-as-json-self-hosted }} -# python-versions: ${{ inputs.python-versions }} -# branch: ${{ inputs.branch }} -# constraints-branch: ${{ inputs.constraints-branch }} -# use-uv: ${{ inputs.use-uv }} -# upgrade-to-newer-dependencies: ${{ inputs.upgrade-to-newer-dependencies }} -# docker-cache: ${{ inputs.docker-cache }} -# disable-airflow-repo-cache: ${{ inputs.disable-airflow-repo-cache }} -# + run: breeze shell --max-time 600 --platform "${PLATFORM}" diff --git a/.github/workflows/additional-prod-image-tests.yml b/.github/workflows/additional-prod-image-tests.yml index e656f48a5a300..e970526c4b0a7 100644 --- a/.github/workflows/additional-prod-image-tests.yml +++ b/.github/workflows/additional-prod-image-tests.yml @@ -20,8 +20,12 @@ name: Additional PROD image tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." + runners: + description: "The array of labels (in json form) determining runners." + required: true + type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string default-branch: @@ -36,10 +40,6 @@ on: # yamllint disable-line rule:truthy description: "Whether to upgrade to newer dependencies (true/false)" required: true type: string - chicken-egg-providers: - description: "Whether to build chicken-egg provider distributions in the same run (true/false)" - required: true - type: string docker-cache: description: "Docker cache specification to build the image (registry, local, disabled)." required: true @@ -67,14 +67,12 @@ jobs: name: PROD image extra checks (main) uses: ./.github/workflows/prod-image-extra-checks.yml with: - runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} python-versions: "[ '${{ inputs.default-python-version }}' ]" - default-python-version: ${{ inputs.default-python-version }} + default-python-version: "${{ inputs.default-python-version }}" branch: ${{ inputs.default-branch }} - use-uv: "false" - build-provider-distributions: ${{ inputs.default-branch == 'main' }} upgrade-to-newer-dependencies: ${{ inputs.upgrade-to-newer-dependencies }} - chicken-egg-providers: ${{ inputs.chicken-egg-providers }} constraints-branch: ${{ inputs.constraints-branch }} docker-cache: ${{ inputs.docker-cache }} disable-airflow-repo-cache: ${{ inputs.disable-airflow-repo-cache }} @@ -84,14 +82,12 @@ jobs: name: PROD image extra checks (release) uses: ./.github/workflows/prod-image-extra-checks.yml with: - runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} python-versions: "[ '${{ inputs.default-python-version }}' ]" - default-python-version: ${{ inputs.default-python-version }} + default-python-version: "${{ inputs.default-python-version }}" branch: ${{ inputs.default-branch }} - use-uv: "false" - build-provider-distributions: ${{ inputs.default-branch == 'main' }} upgrade-to-newer-dependencies: ${{ inputs.upgrade-to-newer-dependencies }} - chicken-egg-providers: ${{ inputs.chicken-egg-providers }} constraints-branch: ${{ inputs.constraints-branch }} docker-cache: ${{ inputs.docker-cache }} disable-airflow-repo-cache: ${{ inputs.disable-airflow-repo-cache }} @@ -100,7 +96,7 @@ jobs: test-examples-of-prod-image-building: timeout-minutes: 60 name: "Test examples of PROD image building" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -111,24 +107,22 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh - name: "Prepare breeze & PROD image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" + platform: ${{ inputs.platform }} image-type: "prod" - python: ${{ inputs.default-python-version }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "Test examples of PROD image building" env: GITHUB_REPOSITORY: ${{ github.repository }} DEFAULT_BRANCH: ${{ inputs.default-branch }} - DEFAULT_PYTHON_VERSION: ${{ inputs.default-python-version }} + DEFAULT_PYTHON_VERSION: "${{ inputs.default-python-version }}" run: " cd ./docker-tests && \ TEST_IMAGE=\"ghcr.io/$GITHUB_REPOSITORY/$DEFAULT_BRANCH\ @@ -138,7 +132,7 @@ jobs: test-docker-compose-quick-start: timeout-minutes: 60 name: "Docker Compose quick start with PROD image verifying" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" GITHUB_REPOSITORY: ${{ github.repository }} @@ -150,14 +144,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 persist-credentials: false - name: "Prepare breeze & PROD image: ${{ env.PYTHON_MAJOR_MINOR_VERSION }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" + platform: ${{ inputs.platform }} image-type: "prod" python: ${{ env.PYTHON_MAJOR_MINOR_VERSION }} use-uv: ${{ inputs.use-uv }} diff --git a/.github/workflows/airflow-distributions-tests.yml b/.github/workflows/airflow-distributions-tests.yml index c7071c5f34d7c..62d4ee1f6b420 100644 --- a/.github/workflows/airflow-distributions-tests.yml +++ b/.github/workflows/airflow-distributions-tests.yml @@ -21,6 +21,14 @@ on: # yamllint disable-line rule:truthy workflow_call: inputs: # Static inputs defined to choose which distribution to test to run + runners: + description: "The array of labels (in json form) determining runners." + required: true + type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" + required: true + type: string distribution-name: description: "The name of the distribution to test" required: true @@ -33,11 +41,6 @@ on: # yamllint disable-line rule:truthy description: "distribution test type" # eg task-sdk-tests required: true type: string - # Environment inputs - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." - required: true - type: string default-python-version: description: "Which version of python should be used by default" required: true @@ -54,13 +57,22 @@ on: # yamllint disable-line rule:truthy description: "Whether this is a canary run (true/false)" required: true type: string + use-local-venv: + description: "Whether local venv should be used for tests (true/false)" + required: true + type: string + test-timeout: + required: false + type: number + default: 60 + permissions: contents: read jobs: distributions-tests: - timeout-minutes: 80 + timeout-minutes: ${{ fromJSON(inputs.test-timeout) }} name: ${{ inputs.distribution-name }}:P${{ matrix.python-version }} tests - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: fail-fast: false matrix: @@ -77,27 +89,43 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ matrix.python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" + platform: ${{ inputs.platform }} python: ${{ matrix.python-version }} use-uv: ${{ inputs.use-uv }} + if: ${{ inputs.use-local-venv != 'true' }} + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + shell: bash + if: ${{ inputs.use-local-venv == 'true' }} + - name: "Install Breeze" + uses: ./.github/actions/breeze + with: + use-uv: ${{ inputs.use-uv }} + if: ${{ inputs.use-local-venv == 'true' }} - name: "Cleanup dist files" run: rm -fv ./dist/* + if: ${{ matrix.python-version == inputs.default-python-version }} # Conditional steps based on the distribution name - name: "Prepare Airflow ${{inputs.distribution-name}}: wheel" env: DISTRIBUTION_TYPE: "${{ inputs.distribution-cmd-format }}" - run: > + USE_LOCAL_HATCH: "${{ inputs.use-local-venv }}" + run: | + uv tool uninstall hatch || true + uv tool install hatch==1.14.1 breeze release-management "${DISTRIBUTION_TYPE}" --distribution-format wheel + if: ${{ matrix.python-version == inputs.default-python-version }} - name: "Verify wheel packages with twine" run: | uv tool uninstall twine || true uv tool install twine && twine check dist/*.whl + if: ${{ matrix.python-version == inputs.default-python-version }} - name: > Run unit tests for Airflow ${{inputs.distribution-name}}:Python ${{ matrix.python-version }} env: diff --git a/.github/workflows/automatic-backport.yml b/.github/workflows/automatic-backport.yml index 4c72401a5d317..4f861ddd58118 100644 --- a/.github/workflows/automatic-backport.yml +++ b/.github/workflows/automatic-backport.yml @@ -37,7 +37,7 @@ jobs: - name: Find PR information id: pr-info - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/backport-cli.yml b/.github/workflows/backport-cli.yml index 673607027496d..0ecdfb8e63e04 100644 --- a/.github/workflows/backport-cli.yml +++ b/.github/workflows/backport-cli.yml @@ -53,7 +53,7 @@ jobs: steps: - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" id: checkout-for-backport - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: true fetch-depth: 0 diff --git a/.github/workflows/basic-tests.yml b/.github/workflows/basic-tests.yml index 2eca2eec2474e..59a326d49b1b6 100644 --- a/.github/workflows/basic-tests.yml +++ b/.github/workflows/basic-tests.yml @@ -20,8 +20,8 @@ name: Basic tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string run-ui-tests: @@ -66,18 +66,18 @@ jobs: run-breeze-tests: timeout-minutes: 10 name: Breeze unit tests - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # Need to fetch all history for selective checks tests fetch-depth: 0 persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -87,25 +87,25 @@ jobs: tests-ui: timeout-minutes: 15 name: React UI tests - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} if: inputs.run-ui-tests == 'true' steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: Setup pnpm uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 9 run_install: false - name: "Setup node" - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: 21 cache: 'pnpm' @@ -155,15 +155,16 @@ jobs: install-pre-commit: timeout-minutes: 5 name: "Install pre-commit for cache" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" + SKIP: ${{ inputs.skip-pre-commits }} steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Install Breeze" @@ -176,6 +177,7 @@ jobs: id: pre-commit with: python-version: ${{steps.breeze.outputs.host-python-version}} + skip-pre-commits: ${{ inputs.skip-pre-commits }} # 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 @@ -183,7 +185,7 @@ jobs: static-checks-basic-checks-only: timeout-minutes: 30 name: "Static checks: basic checks only" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} needs: install-pre-commit if: inputs.basic-checks-only == 'true' steps: @@ -191,11 +193,11 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -205,9 +207,10 @@ jobs: uses: ./.github/actions/install-pre-commit id: pre-commit with: - python-version: ${{steps.breeze.outputs.host-python-version}} + python-version: ${{ steps.breeze.outputs.host-python-version }} + skip-pre-commits: ${{ inputs.skip-pre-commits }} - name: Fetch incoming commit ${{ github.sha }} with its parent - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.sha }} fetch-depth: 2 @@ -220,7 +223,7 @@ jobs: VERBOSE: "false" SKIP_BREEZE_PRE_COMMITS: "true" SKIP: ${{ inputs.skip-pre-commits }} - COLUMNS: "250" + COLUMNS: "202" test-git-clone-on-windows: timeout-minutes: 5 @@ -228,7 +231,7 @@ jobs: runs-on: ["windows-latest"] steps: - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 persist-credentials: false @@ -236,7 +239,7 @@ jobs: upgrade-check: timeout-minutes: 45 name: "Upgrade checks" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} needs: install-pre-commit env: PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" @@ -246,11 +249,11 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -261,6 +264,7 @@ jobs: id: pre-commit with: python-version: ${{steps.breeze.outputs.host-python-version}} + skip-pre-commits: ${{ inputs.skip-pre-commits }} - name: "Autoupdate all pre-commits" run: pre-commit autoupdate - name: "Run automated upgrade for black" @@ -280,25 +284,23 @@ jobs: # For UV we are not failing the upgrade installers check if it is updated because # it is upgraded very frequently, so we want to manually upgrade it rather than # get notified about it - until it stabilizes in 1.* version - - name: "Run automated upgrade for uv (open to see if new version is updated)" + - name: "Run automated upgrade for uv (not failing - just informational)" run: > pre-commit run --all-files --show-diff-on-failure --color always --verbose --hook-stage manual update-installers-and-pre-commit || true if: always() env: - UPGRADE_UV: "true" UPGRADE_PIP: "false" UPGRADE_PRE_COMMIT: "false" UPGRADE_NODE_LTS: "false" - - name: "Run automated upgrade for pip, pre-commit and node" + - name: "Run automated upgrade for pip, pre-commit and node (failing if needed)" run: > pre-commit run --all-files --show-diff-on-failure --color always --verbose --hook-stage manual update-installers-and-pre-commit if: always() env: - UPGRADE_UV: "false" UPGRADE_PIP: "true" UPGRADE_PRE_COMMIT: "true" UPGRADE_NODE_LTS: "true" @@ -306,7 +308,7 @@ jobs: test-airflow-release-commands: timeout-minutes: 80 name: "Test Airflow release commands" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" GITHUB_REPOSITORY: ${{ github.repository }} @@ -319,11 +321,11 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -337,24 +339,27 @@ jobs: - name: Install twine run: pip install twine - name: "Check Airflow create minor branch command" - run: | - ./scripts/ci/testing/run_breeze_command_with_retries.sh \ - release-management create-minor-branch --version-branch 2-8 --answer yes + run: > + breeze release-management create-minor-branch + --version-branch 3-1 --answer yes --dry-run - name: "Check Airflow RC process command" - run: | - ./scripts/ci/testing/run_breeze_command_with_retries.sh \ - release-management start-rc-process --version 2.8.3rc1 --previous-version 2.8.0 --answer yes + run: > + breeze release-management start-rc-process + --version 3.1.0rc1 --previous-version 3.0.0 --answer yes --dry-run - name: "Check Airflow release process command" - run: | - ./scripts/ci/testing/run_breeze_command_with_retries.sh \ - release-management start-release --release-candidate 2.8.3rc1 --previous-release 2.8.0 --answer yes + run: > + breeze release-management start-release --release-candidate 3.1.0rc1 + --previous-release 3.0.0 --answer yes --dry-run - name: "Test providers metadata generation" run: | - ./scripts/ci/testing/run_breeze_command_with_retries.sh \ - release-management generate-providers-metadata --refresh-constraints - - name: "Fetch all git tags" + git remote add apache https://github.com/apache/airflow.git + git fetch apache --tags + breeze release-management generate-providers-metadata --refresh-constraints + 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: | - ./scripts/ci/testing/run_breeze_command_with_retries.sh \ - release-management generate-issue-content-core --limit-pr-count 25 --latest --verbose + breeze release-management generate-issue-content-core \ + --limit-pr-count 2 --previous-release 3.0.1 --current-release 3.0.2 --verbose diff --git a/.github/workflows/ci.yml b/.github/workflows/ci-amd.yml similarity index 78% rename from .github/workflows/ci.yml rename to .github/workflows/ci-amd.yml index 406132c3a0b73..a0a1ed4c8e177 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci-amd.yml @@ -16,7 +16,7 @@ # under the License. # --- -name: Tests +name: Tests AMD on: # yamllint disable-line rule:truthy schedule: - cron: '28 1,7,13,19 * * *' @@ -43,7 +43,7 @@ env: VERBOSE: "true" concurrency: - group: ci-${{ github.event.pull_request.number || github.ref }} + group: ci-amd-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: @@ -59,7 +59,6 @@ jobs: ${{ steps.selective-checks.outputs.all-python-versions-list-as-string }} basic-checks-only: ${{ steps.selective-checks.outputs.basic-checks-only }} canary-run: ${{ steps.source-run-info.outputs.canary-run }} - chicken-egg-providers: ${{ steps.selective-checks.outputs.chicken-egg-providers }} ci-image-build: ${{ steps.selective-checks.outputs.ci-image-build }} core-test-types-list-as-strings-in-json: >- ${{ steps.selective-checks.outputs.core-test-types-list-as-strings-in-json }} @@ -84,12 +83,6 @@ jobs: include-success-outputs: ${{ steps.selective-checks.outputs.include-success-outputs }} individual-providers-test-types-list-as-strings-in-json: >- ${{ steps.selective-checks.outputs.individual-providers-test-types-list-as-strings-in-json }} - is-airflow-runner: ${{ steps.selective-checks.outputs.is-airflow-runner }} - is-amd-runner: ${{ steps.selective-checks.outputs.is-amd-runner }} - is-arm-runner: ${{ steps.selective-checks.outputs.is-arm-runner }} - is-k8s-runner: ${{ steps.selective-checks.outputs.is-k8s-runner }} - is-self-hosted-runner: ${{ steps.selective-checks.outputs.is-self-hosted-runner }} - is-vm-runner: ${{ steps.selective-checks.outputs.is-vm-runner }} kubernetes-combos: ${{ steps.selective-checks.outputs.kubernetes-combos }} kubernetes-combos-list-as-string: >- ${{ steps.selective-checks.outputs.kubernetes-combos-list-as-string }} @@ -120,15 +113,13 @@ jobs: run-coverage: ${{ steps.source-run-info.outputs.run-coverage }} run-kubernetes-tests: ${{ steps.selective-checks.outputs.run-kubernetes-tests }} run-task-sdk-tests: ${{ steps.selective-checks.outputs.run-task-sdk-tests }} + run-go-sdk-tests: ${{ steps.selective-checks.outputs.run-go-sdk-tests }} run-system-tests: ${{ steps.selective-checks.outputs.run-system-tests }} run-tests: ${{ steps.selective-checks.outputs.run-tests }} run-ui-tests: ${{ steps.selective-checks.outputs.run-ui-tests }} run-www-tests: ${{ steps.selective-checks.outputs.run-www-tests }} - runs-on-as-json-default: ${{ steps.selective-checks.outputs.runs-on-as-json-default }} - runs-on-as-json-docs-build: ${{ steps.selective-checks.outputs.runs-on-as-json-docs-build }} - runs-on-as-json-public: ${{ steps.selective-checks.outputs.runs-on-as-json-public }} - runs-on-as-json-self-hosted-asf: ${{ steps.selective-checks.outputs.runs-on-as-json-self-hosted-asf }} - runs-on-as-json-self-hosted: ${{ steps.selective-checks.outputs.runs-on-as-json-self-hosted }} + amd-runners: ${{ steps.selective-checks.outputs.amd-runners }} + arm-runners: ${{ steps.selective-checks.outputs.arm-runners }} selected-providers-list-as-string: >- ${{ steps.selective-checks.outputs.selected-providers-list-as-string }} skip-pre-commits: ${{ steps.selective-checks.outputs.skip-pre-commits }} @@ -144,13 +135,13 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: Fetch incoming commit ${{ github.sha }} with its parent - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.sha }} fetch-depth: 2 @@ -178,16 +169,47 @@ jobs: PR_LABELS: ${{ steps.source-run-info.outputs.pr-labels }} GITHUB_CONTEXT: ${{ toJson(github) }} + run-pin-versions-pre-commit: + name: "Run pin-versions pre-commit" + needs: [build-info] + runs-on: ${{ fromJSON(needs.build-info.outputs.amd-runners) }} + steps: + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Install Python 3.11 as 3.11+ is needed by pin-versions pre-commit" + uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1 + with: + python-version: 3.11 + cache: "pip" + - name: Install pre-commit, uv, and pre-commit-uv + shell: bash + env: + UV_VERSION: "0.7.19" # Keep this comment to allow automatic replacement of uv version + PRE_COMMIT_VERSION: "4.2.0" # Keep this comment to allow automatic replacement of pre-commit version + PRE_COMMIT_UV_VERSION: "4.1.4" # Keep this comment to allow automatic replacement of pre-commit-uv version + run: | + pip install uv==${UV_VERSION} || true + uv tool install pre-commit==${PRE_COMMIT_VERSION} --with uv==${UV_VERSION} \ + --with pre-commit-uv==${PRE_COMMIT_UV_VERSION} + - name: "Run pin-versions pre-commit" + run: > + pre-commit run -c .github/.pre-commit-config.yaml --all-files --verbose --hook-stage manual + pin-versions + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + basic-tests: name: "Basic tests" needs: [build-info] uses: ./.github/workflows/basic-tests.yml with: - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} + runners: ${{ needs.build-info.outputs.amd-runners }} run-ui-tests: ${{needs.build-info.outputs.run-ui-tests}} run-www-tests: ${{needs.build-info.outputs.run-www-tests}} needs-api-codegen: ${{needs.build-info.outputs.needs-api-codegen}} - default-python-version: ${{needs.build-info.outputs.default-python-version}} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" basic-checks-only: ${{needs.build-info.outputs.basic-checks-only}} skip-pre-commits: ${{needs.build-info.outputs.skip-pre-commits}} canary-run: ${{needs.build-info.outputs.canary-run}} @@ -204,17 +226,16 @@ jobs: # from forks. This is to prevent malicious PRs from creating images in the "apache/airflow" repo. packages: write with: - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} - runs-on-as-json-self-hosted: ${{ needs.build-info.outputs.runs-on-as-json-self-hosted }} + runners: ${{ needs.build-info.outputs.amd-runners }} platform: "linux/amd64" push-image: "false" upload-image-artifact: "true" upload-mount-cache-artifact: ${{ needs.build-info.outputs.canary-run }} python-versions: ${{ needs.build-info.outputs.python-versions }} branch: ${{ needs.build-info.outputs.default-branch }} + constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} use-uv: ${{ needs.build-info.outputs.use-uv }} upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} - constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} docker-cache: ${{ needs.build-info.outputs.docker-cache }} disable-airflow-repo-cache: ${{ needs.build-info.outputs.disable-airflow-repo-cache }} if: needs.build-info.outputs.ci-image-build == 'true' @@ -227,15 +248,13 @@ jobs: contents: read packages: write id-token: write - if: needs.build-info.outputs.canary-run == 'true' with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} - runs-on-as-json-self-hosted: ${{ needs.build-info.outputs.runs-on-as-json-self-hosted }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" python-versions: ${{ needs.build-info.outputs.python-versions }} branch: ${{ needs.build-info.outputs.default-branch }} constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} skip-pre-commits: ${{ needs.build-info.outputs.skip-pre-commits }} docker-cache: ${{ needs.build-info.outputs.docker-cache }} @@ -252,12 +271,14 @@ jobs: uses: ./.github/workflows/generate-constraints.yml if: needs.build-info.outputs.ci-image-build == 'true' with: - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }} + python-versions: ${{ needs.build-info.outputs.python-versions }} + generate-pypi-constraints: "true" # generate no providers constraints only in canary builds - they take quite some time to generate # they are not needed for regular builds, they are only needed to update constraints in canaries generate-no-providers-constraints: ${{ needs.build-info.outputs.canary-run }} - chicken-egg-providers: ${{ needs.build-info.outputs.chicken-egg-providers }} debug-resources: ${{ needs.build-info.outputs.debug-resources }} use-uv: ${{ needs.build-info.outputs.use-uv }} @@ -269,20 +290,19 @@ jobs: id-token: write contents: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} - runs-on-as-json-docs-build: ${{ needs.build-info.outputs.runs-on-as-json-docs-build }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" needs-mypy: ${{ needs.build-info.outputs.needs-mypy }} mypy-checks: ${{ needs.build-info.outputs.mypy-checks }} python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }} branch: ${{ needs.build-info.outputs.default-branch }} canary-run: ${{ needs.build-info.outputs.canary-run }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" docs-list-as-string: ${{ needs.build-info.outputs.docs-list-as-string }} latest-versions-only: ${{ needs.build-info.outputs.latest-versions-only }} basic-checks-only: ${{ needs.build-info.outputs.basic-checks-only }} upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} skip-pre-commits: ${{ needs.build-info.outputs.skip-pre-commits }} - chicken-egg-providers: ${{ needs.build-info.outputs.chicken-egg-providers }} ci-image-build: ${{ needs.build-info.outputs.ci-image-build }} include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} debug-resources: ${{ needs.build-info.outputs.debug-resources }} @@ -304,11 +324,13 @@ jobs: packages: read if: > needs.build-info.outputs.skip-providers-tests != 'true' && - needs.build-info.outputs.latest-versions-only != 'true' + needs.build-info.outputs.latest-versions-only != 'true' && + needs.build-info.outputs.run-tests == 'true' with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" canary-run: ${{ needs.build-info.outputs.canary-run }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} selected-providers-list-as-string: ${{ needs.build-info.outputs.selected-providers-list-as-string }} # yamllint disable rule:line-length @@ -328,10 +350,10 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" helm-test-packages: ${{ needs.build-info.outputs.helm-test-packages }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" use-uv: ${{ needs.build-info.outputs.use-uv }} if: > needs.build-info.outputs.needs-helm-tests == 'true' && @@ -346,7 +368,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "postgres" test-name: "Postgres" test-scope: "DB" @@ -373,7 +396,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "postgres" test-name: "Postgres" test-scope: "DB" @@ -400,7 +424,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "mysql" test-name: "MySQL" test-scope: "DB" @@ -427,7 +452,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "mysql" test-name: "MySQL" test-scope: "DB" @@ -455,7 +481,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "sqlite" test-name: "Sqlite" test-name-separator: "" @@ -484,7 +511,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "sqlite" test-name: "Sqlite" test-name-separator: "" @@ -514,7 +542,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "sqlite" test-name: "" test-name-separator: "" @@ -542,7 +571,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" backend: "sqlite" test-name: "" test-name-separator: "" @@ -576,13 +606,14 @@ jobs: needs.build-info.outputs.full-tests-needed == 'true') with: default-branch: ${{ needs.build-info.outputs.default-branch }} - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" core-test-types-list-as-strings-in-json: > ${{ needs.build-info.outputs.core-test-types-list-as-strings-in-json }} providers-test-types-list-as-strings-in-json: > ${{ needs.build-info.outputs.providers-test-types-list-as-strings-in-json }} run-coverage: ${{ needs.build-info.outputs.run-coverage }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" python-versions: ${{ needs.build-info.outputs.python-versions }} default-postgres-version: ${{ needs.build-info.outputs.default-postgres-version }} excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }} @@ -601,11 +632,12 @@ jobs: contents: read packages: read with: - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" testable-core-integrations: ${{ needs.build-info.outputs.testable-core-integrations }} testable-providers-integrations: ${{ needs.build-info.outputs.testable-providers-integrations }} run-system-tests: ${{ needs.build-info.outputs.run-tests }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" default-postgres-version: ${{ needs.build-info.outputs.default-postgres-version }} default-mysql-version: ${{ needs.build-info.outputs.default-mysql-version }} run-coverage: ${{ needs.build-info.outputs.run-coverage }} @@ -624,7 +656,8 @@ jobs: if: > needs.build-info.outputs.run-tests == 'true' with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" test-name: "LowestDeps" force-lowest-dependencies: "true" test-scope: "All" @@ -652,7 +685,8 @@ jobs: packages: read if: needs.build-info.outputs.run-tests == 'true' with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" test-name: "LowestDeps" force-lowest-dependencies: "true" test-scope: "All" @@ -681,19 +715,17 @@ jobs: # from forks. This is to prevent malicious PRs from creating images in the "apache/airflow" repo. packages: write with: - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} - build-type: "Regular" + runners: ${{ needs.build-info.outputs.amd-runners }} platform: "linux/amd64" + build-type: "Regular" push-image: "false" upload-image-artifact: "true" upload-package-artifact: "true" python-versions: ${{ needs.build-info.outputs.python-versions }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" branch: ${{ needs.build-info.outputs.default-branch }} use-uv: ${{ needs.build-info.outputs.use-uv }} - build-provider-distributions: ${{ needs.build-info.outputs.default-branch == 'main' }} upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} - chicken-egg-providers: ${{ needs.build-info.outputs.chicken-egg-providers }} constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} docker-cache: ${{ needs.build-info.outputs.docker-cache }} disable-airflow-repo-cache: ${{ needs.build-info.outputs.disable-airflow-repo-cache }} @@ -704,14 +736,14 @@ jobs: needs: [build-info, build-prod-images, generate-constraints] uses: ./.github/workflows/additional-prod-image-tests.yml with: - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" default-branch: ${{ needs.build-info.outputs.default-branch }} constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} - chicken-egg-providers: ${{ needs.build-info.outputs.chicken-egg-providers }} docker-cache: ${{ needs.build-info.outputs.docker-cache }} disable-airflow-repo-cache: ${{ needs.build-info.outputs.disable-airflow-repo-cache }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" canary-run: ${{ needs.build-info.outputs.canary-run }} use-uv: ${{ needs.build-info.outputs.use-uv }} if: needs.build-info.outputs.prod-image-build == 'true' @@ -724,8 +756,8 @@ jobs: contents: read packages: read with: + runners: ${{ needs.build-info.outputs.amd-runners }} platform: "linux/amd64" - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }} include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} use-uv: ${{ needs.build-info.outputs.use-uv }} @@ -743,39 +775,81 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" python-versions: ${{ needs.build-info.outputs.python-versions }} use-uv: ${{ needs.build-info.outputs.use-uv }} canary-run: ${{ needs.build-info.outputs.canary-run }} distribution-name: "task-sdk" distribution-cmd-format: "prepare-task-sdk-distributions" test-type: "task-sdk-tests" + use-local-venv: 'false' + test-timeout: 20 if: > ( needs.build-info.outputs.run-task-sdk-tests == 'true' || needs.build-info.outputs.run-tests == 'true' && needs.build-info.outputs.only-new-ui-files != 'true') - tests-airflow-ctl: - name: "Airflow CTL tests" - uses: ./.github/workflows/airflow-distributions-tests.yml - needs: [build-info, build-ci-images] - permissions: - contents: read - packages: read - with: - runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} - python-versions: ${{ needs.build-info.outputs.python-versions }} - use-uv: ${{ needs.build-info.outputs.use-uv }} - canary-run: ${{ needs.build-info.outputs.canary-run }} - distribution-name: "airflow-ctl" - distribution-cmd-format: "prepare-airflow-ctl-distributions" - test-type: "airflow-ctl-tests" - if: > - ( needs.build-info.outputs.run-airflow-ctl-tests == 'true' || - needs.build-info.outputs.run-tests == 'true' && - needs.build-info.outputs.only-new-ui-files != 'true') +# tests-go-sdk: +# name: "Go SDK tests" +# needs: [build-info, build-ci-images] +# runs-on: ${{ fromJSON(needs.build-info.outputs.amd-runners) }} +# timeout-minutes: 15 +# permissions: +# contents: read +# packages: read +# if: > +# ( needs.build-info.outputs.run-go-sdk-tests == 'true' || +# needs.build-info.outputs.run-tests == 'true' && +# needs.build-info.outputs.only-new-ui-files != 'true') +# env: +# GITHUB_REPOSITORY: ${{ github.repository }} +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# GITHUB_USERNAME: ${{ github.actor }} +# VERBOSE: "true" +# steps: +# - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" +# uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 +# with: +# persist-credentials: false +# +# # keep this in sync with go.mod in go-sdk/ +# - name: Setup Go +# uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 +# with: +# go-version: 1.24 +# cache-dependency-path: go-sdk/go.sum +# +# - name: "Cleanup dist files" +# run: rm -fv ./dist/* +# +# - name: Run Go tests +# working-directory: ./go-sdk +# run: go test -v ./... +# +# tests-airflow-ctl: +# name: "Airflow CTL tests" +# uses: ./.github/workflows/airflow-distributions-tests.yml +# needs: [build-info] +# permissions: +# contents: read +# packages: read +# with: +# runners: ${{ needs.build-info.outputs.amd-runners }} +# platform: "linux/amd64" +# default-python-version: "${{ needs.build-info.outputs.default-python-version }}" +# python-versions: ${{ needs.build-info.outputs.python-versions }} +# use-uv: ${{ needs.build-info.outputs.use-uv }} +# canary-run: ${{ needs.build-info.outputs.canary-run }} +# distribution-name: "airflow-ctl" +# distribution-cmd-format: "prepare-airflow-ctl-distributions" +# test-type: "airflow-ctl-tests" +# use-local-venv: 'true' +# if: > +# ( needs.build-info.outputs.run-airflow-ctl-tests == 'true' || +# needs.build-info.outputs.run-tests == 'true' && +# needs.build-info.outputs.only-new-ui-files != 'true') finalize-tests: name: Finalize tests @@ -785,28 +859,39 @@ jobs: # This will fire when all the jobs from "needs" are either successful or skipped if: always() && !failure() && !cancelled() needs: + - additional-ci-image-checks + - additional-prod-image-tests + - basic-tests - build-info - - generate-constraints + - build-prod-images - ci-image-checks - - tests-sqlite-core - - tests-sqlite-providers + - generate-constraints + - providers + - tests-helm + - tests-integration-system + - tests-kubernetes - tests-mysql-core - tests-mysql-providers - - tests-postgres-core - - tests-postgres-providers - tests-non-db-core - tests-non-db-providers - - tests-integration-system - - build-prod-images + - tests-postgres-core + - tests-postgres-providers + # - tests-special + - tests-sqlite-core + - tests-sqlite-providers + - tests-task-sdk + # - tests-airflow-ctl + - tests-with-lowest-direct-resolution-core + - tests-with-lowest-direct-resolution-providers uses: ./.github/workflows/finalize-tests.yml with: - runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }} - runs-on-as-json-self-hosted: ${{ needs.build-info.outputs.runs-on-as-json-self-hosted }} + runners: ${{ needs.build-info.outputs.amd-runners }} + platform: "linux/amd64" python-versions: ${{ needs.build-info.outputs.python-versions }} python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }} branch: ${{ needs.build-info.outputs.default-branch }} constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} - default-python-version: ${{ needs.build-info.outputs.default-python-version }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} docker-cache: ${{ needs.build-info.outputs.docker-cache }} @@ -818,17 +903,6 @@ jobs: notify-slack-failure: name: "Notify Slack on Failure" needs: - - basic-tests - - additional-ci-image-checks - - providers - - tests-helm - - tests-special - - tests-with-lowest-direct-resolution-core - - tests-with-lowest-direct-resolution-providers - - additional-prod-image-tests - - tests-kubernetes - - tests-task-sdk - - tests-airflow-ctl - finalize-tests if: github.event_name == 'schedule' && failure() && github.run_attempt == 1 runs-on: ["ubuntu-22.04"] @@ -842,10 +916,51 @@ jobs: # yamllint disable rule:line-length payload: | channel: "internal-airflow-ci-cd" - text: "🚨🕒 Scheduled CI Failure Alert 🕒🚨\n\n*Details:* " + text: "🚨🕒 Scheduled CI Failure Alert (AMD) on branch *${{ github.ref_name }}* 🕒🚨\n\n*Details:* " blocks: - type: "section" text: type: "mrkdwn" - text: "🚨🕒 Scheduled CI Failure Alert 🕒🚨\n\n*Details:* " + text: "🚨🕒 Scheduled CI Failure Alert (AMD) 🕒🚨\n\n*Details:* " # yamllint enable rule:line-length + + summarize-warnings: + timeout-minutes: 15 + name: "Summarize warnings" + runs-on: ${{ fromJSON(needs.build-info.outputs.amd-runners) }} + if: needs.build-info.outputs.run-tests == 'true' + steps: + - name: "Cleanup repo" + shell: bash + run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + - name: "Free up disk space" + shell: bash + run: ./scripts/tools/free_up_disk_space.sh + - name: "Download all test warning artifacts from the current build" + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: ./artifacts + pattern: test-warnings-* + - name: "Setup python" + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: "${{ inputs.default-python-version }}" + - name: "Summarize all warnings" + run: | + ./scripts/ci/testing/summarize_captured_warnings.py ./artifacts \ + --pattern "**/warnings-*.txt" \ + --output ./files + - name: "Upload artifact for summarized warnings" + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: test-summarized-amd-runner-warnings + path: ./files/warn-summary-*.txt + retention-days: 7 + if-no-files-found: ignore + overwrite: true diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml new file mode 100644 index 0000000000000..8c309409ca319 --- /dev/null +++ b/.github/workflows/ci-arm.yml @@ -0,0 +1,610 @@ +# 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: Tests ARM +on: # yamllint disable-line rule:truthy + schedule: + - cron: '28 3,9,15,21 * * *' + push: + branches: + - v[0-9]+-[0-9]+-test + - providers-[a-z]+-?[a-z]*/v[0-9]+-[0-9]+ + workflow_dispatch: +permissions: + # All other permissions are set to none by default + contents: read +env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_USERNAME: ${{ github.actor }} + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + VERBOSE: "true" + +concurrency: + group: ci-arm-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + + build-info: + name: "Build info" + # At build-info stage we do not yet have outputs so we need to hard-code the runs-on to public runners + runs-on: ["ubuntu-22.04"] + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + outputs: + all-python-versions-list-as-string: >- + ${{ steps.selective-checks.outputs.all-python-versions-list-as-string }} + basic-checks-only: ${{ steps.selective-checks.outputs.basic-checks-only }} + canary-run: ${{ steps.source-run-info.outputs.canary-run }} + ci-image-build: ${{ steps.selective-checks.outputs.ci-image-build }} + core-test-types-list-as-strings-in-json: >- + ${{ steps.selective-checks.outputs.core-test-types-list-as-strings-in-json }} + debug-resources: ${{ steps.selective-checks.outputs.debug-resources }} + default-branch: ${{ steps.selective-checks.outputs.default-branch }} + default-constraints-branch: ${{ steps.selective-checks.outputs.default-constraints-branch }} + default-helm-version: ${{ steps.selective-checks.outputs.default-helm-version }} + default-kind-version: ${{ steps.selective-checks.outputs.default-kind-version }} + default-kubernetes-version: ${{ steps.selective-checks.outputs.default-kubernetes-version }} + default-mysql-version: ${{ steps.selective-checks.outputs.default-mysql-version }} + default-postgres-version: ${{ steps.selective-checks.outputs.default-postgres-version }} + default-python-version: ${{ steps.selective-checks.outputs.default-python-version }} + disable-airflow-repo-cache: ${{ steps.selective-checks.outputs.disable-airflow-repo-cache }} + docker-cache: ${{ steps.selective-checks.outputs.docker-cache }} + docs-build: ${{ steps.selective-checks.outputs.docs-build }} + docs-list-as-string: ${{ steps.selective-checks.outputs.docs-list-as-string }} + excluded-providers-as-string: ${{ steps.selective-checks.outputs.excluded-providers-as-string }} + force-pip: ${{ steps.selective-checks.outputs.force-pip }} + full-tests-needed: ${{ steps.selective-checks.outputs.full-tests-needed }} + has-migrations: ${{ steps.selective-checks.outputs.has-migrations }} + helm-test-packages: ${{ steps.selective-checks.outputs.helm-test-packages }} + include-success-outputs: ${{ steps.selective-checks.outputs.include-success-outputs }} + individual-providers-test-types-list-as-strings-in-json: >- + ${{ steps.selective-checks.outputs.individual-providers-test-types-list-as-strings-in-json }} + kubernetes-combos: ${{ steps.selective-checks.outputs.kubernetes-combos }} + kubernetes-combos-list-as-string: >- + ${{ steps.selective-checks.outputs.kubernetes-combos-list-as-string }} + kubernetes-versions-list-as-string: >- + ${{ steps.selective-checks.outputs.kubernetes-versions-list-as-string }} + latest-versions-only: ${{ steps.selective-checks.outputs.latest-versions-only }} + mypy-checks: ${{ steps.selective-checks.outputs.mypy-checks }} + mysql-exclude: ${{ steps.selective-checks.outputs.mysql-exclude }} + mysql-versions: ${{ steps.selective-checks.outputs.mysql-versions }} + needs-api-codegen: ${{ steps.selective-checks.outputs.needs-api-codegen }} + needs-api-tests: ${{ steps.selective-checks.outputs.needs-api-tests }} + needs-helm-tests: ${{ steps.selective-checks.outputs.needs-helm-tests }} + needs-mypy: ${{ steps.selective-checks.outputs.needs-mypy }} + only-new-ui-files: ${{ steps.selective-checks.outputs.only-new-ui-files }} + postgres-exclude: ${{ steps.selective-checks.outputs.postgres-exclude }} + postgres-versions: ${{ steps.selective-checks.outputs.postgres-versions }} + prod-image-build: ${{ steps.selective-checks.outputs.prod-image-build }} + # yamllint disable rule:line-length + providers-compatibility-tests-matrix: > + ${{ steps.selective-checks.outputs.providers-compatibility-tests-matrix }} + providers-test-types-list-as-strings-in-json: >- + ${{ steps.selective-checks.outputs.providers-test-types-list-as-strings-in-json }} + pull-request-labels: ${{ steps.source-run-info.outputs.pr-labels }} + python-versions-list-as-string: ${{ steps.selective-checks.outputs.python-versions-list-as-string }} + python-versions: ${{ steps.selective-checks.outputs.python-versions }} + run-amazon-tests: ${{ steps.selective-checks.outputs.run-amazon-tests }} + run-airflow-ctl-tests: ${{ steps.selective-checks.outputs.run-airflow-ctl-tests }} + run-coverage: ${{ steps.source-run-info.outputs.run-coverage }} + run-kubernetes-tests: ${{ steps.selective-checks.outputs.run-kubernetes-tests }} + run-task-sdk-tests: ${{ steps.selective-checks.outputs.run-task-sdk-tests }} + run-go-sdk-tests: ${{ steps.selective-checks.outputs.run-go-sdk-tests }} + run-system-tests: ${{ steps.selective-checks.outputs.run-system-tests }} + run-tests: ${{ steps.selective-checks.outputs.run-tests }} + run-ui-tests: ${{ steps.selective-checks.outputs.run-ui-tests }} + run-www-tests: ${{ steps.selective-checks.outputs.run-www-tests }} + amd-runners: ${{ steps.selective-checks.outputs.amd-runners }} + arm-runners: ${{ steps.selective-checks.outputs.arm-runners }} + selected-providers-list-as-string: >- + ${{ steps.selective-checks.outputs.selected-providers-list-as-string }} + skip-pre-commits: ${{ steps.selective-checks.outputs.skip-pre-commits }} + skip-providers-tests: ${{ steps.selective-checks.outputs.skip-providers-tests }} + source-head-repo: ${{ steps.source-run-info.outputs.source-head-repo }} + sqlite-exclude: ${{ steps.selective-checks.outputs.sqlite-exclude }} + testable-core-integrations: ${{ steps.selective-checks.outputs.testable-core-integrations }} + testable-providers-integrations: ${{ steps.selective-checks.outputs.testable-providers-integrations }} + use-uv: ${{ steps.selective-checks.outputs.force-pip == 'true' && 'false' || 'true' }} + upgrade-to-newer-dependencies: ${{ steps.selective-checks.outputs.upgrade-to-newer-dependencies }} + steps: + - name: "Cleanup repo" + shell: bash + run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + - name: Fetch incoming commit ${{ github.sha }} with its parent + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.sha }} + fetch-depth: 2 + persist-credentials: false + - name: "Install Breeze" + uses: ./.github/actions/breeze + with: + use-uv: ${{ inputs.use-uv }} + id: breeze + - name: "Get information about the Workflow" + id: source-run-info + run: breeze ci get-workflow-info 2>> ${GITHUB_OUTPUT} + env: + SKIP_BREEZE_SELF_UPGRADE_CHECK: "true" + - name: Selective checks + id: selective-checks + env: + PR_LABELS: "${{ steps.source-run-info.outputs.pr-labels }}" + COMMIT_REF: "${{ github.sha }}" + VERBOSE: "false" + run: breeze ci selective-check 2>> ${GITHUB_OUTPUT} + - name: env + run: printenv + env: + PR_LABELS: ${{ steps.source-run-info.outputs.pr-labels }} + GITHUB_CONTEXT: ${{ toJson(github) }} + + basic-tests: + name: "Basic tests" + needs: [build-info] + uses: ./.github/workflows/basic-tests.yml + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + run-ui-tests: ${{needs.build-info.outputs.run-ui-tests}} + run-www-tests: ${{needs.build-info.outputs.run-www-tests}} + needs-api-codegen: ${{needs.build-info.outputs.needs-api-codegen}} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" + basic-checks-only: ${{needs.build-info.outputs.basic-checks-only}} + skip-pre-commits: ${{needs.build-info.outputs.skip-pre-commits}} + canary-run: ${{needs.build-info.outputs.canary-run}} + latest-versions-only: ${{needs.build-info.outputs.latest-versions-only}} + use-uv: ${{needs.build-info.outputs.use-uv}} + + build-ci-images: + name: Build CI images + needs: [build-info] + uses: ./.github/workflows/ci-image-build.yml + permissions: + contents: read + # This write is only given here for `push` events from "apache/airflow" repo. It is not given for PRs + # from forks. This is to prevent malicious PRs from creating images in the "apache/airflow" repo. + packages: write + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + push-image: "false" + upload-image-artifact: "true" + upload-mount-cache-artifact: ${{ needs.build-info.outputs.canary-run }} + python-versions: ${{ needs.build-info.outputs.python-versions }} + branch: ${{ needs.build-info.outputs.default-branch }} + constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} + docker-cache: ${{ needs.build-info.outputs.docker-cache }} + disable-airflow-repo-cache: ${{ needs.build-info.outputs.disable-airflow-repo-cache }} + if: needs.build-info.outputs.ci-image-build == 'true' + + additional-ci-image-checks: + name: "Additional CI image checks" + needs: [build-info, build-ci-images] + uses: ./.github/workflows/additional-ci-image-checks.yml + permissions: + contents: read + packages: write + id-token: write + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + python-versions: ${{ needs.build-info.outputs.python-versions }} + branch: ${{ needs.build-info.outputs.default-branch }} + constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" + upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} + skip-pre-commits: ${{ needs.build-info.outputs.skip-pre-commits }} + docker-cache: ${{ needs.build-info.outputs.docker-cache }} + disable-airflow-repo-cache: ${{ needs.build-info.outputs.disable-airflow-repo-cache }} + canary-run: ${{ needs.build-info.outputs.canary-run }} + latest-versions-only: ${{ needs.build-info.outputs.latest-versions-only }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + + generate-constraints: + name: "Generate constraints" + needs: [build-info, build-ci-images] + uses: ./.github/workflows/generate-constraints.yml + if: needs.build-info.outputs.ci-image-build == 'true' + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }} + python-versions: ${{ needs.build-info.outputs.python-versions }} + generate-pypi-constraints: "true" + # generate no providers constraints only in canary builds - they take quite some time to generate + # they are not needed for regular builds, they are only needed to update constraints in canaries + generate-no-providers-constraints: ${{ needs.build-info.outputs.canary-run }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + + providers: + name: "provider distributions tests" + uses: ./.github/workflows/test-providers.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + if: > + needs.build-info.outputs.skip-providers-tests != 'true' && + needs.build-info.outputs.latest-versions-only != 'true' + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + canary-run: ${{ needs.build-info.outputs.canary-run }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" + upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} + selected-providers-list-as-string: ${{ needs.build-info.outputs.selected-providers-list-as-string }} + # yamllint disable rule:line-length + providers-compatibility-tests-matrix: > + ${{ needs.build-info.outputs.providers-compatibility-tests-matrix }} + skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }} + python-versions: ${{ needs.build-info.outputs.python-versions }} + providers-test-types-list-as-strings-in-json: > + ${{ needs.build-info.outputs.providers-test-types-list-as-strings-in-json }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + + tests-helm: + name: "Helm tests" + uses: ./.github/workflows/helm-tests.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + helm-test-packages: ${{ needs.build-info.outputs.helm-test-packages }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" + use-uv: ${{ needs.build-info.outputs.use-uv }} + if: > + needs.build-info.outputs.needs-helm-tests == 'true' && + needs.build-info.outputs.default-branch == 'main' && + needs.build-info.outputs.latest-versions-only != 'true' + + tests-postgres-core: + name: "Postgres tests: core" + uses: ./.github/workflows/run-unit-tests.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + backend: "postgres" + test-name: "Postgres" + test-scope: "DB" + test-group: "core" + python-versions: ${{ needs.build-info.outputs.python-versions }} + backend-versions: ${{ needs.build-info.outputs.postgres-versions }} + excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }} + excludes: ${{ needs.build-info.outputs.postgres-exclude }} + test-types-as-strings-in-json: > + ${{ needs.build-info.outputs.core-test-types-list-as-strings-in-json }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + run-migration-tests: "true" + run-coverage: ${{ needs.build-info.outputs.run-coverage }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + if: needs.build-info.outputs.run-tests == 'true' + + tests-postgres-providers: + name: "Postgres tests: providers" + uses: ./.github/workflows/run-unit-tests.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + backend: "postgres" + test-name: "Postgres" + test-scope: "DB" + test-group: "providers" + python-versions: ${{ needs.build-info.outputs.python-versions }} + backend-versions: ${{ needs.build-info.outputs.postgres-versions }} + excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }} + excludes: ${{ needs.build-info.outputs.postgres-exclude }} + test-types-as-strings-in-json: > + ${{ needs.build-info.outputs.providers-test-types-list-as-strings-in-json }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + run-migration-tests: "true" + run-coverage: ${{ needs.build-info.outputs.run-coverage }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + if: needs.build-info.outputs.run-tests == 'true' + + tests-sqlite-core: + name: "Sqlite tests: core" + uses: ./.github/workflows/run-unit-tests.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + backend: "sqlite" + test-name: "Sqlite" + test-name-separator: "" + test-scope: "DB" + test-group: "core" + python-versions: ${{ needs.build-info.outputs.python-versions }} + # No versions for sqlite + backend-versions: "['']" + excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }} + excludes: ${{ needs.build-info.outputs.sqlite-exclude }} + test-types-as-strings-in-json: > + ${{ needs.build-info.outputs.core-test-types-list-as-strings-in-json }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + run-coverage: ${{ needs.build-info.outputs.run-coverage }} + run-migration-tests: "true" + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + if: needs.build-info.outputs.run-tests == 'true' + + tests-sqlite-providers: + name: "Sqlite tests: providers" + uses: ./.github/workflows/run-unit-tests.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + backend: "sqlite" + test-name: "Sqlite" + test-name-separator: "" + test-scope: "DB" + test-group: "providers" + python-versions: ${{ needs.build-info.outputs.python-versions }} + # No versions for sqlite + backend-versions: "['']" + excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }} + excludes: ${{ needs.build-info.outputs.sqlite-exclude }} + test-types-as-strings-in-json: > + ${{ needs.build-info.outputs.providers-test-types-list-as-strings-in-json }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + run-coverage: ${{ needs.build-info.outputs.run-coverage }} + run-migration-tests: "true" + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + if: needs.build-info.outputs.run-tests == 'true' + + + tests-non-db-core: + name: "Non-DB tests: core" + uses: ./.github/workflows/run-unit-tests.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + backend: "sqlite" + test-name: "" + test-name-separator: "" + test-scope: "Non-DB" + test-group: "core" + python-versions: ${{ needs.build-info.outputs.python-versions }} + # No versions for non-db + backend-versions: "['']" + excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }} + excludes: ${{ needs.build-info.outputs.sqlite-exclude }} + test-types-as-strings-in-json: > + ${{ needs.build-info.outputs.core-test-types-list-as-strings-in-json }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + run-coverage: ${{ needs.build-info.outputs.run-coverage }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + if: needs.build-info.outputs.run-tests == 'true' + + tests-non-db-providers: + name: "Non-DB tests: providers" + uses: ./.github/workflows/run-unit-tests.yml + needs: [build-info, build-ci-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + backend: "sqlite" + test-name: "" + test-name-separator: "" + test-scope: "Non-DB" + test-group: "providers" + python-versions: ${{ needs.build-info.outputs.python-versions }} + # No versions for non-db + backend-versions: "['']" + excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }} + excludes: ${{ needs.build-info.outputs.sqlite-exclude }} + test-types-as-strings-in-json: > + ${{ needs.build-info.outputs.providers-test-types-list-as-strings-in-json }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + run-coverage: ${{ needs.build-info.outputs.run-coverage }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + if: needs.build-info.outputs.run-tests == 'true' + + build-prod-images: + name: Build PROD images + needs: [build-info, build-ci-images, generate-constraints] + uses: ./.github/workflows/prod-image-build.yml + permissions: + contents: read + # This write is only given here for `push` events from "apache/airflow" repo. It is not given for PRs + # from forks. This is to prevent malicious PRs from creating images in the "apache/airflow" repo. + packages: write + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + build-type: "Regular" + push-image: "false" + upload-image-artifact: "true" + upload-package-artifact: "true" + python-versions: ${{ needs.build-info.outputs.python-versions }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" + branch: ${{ needs.build-info.outputs.default-branch }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} + constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} + docker-cache: ${{ needs.build-info.outputs.docker-cache }} + disable-airflow-repo-cache: ${{ needs.build-info.outputs.disable-airflow-repo-cache }} + prod-image-build: ${{ needs.build-info.outputs.prod-image-build }} + + tests-kubernetes: + name: "Kubernetes tests" + uses: ./.github/workflows/k8s-tests.yml + needs: [build-info, build-prod-images] + permissions: + contents: read + packages: read + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + kubernetes-combos: ${{ needs.build-info.outputs.kubernetes-combos }} + if: > + ( needs.build-info.outputs.run-kubernetes-tests == 'true' || + needs.build-info.outputs.needs-helm-tests == 'true') + +# tests-go-sdk: +# name: "Go SDK tests" +# needs: [build-info, build-ci-images] +# runs-on: ${{ fromJSON(needs.build-info.outputs.arm-runners) }} +# timeout-minutes: 15 +# permissions: +# contents: read +# packages: read +# if: > +# ( needs.build-info.outputs.run-go-sdk-tests == 'true' || +# needs.build-info.outputs.run-tests == 'true' && +# needs.build-info.outputs.only-new-ui-files != 'true') +# env: +# GITHUB_REPOSITORY: ${{ github.repository }} +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# GITHUB_USERNAME: ${{ github.actor }} +# VERBOSE: "true" +# steps: +# - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" +# uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 +# with: +# persist-credentials: false +# +# # keep this in sync with go.mod in go-sdk/ +# - name: Setup Go +# uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 +# with: +# go-version: 1.24 +# cache-dependency-path: go-sdk/go.sum +# +# - name: "Cleanup dist files" +# run: rm -fv ./dist/* +# +# - name: Run Go tests +# working-directory: ./go-sdk +# run: go test -v ./... + + finalize-tests: + name: Finalize tests + permissions: + contents: write + packages: write + # This will fire when all the jobs from "needs" are either successful or skipped + if: always() && !failure() && !cancelled() + needs: + - additional-ci-image-checks + - basic-tests + - build-info + - basic-tests + - generate-constraints + - build-prod-images + - providers + - tests-helm + - tests-kubernetes + - tests-non-db-core + - tests-non-db-providers + - tests-postgres-core + - tests-postgres-providers + - tests-sqlite-core + - tests-sqlite-providers + uses: ./.github/workflows/finalize-tests.yml + with: + runners: ${{ needs.build-info.outputs.arm-runners }} + platform: "linux/arm64" + python-versions: ${{ needs.build-info.outputs.python-versions }} + python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }} + branch: ${{ needs.build-info.outputs.default-branch }} + constraints-branch: ${{ needs.build-info.outputs.default-constraints-branch }} + default-python-version: "${{ needs.build-info.outputs.default-python-version }}" + upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }} + include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }} + docker-cache: ${{ needs.build-info.outputs.docker-cache }} + disable-airflow-repo-cache: ${{ needs.build-info.outputs.disable-airflow-repo-cache }} + canary-run: ${{ needs.build-info.outputs.canary-run }} + use-uv: ${{ needs.build-info.outputs.use-uv }} + debug-resources: ${{ needs.build-info.outputs.debug-resources }} + + notify-slack-failure: + name: "Notify Slack on Failure" + needs: + - finalize-tests + if: github.event_name == 'schedule' && failure() && github.run_attempt == 1 + runs-on: ["ubuntu-22.04"] + steps: + - name: Notify Slack + id: slack + uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0 + with: + method: chat.postMessage + token: ${{ env.SLACK_BOT_TOKEN }} + # yamllint disable rule:line-length + payload: | + channel: "internal-airflow-ci-cd" + text: "🚨🕒 Scheduled CI Failure Alert (AMD) on branch *${{ github.ref_name }}* 🕒🚨\n\n*Details:* " + blocks: + - type: "section" + text: + type: "mrkdwn" + text: "🚨🕒 Scheduled CI Failure Alert (ARM) 🕒🚨\n\n*Details:* " + # yamllint enable rule:line-length diff --git a/.github/workflows/ci-image-build.yml b/.github/workflows/ci-image-build.yml index c695778b87b99..f58fe1946ca1f 100644 --- a/.github/workflows/ci-image-build.yml +++ b/.github/workflows/ci-image-build.yml @@ -20,12 +20,8 @@ name: Build CI images on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." - required: true - type: string - runs-on-as-json-self-hosted: - description: "The array of labels (in json form) determining self-hosted runners." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string target-commit-sha: @@ -77,7 +73,7 @@ on: # yamllint disable-line rule:truthy required: true type: string branch: - description: "Branch used to run the CI jobs in (main/v2_*_test)." + description: "Branch used to run the CI jobs in (main/v*_*_test)." required: true type: string constraints-branch: @@ -106,17 +102,12 @@ jobs: python-version: ${{ fromJSON(inputs.python-versions) || fromJSON('[""]') }} timeout-minutes: 110 name: "Build CI ${{ inputs.platform }} image ${{ matrix.python-version }}" - # NOTE!!!!! This has to be put in one line for runs-on to recognize the "fromJSON" properly !!!! - # adding space before (with >) apparently turns the `runs-on` processed line into a string "Array" - # instead of an array of strings. - # yamllint disable-line rule:line-length - runs-on: ${{ (inputs.platform == 'linux/amd64') && fromJSON(inputs.runs-on-as-json-public) || fromJSON(inputs.runs-on-as-json-self-hosted) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: BACKEND: sqlite PYTHON_MAJOR_MINOR_VERSION: ${{ matrix.python-version }} DEFAULT_BRANCH: ${{ inputs.branch }} DEFAULT_CONSTRAINTS_BRANCH: ${{ inputs.constraints-branch }} - VERSION_SUFFIX_FOR_PYPI: "dev0" GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_USERNAME: ${{ github.actor }} @@ -126,11 +117,11 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout target branch" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: diff --git a/.github/workflows/ci-image-checks.yml b/.github/workflows/ci-image-checks.yml index 3e7a3bba9088a..caa6f4c8889ba 100644 --- a/.github/workflows/ci-image-checks.yml +++ b/.github/workflows/ci-image-checks.yml @@ -20,12 +20,12 @@ name: CI Image Checks on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string - runs-on-as-json-docs-build: - description: "The array of labels (in json form) determining the labels used for docs build." + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string needs-mypy: @@ -41,7 +41,7 @@ on: # yamllint disable-line rule:truthy required: true type: string branch: - description: "Branch used to run the CI jobs in (main/v2_*_test)." + description: "Branch used to run the CI jobs in (main/v*_*_test)." required: true type: string canary-run: @@ -60,10 +60,6 @@ on: # yamllint disable-line rule:truthy description: "Whether to upgrade to newer dependencies (true/false)" required: true type: string - chicken-egg-providers: - description: "List of providers that should be prepared from sources" - required: false - type: string basic-checks-only: description: "Whether to run only basic checks (true/false)" required: true @@ -121,7 +117,7 @@ jobs: install-pre-commit: timeout-minutes: 5 name: "Install pre-commit for cache (only canary runs)" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" if: inputs.basic-checks-only == 'false' @@ -131,7 +127,7 @@ jobs: run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" if: inputs.canary-run == 'true' - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false if: inputs.canary-run == 'true' @@ -165,7 +161,7 @@ jobs: static-checks: timeout-minutes: 45 name: "Static checks" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} needs: install-pre-commit env: PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" @@ -177,14 +173,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} id: breeze - name: "Install pre-commit" @@ -197,7 +193,7 @@ jobs: env: VERBOSE: "false" SKIP: ${{ inputs.skip-pre-commits }} - COLUMNS: "250" + COLUMNS: "202" SKIP_GROUP_OUTPUT: "true" DEFAULT_BRANCH: ${{ inputs.branch }} RUFF_FORMAT: "github" @@ -205,7 +201,7 @@ jobs: mypy: timeout-minutes: 45 name: "MyPy checks" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} needs: install-pre-commit if: inputs.needs-mypy == 'true' strategy: @@ -220,14 +216,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} id: breeze - name: "Install pre-commit" @@ -239,7 +235,7 @@ jobs: run: pre-commit run --color always --verbose --hook-stage manual "$MYPY_CHECK" --all-files env: VERBOSE: "false" - COLUMNS: "250" + COLUMNS: "202" SKIP_GROUP_OUTPUT: "true" DEFAULT_BRANCH: ${{ inputs.branch }} RUFF_FORMAT: "github" @@ -249,7 +245,7 @@ jobs: build-docs: timeout-minutes: 150 name: "Build documentation" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} if: inputs.docs-build == 'true' strategy: fail-fast: false @@ -268,39 +264,38 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "Restore docs inventory cache" uses: apache/infrastructure-actions/stash/restore@1c35b5ccf8fba5d4c3fdf25a045ca91aa0cbc468 with: path: ./generated/_inventory_cache/ - # TODO(potiuk): do better with determining the key - key: cache-docs-inventory-v1-${{ hashFiles('pyproject.toml') }} + key: cache-docs-inventory-v1-${{ hashFiles('**/pyproject.toml') }} id: restore-docs-inventory-cache - name: "Building docs with ${{ matrix.flag }} flag" env: DOCS_LIST_AS_STRING: ${{ inputs.docs-list-as-string }} run: > - breeze build-docs ${DOCS_LIST_AS_STRING} ${{ matrix.flag }} + breeze build-docs ${DOCS_LIST_AS_STRING} ${{ matrix.flag }} --refresh-airflow-inventories - name: "Save docs inventory cache" uses: apache/infrastructure-actions/stash/save@1c35b5ccf8fba5d4c3fdf25a045ca91aa0cbc468 with: path: ./generated/_inventory_cache/ - key: cache-docs-inventory-v1-${{ hashFiles('pyproject.toml') }} + key: cache-docs-inventory-v1-${{ hashFiles('**/pyproject.toml') }} if-no-files-found: 'error' retention-days: '2' # If we upload from multiple matrix jobs we could end up with a race condition. so just pick one job # to be responsible for updating it. https://github.com/actions/upload-artifact/issues/506 if: steps.restore-docs-inventory-cache != 'true' && matrix.flag == '--docs-only' - name: "Upload build docs" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: airflow-docs path: './generated/_build' @@ -315,7 +310,7 @@ jobs: id-token: write contents: read needs: build-docs - runs-on: ${{ fromJSON(inputs.runs-on-as-json-docs-build) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -324,36 +319,36 @@ jobs: INCLUDE_SUCCESS_OUTPUTS: "${{ inputs.include-success-outputs }}" PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" VERBOSE: "true" - if: inputs.canary-run == 'true' && inputs.branch == 'main' + if: > + inputs.canary-run == 'true' && + (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" + uses: ./.github/actions/prepare_breeze_and_image + with: + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" + use-uv: ${{ inputs.use-uv }} - name: "Download docs prepared as artifacts" - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: airflow-docs path: './generated/_build' - name: Check disk space available - run: df -h + run: df -H - name: Create /mnt/airflow-site directory run: sudo mkdir -p /mnt/airflow-site && sudo chown -R "${USER}" /mnt/airflow-site - name: "Clone airflow-site" run: > git clone https://github.com/apache/airflow-site.git /mnt/airflow-site/airflow-site && echo "AIRFLOW_SITE_DIRECTORY=/mnt/airflow-site/airflow-site" >> "$GITHUB_ENV" - - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" - uses: ./.github/actions/prepare_breeze_and_image - with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} - use-uv: ${{ inputs.use-uv }} - name: "Publish docs" env: DOCS_LIST_AS_STRING: ${{ inputs.docs-list-as-string }} @@ -361,7 +356,7 @@ jobs: breeze release-management publish-docs --override-versioned --run-in-parallel ${DOCS_LIST_AS_STRING} - name: Check disk space available - run: df -h + run: df -H - name: "Generate back references for providers" run: breeze release-management add-back-references all-providers - name: "Generate back references for apache-airflow" @@ -389,7 +384,7 @@ jobs: test-python-api-client: timeout-minutes: 60 name: "Test Python API client" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} if: inputs.needs-api-codegen == 'true' env: BACKEND: "postgres" @@ -407,14 +402,12 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: "apache/airflow-client-python" fetch-depth: 1 @@ -423,13 +416,13 @@ jobs: - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "Generate airflow python client" run: > breeze release-management prepare-python-client --distribution-format both - --version-suffix-for-pypi dev0 --python-client-repo ./airflow-client-python + --python-client-repo ./airflow-client-python - name: "Show diff" run: git diff --color HEAD working-directory: ./airflow-client-python diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1fcf81a84fd5b..28c8cfae81a07 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -47,17 +47,17 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 diff --git a/.github/workflows/finalize-tests.yml b/.github/workflows/finalize-tests.yml index 47db38269b35f..8d8565add51c1 100644 --- a/.github/workflows/finalize-tests.yml +++ b/.github/workflows/finalize-tests.yml @@ -20,12 +20,12 @@ name: Finalize tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string - runs-on-as-json-self-hosted: - description: "The array of labels (in json form) determining self-hosted runners." + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string python-versions: @@ -80,7 +80,7 @@ permissions: contents: read jobs: update-constraints: - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} timeout-minutes: 80 name: "Update constraints" permissions: @@ -93,32 +93,32 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_USERNAME: ${{ github.actor }} VERBOSE: "true" - if: inputs.upgrade-to-newer-dependencies != 'false' + if: inputs.upgrade-to-newer-dependencies != 'false' && inputs.platform == 'linux/amd64' steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # Needed to perform push action persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Set constraints branch name" id: constraints-branch run: ./scripts/ci/constraints/ci_branch_constraints.sh >> ${GITHUB_OUTPUT} - name: Checkout ${{ steps.constraints-branch.outputs.branch }} - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: "constraints" ref: ${{ steps.constraints-branch.outputs.branch }} persist-credentials: true fetch-depth: 0 - name: "Download constraints from the constraints generated by build CI image" - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: - name: constraints + pattern: constraints-* path: ./files - name: "Diff in constraints for Python: ${{ inputs.python-versions-list-as-string }}" run: ./scripts/ci/constraints/ci_diff_constraints.sh @@ -127,25 +127,62 @@ jobs: run: ./scripts/ci/constraints/ci_commit_constraints.sh if: inputs.canary-run == 'true' - name: "Push changes" - if: inputs.canary-run == 'true' + if: inputs.canary-run == 'true' && github.event_name != 'pull_request' working-directory: "constraints" run: git push - push-buildx-cache-to-github-registry-amd: - name: Push Regular AMD Image Cache + dependency-upgrade-summary: + runs-on: ${{ fromJSON(inputs.runners) }} + needs: [update-constraints] + if: inputs.upgrade-to-newer-dependencies == 'true' && inputs.platform == 'linux/amd64' + name: "Deps ${{ matrix.python-version }}:${{ matrix.constraints-mode }}" + strategy: + matrix: + python-version: ${{ fromJson(inputs.python-versions) }} + constraints-mode: ["constraints", "constraints-source-providers", "constraints-no-providers"] + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: "Cleanup repo" + shell: bash + run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Prepare breeze & CI image: ${{ matrix.python-version }}" + uses: ./.github/actions/prepare_breeze_and_image + with: + platform: ${{ inputs.platform }} + python: ${{ matrix.python-version }} + use-uv: ${{ inputs.use-uv }} + - name: "Deps: ${{ matrix.python-version }}:${{ matrix.constraints-mode }}" + shell: bash + run: > + breeze release-management constraints-version-check + --python "${MATRIX_PYTHON_VERSION}" + --airflow-constraints-mode "${MATRIX_CONSTRAINTS_MODE}" --explain-why + env: + MATRIX_PYTHON_VERSION: "${{ matrix.python-version }}" + MATRIX_CONSTRAINTS_MODE: "${{ matrix.constraints-mode }}" + VERBOSE: "false" + + push-buildx-cache-to-github-registry: + name: Push Regular Image Cache ${{ inputs.platform }} needs: [update-constraints] uses: ./.github/workflows/push-image-cache.yml permissions: contents: read + # This write is only given here for `push` events from "apache/airflow" repo. It is not given for PRs + # from forks. This is to prevent malicious PRs from creating images in the "apache/airflow" repo. packages: write with: - runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} - runs-on-as-json-self-hosted: ${{ inputs.runs-on-as-json-self-hosted }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} cache-type: "Regular AMD" include-prod-images: "true" push-latest-images: "true" - platform: "linux/amd64" python-versions: ${{ inputs.python-versions }} branch: ${{ inputs.branch }} constraints-branch: ${{ inputs.constraints-branch }} @@ -153,66 +190,6 @@ jobs: include-success-outputs: ${{ inputs.include-success-outputs }} docker-cache: ${{ inputs.docker-cache }} disable-airflow-repo-cache: ${{ inputs.disable-airflow-repo-cache }} - if: inputs.canary-run == 'true' - - # push-buildx-cache-to-github-registry-arm: - # name: Push Regular ARM Image Cache - # needs: [update-constraints] - # uses: ./.github/workflows/push-image-cache.yml - # permissions: - # contents: read - # packages: write - # with: - # runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} - # runs-on-as-json-self-hosted: ${{ inputs.runs-on-as-json-self-hosted }} - # cache-type: "Regular ARM" - # include-prod-images: "true" - # push-latest-images: "true" - # platform: "linux/arm64" - # python-versions: ${{ inputs.python-versions }} - # branch: ${{ inputs.branch }} - # constraints-branch: ${{ inputs.constraints-branch }} - # use-uv: "true" - # include-success-outputs: ${{ inputs.include-success-outputs }} - # docker-cache: ${{ inputs.docker-cache }} - # if: inputs.canary-run == 'true' - - summarize-warnings: - timeout-minutes: 15 - name: "Summarize warnings" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} - steps: - - name: "Cleanup repo" - shell: bash - run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 - with: - persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh - - name: "Free up disk space" - shell: bash - run: ./scripts/tools/free_up_disk_space.sh - - name: "Download all test warning artifacts from the current build" - uses: actions/download-artifact@v4 - with: - path: ./artifacts - pattern: test-warnings-* - - name: "Setup python" - uses: actions/setup-python@v5 - with: - python-version: ${{ inputs.default-python-version }} - - name: "Summarize all warnings" - run: | - ./scripts/ci/testing/summarize_captured_warnings.py ./artifacts \ - --pattern "**/warnings-*.txt" \ - --output ./files - - name: "Upload artifact for summarized warnings" - uses: actions/upload-artifact@v4 - with: - name: test-summarized-warnings - path: ./files/warn-summary-*.txt - retention-days: 7 - if-no-files-found: ignore - overwrite: true + if: > + inputs.canary-run == 'true' && + (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') diff --git a/.github/workflows/generate-constraints.yml b/.github/workflows/generate-constraints.yml index 0f74081686316..d2d0db0685a58 100644 --- a/.github/workflows/generate-constraints.yml +++ b/.github/workflows/generate-constraints.yml @@ -20,20 +20,28 @@ name: Generate constraints on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." + runners: + description: "The array of labels (in json form) determining runners." + required: true + type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string python-versions-list-as-string: description: "Stringified array of all Python versions to test - separated by spaces." required: true type: string + python-versions: + description: "JSON-formatted array of Python versions to generate constraints for" + required: true + type: string generate-no-providers-constraints: description: "Whether to generate constraints without providers (true/false)" required: true type: string - chicken-egg-providers: - description: "Space-separated list of providers that should be installed from context files" + generate-pypi-constraints: + description: "Whether to generate PyPI constraints (true/false)" required: true type: string debug-resources: @@ -45,107 +53,86 @@ on: # yamllint disable-line rule:truthy required: true type: string jobs: - generate-constraints: + generate-constraints-matrix: permissions: contents: read timeout-minutes: 70 - name: Generate constraints ${{ inputs.python-versions-list-as-string }} - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + name: Generate constraints for ${{ matrix.python-version }} on ${{ inputs.platform }} + runs-on: ${{ fromJSON(inputs.runners) }} + strategy: + matrix: + python-version: ${{ fromJson(inputs.python-versions) }} env: DEBUG_RESOURCES: ${{ inputs.debug-resources }} GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_USERNAME: ${{ github.actor }} INCLUDE_SUCCESS_OUTPUTS: "true" - PYTHON_VERSIONS: ${{ inputs.python-versions-list-as-string }} + PYTHON_VERSION: ${{ matrix.python-version }} VERBOSE: "true" - VERSION_SUFFIX_FOR_PYPI: "dev0" steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh - shell: bash - - name: "Install Breeze" - uses: ./.github/actions/breeze + - name: "Prepare breeze & CI image: ${{ matrix.python-version }}" + uses: ./.github/actions/prepare_breeze_and_image with: + platform: ${{ inputs.platform }} + python: ${{ matrix.python-version }} use-uv: ${{ inputs.use-uv }} - id: breeze - - name: "Prepare all CI images: ${{ inputs.python-versions-list-as-string}}" - uses: ./.github/actions/prepare_all_ci_images - with: - platform: "linux/amd64" - python-versions-list-as-string: ${{ inputs.python-versions-list-as-string }} - docker-volume-location: "" # TODO(jscheffl): Understand why it fails here and fix it - - name: "Verify all CI images ${{ inputs.python-versions-list-as-string }}" - run: breeze ci-image verify --run-in-parallel - name: "Source constraints" shell: bash run: > - breeze release-management generate-constraints --run-in-parallel + breeze release-management generate-constraints --airflow-constraints-mode constraints-source-providers --answer yes + --python "${PYTHON_VERSION}" - name: "No providers constraints" shell: bash timeout-minutes: 25 run: > - breeze release-management generate-constraints --run-in-parallel - --airflow-constraints-mode constraints-no-providers --answer yes --parallelism 3 - # The no providers constraints are only needed when we want to update constraints (in canary builds) - # They slow down the start of PROD image builds so we want to only run them when needed. + breeze release-management generate-constraints + --airflow-constraints-mode constraints-no-providers --answer yes + --python "${PYTHON_VERSION}" if: inputs.generate-no-providers-constraints == 'true' - - name: "Prepare chicken-eggs provider distributions" - # In case of provider distributions which use latest dev0 version of providers, we should prepare them - # from the source code, not from the PyPI because they have apache-airflow>=X.Y.Z dependency - # And when we prepare them from sources they will have apache-airflow>=X.Y.Z.dev0 + - name: "Prepare updated provider distributions" shell: bash - env: - CHICKEN_EGG_PROVIDERS: ${{ inputs.chicken-egg-providers }} run: > - breeze release-management prepare-provider-distributions --include-not-ready-providers - --distribution-format wheel --version-suffix-for-pypi dev0 - ${CHICKEN_EGG_PROVIDERS} - if: inputs.chicken-egg-providers != '' + breeze release-management prepare-provider-distributions + --include-not-ready-providers --distribution-format wheel + if: inputs.generate-pypi-constraints == 'true' - name: "Prepare airflow distributions" shell: bash run: > - breeze release-management prepare-airflow-distributions - --distribution-format wheel --version-suffix-for-pypi dev0 + breeze release-management prepare-airflow-distributions --distribution-format wheel + if: inputs.generate-pypi-constraints == 'true' - name: "Prepare task-sdk distribution" shell: bash run: > - breeze release-management prepare-task-sdk-distributions - --distribution-format wheel --version-suffix-for-pypi dev0 + breeze release-management prepare-task-sdk-distributions --distribution-format wheel + if: inputs.generate-pypi-constraints == 'true' - name: "PyPI constraints" shell: bash timeout-minutes: 25 - env: - CHICKEN_EGG_PROVIDERS: ${{ inputs.chicken-egg-providers }} run: | - for PYTHON in $PYTHON_VERSIONS; do - breeze release-management generate-constraints \ - --airflow-constraints-mode constraints --answer yes \ - --chicken-egg-providers "${CHICKEN_EGG_PROVIDERS}" \ - --python "${PYTHON}" - done - - name: "Dependency upgrade summary" - shell: bash - env: - PYTHON_VERSIONS: ${{ env.PYTHON_VERSIONS }} - run: | - for PYTHON_VERSION in $PYTHON_VERSIONS; do - echo "Summarizing Python $PYTHON_VERSION" - cat "files/constraints-${PYTHON_VERSION}"/*.md >> $GITHUB_STEP_SUMMARY || true - df -H - done + breeze release-management generate-constraints --airflow-constraints-mode constraints \ + --answer yes --python "${PYTHON_VERSION}" + if: inputs.generate-pypi-constraints == 'true' - name: "Upload constraint artifacts" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: constraints - path: ./files/constraints-*/constraints-*.txt + name: constraints-${{ matrix.python-version }} + path: ./files/constraints-${{ matrix.python-version }}/constraints-*.txt retention-days: 7 if-no-files-found: error + - name: "Dependency upgrade summary" + shell: bash + env: + PYTHON_VERSION: ${{ matrix.python-version }} + run: | + echo "Summarizing Python $PYTHON_VERSION" + cat "files/constraints-${PYTHON_VERSION}"/*.md >> $GITHUB_STEP_SUMMARY || true + df -H diff --git a/.github/workflows/helm-tests.yml b/.github/workflows/helm-tests.yml index 1b4aa19cbe595..f2f712a6831ec 100644 --- a/.github/workflows/helm-tests.yml +++ b/.github/workflows/helm-tests.yml @@ -20,12 +20,12 @@ name: Helm tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string helm-test-packages: @@ -46,7 +46,7 @@ jobs: tests-helm: timeout-minutes: 80 name: "Unit tests Helm: ${{ matrix.helm-test-package }}" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: fail-fast: false matrix: @@ -68,14 +68,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "Helm Unit Tests: ${{ matrix.helm-test-package }}" env: @@ -85,7 +85,7 @@ jobs: tests-helm-release: timeout-minutes: 80 name: "Release Helm" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: PYTHON_MAJOR_MINOR_VERSION: "${{inputs.default-python-version}}" steps: @@ -93,11 +93,11 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -130,13 +130,12 @@ jobs: SIGN_WITH: dev@airflow.apache.org - name: "Fetch Git Tags" run: git fetch --tags - - name: "Test helm chart issue generation automatically" - # Adding same tags for now, will address in a follow-up + - name: "Test helm chart issue generation" run: > - breeze release-management generate-issue-content-helm-chart --limit-pr-count 10 - --latest --verbose + breeze release-management generate-issue-content-helm-chart --limit-pr-count 2 + --previous-release helm-chart/1.15.0 --current-release helm-chart/1.16.0 --verbose - name: "Upload Helm artifacts" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: Helm artifacts path: ./dist/airflow-* diff --git a/.github/workflows/integration-system-tests.yml b/.github/workflows/integration-system-tests.yml index fc3159223e8fb..0a728a351ed35 100644 --- a/.github/workflows/integration-system-tests.yml +++ b/.github/workflows/integration-system-tests.yml @@ -20,10 +20,14 @@ name: Integration and system tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: + runners: description: "The array of labels (in json form) determining public runners." required: true type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" + required: true + type: string testable-core-integrations: description: "The list of testable core integrations as JSON array." required: true @@ -71,7 +75,7 @@ jobs: timeout-minutes: 30 if: inputs.testable-core-integrations != '[]' name: "Integration core ${{ matrix.integration }}" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: fail-fast: false matrix: @@ -93,14 +97,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "Integration: core ${{ matrix.integration }}" env: @@ -111,7 +115,7 @@ jobs: uses: ./.github/actions/post_tests_success with: codecov-token: ${{ secrets.CODECOV_TOKEN }} - python-version: ${{ inputs.default-python-version }} + python-version: "${{ inputs.default-python-version }}" - name: "Post Tests failure" uses: ./.github/actions/post_tests_failure if: failure() @@ -120,7 +124,7 @@ jobs: timeout-minutes: 30 if: inputs.testable-providers-integrations != '[]' && inputs.skip-providers-tests != 'true' name: "Integration: providers ${{ matrix.integration }}" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: fail-fast: false matrix: @@ -142,14 +146,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "Integration: providers ${{ matrix.integration }}" env: @@ -159,7 +163,7 @@ jobs: uses: ./.github/actions/post_tests_success with: codecov-token: ${{ secrets.CODECOV_TOKEN }} - python-version: ${{ inputs.default-python-version }} + python-version: "${{ inputs.default-python-version }}" - name: "Post Tests failure" uses: ./.github/actions/post_tests_failure if: failure() @@ -168,7 +172,7 @@ jobs: timeout-minutes: 30 if: inputs.run-system-tests == 'true' name: "System Tests" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} env: BACKEND: "postgres" BACKEND_VERSION: ${{ inputs.default-postgres-version }}" @@ -186,14 +190,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "System Tests" run: > @@ -202,7 +206,7 @@ jobs: uses: ./.github/actions/post_tests_success with: codecov-token: ${{ secrets.CODECOV_TOKEN }} - python-version: ${{ inputs.default-python-version }} + python-version: "${{ inputs.default-python-version }}" - name: "Post Tests failure" uses: ./.github/actions/post_tests_failure if: failure() diff --git a/.github/workflows/k8s-tests.yml b/.github/workflows/k8s-tests.yml index 40f73e3c59c66..37aa3aa703ce1 100644 --- a/.github/workflows/k8s-tests.yml +++ b/.github/workflows/k8s-tests.yml @@ -20,12 +20,12 @@ name: K8s tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - platform: - description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" + runners: + description: "The array of labels (in json form) determining runners." required: true type: string - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string python-versions-list-as-string: @@ -54,7 +54,7 @@ jobs: tests-kubernetes: timeout-minutes: 60 name: "K8S System:${{ matrix.executor }}-${{ matrix.kubernetes-combo }}-${{ matrix.use-standard-naming }}" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: matrix: executor: [KubernetesExecutor, CeleryExecutor, LocalExecutor] @@ -80,7 +80,7 @@ jobs: echo "PYTHON_MAJOR_MINOR_VERSION=${KUBERNETES_COMBO}" | sed 's/-.*//' >> $GITHUB_ENV echo "KUBERNETES_VERSION=${KUBERNETES_COMBO}" | sed 's/=[^-]*-/=/' >> $GITHUB_ENV - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false # env.PYTHON_MAJOR_MINOR_VERSION, env.KUBERNETES_VERSION are set in the previous @@ -103,27 +103,26 @@ jobs: USE_STANDARD_NAMING: ${{ matrix.use-standard-naming }} VERBOSE: "false" - name: "\ - Upload KinD logs on failure ${{ matrix.executor }}-${{ matrix.kubernetes-combo }}-\ + Print logs ${{ matrix.executor }}-${{ matrix.kubernetes-combo }}-\ ${{ matrix.use-standard-naming }}" - uses: actions/upload-artifact@v4 - if: failure() || cancelled() - with: - name: "\ - kind-logs-${{ matrix.kubernetes-combo }}-${{ matrix.executor }}-\ - ${{ matrix.use-standard-naming }}" - path: /tmp/kind_logs_* - retention-days: '7' + run: | + for file in `find /tmp/kind_logs_*/ -type f` ; do + echo "::group::${file}" + cat $file + echo "::endgroup::" + done + if: failure() || cancelled() || inputs.include-success-outputs == 'true' - name: "\ - Upload test resource logs on failure ${{ matrix.executor }}-${{ matrix.kubernetes-combo }}-\ + Upload KinD logs ${{ matrix.executor }}-${{ matrix.kubernetes-combo }}-\ ${{ matrix.use-standard-naming }}" - uses: actions/upload-artifact@v4 - if: failure() || cancelled() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: "\ - k8s-test-resources-${{ matrix.kubernetes-combo }}-${{ matrix.executor }}-\ + kind-logs-${{ matrix.kubernetes-combo }}-${{ matrix.executor }}-\ ${{ matrix.use-standard-naming }}" - path: /tmp/k8s_test_resources_* + path: /tmp/kind_logs_* retention-days: '7' + if: failure() || cancelled() || inputs.include-success-outputs == 'true' - name: "Delete clusters just in case they are left" run: breeze k8s delete-cluster --all if: always() diff --git a/.github/workflows/news-fragment.yml b/.github/workflows/news-fragment.yml index f6f68d1288a35..04e308c306138 100644 --- a/.github/workflows/news-fragment.yml +++ b/.github/workflows/news-fragment.yml @@ -30,7 +30,7 @@ jobs: if: "contains(github.event.pull_request.labels.*.name, 'airflow3.0:breaking')" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false # `towncrier check` runs `git diff --name-only origin/main...`, which diff --git a/.github/workflows/prod-image-build.yml b/.github/workflows/prod-image-build.yml index a335576d4bcf5..4819ee7be1470 100644 --- a/.github/workflows/prod-image-build.yml +++ b/.github/workflows/prod-image-build.yml @@ -20,8 +20,8 @@ name: Build PROD images on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining default runner used for the build." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string build-type: @@ -85,25 +85,17 @@ on: # yamllint disable-line rule:truthy required: true type: string branch: - description: "Branch used to run the CI jobs in (main/v2_*_test)." + description: "Branch used to run the CI jobs in (main/v*_*_test)." required: true type: string constraints-branch: description: "Branch used to construct constraints URL from." required: true type: string - build-provider-distributions: - description: "Whether to build provider distributions (true/false). If false providers are from PyPI" - required: true - type: string upgrade-to-newer-dependencies: description: "Whether to attempt to upgrade image to newer dependencies (true/false)" required: true type: string - chicken-egg-providers: - description: "Space-separated list of providers that should be installed from context files" - required: true - type: string docker-cache: description: "Docker cache specification to build the image (registry, local, disabled)." required: true @@ -122,22 +114,21 @@ jobs: build-prod-packages: name: "Build Airflow and provider distributions" timeout-minutes: 10 - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} if: inputs.prod-image-build == 'true' env: PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}" - VERSION_SUFFIX_FOR_PYPI: ${{ inputs.branch == 'main' && 'dev0' || '' }} steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" if: inputs.upload-package-artifact == 'true' - name: "Checkout target branch" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh if: inputs.upload-package-artifact == 'true' - name: "Cleanup dist and context file" shell: bash @@ -148,25 +139,22 @@ jobs: with: use-uv: ${{ inputs.use-uv }} if: inputs.upload-package-artifact == 'true' - - name: "Prepare providers packages" + - name: "Prepare providers packages - all providers built from sources" shell: bash run: > breeze release-management prepare-provider-distributions --distributions-list-file ./prod_image_installed_providers.txt - --distribution-format wheel --include-not-ready-providers + --distribution-format wheel --include-not-ready-providers --skip-tag-check if: > - inputs.upload-package-artifact == 'true' && - inputs.build-provider-distributions == 'true' - - name: "Prepare chicken-eggs provider distributions" + inputs.upload-package-artifact == 'true' && inputs.branch == 'main' + - name: "Prepare providers packages with only new versions of providers" shell: bash - env: - CHICKEN_EGG_PROVIDERS: ${{ inputs.chicken-egg-providers }} run: > breeze release-management prepare-provider-distributions - --distribution-format wheel ${CHICKEN_EGG_PROVIDERS} + --distributions-list-file ./prod_image_installed_providers.txt + --distribution-format wheel --include-not-ready-providers if: > - inputs.upload-package-artifact == 'true' && - inputs.chicken-egg-providers != '' + inputs.upload-package-artifact == 'true' && inputs.branch != 'main' - name: "Prepare airflow package" shell: bash run: > @@ -183,7 +171,7 @@ jobs: breeze release-management prepare-airflow-ctl-distributions --distribution-format wheel if: inputs.upload-package-artifact == 'true' - name: "Upload prepared packages as artifacts" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: prod-packages path: ./dist @@ -198,7 +186,7 @@ jobs: python-version: ${{ fromJSON(inputs.python-versions) || fromJSON('[""]') }} timeout-minutes: 80 name: "Build PROD ${{ inputs.build-type }} image ${{ matrix.python-version }}" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-public) }} + runs-on: ${{ fromJSON(inputs.runners) }} needs: - build-prod-packages env: @@ -206,7 +194,6 @@ jobs: PYTHON_MAJOR_MINOR_VERSION: "${{ matrix.python-version }}" DEFAULT_BRANCH: ${{ inputs.branch }} DEFAULT_CONSTRAINTS_BRANCH: ${{ inputs.constraints-branch }} - VERSION_SUFFIX_FOR_PYPI: ${{ inputs.branch == 'main' && 'dev0' || '' }} INCLUDE_NOT_READY_PROVIDERS: "true" # You can override CONSTRAINTS_GITHUB_REPOSITORY by setting secret in your repo but by default the # Airflow one is going to be used @@ -217,17 +204,18 @@ jobs: GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_USERNAME: ${{ github.actor }} + PLATFORM: ${{ inputs.platform }} VERBOSE: "true" steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout target branch" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -236,15 +224,27 @@ jobs: shell: bash run: rm -fv ./dist/* ./docker-context-files/* - name: "Download packages prepared as artifacts" - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: prod-packages path: ./docker-context-files + - name: "Show downloaded packages" + run: ls -la ./docker-context-files - name: "Download constraints" - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: - name: constraints + pattern: constraints-* path: ./docker-context-files + - name: "Show constraints" + run: | + for file in ./docker-context-files/constraints*/constraints*.txt + do + echo "=== ${file} ===" + echo + cat ${file} + echo + echo "=== END ${file} ===" + done - name: "Login to ghcr.io" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -267,25 +267,7 @@ jobs: INSTALL_MYSQL_CLIENT_TYPE: ${{ inputs.install-mysql-client-type }} UPGRADE_TO_NEWER_DEPENDENCIES: ${{ inputs.upgrade-to-newer-dependencies }} INCLUDE_NOT_READY_PROVIDERS: "true" - if: inputs.build-provider-distributions == 'true' - - name: "Build PROD images with PyPi providers ${{ env.PYTHON_MAJOR_MINOR_VERSION }}" - shell: bash - run: > - breeze prod-image build - --builder airflow_cache - --commit-sha "${{ github.sha }}" - --install-distributions-from-context - --airflow-constraints-mode constraints - --use-constraints-for-context-distributions - env: - PUSH: ${{ inputs.push-image }} - DOCKER_CACHE: ${{ inputs.docker-cache }} - DISABLE_AIRFLOW_REPO_CACHE: ${{ inputs.disable-airflow-repo-cache }} - DEBIAN_VERSION: ${{ inputs.debian-version }} - INSTALL_MYSQL_CLIENT_TYPE: ${{ inputs.install-mysql-client-type }} - UPGRADE_TO_NEWER_DEPENDENCIES: ${{ inputs.upgrade-to-newer-dependencies }} - INCLUDE_NOT_READY_PROVIDERS: "true" - if: inputs.build-provider-distributions != 'true' + USE_UV: ${{ inputs.use-uv }} - name: "Verify PROD image ${{ env.PYTHON_MAJOR_MINOR_VERSION }}" run: breeze prod-image verify - name: "Export PROD docker image ${{ env.PYTHON_MAJOR_MINOR_VERSION }}" diff --git a/.github/workflows/prod-image-extra-checks.yml b/.github/workflows/prod-image-extra-checks.yml index 0b208cb552059..2d8a950982f8e 100644 --- a/.github/workflows/prod-image-extra-checks.yml +++ b/.github/workflows/prod-image-extra-checks.yml @@ -20,8 +20,12 @@ name: PROD images extra checks on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." + runners: + description: "The array of labels (in json form) determining runners." + required: true + type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string python-versions: @@ -33,25 +37,13 @@ on: # yamllint disable-line rule:truthy required: true type: string branch: - description: "Branch used to run the CI jobs in (main/v2_*_test)." - required: true - type: string - use-uv: - description: "Whether to use uv to build the image (true/false)" - required: true - type: string - build-provider-distributions: - description: "Whether to build provider distributions (true/false). If false providers are from PyPI" + description: "Branch used to run the CI jobs in (main/v*_*_test)." required: true type: string upgrade-to-newer-dependencies: description: "Whether to attempt to upgrade image to newer dependencies (false/RANDOM_VALUE)" required: true type: string - chicken-egg-providers: - description: "Space-separated list of providers that should be installed from context files" - required: true - type: string constraints-branch: description: "Branch used to construct constraints URL from." required: true @@ -70,21 +62,19 @@ jobs: myssql-client-image: uses: ./.github/workflows/prod-image-build.yml with: - runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} build-type: "MySQL Client" upload-image-artifact: "false" upload-package-artifact: "false" install-mysql-client-type: "mysql" python-versions: ${{ inputs.python-versions }} - default-python-version: ${{ inputs.default-python-version }} - platform: "linux/amd64" + default-python-version: "${{ inputs.default-python-version }}" branch: ${{ inputs.branch }} # Always build images during the extra checks and never push them push-image: "false" - use-uv: ${{ inputs.use-uv }} - build-provider-distributions: ${{ inputs.build-provider-distributions }} + use-uv: "true" upgrade-to-newer-dependencies: ${{ inputs.upgrade-to-newer-dependencies }} - chicken-egg-providers: ${{ inputs.chicken-egg-providers }} constraints-branch: ${{ inputs.constraints-branch }} docker-cache: ${{ inputs.docker-cache }} disable-airflow-repo-cache: ${{ inputs.disable-airflow-repo-cache }} @@ -92,24 +82,20 @@ jobs: pip-image: uses: ./.github/workflows/prod-image-build.yml - # Skip testing PIP image on release branches as all images there are built with pip - if: ${{ inputs.use-uv == 'true' }} with: - runs-on-as-json-public: ${{ inputs.runs-on-as-json-public }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} build-type: "pip" upload-image-artifact: "false" upload-package-artifact: "false" install-mysql-client-type: "mysql" python-versions: ${{ inputs.python-versions }} - default-python-version: ${{ inputs.default-python-version }} - platform: "linux/amd64" + default-python-version: "${{ inputs.default-python-version }}" branch: ${{ inputs.branch }} # Always build images during the extra checks and never push them push-image: "false" use-uv: "false" - build-provider-distributions: ${{ inputs.build-provider-distributions }} upgrade-to-newer-dependencies: ${{ inputs.upgrade-to-newer-dependencies }} - chicken-egg-providers: ${{ inputs.chicken-egg-providers }} constraints-branch: ${{ inputs.constraints-branch }} docker-cache: ${{ inputs.docker-cache }} disable-airflow-repo-cache: ${{ inputs.disable-airflow-repo-cache }} diff --git a/.github/workflows/publish-docs-to-s3.yml b/.github/workflows/publish-docs-to-s3.yml new file mode 100644 index 0000000000000..6c1eb1dd48a1d --- /dev/null +++ b/.github/workflows/publish-docs-to-s3.yml @@ -0,0 +1,315 @@ +# 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: Publish Docs to S3 +on: # yamllint disable-line rule:truthy + workflow_dispatch: + inputs: + ref: + description: "The branch or tag to checkout for the docs publishing" + required: true + type: string + destination: + description: "The destination location in S3" + required: false + default: auto + type: choice + options: + - auto + - live + - staging + include-docs: + description: "Space separated list of packages to build" + required: true + type: string + exclude-docs: + description: "Comma separated list of docs to exclude" + required: false + default: "no-docs-excluded" + type: string + skip-write-to-stable-folder: + description: "Do not override stable version" + required: false + default: false + type: boolean + build-sboms: + description: "Build SBOMs" + required: false + default: false + type: boolean + +permissions: + contents: read +jobs: + build-info: + timeout-minutes: 10 + name: "Build Info" + runs-on: ["ubuntu-24.04"] + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + VERBOSE: true + REF: ${{ inputs.ref }} + INCLUDE_DOCS: ${{ inputs.include-docs }} + EXCLUDE_DOCS: ${{ inputs.exclude-docs }} + DESTINATION: ${{ inputs.destination }} + SKIP_WRITE_TO_STABLE_FOLDER: ${{ inputs.skip-write-to-stable-folder }} + BUILD_SBOMS: ${{ inputs.build-sboms }} + outputs: + include-docs: ${{ inputs.include-docs == 'all' && '' || inputs.include-docs }} + destination-location: ${{ steps.parameters.outputs.destination-location }} + destination: ${{ steps.parameters.outputs.destination }} + extra-build-options: ${{ steps.parameters.outputs.extra-build-options }} + airflow-base-version: ${{ steps.parameters.outputs.airflow-base-version }} + airflow-version: ${{ steps.parameters.outputs.airflow-version }} + # yamllint disable rule:line-length + skip-write-to-stable-folder: ${{ inputs.skip-write-to-stable-folder && '--skip-write-to-stable-folder' || '' }} + default-python-version: "3.10" + if: contains(fromJSON('[ + "ashb", + "eladkal", + "ephraimbuddy", + "jedcunningham", + "kaxil", + "pierrejeambrun", + "potiuk", + "utkarsharma2" + ]'), github.event.sender.login) + steps: + - name: "Input parameters summary" + shell: bash + id: parameters + run: | + echo "Input parameters summary" + echo "=========================" + echo "Ref: '${REF}'" + echo "Included docs : '${INCLUDE_DOCS}'" + echo "Exclude docs: '${EXCLUDE_DOCS}'" + echo "Destination: '${DESTINATION}'" + echo "Skip write to stable folder: '${SKIP_WRITE_TO_STABLE_FOLDER}'" + echo "Build SBOMs: '${BUILD_SBOMS}'" + if [[ "${DESTINATION}" == "auto" ]]; then + if [[ "${REF}" =~ ^.*[0-9]*\.[0-9]*\.[0-9]*$ ]]; then + echo "${REF} looks like final release, using live destination" + DESTINATION="live" + else + echo "${REF} does not looks like final release, using staging destination" + DESTINATION="staging" + fi + fi + echo "destination=${DESTINATION}" >> ${GITHUB_OUTPUT} + if [[ "${DESTINATION}" == "live" ]]; then + echo "destination-location=s3://live-docs-airflow-apache-org/docs/" >> ${GITHUB_OUTPUT} + else + echo "destination-location=s3://staging-docs-airflow-apache-org/docs/" >> ${GITHUB_OUTPUT} + fi + if [[ " ${INCLUDE_DOCS} " =~ " apache-airflow " ]]; then + AIRFLOW_BASE_VERSION=$(echo "${REF}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') + AIRFLOW_VERSION="${REF}" + echo "airflow-base-version=${AIRFLOW_BASE_VERSION}" >> ${GITHUB_OUTPUT} + echo "airflow-version=${AIRFLOW_VERSION}" >> ${GITHUB_OUTPUT} + else + echo "airflow-version=no-airflow" >> ${GITHUB_OUTPUT} + echo "airflow-base-version=no-airflow" >> ${GITHUB_OUTPUT} + fi + + build-docs: + needs: [build-info] + timeout-minutes: 150 + name: "Build documentation" + runs-on: ubuntu-latest + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_USERNAME: ${{ github.actor }} + INCLUDE_SUCCESS_OUTPUTS: false + VERBOSE: "true" + EXTRA_BUILD_OPTIONS: ${{ needs.build-info.outputs.extra-build-options }} + steps: + - name: "Cleanup repo" + shell: bash + run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + - name: "Checkout current version first to clean-up stuff" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + path: current-version + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + working-directory: current-version + # We are checking repo for both - breeze and docs from the ref provided as input + # This will take longer as we need to rebuild CI image and it will not use cache + # but it will build the CI image from the version of Airflow that is used to check out things + - name: "Checkout ${{ inputs.ref }} " + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + ref: ${{ inputs.ref }} + fetch-depth: 0 + fetch-tags: true + - name: "Install Breeze from the ${{ inputs.ref }} reference" + uses: ./.github/actions/breeze + with: + use-uv: ${{ inputs.use-uv }} + python-version: "${{ needs.build-info.outputs.default-python-version }}" + - name: "Building image from the ${{ inputs.ref }} reference" + env: + INCLUDE_DOCS: ${{ needs.build-info.outputs.include-docs }} + INCLUDE_COMMITS: ${{ startsWith(inputs.ref, 'providers') && 'true' || 'false' }} + run: > + breeze ci-image build + - name: "Building docs with --docs-only flag using ${{ inputs.ref }} reference breeze" + env: + INCLUDE_DOCS: ${{ needs.build-info.outputs.include-docs }} + INCLUDE_COMMITS: ${{ startsWith(inputs.ref, 'providers') && 'true' || 'false' }} + run: > + breeze build-docs ${INCLUDE_DOCS} --docs-only + - name: "Checkout current version to run SBOM generation" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + fetch-depth: 0 + fetch-tags: true + path: current-version + if: inputs.build-sboms + - name: "Reinstall breeze from the current version" + run: | + breeze setup self-upgrade --use-current-airflow-sources + if: inputs.build-sboms + working-directory: current-version + - name: "Make sure SBOM dir exists and has the right permissions" + run: | + sudo mkdir -vp ./files/sbom + sudo chown -R "${USER}" . + working-directory: current-version + if: inputs.build-sboms + - name: "Prepare SBOMs using current version of Breeze" + env: + AIRFLOW_VERSION: ${{ needs.build-info.outputs.airflow-version }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PYTHON_VERSION: "${{ needs.build-info.outputs.default-python-version }}" + FORCE: "true" + run: > + breeze sbom update-sbom-information + --airflow-version ${AIRFLOW_VERSION} --remote-name origin --force + --all-combinations --run-in-parallel --airflow-root-path "${GITHUB_WORKSPACE}" + working-directory: current-version + if: inputs.build-sboms + - name: "Generated SBOM files" + run: | + echo "Generated SBOM files:" + find ./generated/_build/docs/apache-airflow/stable/sbom/ -type f | sort + if: inputs.build-sboms + - name: "Reinstall breeze from ${{ inputs.ref }} reference" + run: + breeze setup self-upgrade --use-current-airflow-sources + if: inputs.build-sboms + - name: Check disk space available + run: df -H + # Here we will create temp airflow-site dir to publish docs + - name: Create /mnt/airflow-site directory + run: | + sudo mkdir -p /mnt/airflow-site && sudo chown -R "${USER}" /mnt/airflow-site + echo "AIRFLOW_SITE_DIRECTORY=/mnt/airflow-site/" >> "$GITHUB_ENV" + - name: "Publish docs to /mnt/airflow-site directory using ${{ inputs.ref }} reference breeze" + env: + INCLUDE_DOCS: ${{ needs.build-info.outputs.include-docs }} + run: > + breeze release-management publish-docs --override-versioned --run-in-parallel ${INCLUDE_DOCS} + - name: "Upload build docs" + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: airflow-docs + path: /mnt/airflow-site + retention-days: '7' + if-no-files-found: 'error' + overwrite: 'true' + + publish-docs-to-s3: + needs: [build-docs, build-info] + name: "Publish documentation to S3" + permissions: + id-token: write + contents: read + runs-on: ubuntu-latest + env: + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_USERNAME: ${{ github.actor }} + INCLUDE_SUCCESS_OUTPUTS: false + PYTHON_MAJOR_MINOR_VERSION: 3.10 + VERBOSE: "true" + steps: + - name: "Cleanup repo" + shell: bash + run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + # We are checking repo for both - breeze and docs from the "workflow' branch + # This will take longer as we need to rebuild CI image and it will not use cache + # but it will build the CI image from the version of Airflow that is used to check out things + - name: "Checkout ${{ inputs.ref }} " + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + - name: "Install Breeze" + uses: ./.github/actions/breeze + with: + use-uv: ${{ inputs.use-uv }} + - name: "Download docs prepared as artifacts" + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: airflow-docs + path: /mnt/airflow-site + - name: Check disk space available + run: df -H + - name: "Update watermarks" + env: + SOURCE_DIR_PATH: "/mnt/airflow-site/docs-archive/" + # yamllint disable rule:line-length + run: | + curl -sSf -o add_watermark.py https://raw.githubusercontent.com/apache/airflow-site/refs/heads/main/.github/scripts/add_watermark.py \ + --header "Authorization: Bearer ${{ github.token }} " --header "X-GitHub-Api-Version: 2022-11-28" + chmod a+x add_watermark.py + mkdir -p images + curl -sSf -o images/staging.png https://raw.githubusercontent.com/apache/airflow-site/refs/heads/main/.github/scripts/images/staging.png + uv run add_watermark.py --pattern 'main.min*css' --folder ${SOURCE_DIR_PATH} \ + --image-directory images --url-prefix /images + if: needs.build-info.outputs.destination == 'staging' + - name: Install AWS CLI v2 + run: | + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip + unzip -q /tmp/awscliv2.zip -d /tmp + rm /tmp/awscliv2.zip + sudo /tmp/aws/install --update + rm -rf /tmp/aws/ + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + with: + aws-access-key-id: ${{ secrets.DOCS_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.DOCS_AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-2 + - name: "Syncing docs to S3" + env: + DESTINATION_LOCATION: "${{ needs.build-info.outputs.destination-location }}" + SOURCE_DIR_PATH: "/mnt/airflow-site/docs-archive/" + EXCLUDE_DOCS: "${{ inputs.exclude-docs }}" + SKIP_WRITE_TO_STABLE_FOLDER: "${{ needs.build-info.outputs.skip-write-to-stable-folder }}" + run: | + breeze release-management publish-docs-to-s3 --source-dir-path ${SOURCE_DIR_PATH} \ + --destination-location ${DESTINATION_LOCATION} --stable-versions \ + --exclude-docs ${EXCLUDE_DOCS} --overwrite ${SKIP_WRITE_TO_STABLE_FOLDER} diff --git a/.github/workflows/push-image-cache.yml b/.github/workflows/push-image-cache.yml index cf8097cebd768..b523577b46c99 100644 --- a/.github/workflows/push-image-cache.yml +++ b/.github/workflows/push-image-cache.yml @@ -20,12 +20,8 @@ name: Push image cache on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-public: - description: "The array of labels (in json form) determining public runners." - required: true - type: string - runs-on-as-json-self-hosted: - description: "The array of labels (in json form) determining self-hosted runners." + runners: + description: "The array of labels (in json form) determining runners." required: true type: string cache-type: @@ -57,7 +53,7 @@ on: # yamllint disable-line rule:truthy required: true type: string branch: - description: "Branch used to run the CI jobs in (main/v2_*_test)." + description: "Branch used to run the CI jobs in (main/v*_*_test)." required: true type: string constraints-branch: @@ -83,11 +79,7 @@ on: # yamllint disable-line rule:truthy jobs: push-ci-image-cache: name: "Push CI ${{ inputs.cache-type }}:${{ matrix.python }} image cache " - # NOTE!!!!! This has to be put in one line for runs-on to recognize the "fromJSON" properly !!!! - # adding space before (with >) apparently turns the `runs-on` processed line into a string "Array" - # instead of an array of strings. - # yamllint disable-line rule:line-length - runs-on: ${{ (inputs.platform == 'linux/amd64') && fromJSON(inputs.runs-on-as-json-public) || fromJSON(inputs.runs-on-as-json-self-hosted) }} + runs-on: ${{ fromJSON(inputs.runners) }} permissions: contents: read packages: write @@ -116,17 +108,16 @@ jobs: PYTHON_MAJOR_MINOR_VERSION: "${{ matrix.python }}" UPGRADE_TO_NEWER_DEPENDENCIES: "false" VERBOSE: "true" - VERSION_SUFFIX_FOR_PYPI: "dev0" steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -159,11 +150,7 @@ jobs: push-prod-image-cache: name: "Push PROD ${{ inputs.cache-type }}:${{ matrix.python }} image cache" - # NOTE!!!!! This has to be put in one line for runs-on to recognize the "fromJSON" properly !!!! - # adding space before (with >) apparently turns the `runs-on` processed line into a string "Array" - # instead of an array of strings. - # yamllint disable-line rule:line-length - runs-on: ${{ (inputs.platform == 'linux/amd64') && fromJSON(inputs.runs-on-as-json-public) || fromJSON(inputs.runs-on-as-json-self-hosted) }} + runs-on: ${{ fromJSON(inputs.runners) }} permissions: contents: read packages: write @@ -191,18 +178,17 @@ jobs: PYTHON_MAJOR_MINOR_VERSION: "${{ matrix.python }}" UPGRADE_TO_NEWER_DEPENDENCIES: "false" VERBOSE: "true" - VERSION_SUFFIX_FOR_PYPI: "dev0" if: inputs.include-prod-images == 'true' steps: - name: "Cleanup repo" shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh - name: "Install Breeze" uses: ./.github/actions/breeze with: @@ -210,7 +196,7 @@ jobs: - name: "Cleanup dist and context file" run: rm -fv ./dist/* ./docker-context-files/* - name: "Download packages prepared as artifacts" - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: prod-packages path: ./docker-context-files diff --git a/.github/workflows/recheck-old-bug-report.yml b/.github/workflows/recheck-old-bug-report.yml index 217092b86f87e..c245f73923216 100644 --- a/.github/workflows/recheck-old-bug-report.yml +++ b/.github/workflows/recheck-old-bug-report.yml @@ -28,7 +28,7 @@ jobs: recheck-old-bug-report: runs-on: ["ubuntu-22.04"] steps: - - uses: actions/stale@v9 + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 with: only-issue-labels: 'kind:bug' stale-issue-label: 'Stale Bug Report' diff --git a/.github/workflows/release_dockerhub_image.yml b/.github/workflows/release_dockerhub_image.yml index 7f83b7274c6ac..2499e521d74a3 100644 --- a/.github/workflows/release_dockerhub_image.yml +++ b/.github/workflows/release_dockerhub_image.yml @@ -21,17 +21,16 @@ on: # yamllint disable-line rule:truthy workflow_dispatch: inputs: airflowVersion: - description: 'Airflow version' + description: 'Airflow version (e.g. 3.0.1, 3.0.1rc1, 3.0.1b1)' required: true - skipLatest: - description: 'Skip Latest: Set to true if not latest.' - default: '' - required: false - includePreRelease: - description: 'Include pre-release: Set to true to include pre-releases.' - default: '' + amdOnly: type: boolean - required: false + description: 'Limit to amd64 images' + default: false + limitPythonVersions: + type: string + description: 'Force python versions (e.g. "3.9 3.10")' + default: '' permissions: contents: read packages: read @@ -45,47 +44,20 @@ jobs: build-info: timeout-minutes: 10 name: "Build Info" - runs-on: ["ubuntu-22.04"] + runs-on: ["ubuntu-24.04"] outputs: - pythonVersions: ${{ steps.selective-checks.outputs.python-versions }} - allPythonVersions: ${{ steps.selective-checks.outputs.all-python-versions }} - defaultPythonVersion: ${{ steps.selective-checks.outputs.default-python-version }} - chicken-egg-providers: ${{ steps.selective-checks.outputs.chicken-egg-providers }} - skipLatest: ${{ github.event.inputs.skipLatest == '' && ' ' || '--skip-latest' }} - includePreRelease: ${{ github.event.inputs.includePreRelease == '' && ' ' || '--include-pre-release' }} - limitPlatform: ${{ github.repository == 'apache/airflow' && ' ' || '--limit-platform linux/amd64' }} + pythonVersions: ${{ steps.determine-python-versions.outputs.python-versions }} + platformMatrix: ${{ steps.determine-matrix.outputs.platformMatrix }} + airflowVersion: ${{ steps.check-airflow-version.outputs.airflowVersion }} + skipLatest: ${{ steps.check-airflow-version.outputs.skip-latest }} + amd-runners: ${{ steps.selective-checks.outputs.amd-runners }} + arm-runners: ${{ steps.selective-checks.outputs.arm-runners }} env: GITHUB_CONTEXT: ${{ toJson(github) }} VERBOSE: true - steps: - - name: "Cleanup repo" - shell: bash - run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 - with: - persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh - - name: "Install Breeze" - uses: ./.github/actions/breeze - with: - use-uv: "false" - - name: Selective checks - id: selective-checks - env: - VERBOSE: "false" - run: breeze ci selective-check 2>> ${GITHUB_OUTPUT} - - release-images: - timeout-minutes: 120 - name: "Release images: ${{ github.event.inputs.airflowVersion }}, ${{ matrix.python-version }}" - runs-on: ["ubuntu-22.04"] - needs: [build-info] - strategy: - fail-fast: false - matrix: - python-version: ${{ fromJSON(needs.build-info.outputs.pythonVersions) }} + AIRFLOW_VERSION: ${{ github.event.inputs.airflowVersion }} + AMD_ONLY: ${{ github.event.inputs.amdOnly }} + LIMIT_PYTHON_VERSIONS: ${{ github.event.inputs.limitPythonVersions }} if: contains(fromJSON('[ "ashb", "eladkal", @@ -97,132 +69,82 @@ jobs: "utkarsharma2" ]'), github.event.sender.login) steps: + - name: "Input parameters summary" + shell: bash + run: | + echo "Input parameters summary" + echo "=========================" + echo "Airflow version: '${AIRFLOW_VERSION}'" + echo "AMD only: '${AMD_ONLY}'" + echo "Limit python versions: '${LIMIT_PYTHON_VERSIONS}'" - name: "Cleanup repo" shell: bash - run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + run: > + docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - - name: "Cleanup docker" - run: ./scripts/ci/cleanup_docker.sh + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + - name: "Install uv" + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: "Check airflow version" + id: check-airflow-version + shell: bash + run: uv run scripts/ci/airflow_version_check.py "${AIRFLOW_VERSION}" >> "${GITHUB_OUTPUT}" - name: "Install Breeze" uses: ./.github/actions/breeze with: - use-uv: "false" - - name: Free space - run: breeze ci free-space --answer yes - - name: "Cleanup dist and context file" - run: rm -fv ./dist/* ./docker-context-files/* - - name: "Login to hub.docker.com" - run: > - echo ${{ secrets.DOCKERHUB_TOKEN }} | - docker login --password-stdin --username ${{ secrets.DOCKERHUB_USER }} - - name: Login to ghcr.io + use-uv: "true" + - name: Selective checks + id: selective-checks env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ACTOR: ${{ github.actor }} - run: echo "${GITHUB_TOKEN}" | docker login ghcr.io -u ${ACTOR} --password-stdin - - name: "Install buildx plugin" - # yamllint disable rule:line-length - run: | - sudo apt-get update - sudo apt-get install ca-certificates curl - sudo install -m 0755 -d /etc/apt/keyrings - sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc - sudo chmod a+r /etc/apt/keyrings/docker.asc - - # Add the repository to Apt sources: - echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ - sudo tee /etc/apt/sources.list.d/docker.list > /dev/null - sudo apt-get update - sudo apt install docker-buildx-plugin - - name: "Install regctl" - # yamllint disable rule:line-length - run: | - mkdir -p ~/bin - curl -L https://github.com/regclient/regclient/releases/latest/download/regctl-linux-amd64 >${HOME}/bin/regctl - chmod 755 ${HOME}/bin/regctl - echo "${HOME}/bin" >>${GITHUB_PATH} - - name: "Install emulation support" - run: docker run --privileged --rm tonistiigi/binfmt --install all - - name: "Create airflow_cache builder" - run: docker buildx create --name airflow_cache - - name: "Prepare chicken-eggs provider distributions" - # In case of provider distributions which use latest dev0 version of providers, we should prepare them - # from the source code, not from the PyPI because they have apache-airflow>=X.Y.Z dependency - # And when we prepare them from sources they will have apache-airflow>=X.Y.Z.dev0 + VERBOSE: "false" + run: breeze ci selective-check 2>> ${GITHUB_OUTPUT} + - name: "Determine build matrix" shell: bash - env: - CHICKEN_EGG_PROVIDERS: ${{ needs.build-info.outputs.chicken-egg-providers }} - run: > - breeze release-management prepare-provider-distributions - --distribution-format wheel - --version-suffix-for-pypi dev0 ${CHICKEN_EGG_PROVIDERS} - if: needs.build-info.outputs.chicken-egg-providers != '' - - name: "Copy dist packages to docker-context files" + id: determine-matrix + run: | + if [[ "${AMD_ONLY}" = "true" ]]; then + echo 'platformMatrix=["linux/amd64"]' >> "${GITHUB_OUTPUT}" + else + echo 'platformMatrix=["linux/amd64", "linux/arm64"]' >> "${GITHUB_OUTPUT}" + fi + - name: "Determine python versions" shell: bash - run: cp -v --no-preserve=mode,ownership ./dist/*.whl ./docker-context-files - if: needs.build-info.outputs.chicken-egg-providers != '' - - name: > - Release regular images: ${{ github.event.inputs.airflowVersion }}, ${{ matrix.python-version }} - env: - COMMIT_SHA: ${{ github.sha }} - REPOSITORY: ${{ github.repository }} - PYTHON_VERSION: ${{ matrix.python-version }} - AIRFLOW_VERSION: ${{ github.event.inputs.airflowVersion }} - SKIP_LATEST: ${{ needs.build-info.outputs.skipLatest }} - LIMIT_PLATFORM: ${{ needs.build-info.outputs.limitPlatform }} - CHICKEN_EGG_PROVIDERS: ${{ needs.build-info.outputs.chicken-egg-providers }} - run: > - breeze release-management release-prod-images - --dockerhub-repo "${REPOSITORY}" - --airflow-version "${AIRFLOW_VERSION}" - ${SKIP_LATEST} - ${LIMIT_PLATFORM} - --limit-python ${PYTHON_VERSION} - --chicken-egg-providers "${CHICKEN_EGG_PROVIDERS}" - - name: > - Release slim images: ${{ github.event.inputs.airflowVersion }}, ${{ matrix.python-version }} + id: determine-python-versions env: - COMMIT_SHA: ${{ github.sha }} - REPOSITORY: ${{ github.repository }} - PYTHON_VERSION: ${{ matrix.python-version }} - AIRFLOW_VERSION: ${{ github.event.inputs.airflowVersion }} - SKIP_LATEST: ${{ needs.build-info.outputs.skipLatest }} - LIMIT_PLATFORM: ${{ needs.build-info.outputs.limitPlatform }} - run: > - breeze release-management release-prod-images - --dockerhub-repo "${REPOSITORY}" - --airflow-version "${AIRFLOW_VERSION}" - ${SKIP_LATEST} - ${LIMIT_PLATFORM} - --limit-python ${PYTHON_VERSION} --slim-images - - name: > - Verify regular AMD64 image: ${{ github.event.inputs.airflowVersion }}, ${{ matrix.python-version }} - env: - PYTHON_VERSION: ${{ matrix.python-version }} - AIRFLOW_VERSION: ${{ github.event.inputs.airflowVersion }} - REPOSITORY: ${{ github.repository }} - run: > - breeze prod-image verify - --pull - --image-name - ${REPOSITORY}:${AIRFLOW_VERSION}-python${PYTHON_VERSION} - - name: > - Verify slim AMD64 image: ${{ github.event.inputs.airflowVersion }}, ${{ matrix.python-version }} - env: - PYTHON_VERSION: ${{ matrix.python-version }} - AIRFLOW_VERSION: ${{ github.event.inputs.airflowVersion }} - REPOSITORY: ${{ github.repository }} - run: > - breeze prod-image verify - --pull - --slim-image - --image-name - ${REPOSITORY}:slim-${AIRFLOW_VERSION}-python${PYTHON_VERSION} - - name: "Docker logout" - run: docker logout - if: always() + ALL_PYTHON_VERSIONS: ${{ steps.selective-checks.outputs.all-python-versions }} + # yamllint disable rule:line-length + run: | + # override python versions if specified + if [[ "${LIMIT_PYTHON_VERSIONS}" != "" ]]; then + PYTHON_VERSIONS=$(python3 -c "import json; print(json.dumps('${LIMIT_PYTHON_VERSIONS}'.split(' ')))") + else + PYTHON_VERSIONS=${ALL_PYTHON_VERSIONS} + fi + echo "python-versions=${PYTHON_VERSIONS}" >> "${GITHUB_OUTPUT}" + + + release-images: + name: "Release images" + needs: [build-info] + strategy: + fail-fast: false + matrix: + python: ${{ fromJSON(needs.build-info.outputs.pythonVersions) }} + uses: ./.github/workflows/release_single_dockerhub_image.yml + secrets: + DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + permissions: + contents: read + with: + pythonVersion: ${{ matrix.python }} + airflowVersion: ${{ needs.build-info.outputs.airflowVersion }} + platformMatrix: ${{ needs.build-info.outputs.platformMatrix }} + skipLatest: ${{ needs.build-info.outputs.skipLatest }} + armRunners: ${{ needs.build-info.outputs.arm-runners }} + amdRunners: ${{ needs.build-info.outputs.amd-runners }} diff --git a/.github/workflows/release_single_dockerhub_image.yml b/.github/workflows/release_single_dockerhub_image.yml new file mode 100644 index 0000000000000..fd572adbabab1 --- /dev/null +++ b/.github/workflows/release_single_dockerhub_image.yml @@ -0,0 +1,242 @@ +# 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: "Release single PROD image" +on: # yamllint disable-line rule:truthy + workflow_call: + inputs: + airflowVersion: + description: 'Airflow version (e.g. 3.0.1, 3.0.1rc1, 3.0.1b1)' + type: string + required: true + platformMatrix: + description: 'Platform matrix formatted as json (e.g. ["linux/amd64", "linux/arm64"])' + type: string + required: true + pythonVersion: + description: 'Python version (e.g. 3.8, 3.9, 3.10, 3.11)' + type: string + required: true + skipLatest: + description: "Skip tagging latest release (true/false)" + type: string + required: true + amdRunners: + description: "Amd64 runners (e.g. [\"ubuntu-22.04\", \"ubuntu-24.04\"])" + type: string + required: true + armRunners: + description: "Arm64 runners (e.g. [\"ubuntu-22.04\", \"ubuntu-24.04\"])" + type: string + required: true + secrets: + DOCKERHUB_USER: + required: true + DOCKERHUB_TOKEN: + required: true +permissions: + contents: read +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERBOSE: true +jobs: + build-images: + timeout-minutes: 50 + # yamllint disable rule:line-length + name: "Build: ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}, ${{ matrix.platform }}" + runs-on: ${{ (matrix.platform == 'linux/amd64') && fromJSON(inputs.amdRunners) || fromJSON(inputs.armRunners) }} + strategy: + fail-fast: false + matrix: + platform: ${{ fromJSON(inputs.platformMatrix) }} + env: + AIRFLOW_VERSION: ${{ inputs.airflowVersion }} + PYTHON_MAJOR_MINOR_VERSION: ${{ inputs.pythonVersion }} + PLATFORM: ${{ matrix.platform }} + SKIP_LATEST: ${{ inputs.skipLatest == 'true' && '--skip-latest' || '' }} + COMMIT_SHA: ${{ github.sha }} + REPOSITORY: ${{ github.repository }} + steps: + - name: "Cleanup repo" + shell: bash + run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + - name: "Install Breeze" + uses: ./.github/actions/breeze + with: + use-uv: "false" + - name: Free space + run: breeze ci free-space --answer yes + - name: "Cleanup dist and context file" + run: rm -fv ./dist/* ./docker-context-files/* + - name: "Login to hub.docker.com" + run: > + echo ${{ secrets.DOCKERHUB_TOKEN }} | + docker login --password-stdin --username ${{ secrets.DOCKERHUB_USER }} + - name: "Get env vars for metadata" + shell: bash + run: | + echo "ARTIFACT_NAME=metadata-${PYTHON_MAJOR_MINOR_VERSION}-${PLATFORM/\//_}" >> "${GITHUB_ENV}" + echo "MANIFEST_FILE_NAME=metadata-${AIRFLOW_VERSION}-${PLATFORM/\//_}-${PYTHON_MAJOR_MINOR_VERSION}.json" >> "${GITHUB_ENV}" + echo "MANIFEST_SLIM_FILE_NAME=metadata-${AIRFLOW_VERSION}-slim-${PLATFORM/\//_}-${PYTHON_MAJOR_MINOR_VERSION}.json" >> "${GITHUB_ENV}" + - name: Login to ghcr.io + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ACTOR: ${{ github.actor }} + run: echo "${GITHUB_TOKEN}" | docker login ghcr.io -u ${ACTOR} --password-stdin + - name: "Install buildx plugin" + # yamllint disable rule:line-length + run: | + sudo apt-get update + sudo apt-get install ca-certificates curl + sudo install -m 0755 -d /etc/apt/keyrings + sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + sudo chmod a+r /etc/apt/keyrings/docker.asc + + # Add the repository to Apt sources: + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + sudo apt-get update + sudo apt install docker-buildx-plugin + - name: "Create airflow_cache builder" + run: docker buildx create --name airflow_cache --driver docker-container + - name: > + Build regular images: ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}, ${{ matrix.platform }} + run: > + breeze release-management release-prod-images --dockerhub-repo "${REPOSITORY}" + --airflow-version "${AIRFLOW_VERSION}" ${SKIP_LATEST} + --python ${PYTHON_MAJOR_MINOR_VERSION} + --metadata-folder dist + - name: > + Verify regular image: ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}, ${{ matrix.platform }} + run: > + breeze prod-image verify --pull --manifest-file dist/${MANIFEST_FILE_NAME} + - name: > + Release slim images: ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}, ${{ matrix.platform }} + run: > + breeze release-management release-prod-images --dockerhub-repo "${REPOSITORY}" + --airflow-version "${AIRFLOW_VERSION}" ${SKIP_LATEST} + --python ${PYTHON_MAJOR_MINOR_VERSION} --slim-images + --metadata-folder dist + - name: > + Verify slim image: ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}, ${{ matrix.platform }} + run: > + breeze prod-image verify --pull --slim-image --manifest-file dist/${MANIFEST_SLIM_FILE_NAME} + - name: "List upload-able artifacts" + shell: bash + run: find ./dist -name '*.json' + - name: "Upload metadata artifact ${{ env.ARTIFACT_NAME }}" + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: ${{ env.ARTIFACT_NAME }} + path: ./dist/metadata-* + retention-days: 7 + if-no-files-found: error + - name: "Docker logout" + run: docker logout + if: always() + + merge-images: + timeout-minutes: 5 + name: "Merge: ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}" + runs-on: ["ubuntu-22.04"] + needs: [build-images] + env: + AIRFLOW_VERSION: ${{ inputs.airflowVersion }} + PYTHON_MAJOR_MINOR_VERSION: ${{ inputs.pythonVersion }} + SKIP_LATEST: ${{ inputs.skipLatest == 'true' && '--skip-latest' || '' }} + COMMIT_SHA: ${{ github.sha }} + REPOSITORY: ${{ github.repository }} + steps: + - name: "Cleanup repo" + shell: bash + run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" + - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: "Prepare and cleanup runner" + run: ./scripts/ci/prepare_and_cleanup_runner.sh + - name: "Install Breeze" + uses: ./.github/actions/breeze + with: + use-uv: "false" + - name: Free space + run: breeze ci free-space --answer yes + - name: "Cleanup dist and context file" + run: rm -fv ./dist/* ./docker-context-files/* + - name: "Login to hub.docker.com" + run: > + echo ${{ secrets.DOCKERHUB_TOKEN }} | + docker login --password-stdin --username ${{ secrets.DOCKERHUB_USER }} + - name: Login to ghcr.io + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ACTOR: ${{ github.actor }} + run: echo "${GITHUB_TOKEN}" | docker login ghcr.io -u ${ACTOR} --password-stdin + - name: "Download metadata artifacts" + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + path: ./dist + pattern: metadata-${{ inputs.pythonVersion }}-* + - name: "List downloaded artifacts" + shell: bash + run: find ./dist -name '*.json' + - name: "Install buildx plugin" + # yamllint disable rule:line-length + run: | + sudo apt-get update + sudo apt-get install ca-certificates curl + sudo install -m 0755 -d /etc/apt/keyrings + sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + sudo chmod a+r /etc/apt/keyrings/docker.asc + + # Add the repository to Apt sources: + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + sudo apt-get update + sudo apt install docker-buildx-plugin + - name: "Install regctl" + # yamllint disable rule:line-length + run: | + mkdir -p ~/bin + curl -L https://github.com/regclient/regclient/releases/latest/download/regctl-linux-amd64 >${HOME}/bin/regctl + chmod 755 ${HOME}/bin/regctl + echo "${HOME}/bin" >>${GITHUB_PATH} + - name: "Merge regular images ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}" + run: > + breeze release-management merge-prod-images --dockerhub-repo "${REPOSITORY}" + --airflow-version "${AIRFLOW_VERSION}" ${SKIP_LATEST} + --python ${PYTHON_MAJOR_MINOR_VERSION} --metadata-folder dist + - name: "Merge slim images ${{ inputs.airflowVersion }}, ${{ inputs.pythonVersion }}" + run: > + breeze release-management merge-prod-images --dockerhub-repo "${REPOSITORY}" + --airflow-version "${AIRFLOW_VERSION}" ${SKIP_LATEST} + --python ${PYTHON_MAJOR_MINOR_VERSION} --metadata-folder dist --slim-images + - name: "Docker logout" + run: docker logout + if: always() diff --git a/.github/workflows/run-unit-tests.yml b/.github/workflows/run-unit-tests.yml index 939fa2b634179..035248113dac1 100644 --- a/.github/workflows/run-unit-tests.yml +++ b/.github/workflows/run-unit-tests.yml @@ -20,8 +20,12 @@ name: Unit tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." + runners: + description: "The array of labels (in json form) determining public AMD runners." + required: true + type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string test-group: @@ -37,7 +41,7 @@ on: # yamllint disable-line rule:truthy required: true type: string test-scope: - description: "The scope of the test to run: ('DB', 'Non-DB', 'All', 'ARM collection')" + description: "The scope of the test to run: ('DB', 'Non-DB', 'All')" required: true type: string test-name: @@ -120,12 +124,12 @@ permissions: contents: read jobs: tests: - timeout-minutes: 120 + timeout-minutes: 65 name: "\ ${{ inputs.test-scope }}-${{ inputs.test-group }}:\ ${{ inputs.test-name }}${{ inputs.test-name-separator }}${{ matrix.backend-version }}:\ ${{ matrix.python-version}}:${{ matrix.test-types.description }}" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: fail-fast: false matrix: @@ -147,6 +151,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_USERNAME: ${{ github.actor }} INCLUDE_SUCCESS_OUTPUTS: ${{ inputs.include-success-outputs }} + PLATFORM: "${{ inputs.platform }}" # yamllint disable rule:line-length JOB_ID: "${{ inputs.test-group }}-${{ matrix.test-types.description }}-${{ inputs.test-scope }}-${{ inputs.test-name }}-${{inputs.backend}}-${{ matrix.backend-version }}-${{ matrix.python-version }}" MOUNT_SOURCES: "skip" @@ -162,13 +167,13 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ matrix.python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" + platform: ${{ inputs.platform }} python: ${{ matrix.python-version }} use-uv: ${{ inputs.use-uv }} - name: > diff --git a/.github/workflows/special-tests.yml b/.github/workflows/special-tests.yml index d47907f923f54..a41ab1693c830 100644 --- a/.github/workflows/special-tests.yml +++ b/.github/workflows/special-tests.yml @@ -20,8 +20,12 @@ name: Special tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." + runners: + description: "The array of labels (in json form) determining runners." + required: true + type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string default-branch: @@ -90,7 +94,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} downgrade-sqlalchemy: "true" test-name: "MinSQLAlchemy-Postgres" test-scope: "DB" @@ -113,7 +118,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} downgrade-sqlalchemy: "true" test-name: "MinSQLAlchemy-Postgres" test-scope: "DB" @@ -136,7 +142,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} upgrade-boto: "true" test-name: "LatestBoto-Postgres" test-scope: "All" @@ -160,7 +167,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} upgrade-boto: "true" test-name: "LatestBoto-Postgres" test-scope: "All" @@ -185,7 +193,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} downgrade-pendulum: "true" test-name: "Pendulum2-Postgres" test-scope: "All" @@ -209,7 +218,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} downgrade-pendulum: "true" test-name: "Pendulum2-Postgres" test-scope: "All" @@ -233,7 +243,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} test-name: "Postgres" test-scope: "Quarantined" test-group: "core" @@ -256,7 +267,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} test-name: "Postgres" test-scope: "Quarantined" test-group: "providers" @@ -272,56 +284,6 @@ jobs: skip-providers-tests: ${{ inputs.skip-providers-tests }} use-uv: ${{ inputs.use-uv }} - - tests-arm-collection-core: - name: "ARM Collection test: core" - uses: ./.github/workflows/run-unit-tests.yml - permissions: - contents: read - packages: read - with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} - test-name: "Postgres" - test-scope: "ARM collection" - test-group: "core" - backend: "postgres" - python-versions: "['${{ inputs.default-python-version }}']" - backend-versions: "['${{ inputs.default-postgres-version }}']" - excluded-providers-as-string: ${{ inputs.excluded-providers-as-string }} - excludes: "[]" - test-types-as-strings-in-json: ${{ inputs.core-test-types-list-as-strings-in-json }} - include-success-outputs: ${{ inputs.include-success-outputs }} - run-coverage: ${{ inputs.run-coverage }} - debug-resources: ${{ inputs.debug-resources }} - skip-providers-tests: ${{ inputs.skip-providers-tests }} - use-uv: ${{ inputs.use-uv }} - if: ${{ inputs.default-branch == 'main' }} - - tests-arm-collection-providers: - name: "ARM Collection test: providers" - uses: ./.github/workflows/run-unit-tests.yml - permissions: - contents: read - packages: read - with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} - test-name: "Postgres" - test-scope: "ARM collection" - test-group: "providers" - backend: "postgres" - python-versions: "['${{ inputs.default-python-version }}']" - backend-versions: "['${{ inputs.default-postgres-version }}']" - excluded-providers-as-string: ${{ inputs.excluded-providers-as-string }} - excludes: "[]" - test-types-as-strings-in-json: ${{ inputs.core-test-types-list-as-strings-in-json }} - include-success-outputs: ${{ inputs.include-success-outputs }} - run-coverage: ${{ inputs.run-coverage }} - debug-resources: ${{ inputs.debug-resources }} - skip-providers-tests: ${{ inputs.skip-providers-tests }} - use-uv: ${{ inputs.use-uv }} - if: ${{ inputs.default-branch == 'main' }} - - tests-system-core: name: "System test: ${{ matrix.test-group }}" uses: ./.github/workflows/run-unit-tests.yml @@ -329,7 +291,8 @@ jobs: contents: read packages: read with: - runs-on-as-json-default: ${{ inputs.runs-on-as-json-default }} + runners: ${{ inputs.runners }} + platform: ${{ inputs.platform }} test-name: "SystemTest" test-scope: "System" test-group: "core" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 2e03e9f33b120..5724a17314aec 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -29,7 +29,7 @@ jobs: stale: runs-on: ["ubuntu-22.04"] steps: - - uses: actions/stale@v9 + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 with: stale-pr-message: > This pull request has been automatically marked as stale because it has not had diff --git a/.github/workflows/test-providers.yml b/.github/workflows/test-providers.yml index 39f96b2c89afc..51a0876e5717d 100644 --- a/.github/workflows/test-providers.yml +++ b/.github/workflows/test-providers.yml @@ -20,8 +20,12 @@ name: Provider tests on: # yamllint disable-line rule:truthy workflow_call: inputs: - runs-on-as-json-default: - description: "The array of labels (in json form) determining default runner used for the build." + runners: + description: "The array of labels (in json form) determining public AMD runners." + required: true + type: string + platform: + description: "Platform for the build - 'linux/amd64' or 'linux/arm64'" required: true type: string canary-run: @@ -68,7 +72,7 @@ jobs: prepare-install-verify-provider-distributions: timeout-minutes: 80 name: "Providers ${{ matrix.package-format }} tests" - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: fail-fast: false matrix: @@ -85,14 +89,14 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" - python: ${{ inputs.default-python-version }} + platform: ${{ inputs.platform }} + python: "${{ inputs.default-python-version }}" use-uv: ${{ inputs.use-uv }} - name: "Cleanup dist files" run: rm -fv ./dist/* @@ -104,14 +108,14 @@ jobs: - name: "Prepare provider distributions: ${{ matrix.package-format }}" run: > breeze release-management prepare-provider-distributions --include-not-ready-providers - --version-suffix-for-pypi dev0 --distribution-format ${{ matrix.package-format }} + --skip-tag-check --distribution-format ${{ matrix.package-format }} - name: "Prepare airflow package: ${{ matrix.package-format }}" run: > - breeze release-management prepare-airflow-distributions --version-suffix-for-pypi dev0 + breeze release-management prepare-airflow-distributions --distribution-format ${{ matrix.package-format }} - name: "Prepare task-sdk package: ${{ matrix.package-format }}" run: > - breeze release-management prepare-task-sdk-distributions --version-suffix-for-pypi dev0 + breeze release-management prepare-task-sdk-distributions --distribution-format ${{ matrix.package-format }} - name: "Verify ${{ matrix.package-format }} packages with twine" run: | @@ -134,7 +138,8 @@ jobs: - name: "Install and verify wheel provider distributions" env: DISTRIBUTION_FORMAT: ${{ matrix.package-format }} - AIRFLOW_SKIP_CONSTRAINTS: "${{ inputs.upgrade-to-newer-dependencies }}" + # yamllint disable rule:line-length + INSTALL_AIRFLOW_WITH_CONSTRAINTS: "${{ inputs.upgrade-to-newer-dependencies == 'true' && 'false' || 'true' }}" run: > breeze release-management verify-provider-distributions --use-distributions-from-dist @@ -163,7 +168,7 @@ jobs: timeout-minutes: 80 # yamllint disable rule:line-length name: Compat ${{ matrix.compat.airflow-version }}:P${{ matrix.compat.python-version }}:${{ matrix.compat.test-types.description }} - runs-on: ${{ fromJSON(inputs.runs-on-as-json-default) }} + runs-on: ${{ fromJSON(inputs.runners) }} strategy: fail-fast: false matrix: @@ -175,7 +180,6 @@ jobs: GITHUB_USERNAME: ${{ github.actor }} INCLUDE_NOT_READY_PROVIDERS: "true" PYTHON_MAJOR_MINOR_VERSION: "${{ matrix.compat.python-version }}" - VERSION_SUFFIX_FOR_PYPI: "dev0" VERBOSE: "true" CLEAN_AIRFLOW_INSTALLATION: "true" if: inputs.skip-providers-tests != 'true' @@ -184,13 +188,13 @@ jobs: shell: bash run: docker run -v "${GITHUB_WORKSPACE}:/workspace" -u 0:0 bash -c "rm -rf /workspace/*" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: "Prepare breeze & CI image: ${{ matrix.compat.python-version }}" uses: ./.github/actions/prepare_breeze_and_image with: - platform: "linux/amd64" + platform: ${{ inputs.platform }} python: ${{ matrix.compat.python-version }} use-uv: ${{ inputs.use-uv }} - name: "Cleanup dist files" @@ -198,7 +202,7 @@ jobs: - name: "Prepare provider distributions: wheel" run: > breeze release-management prepare-provider-distributions --include-not-ready-providers - --distribution-format wheel + --distribution-format wheel --skip-tag-check # yamllint disable rule:line-length - name: Remove incompatible Airflow ${{ matrix.compat.airflow-version }}:Python ${{ matrix.compat.python-version }} provider distributions env: diff --git a/.gitignore b/.gitignore index 1b0a579167847..026a52c50a6cf 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ airflow/git_version airflow/ui/coverage/ logs/ airflow-webserver.pid +airflow-api-server.pid standalone_admin_password.txt warnings.txt warn-summary-*.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 503814fbf5c77..3dc226a64dfdd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,8 @@ default_stages: [pre-commit, pre-push] default_language_version: python: python3 - node: 22.14.0 + node: 22.17.0 + golang: 1.24.0 minimum_pre_commit_version: '3.2.0' exclude: ^.*/.*_vendor/ repos: @@ -35,7 +36,15 @@ repos: - id: doctoc name: Add TOC for Markdown and RST files files: - ^README\.md$|^UPDATING.*\.md$|^chart/UPDATING.*\.md$|^dev/.*\.md$|^dev/.*\.rst$|^\.github/.*\.md|^airflow-core/tests/system/README\.md$ + (?x) + ^README\.md$| + ^UPDATING.*\.md$| + ^chart/UPDATING.*\.md$| + ^dev/.*\.md$| + ^dev/.*\.rst$| + ^docs/README\.md$| + ^\.github/.*\.md$| + ^airflow-core/tests/system/README\.md$ args: - "--maxlevel" - "2" @@ -96,7 +105,7 @@ repos: - --fuzzy-match-generates-todo - id: insert-license name: Add license for all Python files - exclude: ^\.github/.*$|^.*/_vendor/.*$ + exclude: ^\.github/.*$|^.*/_vendor/.*$|^airflow-ctl/.*/.*generated\.py$ files: \.py$|\.pyi$ args: - --comment-style @@ -125,7 +134,14 @@ repos: - --fuzzy-match-generates-todo - id: insert-license name: Add license for all YAML files except Helm templates - exclude: ^\.github/.*$|^chart/templates/.*|.*reproducible_build\.yaml$|^.*/v1.*\.yaml$|^.*/openapi/_private_ui.*\.yaml$|^.*/pnpm-lock\.yaml$ + exclude: > + (?x) + ^\.github/.*$|^chart/templates/.*| + .*reproducible_build\.yaml$| + ^.*/v2.*\.yaml$| + ^.*/openapi/_private_ui.*\.yaml$| + ^.*/pnpm-lock\.yaml$| + .*-generated\.yaml$ types: [yaml] files: \.ya?ml$ args: @@ -210,7 +226,9 @@ repos: language: python entry: ./scripts/ci/pre_commit/check_deferrable_default.py pass_filenames: false - additional_dependencies: ['libcst>=1.1.0'] + # libcst doesn't have source wheels for all PY except PY3.12, excluding it + # libcst 1.8.1 doesn't include typing-extensions which is needed for Python 3.9 + additional_dependencies: ['libcst>=1.1.0,!=1.8.0,!=1.8.1'] files: ^(providers/.*/)?airflow/.*/(sensors|operators)/.*\.py$ - repo: https://github.com/asottile/blacken-docs rev: 1.19.1 @@ -239,16 +257,29 @@ repos: exclude: ^providers/ssh/docs/connections/ssh\.rst$ - id: end-of-file-fixer name: Make sure that there is an empty line at the end - exclude: ^airflow-core/docs/img/.*\.dot|^airflow-core/docs/img/.*\.sha256|.*/dist/.*|LICENSES-ui\.txt$ + exclude: > + (?x) + ^airflow-core/docs/img/.*\.dot| + ^airflow-core/docs/img/.*\.sha256| + .*/dist/.*| + LICENSES-ui\.txt$| + .*/openapi-gen/.* - id: mixed-line-ending name: Detect if mixed line ending is used (\r vs. \r\n) - id: check-executables-have-shebangs name: Check that executables have shebang - id: check-xml name: Check XML files with xmllint + exclude: > + (?x) + ^scripts/ci/docker-compose/gremlin/. - id: trailing-whitespace name: Remove trailing whitespace at end of line - exclude: ^airflow-core/docs/img/.*\.dot$|^dev/breeze/doc/images/output.*$ + exclude: > + (?x) + ^airflow-core/docs/img/.*\.dot$| + ^dev/breeze/doc/images/output.*$| + ^.*/openapi-gen/.*$ - id: fix-encoding-pragma name: Remove encoding header from Python files args: @@ -270,7 +301,7 @@ repos: - id: python-no-log-warn name: Check if there are no deprecate log warn - repo: https://github.com/adrienverge/yamllint - rev: v1.36.2 + rev: v1.37.1 hooks: - id: yamllint name: Check YAML files with yamllint @@ -281,6 +312,7 @@ repos: ^.*airflow\.template\.yaml$| ^.*init_git_sync\.template\.yaml$| ^chart/(?:templates|files)/.*\.yaml$| + ^helm-tests/tests/chart_utils/keda.sh_scaledobjects\.yaml$| .*/v1.*\.yaml$| ^.*openapi.*\.yaml$| ^\.pre-commit-config\.yaml$| @@ -308,13 +340,23 @@ repos: The word(s) should be in lowercase." && exec codespell "$@"' -- language: python types: [text] - exclude: material-icons\.css$|^images/.*$|^RELEASE_NOTES\.txt$|^.*package-lock\.json$|^.*/kinglear\.txt$|^.*pnpm-lock\.yaml$|.*/dist/.* + exclude: > + (?x) + material-icons\.css$| + ^images/.*$| + ^RELEASE_NOTES\.txt$| + ^.*package-lock\.json$| + ^.*/kinglear\.txt$| + ^.*pnpm-lock\.yaml$| + .*/dist/.*| + ^airflow-core/src/airflow/ui/src/i18n/locales/de/| + ^airflow-core/src/airflow/ui/src/i18n/locales/pl/ args: - --ignore-words=docs/spelling_wordlist.txt - - --skip=providers/.*/src/airflow/providers/*/*.rst,providers/*/docs/changelog.rst,docs/*/commits.rst,providers/*/docs/commits.rst,providers/*/*/docs/commits.rst,docs/apache-airflow/tutorial/pipeline_example.csv,*.min.js,*.lock,INTHEWILD.md + - --skip=providers/.*/src/airflow/providers/*/*.rst,providers/*/docs/changelog.rst,docs/*/commits.rst,providers/*/docs/commits.rst,providers/*/*/docs/commits.rst,docs/apache-airflow/tutorial/pipeline_example.csv,*.min.js,*.lock,INTHEWILD.md,*.svg - --exclude-file=.codespellignorelines - repo: https://github.com/woodruffw/zizmor-pre-commit - rev: v1.5.1 + rev: v1.7.0 hooks: - id: zizmor name: Run zizmor to check for github workflow syntax errors @@ -370,7 +412,7 @@ repos: types_or: [python, pyi] args: [--fix] require_serial: true - additional_dependencies: ['ruff==0.11.2'] + additional_dependencies: ['ruff==0.11.13'] exclude: ^airflow-core/tests/unit/dags/test_imports\.py$|^performance/tests/test_.*\.py$ - id: ruff-format name: Run 'ruff format' @@ -380,14 +422,14 @@ repos: types_or: [python, pyi] args: [] require_serial: true - additional_dependencies: ['ruff==0.11.2'] + additional_dependencies: ['ruff==0.11.13'] exclude: ^airflow-core/tests/unit/dags/test_imports\.py$ - id: replace-bad-characters name: Replace bad characters entry: ./scripts/ci/pre_commit/replace_bad_characters.py language: python types: [file, text] - exclude: ^clients/gen/go\.sh$|^\.gitmodules$|.*/dist/.* + exclude: ^clients/gen/go\.sh$|^\.gitmodules$|.*/dist/.*|\.go$|/go\.(mod|sum)$ additional_dependencies: ['rich>=12.4.4'] - id: lint-dockerfile name: Lint Dockerfile @@ -422,7 +464,7 @@ repos: - id: check-airflow-providers-bug-report-template name: Sort airflow-bug-report provider list language: python - files: ^\.github/ISSUE_TEMPLATE/airflow_providers_bug_report\.yml$ + files: ^\.github/ISSUE_TEMPLATE/3-airflow_providers_bug_report\.yml$ require_serial: true entry: ./scripts/ci/pre_commit/check_airflow_bug_report_template.py additional_dependencies: ['rich>=12.4.4', 'pyyaml>=6.0.2'] @@ -476,7 +518,10 @@ repos: name: Generate airflow diagrams entry: ./scripts/ci/pre_commit/generate_airflow_diagrams.py language: python - files: ^airflow-core/docs/.*/diagram_[^/]*\.py$ + files: > + (?x) + ^airflow-core/docs/.*/diagram_[^/]*\.py$| + ^docs/images/.*\.py$ pass_filenames: true additional_dependencies: ['rich>=12.4.4', 'diagrams>=0.23.4'] - id: generate-volumes-for-sources @@ -511,7 +556,7 @@ repos: name: Update versions in docs entry: ./scripts/ci/pre_commit/update_versions.py language: python - files: ^docs|^airflow-core/src/airflow/__init__\.py$ + files: ^docs|^airflow-core/src/airflow/__init__\.py$|.*/pyproject\.toml$ pass_filenames: false additional_dependencies: ['rich>=12.4.4'] - id: check-pydevd-left-in-code @@ -583,8 +628,9 @@ repos: pass_filenames: true exclude: > (?x) - ^clients/python/openapi_v1.yaml$| + ^airflow-core/src/airflow/ui/src/i18n/config\.ts$| ^airflow-core/src/airflow/ui/openapi-gen/| + ^airflow-core/src/airflow/ui/src/i18n/locales/de/README\.md$| ^airflow-core/src/airflow/cli/commands/local_commands/fastapi_api_command\.py$| ^airflow-core/src/airflow/config_templates/| ^airflow-core/src/airflow/models/baseoperator\.py$| @@ -606,6 +652,7 @@ repos: ^providers/google/src/airflow/providers/google/cloud/operators/cloud_build\.py$| ^providers/google/src/airflow/providers/google/cloud/operators/dataproc\.py$| ^providers/google/src/airflow/providers/google/cloud/operators/mlengine\.py$| + ^providers/keycloak/src/airflow/providers/keycloak/auth_manager/cli/definition.py| ^providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/cosmos\.py$| ^providers/microsoft/winrm/src/airflow/providers/microsoft/winrm/hooks/winrm\.py$| ^airflow-core/docs/.*commits\.rst$| @@ -619,6 +666,7 @@ repos: ^airflow-core/src/airflow/utils/trigger_rule\.py$| ^chart/values.schema\.json$| ^helm-tests/tests/chart_utils/helm_template_generator\.py$| + ^helm-tests/tests/chart_utils/ingress-networking-v1beta1\.json$| ^dev/| ^devel-common/src/docs/README\.rst$| ^docs/apache-airflow-providers-amazon/secrets-backends/aws-ssm-parameter-store\.rst$| @@ -645,7 +693,7 @@ repos: ^.*commits\.(rst|txt)$| ^.*RELEASE_NOTES\.rst$| ^contributing-docs/03_contributors_quick_start\.rst$| - ^.*\.(png|gif|jp[e]?g|tgz|lock)$| + ^.*\.(png|gif|jp[e]?g|svg|tgz|lock)$| git| ^airflow-core/newsfragments/43349\.significant\.rst$| ^airflow-core/newsfragments/41368\.significant\.rst$| @@ -834,7 +882,6 @@ repos: - id: compile-fab-assets name: Compile FAB provider assets language: node - 'types_or': [javascript, ts, tsx] files: ^providers/fab/.*/www/ entry: ./scripts/ci/pre_commit/compile_fab_assets.py pass_filenames: false @@ -886,7 +933,7 @@ repos: name: Update Airflow's meta-package pyproject.toml language: python entry: ./scripts/ci/pre_commit/update_airflow_pyproject_toml.py - files: ^pyproject\.toml$ + files: ^.*/pyproject\.toml$|^scripts/ci/pre_commit/update_airflow_pyproject_toml\.py$ pass_filenames: false require_serial: true additional_dependencies: ['rich>=12.4.4', 'tomli>=2.0.1', 'packaging>=23.2' ] @@ -970,6 +1017,7 @@ repos: exclude: > (?x) ^scripts/ci/docker-compose/grafana/.| + ^scripts/ci/docker-compose/gremlin/.| ^scripts/ci/docker-compose/.+-config\.ya?ml$ require_serial: true additional_dependencies: ['jsonschema>=3.2.0,<5.0', 'pyyaml>=6.0.2', 'requests==2.32.3', 'rich>=12.4.4'] @@ -1208,6 +1256,40 @@ repos: files: ^airflow-core/src/airflow/migrations/versions/.*\.py$ exclude: airflow-core/src/airflow/migrations/versions/0028_3_0_0_drop_ab_user_id_foreign_key.py + - id: ts-compile-lint-ui + name: Compile / format / lint UI + description: TS types generation / ESLint / Prettier new UI files + language: node + files: | + (?x) + ^airflow-core/src/airflow/ui/.*\.(js|ts|tsx|yaml|css|json)| + ^airflow-core/src/airflow/api_fastapi/core_api/openapi/.*\.yaml$| + ^airflow-core/src/airflow/api_fastapi/auth/managers/simple/openapi/v1.*\.yaml$ + exclude: | + (?x) + ^airflow-core/src/airflow/ui/node-modules/.*| + ^airflow-core/src/airflow/ui/.pnpm-store + entry: ./scripts/ci/pre_commit/ts_compile_lint_ui.py + additional_dependencies: ['pnpm@9.7.1'] + pass_filenames: true + require_serial: true + - id: ts-compile-lint-simple-auth-manager-ui + name: Compile / format / lint simple auth manager UI + description: TS types generation / ESLint / Prettier new UI files + language: node + files: | + (?x) + ^airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui/.*\.(js|ts|tsx|yaml|css|json)| + ^airflow-core/src/airflow/api_fastapi/core_api/openapi/.*\.yaml$| + ^airflow-core/src/airflow/api_fastapi/auth/managers/simple/openapi/v1.*\.yaml$ + exclude: | + (?x) + ^airflow-core/src/airflow/api_fastapi/node-modules/.*| + ^airflow-core/src/airflow/api_fastapi/.pnpm-store + entry: ./scripts/ci/pre_commit/ts_compile_lint_simple_auth_manager_ui.py + additional_dependencies: ['pnpm@9.7.1'] + pass_filenames: true + require_serial: true ## ADD MOST PRE-COMMITS ABOVE THAT LINE # The below pre-commits are those requiring CI image to be built - id: mypy-dev @@ -1295,6 +1377,7 @@ repos: language: python entry: ./scripts/ci/pre_commit/mypy.py files: ^airflow-ctl/src/airflowctl/.*\.py$|^airflow-ctl/tests/.*\.py$ + exclude: .*generated.py require_serial: true additional_dependencies: ['rich>=12.4.4'] - id: mypy-airflow-ctl @@ -1309,25 +1392,19 @@ repos: - id: generate-openapi-spec name: Generate the FastAPI API spec language: python - entry: ./scripts/ci/pre_commit/update_fastapi_api_spec.py + entry: ./scripts/ci/pre_commit/generate_openapi_spec.py pass_filenames: false files: ^airflow-core/src/airflow/api_fastapi/.*\.py$|^airflow-core/src/airflow/api_fastapi/auth/managers/simple/.*\.py$|^providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/.*\.py$ exclude: ^airflow-core/src/airflow/api_fastapi/execution_api/.* - additional_dependencies: ['rich>=12.4.4'] - - id: ts-compile-format-lint-ui - name: Compile / format / lint UI - description: TS types generation / ESLint / Prettier new UI files - language: node - types_or: [javascript, ts, tsx, yaml, css, json] - files: | - (?x) - ^airflow-core/src/airflow/ui/| - ^airflow-core/src/airflow/api_fastapi/core_api/openapi/.*\.yaml$| - ^airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui/| - ^airflow-core/src/airflow/api_fastapi/auth/managers/simple/openapi/v1.*\.yaml$ - entry: ./scripts/ci/pre_commit/compile_lint_ui.py - additional_dependencies: ['pnpm@9.7.1'] + additional_dependencies: ['rich>=12.4.4', 'openapi-spec-validator>=0.7.1'] + - id: generate-openapi-spec-fab + name: Generate the FastAPI API spec for FAB + language: python + entry: ./scripts/ci/pre_commit/generate_openapi_spec_fab.py pass_filenames: false + files: ^airflow-core/src/airflow/api_fastapi/.*\.py$|^airflow-core/src/airflow/api_fastapi/auth/managers/simple/.*\.py$|^providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/.*\.py$ + exclude: ^airflow-core/src/airflow/api_fastapi/execution_api/.* + additional_dependencies: ['rich>=12.4.4', 'openapi-spec-validator>=0.7.1'] - id: check-provider-yaml-valid name: Validate provider.yaml files entry: ./scripts/ci/pre_commit/check_provider_yaml_files.py diff --git a/.rat-excludes b/.rat-excludes index 75a85f9873fa1..95e31f35fba37 100644 --- a/.rat-excludes +++ b/.rat-excludes @@ -161,9 +161,17 @@ PKG-INFO .openapi-generator-ignore version.txt v1*.yaml +v2*.yaml _private_ui*.yaml # Front end generated files api-generated.ts openapi-gen pnpm-lock.yaml + +# python generated file +generated.py +auth_generated.py + +# hash files +www-hash.txt diff --git a/Dockerfile b/Dockerfile index 37ac245da5b20..023fb2442946c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,7 +46,7 @@ ARG AIRFLOW_UID="50000" ARG AIRFLOW_USER_HOME_DIR=/home/airflow # latest released version here -ARG AIRFLOW_VERSION="2.10.5" +ARG AIRFLOW_VERSION="3.0.1" ARG PYTHON_BASE_IMAGE="python:3.9-slim-bookworm" @@ -54,10 +54,10 @@ ARG PYTHON_BASE_IMAGE="python:3.9-slim-bookworm" # You can swap comments between those two args to test pip from the main version # When you attempt to test if the version of `pip` from specified branch works for our builds # Also use `force pip` label on your PR to swap all places we use `uv` to `pip` -ARG AIRFLOW_PIP_VERSION=25.0.1 +ARG AIRFLOW_PIP_VERSION=25.1.1 # ARG AIRFLOW_PIP_VERSION="git+https://github.com/pypa/pip.git@main" -ARG AIRFLOW_SETUPTOOLS_VERSION=78.1.0 -ARG AIRFLOW_UV_VERSION=0.6.13 +ARG AIRFLOW_SETUPTOOLS_VERSION=80.9.0 +ARG AIRFLOW_UV_VERSION=0.7.19 ARG AIRFLOW_USE_UV="false" ARG UV_HTTP_TIMEOUT="300" ARG AIRFLOW_IMAGE_REPOSITORY="https://github.com/apache/airflow" @@ -137,7 +137,7 @@ function get_runtime_apt_deps() { echo if [[ "${RUNTIME_APT_DEPS=}" == "" ]]; then RUNTIME_APT_DEPS="apt-transport-https apt-utils ca-certificates \ -curl dumb-init freetds-bin krb5-user libev4 libgeos-dev \ +curl dumb-init freetds-bin git krb5-user libev4 libgeos-dev \ ldap-utils libsasl2-2 libsasl2-modules libxmlsec1 locales ${debian_version_apt_deps} \ lsb-release openssh-client python3-selinux rsync sasl2-bin sqlite3 sudo unixodbc" export RUNTIME_APT_DEPS @@ -232,6 +232,24 @@ readonly MARIADB_LTS_VERSION="10.11" : "${INSTALL_MYSQL_CLIENT:?Should be true or false}" : "${INSTALL_MYSQL_CLIENT_TYPE:-mariadb}" +retry() { + local retries=3 + local count=0 + # adding delay of 10 seconds + local delay=10 + until "$@"; do + exit_code=$? + count=$((count + 1)) + if [[ $count -lt $retries ]]; then + echo "Command failed. Attempt $count/$retries. Retrying in ${delay}s..." + sleep $delay + else + echo "Command failed after $retries attempts." + return $exit_code + fi + done +} + install_mysql_client() { if [[ "${1}" == "dev" ]]; then packages=("libmysqlclient-dev" "mysql-client") @@ -257,8 +275,8 @@ install_mysql_client() { echo "deb http://repo.mysql.com/apt/debian/ $(lsb_release -cs) mysql-${MYSQL_LTS_VERSION}" > \ /etc/apt/sources.list.d/mysql.list - apt-get update - apt-get install --no-install-recommends -y "${packages[@]}" + retry apt-get update + retry apt-get install --no-install-recommends -y "${packages[@]}" apt-get autoremove -yqq --purge apt-get clean && rm -rf /var/lib/apt/lists/* @@ -302,8 +320,8 @@ install_mariadb_client() { /etc/apt/sources.list.d/mariadb.list # Make sure that dependencies from MariaDB repo are preferred over Debian dependencies printf "Package: *\nPin: release o=MariaDB\nPin-Priority: 999\n" > /etc/apt/preferences.d/mariadb - apt-get update - apt-get install --no-install-recommends -y "${packages[@]}" + retry apt-get update + retry apt-get install --no-install-recommends -y "${packages[@]}" apt-get autoremove -yqq --purge apt-get clean && rm -rf /var/lib/apt/lists/* } @@ -455,14 +473,19 @@ function common::get_packaging_tool() { echo export PACKAGING_TOOL="uv" export PACKAGING_TOOL_CMD="uv pip" - export EXTRA_INSTALL_FLAGS="--group=dev" + if [[ ${AIRFLOW_INSTALLATION_METHOD=} == "." && -f "./pyproject.toml" ]]; then + # for uv only install dev group when we install from sources + export EXTRA_INSTALL_FLAGS="--group=dev" + else + export EXTRA_INSTALL_FLAGS="" + fi export EXTRA_UNINSTALL_FLAGS="" export UPGRADE_TO_HIGHEST_RESOLUTION="--upgrade --resolution highest" export UPGRADE_IF_NEEDED="--upgrade" UV_CONCURRENT_DOWNLOADS=$(nproc --all) export UV_CONCURRENT_DOWNLOADS if [[ ${INCLUDE_PRE_RELEASE=} == "true" ]]; then - EXTRA_INSTALL_FLAGS="${EXTRA_INSTALL_FLAGS} --prerelease allow" + EXTRA_INSTALL_FLAGS="${EXTRA_INSTALL_FLAGS} --prerelease if-necessary" fi else echo @@ -491,7 +514,7 @@ function common::get_airflow_version_specification() { function common::get_constraints_location() { # auto-detect Airflow-constraint reference and location if [[ -z "${AIRFLOW_CONSTRAINTS_REFERENCE=}" ]]; then - if [[ ${AIRFLOW_VERSION} =~ v?2.* && ! ${AIRFLOW_VERSION} =~ .*dev.* ]]; then + if [[ ${AIRFLOW_VERSION} =~ v?2.* || ${AIRFLOW_VERSION} =~ v?3.* ]]; then AIRFLOW_CONSTRAINTS_REFERENCE=constraints-${AIRFLOW_VERSION} else AIRFLOW_CONSTRAINTS_REFERENCE=${DEFAULT_CONSTRAINTS_BRANCH} @@ -650,7 +673,7 @@ if [[ $(id -u) == "0" ]]; then echo echo "${COLOR_RED}You are running pip as root. Please use 'airflow' user to run pip!${COLOR_RESET}" echo - echo "${COLOR_YELLOW}See: https://airflow.apache.org/docs/docker-stack/build.html#adding-a-new-pypi-package${COLOR_RESET}" + echo "${COLOR_YELLOW}See: https://airflow.apache.org/docs/docker-stack/build.html#adding-new-pypi-packages-individually${COLOR_RESET}" echo exit 1 fi @@ -1290,7 +1313,7 @@ function check_uid_gid() { >&2 echo " This is to make sure you can run the image with an arbitrary UID in the future." >&2 echo >&2 echo " See more about it in the Airflow's docker image documentation" - >&2 echo " http://airflow.apache.org/docs/docker-stack/entrypoint" + >&2 echo " https://airflow.apache.org/docs/docker-stack/entrypoint.html" >&2 echo # We still allow the image to run with `airflow` user. return @@ -1304,7 +1327,7 @@ function check_uid_gid() { >&2 echo " This is to make sure you can run the image with an arbitrary UID." >&2 echo >&2 echo " See more about it in the Airflow's docker image documentation" - >&2 echo " http://airflow.apache.org/docs/docker-stack/entrypoint" + >&2 echo " https://airflow.apache.org/docs/docker-stack/entrypoint.html" # This will not work so we fail hard exit 1 fi @@ -1599,12 +1622,12 @@ COPY --chown=airflow:0 ${AIRFLOW_SOURCES_FROM} ${AIRFLOW_SOURCES_TO} ARG ADDITIONAL_PYTHON_DEPS="" -ARG VERSION_SUFFIX_FOR_PYPI="" +ARG VERSION_SUFFIX="" ENV ADDITIONAL_PYTHON_DEPS=${ADDITIONAL_PYTHON_DEPS} \ INSTALL_DISTRIBUTIONS_FROM_CONTEXT=${INSTALL_DISTRIBUTIONS_FROM_CONTEXT} \ USE_CONSTRAINTS_FOR_CONTEXT_DISTRIBUTIONS=${USE_CONSTRAINTS_FOR_CONTEXT_DISTRIBUTIONS} \ - VERSION_SUFFIX_FOR_PYPI=${VERSION_SUFFIX_FOR_PYPI} + VERSION_SUFFIX=${VERSION_SUFFIX} WORKDIR ${AIRFLOW_HOME} diff --git a/Dockerfile.ci b/Dockerfile.ci index b722ff0132935..7fc0d572bf0c0 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -76,7 +76,7 @@ function get_runtime_apt_deps() { echo if [[ "${RUNTIME_APT_DEPS=}" == "" ]]; then RUNTIME_APT_DEPS="apt-transport-https apt-utils ca-certificates \ -curl dumb-init freetds-bin krb5-user libev4 libgeos-dev \ +curl dumb-init freetds-bin git krb5-user libev4 libgeos-dev \ ldap-utils libsasl2-2 libsasl2-modules libxmlsec1 locales ${debian_version_apt_deps} \ lsb-release openssh-client python3-selinux rsync sasl2-bin sqlite3 sudo unixodbc" export RUNTIME_APT_DEPS @@ -171,6 +171,24 @@ readonly MARIADB_LTS_VERSION="10.11" : "${INSTALL_MYSQL_CLIENT:?Should be true or false}" : "${INSTALL_MYSQL_CLIENT_TYPE:-mariadb}" +retry() { + local retries=3 + local count=0 + # adding delay of 10 seconds + local delay=10 + until "$@"; do + exit_code=$? + count=$((count + 1)) + if [[ $count -lt $retries ]]; then + echo "Command failed. Attempt $count/$retries. Retrying in ${delay}s..." + sleep $delay + else + echo "Command failed after $retries attempts." + return $exit_code + fi + done +} + install_mysql_client() { if [[ "${1}" == "dev" ]]; then packages=("libmysqlclient-dev" "mysql-client") @@ -196,8 +214,8 @@ install_mysql_client() { echo "deb http://repo.mysql.com/apt/debian/ $(lsb_release -cs) mysql-${MYSQL_LTS_VERSION}" > \ /etc/apt/sources.list.d/mysql.list - apt-get update - apt-get install --no-install-recommends -y "${packages[@]}" + retry apt-get update + retry apt-get install --no-install-recommends -y "${packages[@]}" apt-get autoremove -yqq --purge apt-get clean && rm -rf /var/lib/apt/lists/* @@ -241,8 +259,8 @@ install_mariadb_client() { /etc/apt/sources.list.d/mariadb.list # Make sure that dependencies from MariaDB repo are preferred over Debian dependencies printf "Package: *\nPin: release o=MariaDB\nPin-Priority: 999\n" > /etc/apt/preferences.d/mariadb - apt-get update - apt-get install --no-install-recommends -y "${packages[@]}" + retry apt-get update + retry apt-get install --no-install-recommends -y "${packages[@]}" apt-get autoremove -yqq --purge apt-get clean && rm -rf /var/lib/apt/lists/* } @@ -394,14 +412,19 @@ function common::get_packaging_tool() { echo export PACKAGING_TOOL="uv" export PACKAGING_TOOL_CMD="uv pip" - export EXTRA_INSTALL_FLAGS="--group=dev" + if [[ ${AIRFLOW_INSTALLATION_METHOD=} == "." && -f "./pyproject.toml" ]]; then + # for uv only install dev group when we install from sources + export EXTRA_INSTALL_FLAGS="--group=dev" + else + export EXTRA_INSTALL_FLAGS="" + fi export EXTRA_UNINSTALL_FLAGS="" export UPGRADE_TO_HIGHEST_RESOLUTION="--upgrade --resolution highest" export UPGRADE_IF_NEEDED="--upgrade" UV_CONCURRENT_DOWNLOADS=$(nproc --all) export UV_CONCURRENT_DOWNLOADS if [[ ${INCLUDE_PRE_RELEASE=} == "true" ]]; then - EXTRA_INSTALL_FLAGS="${EXTRA_INSTALL_FLAGS} --prerelease allow" + EXTRA_INSTALL_FLAGS="${EXTRA_INSTALL_FLAGS} --prerelease if-necessary" fi else echo @@ -430,7 +453,7 @@ function common::get_airflow_version_specification() { function common::get_constraints_location() { # auto-detect Airflow-constraint reference and location if [[ -z "${AIRFLOW_CONSTRAINTS_REFERENCE=}" ]]; then - if [[ ${AIRFLOW_VERSION} =~ v?2.* && ! ${AIRFLOW_VERSION} =~ .*dev.* ]]; then + if [[ ${AIRFLOW_VERSION} =~ v?2.* || ${AIRFLOW_VERSION} =~ v?3.* ]]; then AIRFLOW_CONSTRAINTS_REFERENCE=constraints-${AIRFLOW_VERSION} else AIRFLOW_CONSTRAINTS_REFERENCE=${DEFAULT_CONSTRAINTS_BRANCH} @@ -808,7 +831,6 @@ if [[ ${VERBOSE_COMMANDS:="false"} == "true" ]]; then set -x fi - . "${AIRFLOW_SOURCES:-/opt/airflow}"/scripts/in_container/_in_container_script_init.sh LD_PRELOAD="/usr/lib/$(uname -m)-linux-gnu/libstdc++.so.6" @@ -826,6 +848,10 @@ mkdir "${AIRFLOW_HOME}/sqlite" -p || true ASSET_COMPILATION_WAIT_MULTIPLIER=${ASSET_COMPILATION_WAIT_MULTIPLIER:=1} +if [[ "${CI=}" == "true" ]]; then + export COLUMNS="202" +fi + . "${IN_CONTAINER_DIR}/check_connectivity.sh" function wait_for_asset_compilation() { @@ -950,6 +976,12 @@ function environment_initialization() { cd "${AIRFLOW_SOURCES}" + # Temporarily add /opt/airflow/providers/standard/tests to PYTHONPATH in order to see example dags + # in the UI when testing in Breeze. This might be solved differently in the future + if [[ -d /opt/airflow/providers/standard/tests ]]; then + export PYTHONPATH=${PYTHONPATH=}:/opt/airflow/providers/standard/tests + fi + if [[ ${START_AIRFLOW:="false"} == "true" || ${START_AIRFLOW} == "True" ]]; then export AIRFLOW__CORE__LOAD_EXAMPLES=${LOAD_EXAMPLES} wait_for_asset_compilation @@ -985,7 +1017,7 @@ function determine_airflow_to_use() { echo "${COLOR_BLUE}Uninstalling all packages first${COLOR_RESET}" echo # shellcheck disable=SC2086 - ${PACKAGING_TOOL_CMD} freeze | grep -ve "^-e" | grep -ve "^#" | grep -ve "^uv" | \ + ${PACKAGING_TOOL_CMD} freeze | grep -ve "^-e" | grep -ve "^#" | grep -ve "^uv" | grep -v "@" | \ xargs ${PACKAGING_TOOL_CMD} uninstall ${EXTRA_UNINSTALL_FLAGS} # Now install rich ad click first to use the installation script # shellcheck disable=SC2086 @@ -997,7 +1029,9 @@ function determine_airflow_to_use() { echo # Use uv run to install necessary dependencies automatically # in the future we will be able to use uv sync when `uv.lock` is supported - uv run /opt/airflow/scripts/in_container/install_development_dependencies.py \ + # for the use in parallel runs in docker containers--no-cache is needed - otherwise there is + # possibility of overriding temporary environments by multiple parallel processes + uv run --no-cache /opt/airflow/scripts/in_container/install_development_dependencies.py \ --constraint https://raw.githubusercontent.com/apache/airflow/constraints-main/constraints-${PYTHON_MAJOR_MINOR_VERSION}.txt # Some packages might leave legacy typing module which causes test issues # shellcheck disable=SC2086 @@ -1029,7 +1063,7 @@ function check_boto_upgrade() { # shellcheck disable=SC2086 ${PACKAGING_TOOL_CMD} uninstall ${EXTRA_UNINSTALL_FLAGS} aiobotocore s3fs || true # shellcheck disable=SC2086 - ${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade boto3 botocore + ${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade "boto3<1.38.3" "botocore<1.38.3" set +x } @@ -1038,12 +1072,12 @@ function check_downgrade_sqlalchemy() { return fi local min_sqlalchemy_version - min_sqlalchemy_version=$(grep "sqlalchemy>=" airflow-core/pyproject.toml | sed "s/.*>=\([0-9\.]*\).*/\1/" | xargs) + min_sqlalchemy_version=$(grep "sqlalchemy\[asyncio\]>=" airflow-core/pyproject.toml | sed "s/.*>=\([0-9\.]*\).*/\1/" | xargs) echo echo "${COLOR_BLUE}Downgrading sqlalchemy to minimum supported version: ${min_sqlalchemy_version}${COLOR_RESET}" echo # shellcheck disable=SC2086 - ${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} "sqlalchemy==${min_sqlalchemy_version}" + ${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} "sqlalchemy[asyncio]==${min_sqlalchemy_version}" pip check } @@ -1066,13 +1100,6 @@ function check_run_tests() { return fi - if [[ ${REMOVE_ARM_PACKAGES:="false"} == "true" ]]; then - # Test what happens if we do not have ARM packages installed. - # This is useful to see if pytest collection works without ARM packages which is important - # for the MacOS M1 users running tests in their ARM machines with `breeze testing *-tests` command - python "${IN_CONTAINER_DIR}/remove_arm_packages.py" - fi - if [[ ${TEST_GROUP:=""} == "system" ]]; then exec "${IN_CONTAINER_DIR}/run_system_tests.sh" "${@}" else @@ -1115,23 +1142,32 @@ function check_airflow_python_client_installation() { python "${IN_CONTAINER_DIR}/install_airflow_python_client.py" } +function initialize_db() { + # If we are going to start the api server OR we are a system test (which may or may not start the api server, + # depending on the Airflow version being used to run the tests), then migrate the DB. + if [[ ${START_API_SERVER_WITH_EXAMPLES=} == "true" || ${TEST_GROUP:=""} == "system" ]]; then + echo + echo "${COLOR_BLUE}Initializing database${COLOR_RESET}" + echo + airflow db migrate + echo + echo "${COLOR_BLUE}Database initialized${COLOR_RESET}" + fi +} + function start_api_server_with_examples(){ - # check if we should not start the api server with examples by checking if both - # START_API_SERVER_WITH_EXAMPLES is false AND the TEST_GROUP env var is not equal to "system" + USE_AIRFLOW_VERSION="${USE_AIRFLOW_VERSION:=""}" + # Do not start the api server if either START_API_SERVER_WITH_EXAMPLES is false or the TEST_GROUP env var is not + # equal to "system". if [[ ${START_API_SERVER_WITH_EXAMPLES=} != "true" && ${TEST_GROUP:=""} != "system" ]]; then return fi + # If the use Airflow version is set and it is <= 3.0.0 (which does not have the API server anyway) also return + if [[ ${USE_AIRFLOW_VERSION} != "" && ${USE_AIRFLOW_VERSION} < "3.0.0" ]]; then + return + fi export AIRFLOW__CORE__LOAD_EXAMPLES=True - export AIRFLOW__WEBSERVER__EXPOSE_CONFIG=True - echo - echo "${COLOR_BLUE}Initializing database${COLOR_RESET}" - echo - airflow db migrate - echo - echo "${COLOR_BLUE}Database initialized${COLOR_RESET}" - echo - echo "${COLOR_BLUE}Parsing example dags${COLOR_RESET}" - echo + export AIRFLOW__API__EXPOSE_CONFIG=True airflow dags reserialize echo "Example dags parsing finished" if airflow config get-value core auth_manager | grep -q "FabAuthManager"; then @@ -1168,6 +1204,7 @@ check_downgrade_sqlalchemy check_downgrade_pendulum check_force_lowest_dependencies check_airflow_python_client_installation +initialize_db start_api_server_with_examples check_run_tests "${@}" @@ -1199,7 +1236,7 @@ ARG AIRFLOW_IMAGE_REPOSITORY="https://github.com/apache/airflow" # NOTE! When you want to make sure dependencies are installed from scratch in your PR after removing # some dependencies, you also need to set "disable image cache" in your PR to make sure the image is # not built using the "main" version of those dependencies. -ARG DEPENDENCIES_EPOCH_NUMBER="14" +ARG DEPENDENCIES_EPOCH_NUMBER="15" # Make sure noninteractive debian install is used and language variables set ENV PYTHON_BASE_IMAGE=${PYTHON_BASE_IMAGE} \ @@ -1353,10 +1390,10 @@ COPY --from=scripts common.sh install_packaging_tools.sh install_additional_depe # You can swap comments between those two args to test pip from the main version # When you attempt to test if the version of `pip` from specified branch works for our builds # Also use `force pip` label on your PR to swap all places we use `uv` to `pip` -ARG AIRFLOW_PIP_VERSION=25.0.1 +ARG AIRFLOW_PIP_VERSION=25.1.1 # ARG AIRFLOW_PIP_VERSION="git+https://github.com/pypa/pip.git@main" -ARG AIRFLOW_SETUPTOOLS_VERSION=78.1.0 -ARG AIRFLOW_UV_VERSION=0.6.13 +ARG AIRFLOW_SETUPTOOLS_VERSION=80.9.0 +ARG AIRFLOW_UV_VERSION=0.7.19 # TODO(potiuk): automate with upgrade check (possibly) ARG AIRFLOW_PRE_COMMIT_VERSION="4.2.0" ARG AIRFLOW_PRE_COMMIT_UV_VERSION="4.1.4" @@ -1391,10 +1428,10 @@ COPY --from=scripts install_airflow_when_building_images.sh /scripts/docker/ COPY . ${AIRFLOW_SOURCES}/ ARG UPGRADE_RANDOM_INDICATOR_STRING="" -ARG VERSION_SUFFIX_FOR_PYPI="" +ARG VERSION_SUFFIX="" ENV UPGRADE_RANDOM_INDICATOR_STRING=${UPGRADE_RANDOM_INDICATOR_STRING} \ - VERSION_SUFFIX_FOR_PYPI=${VERSION_SUFFIX_FOR_PYPI} + VERSION_SUFFIX=${VERSION_SUFFIX} # The goal of this line is to install the dependencies from the most current pyproject.toml from sources # This will be usually incremental small set of packages in CI optimized build, so it will be very fast diff --git a/INSTALLING.md b/INSTALLING.md new file mode 100644 index 0000000000000..e62b66a7a2a0e --- /dev/null +++ b/INSTALLING.md @@ -0,0 +1,103 @@ + + +## Local Development Setup + +This section outlines a recommended approach for setting up a local development environment for Apache Airflow on macOS and Linux, primarily using PyEnv for Python version management. + +> ⚠️ Avoid using either system-installed Python or Python from Homebrew, as these versions are often labeled `--externally-managed` resulting in restricted dependency installation. + +You can use other ways to install Python and airflow. Airflow development setup requires `uv` and if you want to setup environment for development, `uv` is the only supported local development environment setup, because we are using `uv workspace` extensively. See [local virtualenv setup in contributing docs](https://github.com/apache/airflow/blob/main/contributing-docs/07_local_virtualenv.rst) for details. + +If you are just installing airflow to run it locally, You can use other ways to set up your Python and virtualenv: `uv` is one of the options (refer to `uv` documentation), but you can also use more traditional tools - for example `pyenv`. Note that it is recommended to install airflow with constraints - at least initially - because this way you can reproducibly install airflow. See [Installation from PyPI](https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html) for more details. + +### ✅ Setup using pyenv: + +1. **Install pyenv (macOS and Linux)**: + +```bash +brew install pyenv +``` + +(Note: Homebrew is the recommended method on macOS. For Linux, you can typically install pyenv using the `pyenv-installer` script as detailed in the official documentation: [https://github.com/pyenv/pyenv#installation](https://github.com/pyenv/pyenv#installation).) + +2. **Install Python**: + +```bash +pyenv install 3.11.9 +pyenv global 3.11.9 +``` + +3. **Check Python version**: + +```bash +python --version +``` + +4. **Create and Activate a Virtual Environment**: Since Apache Airflow requires multiple dependencies, it's a good practice to isolate these dependencies in a virtual environment. + +- Create a virtual environment: + +```bash +python -m venv airflow_venv +``` + +- Activate the virtual environment: + +```bash +source airflow_venv/bin/activate +``` + +5. **Install Apache Airflow**: Apache Airflow is available on PyPI. To install it, you can use the following command in your terminal: + +```bash +pip install apache-airflow==3.0.0 --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-3.0.0/constraints-3.11.txt" +``` + +Note that installing with constraints - at least initially - is recommended for reproducible installation. It might sometimes happen that 3rd-party distributions are released and their latest versions break airflow. Using constraints makes the installation reproducible with versions of dependencies that were "frozen" at the time of releasing airflow. Note you have to specify both - airflow version and Python version you are using. + +You can also specify additional extras - when you want to install airflow with additional providers: + +```bash +pip install apache-airflow[amazon,google]==3.0.0 --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-3.0.0/constraints-3.11.txt" +``` + +6. **Set the AIRFLOW_HOME Environment Variable**: Apache Airflow requires a directory to store configuration files, logs, and other data. Set the AIRFLOW_HOME variable to specify this directory. + +- Set the Airflow home directory: + +```bash +export AIRFLOW_HOME=~/airflow +``` + +7. **Run Airflow in standalone mode**: Apache Airflow runs several components, like the scheduler, web server, and API server, to manage workflows and show the UI. + +- To run Airflow in standalone mode (which will automatically start the required components): + +```bash +airflow standalone +``` + +8. **Access the Airflow Web UI**: Once the components are up and running, you can access the Airflow UI through your browser: + +- Open your browser and go to: + +```text +http://localhost:8080 +``` diff --git a/PROVIDERS.rst b/PROVIDERS.rst index 1d1386cceb454..ced8f5fb1b4cd 100644 --- a/PROVIDERS.rst +++ b/PROVIDERS.rst @@ -57,7 +57,7 @@ releasing new versions of the providers. This means that the code changes in the reviewed by Airflow committers and merged when they are accepted by them. Also we must have sufficient test coverage and documentation that allow us to maintain the providers, and our users to use them. -The providers - their latest version in "main" branch of airflow repository - are installed and tested together +The providers - their latest version in "main" branch of Airflow repository - are installed and tested together with other community providers and one of the key properties of the community providers is that the latest version of providers contribute their dependencies to constraints of Airflow, published when Airflow Core is released. This means that when users are using constraints published by Airflow, they can install all @@ -92,7 +92,7 @@ Accepting new community providers --------------------------------- Accepting new community providers should be a deliberate process that requires ``[DISCUSSION]`` -followed by ``[VOTE]`` thread at the airflow `devlist `_. +followed by ``[VOTE]`` thread at the Airflow `devlist `_. In case the provider is integration with an open-source software rather than service we can relax the vote procedure a bit. Particularly if the open-source software is an Apache Software Foundation, diff --git a/README.md b/README.md index 8c93ff8f9260b..769525febc749 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,9 @@ # Apache Airflow [![PyPI version](https://badge.fury.io/py/apache-airflow.svg)](https://badge.fury.io/py/apache-airflow) -[![GitHub Build](https://github.com/apache/airflow/actions/workflows/ci.yml/badge.svg)](https://github.com/apache/airflow/actions) +[![GitHub Build main](https://github.com/apache/airflow/actions/workflows/ci-amd.yml/badge.svg)](https://github.com/apache/airflow/actions) +[![GitHub Build 3.0](https://github.com/apache/airflow/actions/workflows/ci-amd.yml/badge.svg?branch=v3-0-test)](https://github.com/apache/airflow/actions) +[![GitHub Build 2.11](https://github.com/apache/airflow/actions/workflows/ci.yml/badge.svg?branch=v2-11-test)](https://github.com/apache/airflow/actions) [![Coverage Status](https://codecov.io/gh/apache/airflow/graph/badge.svg?token=WdLKlKHOAU)](https://codecov.io/gh/apache/airflow) [![License](https://img.shields.io/:license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/apache-airflow.svg)](https://pypi.org/project/apache-airflow/) @@ -58,6 +60,7 @@ Use Airflow to author workflows as directed acyclic graphs (DAGs) of tasks. The - [Requirements](#requirements) - [Getting started](#getting-started) - [Installing from PyPI](#installing-from-pypi) +- [Installation](#installation) - [Official source code](#official-source-code) - [Convenience packages](#convenience-packages) - [User Interface](#user-interface) @@ -96,14 +99,14 @@ Airflow is not a streaming solution, but it is often used to process real-time d Apache Airflow is tested with: -| | Main version (dev) | Stable version (2.10.5) | -|------------|------------------------|----------------------------| -| Python | 3.9, 3.10, 3.11, 3.12 | 3.8, 3.9, 3.10, 3.11, 3.12 | -| Platform | AMD64/ARM64(\*) | AMD64/ARM64(\*) | -| Kubernetes | 1.29, 1.30, 1.31, 1.32 | 1.27, 1.28, 1.29, 1.30 | -| PostgreSQL | 13, 14, 15, 16, 17 | 12, 13, 14, 15, 16 | -| MySQL | 8.0, 8.4, Innovation | 8.0, 8.4, Innovation | -| SQLite | 3.15.0+ | 3.15.0+ | +| | Main version (dev) | Stable version (3.0.1) | +|------------|------------------------|------------------------| +| Python | 3.9, 3.10, 3.11, 3.12 | 3.9, 3.10, 3.11, 3.12 | +| Platform | AMD64/ARM64(\*) | AMD64/ARM64(\*) | +| Kubernetes | 1.30, 1.31, 1.32, 1.33 | 1.30, 1.31, 1.32, 1.33 | +| PostgreSQL | 13, 14, 15, 16, 17 | 13, 14, 15, 16, 17 | +| MySQL | 8.0, 8.4, Innovation | 8.0, 8.4, Innovation | +| SQLite | 3.15.0+ | 3.15.0+ | \* Experimental @@ -139,6 +142,7 @@ Documentation for dependent projects like provider distributions, Docker image, + ## Installing from PyPI We publish Apache Airflow as `apache-airflow` package in PyPI. Installing it however might be sometimes tricky @@ -154,7 +158,6 @@ constraints files separately per major/minor Python version. You can use them as constraint files when installing Airflow from PyPI. Note that you have to specify correct Airflow tag/version/branch and Python versions in the URL. - 1. Installing just Airflow: > Note: Only `pip` installation is currently officially supported. @@ -174,21 +177,26 @@ them to the appropriate format and workflow that your tool requires. ```bash -pip install 'apache-airflow==2.10.5' \ - --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-2.10.5/constraints-3.9.txt" +pip install 'apache-airflow==3.0.1' \ + --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-3.0.1/constraints-3.9.txt" ``` 2. Installing with extras (i.e., postgres, google) ```bash -pip install 'apache-airflow[postgres,google]==2.10.5' \ - --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-2.10.5/constraints-3.9.txt" +pip install 'apache-airflow[postgres,google]==3.0.1' \ + --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-3.0.1/constraints-3.9.txt" ``` For information on installing provider distributions, check [providers](http://airflow.apache.org/docs/apache-airflow-providers/index.html). + +## Installation + +For comprehensive instructions on setting up your local development environment and installing Apache Airflow, please refer to the [INSTALLING.md](INSTALLING.md) file. + ## Official source code @@ -230,27 +238,31 @@ following the ASF Policy. - **DAGs**: Overview of all DAGs in your environment. - ![DAGs](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/dags.png) + ![DAGs](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/ui-dark/dags.png) + +- **Assets**: Overview of Assets with dependencies. + + ![Asset Dependencies](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/ui-dark/assets_graph.png) - **Grid**: Grid representation of a DAG that spans across time. - ![Grid](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/grid.png) + ![Grid](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/ui-dark/grid.png) - **Graph**: Visualization of a DAG's dependencies and their current status for a specific run. - ![Graph](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/graph.png) + ![Graph](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/ui-dark/graph.png) - **Home**: Summary statistics of your Airflow environment. - ![Home](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/home.png) + ![Home](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/ui-dark/home.png) - **Backfill**: Backfilling a DAG for a specific date range. - ![Backfill](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/backfill.png) + ![Backfill](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/ui-dark/backfill.png) - **Code**: Quick way to view source code of a DAG. - ![Code](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/code.png) + ![Code](https://raw.githubusercontent.com/apache/airflow/main/airflow-core/docs/img/ui-dark/code.png) ## Semantic versioning @@ -285,13 +297,14 @@ Apache Airflow version life cycle: -| Version | Current Patch/Minor | State | First Release | Limited Support | EOL/Terminated | -|-----------|-----------------------|-----------|-----------------|-------------------|------------------| -| 2 | 2.10.5 | Supported | Dec 17, 2020 | TBD | TBD | -| 1.10 | 1.10.15 | EOL | Aug 27, 2018 | Dec 17, 2020 | June 17, 2021 | -| 1.9 | 1.9.0 | EOL | Jan 03, 2018 | Aug 27, 2018 | Aug 27, 2018 | -| 1.8 | 1.8.2 | EOL | Mar 19, 2017 | Jan 03, 2018 | Jan 03, 2018 | -| 1.7 | 1.7.1.2 | EOL | Mar 28, 2016 | Mar 19, 2017 | Mar 19, 2017 | +| Version | Current Patch/Minor | State | First Release | Limited Maintenance | EOL/Terminated | +|-----------|-----------------------|-----------|-----------------|-----------------------|------------------| +| 3 | 3.0.3 | Supported | Apr 22, 2025 | TBD | TBD | +| 2 | 2.11.0 | Supported | Dec 17, 2020 | Oct 22, 2025 | Apr 22, 2026 | +| 1.10 | 1.10.15 | EOL | Aug 27, 2018 | Dec 17, 2020 | June 17, 2021 | +| 1.9 | 1.9.0 | EOL | Jan 03, 2018 | Aug 27, 2018 | Aug 27, 2018 | +| 1.8 | 1.8.2 | EOL | Mar 19, 2017 | Jan 03, 2018 | Jan 03, 2018 | +| 1.7 | 1.7.1.2 | EOL | Mar 28, 2016 | Mar 19, 2017 | Mar 19, 2017 | @@ -421,7 +434,7 @@ Want to help build Apache Airflow? Check out our [contributors' guide](https://g If you can't wait to contribute, and want to get started asap, check out the [contribution quickstart](https://github.com/apache/airflow/blob/main/contributing-docs/03_contributors_quick_start.rst) here! -Official Docker (container) images for Apache Airflow are described in [images](dev/breeze/doc/ci/02_images.md). +Official Docker (container) images for Apache Airflow are described in [images](https://github.com/apache/airflow/blob/main/dev/breeze/doc/ci/02_images.md). diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 7fe4191a52f2f..06ccda68e4fb0 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -19,8632 +19,4465 @@ :local: :depth: 1 +.. note:: + Release notes for older versions can be found in the versioned documentation. + .. towncrier release notes start +Airflow 3.0.3 (2025-07-14) +-------------------------- + +Significant Changes +^^^^^^^^^^^^^^^^^^^ + +No significant changes. + +Bug Fixes +""""""""" + +- Fix task execution failures with large data by improving internal communication protocol (#51924, #53194) +- Fix reschedule sensors failing after multiple re-queue attempts over long periods (#52706) +- Improve ``xcom_pull`` to cover different scenarios for mapped tasks (#51568) +- Fix connection retrieval failures in triggerer when schema field is used (#52691) +- Add back user impersonation (``run_as_user``) support for task execution (#51780) +- Fix DAG version not updating when bundle name changes without DAG structure changes (#51939) +- Add back ``exception`` to context for task callbacks (#52066) +- Fix task log retrieval for retry attempts showing incorrect logs (#51592) +- Fix data interval handling for DAGs created before AIP-39 during serialization (#51913) +- Fix lingering task supervisors when ``EOF`` is missed (#51180) (#51970) +- Persist ``EventsTimetable``'s description during serialization (#51926) +- Delete import error when a dag bundle becomes inactive (#51921) +- Cleanup import errors during DB migration (#51919) +- Fix ``EOF`` detection of subprocesses in Dag Processor (#51895) +- Stop streaming task logs if end of log mark is missing (#51482) +- Allow more empty loops before stopping log streaming (#52624) +- Fix Jinja2 Template deep copy error with ``dag.test`` (#51673) +- Explicitly close log file descriptor in the supervise function (#51654) +- Improve structured logging format and layout (#51567) (#51626) +- Use Connection Hook Names for Dropdown instead of connection IDs (#51613) +- Add back config setting to control exposing stacktrace (#51617) +- Fix task level alias resolution in structure endpoint (#51579) +- Fix backfill creation to include DAG run configuration from form (#51584) +- Fix structure edges in API responses (#51489) +- Make ``dag.test`` consistent with ``airflow dags test`` CLI command (#51476) +- Fix downstream asset attachment at task level in structure endpoint (#51425) +- Fix Task Instance ``No Status`` Filter (#52154) +- UI: Fix backfill creation to respect run backwards setting from form (#52168) +- UI: Set downstream option to default on task instance clear (#52246) +- UI: Enable iframe script execution (#52568) +- UI: Fix DAG tags filter not showing all tags in UI when tags are greater than 50 (#52714) +- UI: Add real-time clock updates to timezone selector (#52414) +- Improve Grid view performance and responsiveness with optimized data loading (#52718,#52822,#52919) +- Fix editing connection with sensitive extra field (#52445) +- Fix archival for cascading deletes by archiving dependent tables first (#51952) +- Fix whitespace handling in DAG owners parsing for multiple owners (#52221) +- Fix SQLite migration from 2.7.0 to 3.0.0 (#51431) +- Fix http exception when ti not found for extra links API (#51465) +- Fix Starting from Trigger when using ``MappedOperator`` (#52681) +- Add ti information to re-queue logs (#49995) +- Task SDK: Fix ``AssetEventOperations.get`` to use ``alias_name`` when specified (#52324) +- Ensure trigger kwargs are properly deserialized during trigger execution (#52721) +- Fixing bad cadwyn migration for upstream map indexes (#52797) +- Run trigger expansion logic only when ``start_from_trigger`` is True (#52873) +- Fix example dag ``example_external_task_parent_deferrable.py`` imports (#52957) +- Fixes pagination in DAG run lists (#52989) +- Fix db downgrade check condition (#53005) +- Fix log viewing for skipped task (#53028,#53101) +- Fixes Grid view refresh after user actions (#53086) +- Fix ``no_status`` and ``duration`` for grid summaries (#53092) +- Fix ``ti.log_url`` not in Task Context (#50376) +- Fix XCom data deserialization when using ``XCom.get_all()`` method (#53102) + +Miscellaneous +""""""""""""" + +- Update ``connections_test`` CLI to use Connection instead of BaseHook (#51834) (#51917) +- Fix table pagination when DAG filtering changes (#51795) +- UI: Move asset events to its own tab (#51655) +- Exclude ``libcst`` 1.8.1 for Python 3.9 (#51609) +- UI: Implement navigation on bar click (#50416) +- Reduce unnecessary logging when retrieving connections and variables (#51826) + +Doc Only Changes +"""""""""""""""" + +- Add note about payload size considerations in API docs (#51768) +- Enhance ENV vars and conns visibility docs (#52026) +- Add http-only warning when running behind proxy in documentation (#52699) +- Publish separate docs for Task SDK (#52682) +- Streamline Taskflow examples and link to core tutorial (#52709) +- Refresh Public Interface & align how-to guides for Airflow 3.0+ (#53011) + +Airflow 3.0.2 (2025-06-10) +-------------------------- + +Significant Changes +^^^^^^^^^^^^^^^^^^^ + +No significant changes. + +Bug Fixes +""""""""" + +- Fix memory leak in dag-processor (#50558) +- Add back invalid inlet and outlet check before running tasks (#50773) +- Implement slice on LazyXComSequence to allow filtering items from a mapped task(#50117) +- Fix execution API server URL handling for relative paths in KE (#51183) +- Add log lookup exception for Empty operator subtypes (#50325) +- Increase the max zoom on the graph view to make it easier to see small dags on big monitor screens (#50772) +- Fix timezone selection and dashboard layout (#50463) +- Creating backfill for a dag is affecting other dags (#50577) +- Fix next asset schedule and dag card UX (#50271) +- Add bundle path to ``sys.path`` in task runner (#51318) +- Add bundle path to ``sys.path`` in dag processor (#50385) +- Prevent CPU spike in task supervisor when heartbeat timeout exceeded (#51023) +- Fix Airflow Connection Form widget error (#51168) +- Add backwards compatibility shim and deprecation warning for EmailOperator (#51004) +- Handle ``SIGSEGV`` signals during DAG file imports (#51171) +- Fix deferred task resumption in ``dag.test()`` (#51182) +- Fix get dags query to not have join explosion (#50984) +- Ensure Logical date is populated correctly in Context vars (#50898) +- Mask variable values in task logs only if the variable key is sensitive (#50775) +- Mask secrets when retrieving variables from secrets backend (#50895) +- Deserialize should work while retrieving variables with secrets backend (#50889) +- Fix XCom deserialization for mapped tasks with custom backend (#50687) +- Support macros defined via plugins in Airflow 3 (#50642) +- Fix Pydantic ``ForwardRef`` error by reordering discriminated union definitions (#50688) +- Adding backwards compatibility shim for ``BaseNotifier`` (#50340) +- Use latest bundle version when clearing / re-running dag (#50040) +- Handle ``upstream_mapped_index`` when xcom access is needed (#50641) +- Remove unnecessary breaking flag in config command (#50781) +- Do not flood worker logs with secrets backend loading logs (#50581) +- Persist table sorting preferences across sessions using local storage (#50720) +- Fixed patch_task_instance API endpoint to support task instance summaries and task groups (#50550) +- Fixed bulk API schemas to improve OpenAPI compatibility and client generation (#50852) +- Fixed variable API endpoints to support keys containing slashes (#50841) +- Restored backward compatibility for the ``/run`` API endpoint for older Task SDK clients +- Fixed dropdown overflow and error text styling in ``FlexibleForm`` component (#50845) +- Corrected DAG tag rendering to display ``+1 more`` when tags exceed the display limit by one (#50669) +- Fix permission check on the ui config endpoint (#50564) +- Fix ``default_args`` handling in operator ``.partial()`` to prevent ``TypeError`` when unused keys are present (#50525) +- DAG Processor: Fix index to sort by last parsing duration (#50388) +- UI: Fix border overlap issue in the Events page (#50453) +- Fix ``airflow tasks clear`` command (#49631) +- Restored support for ``--local`` flag in ``dag list`` and ``dag list-import-errors`` CLI commands (#49380) +- CLI: Exclude example dags when a bundle is passed (#50401) +- Fix CLI export to handle stdout without file descriptors (#50328) +- Fix ``DagProcessor`` stats log to show the correct parse duration (#50316) +- Fix OpenAPI schema for ``get_log`` API (#50547) +- Remove ``logical_date`` check when validating inlets and outlets (#51464) +- Guard ``ti`` update state and set task to fail if exception encountered (#51295) + +Miscellaneous +""""""""""""" + +- UI: Implement navigation on bar click (#50416) +- UI: Always Show Trends count in Dag Overview (#50183) +- UI: Add basic json check to variable value +- Remove filtering by last dag run state in patch dags endpoint (#51347) +- Ensure that both public and ui dags endpoints map to DagService (#51226) +- Refresh Dag details page on new run (#51173) +- Log fallback to None when no XCom value is found (#51285) +- Move ``example_dags`` in standard provider to ``example_dags`` in sources (#51275) +- Bring back "standard" example dags to the ``airflow-core`` package (#51192) +- Faster note on grid endpoint (#51247) +- Port ``task.test`` to Task SDK (#50827) +- Port ``dag.test`` to Task SDK (#50300,#50419) +- Port ``ti.run`` to Task SDK execution path (#50141) +- Support running ``airflow dags test`` from local files (#50420) +- Move macros to task SDK ``execution_time`` module (#50940) +- Add a link to the Airflow logo in Nav (#50304) +- UI: Bump minor and patch package json dependencies (#50298) +- Added a direct link to the latest DAG run in the DAG header (#51119,#51148) +- Fetch only the most recent ``dagrun`` value for list display (#50834) +- Move ``secret_key`` config to ``api`` section (#50839) +- Move various ``webserver`` configs to ``fab`` provider (#50774,#50269,#50208,#50896) +- Make ``dag_run`` nullable in Details page (#50719) +- Rename Operation IDs for task instance endpoints to include map indexes (#49608) +- Update default sort for connections and dags (#50600) +- Raise exception if downgrade can't proceed due to no ``ab_user`` table (#50343) +- Enable JSON serialization for variables created via the bulk API (#51057) +- Always display the backfill option in the UI; enable it only for DAGs with a defined schedule (#50969) +- Optimized DAG header to fetch only the most recent DAG run for improved performance (#50767) +- Add ``owner_links`` field to ``DAGDetailsResponse`` for enhanced owner metadata in the API (#50557) +- UI: Move map index column to be in line with other columns when viewing a summary mapped tasks (#50302) +- Separate configurations for colorized and json logs in Task SDK / Celery Executor (#51082) +- Enhanced task log viewer with virtualized rendering for improved performance on large logs (#50746) + +Doc Only Changes +"""""""""""""""" + +- Add dates for Limited Maintenance & EOL for Airflow 2.x (#50794) +- Add Apache Airflow setup instructions for Apple Silicon (#50179) +- Update recommendation for upgrade path to airflow 3 (#50318) +- Add "disappearing DAGs" section on FAQ doc (#49987) +- Update Airflow 3 migration guide with step about custom operators (#50871) (#50948) +- Use ``AssetAlias`` for alias in Asset ``Metadata`` example (#50768) +- Do not use outdated ``schedule_interval`` in tutorial dags (#50947) +- Add Airflow Version in Page Title (#50358) +- Fix callbacks docs (#50377) +- Updating operator extra links doc (#50197) +- Prune old Airflow versions from release notes (#50860) +- Fix types in config templates reference (#50792) +- Fix wrong import for ``PythonOperator`` in tutorial dag (#50962) +- Better structure of extras documentation (#50495) + +Airflow 3.0.1 (2025-05-12) +-------------------------- + +Significant Changes +^^^^^^^^^^^^^^^^^^^ + +No significant changes. + +Bug Fixes +""""""""" + +- Improves the handling of value masking when setting Airflow variables for enhanced security (#43123) +- Make entire task box clickable to select the task (#49299) +- Vertically align task log header components in full screen mode (#49569) +- Remove ``dag_code`` records with no serialized dag (#49478) +- Clear out the ``dag_code`` and ``serialized_dag`` tables on 3.0 upgrade (#49563) +- Remove extra slash so that the runs tab is selected (#49600) +- Null out the ``scheduler_interval`` field on downgrade (#49583) +- Logout functionality should respect ``base_url`` in api server (#49545) +- Fix bug with showing invalid credentials on Login UI (#49556) +- Fix Dag Code text selection when dark mode is enabled (#49649) +- Bugfix: ``max_active_tis_per_dag`` is not respected by dynamically mapped tasks (#49708) +- Fix infinite redirect caused by mistakenly setting token cookie as secure (#49721) +- Better handle safe url redirects in login form for ``SimpleAuthManager`` (#49697)(#49866) +- API: Add missing ``bundle_version`` to DagRun response (#49726) +- Display bundle version in Dag details tab (#49787) +- Fix gcp remote log module import in airflow local settings (#49788) +- Bugfix: Grid view stops loading when there is a pending task to be expanded (#49772) +- Treat single ``task_ids`` in ``xcom_pull`` the same as multiple when provided as part of a list (#49692) +- UI: Auto refresh Home page stats (#49830) +- UI: Error alert overflows out of the alert box (#49880) +- Show backfill banner after creating a new backfill (#49666) +- Mark ``DAGModel`` stale and associate bundle on import errors to aid migration from 2.10.5 (#49769) +- Improve detection and handling of timed out DAG processor processes (#49868) +- Fix editing port for connections (#50002) +- Improve & Fix grid endpoint response time (#49969) +- Update time duration format (#49914) +- Fix Dashboard overflow and handle no status tasks (#49964) +- Fix timezone setting for logical date input on Trigger Run form (#49662) +- Help ``pip`` with avoiding resolution too deep issues in Python 3.12 (#49853) +- Bugfix: backfill dry run does not use same timezone as create backfill (#49911) +- Fix Edit Connection when connection is imported (#49989) +- Bugfix: Filtering items from a mapped task is broken (#50011) +- Fix Dashboard for queued DagRuns (#49961) +- Fix backwards-compat import path for ``BashSensor`` (#49935) +- Apply task group sorting based on webserver config in grid structure response (#49418) +- Render custom ``map_index_template`` on task completion (#49809) +- Fix ``ContinuousTimetable`` false triggering when last run ends in future (#45175) +- Make Trigger Dag form warning more obvious (#49981) +- Restore task hover and selection indicators in the Grid view (#50050) +- Fix datetime validation for backfills (#50116) +- Fix duration charts (#50094) +- Fix DAG node selections (#50095) +- UI: Fix date range field alignment (#50086) +- Add auto-refresh for ``Stats`` (#50088) +- UI: Fixes validation error and adds error indicator for Params form (#50127) +- fix: wrap overflowing texts of asset events (#50173) +- Add audit log extra to table and improve UX (#50100) +- Handle map indexes for Mapped ``TaskGroup`` (#49996) +- Do not use introspection in migration to fix offline SQL generation (#49873) +- Fix operator extra links for mapped tasks (#50238) +- Fix backfill form (#50249)(#50243) +- UI: Fix operator overflow in graph (#50252) +- UI: Pass ``mapIndex`` to clear the relevant task instances. (#50256) +- Fix markdown rendering on dag docs (#50142) + +Miscellaneous +""""""""""""" + +- Add ``STRAIGHT_JOIN`` prefix for MySQL query optimization in ``get_sorted_triggers`` (#46303) +- Ensure ``sqlalchemy[asyncio]`` extra is in core deps (#49452) +- Remove unused constant ``HANDLER_SUPPORTS_TRIGGERER`` (#49370) +- Remove sort indicators on XCom table to avoid confusion (#49547) +- Remove ``gitpython`` as a core dependency (#49537) +- Bump ``@babel/runtime`` from ``7.26.0`` to ``7.27.0`` (#49479) +- Add backwards compatibility shim for ``get_current_context`` (#49630) +- AIP-38: enhance layout for ``RunBackfillForm`` (#49609) +- AIP-38: merge Backfill and Trigger Dag Run (#49490) +- Add count to Stats Cards in Dashboard (#49519) +- Add auto-refresh to health section for live updates. (#49645) +- Tweak Execution API OpenAPI spec to improve code Generation (#49700) +- Stricter validation for ``backfill_id`` (#49691)(#49716) +- Add ``SimpleAllAdminMiddleware`` to allow api usage without auth header in request (#49599) +- Bump ``react-router`` and ``react-router-dom`` from 7.4.0 to 7.5.2 (#49742) +- Remove reference to ``root_dag_id`` in dagbag and restore logic (#49668) +- Fix a few SqlAlchemy deprecation warnings (#49477) +- Make default execution server URL be relative to API Base URL (#49747)(#49782) +- Common ``airflow.cfg`` files across all containers in default ``docker-compose.yaml`` (#49681) +- Add redirects for old operators location to standard provider (#49776) +- Bump packaging from 24.2 to 25.0 in ``/airflow-core`` (#49512) +- Move some non-core dependencies to the ``apache-airflow`` meta package (#49846) +- Add more lower-bind limits to address resolution too deep (#49860) +- UI: Add counts to pool bar (#49894) +- Add type hints for ``@task.kuberenetes_cmd`` (#46913) +- Bump ``vite`` from ``5.4.17`` to ``5.4.19`` for Airflow UI (#49162)(#50074) +- Add ``map_index`` filter option to ``GetTICount`` and ``GetTaskStates`` (#49818) +- Add ``stats`` ui endpoint (#49985) +- Add link to tag to filter dags associated with the tag (#49680) +- Add keyboard shortcut for full screen and wrap in logs. (#50008) +- Update graph node styling to decrease border width on tasks in UI (#50047) (#50073) +- Allow non-string valid JSON values in Variable import. (#49844) +- Bump min versions of crucial providers (#50076) +- Add ``state`` attribute to ``RuntimeTaskInstance`` for easier ``ti.state`` access in Task Context (#50031) +- Move SQS message queue to Amazon provider (#50057) +- Execution API: Improve task instance logging with structlog context (#50120) +- Add ``dag_run_conf`` to ``RunBackfillForm`` (#49763) +- Refactor Dashboard to enhance layout (#50026) +- Add the download button on the assets page (#50045) +- Add ``dateInterval`` validation and error handling (#50072) +- Add ``Task Instances [{map_index}]`` tab to mapped task details (#50085) +- Add focus view on grid and graph on second click (#50125) +- Add formatted extra to asset events (#50124) +- Move webserver expose config to api section (#50209) + +Doc Only Changes +"""""""""""""""" + +- Remove flask application configuration from docs for AF3 (#49393) +- Docker compose: airflow-cli to depend on airflow common services (#49318) +- Better upgrade docs about flask/fab plugins in Airflow 3 (#49632)(#49614)(#49628) +- Various Airflow 3.0 Release notes & Updating guide docs updates (#49623)(#49401)(#49654)(#49663)(#49988)(#49954)(#49840)(#50195)(#50264) +- Add using the rest api by referring to ``security/api.rst`` (#49675) +- Add correct redirects for rest api and upgrade docs (#49764) +- Update ``max_consecutive_failed_dag_runs`` default value to zero in TaskSDK dag (#49795) (#49803) +- Fix spacing issues in params example dag (``example_params_ui_tutorial``) (#49905) +- Doc: Fix Kubernetes duplicated version in maintenance policy (#50030) +- Fix links to source examples in Airflow docs (#50082) +- Update ruff instructions for migration checks (#50232) +- Fix example of backfill command (#50222) +- Update docs for running behind proxy for Content-Security-Policy (#50236) + Airflow 3.0.0 (2025-04-22) -------------------------- -We are proud to announce the General Availability of **Apache Airflow® 3.0**, the most significant release in the -project's history. Airflow 3.0 builds on the foundation of Airflow 2 and introduces a new service-oriented architecture, -a modern React-based UI, enhanced security, and a host of long-requested features such as DAG versioning, improved -backfills, event-driven scheduling, and support for remote execution. +We are proud to announce the General Availability of Apache Airflow 3.0 — the most significant release in the project's +history. This version introduces a service-oriented architecture, a stable DAG authoring interface, expanded support for +event-driven and ML workflows, and a fully modernized UI built on React. Airflow 3.0 reflects years of community +investment and lays the foundation for the next era of scalable, modular orchestration. Highlights ^^^^^^^^^^ -Major Architectural Advancements -"""""""""""""""""""""""""""""""" +- **Service-Oriented Architecture**: A new Task Execution API and ``airflow api-server`` enable task execution in remote environments with improved isolation and flexibility (AIP-72). -- **Task Execution API & Task SDK (AIP-72)**: Airflow 3.0 introduces a service-oriented architecture and a new API Server, enabling tasks to run anywhere, in any language, with improved isolation and security. -- **Edge Executor (AIP-69)**: A new experimental executor that enables edge compute patterns and event-driven orchestration scenarios. -- **Split CLI (AIP-81)**: The core CLI is now divided between local and remote functionality, with a new provider package (``airflowctl``) for API-based remote interactions. +- **Edge Executor**: A new executor that supports distributed, event-driven, and edge-compute workflows (AIP-69), now generally available. -UI Overhaul -""""""""""" +- **Stable Authoring Interface**: DAG authors should now use the new ``airflow.sdk`` namespace to import core DAG constructs like ``@dag``, ``@task``, and ``DAG``. -- **Modern React UI (AIP-38, AIP-84)**: Airflow's UI has been completely rewritten using React and FastAPI. This new UI supports a better UX across Grid, Graph, and Asset views. -- **DAG Versioning (AIP-65, AIP-66)**: DAG structure changes are now tracked natively. Users can inspect DAG history directly from the UI. +- **Scheduler-Managed Backfills**: Backfills are now scheduled and tracked like regular DAG runs, with native UI and API support (AIP-78). -Expanded Scheduling and Execution -""""""""""""""""""""""""""""""""" +- **DAG Versioning**: Airflow now tracks structural changes to DAGs over time, enabling inspection of historical DAG definitions via the UI and API (AIP-66). -- **Data Assets & Asset-Driven DAGs (AIP-74, AIP-75)**: Data-aware scheduling has evolved into first-class Asset support, including a new ``@asset`` decorator syntax and asset-based execution. -- **External Event Scheduling (AIP-82)**: DAGs can now be triggered from external events via a pluggable message bus interface. Initial support for AWS SQS is included. -- **Scheduler-Managed Backfills (AIP-78)**: Backfills are now managed by the scheduler, with UI support and enhanced diagnostics. +- **Asset-Based Scheduling**: The dataset model has been renamed and redesigned as assets, with a new ``@asset`` decorator and cleaner event-driven DAG definition (AIP-74, AIP-75). -ML & AI Use Cases -""""""""""""""""" +- **Support for ML and AI Workflows**: DAGs can now run with ``logical_date=None``, enabling use cases such as model inference, hyperparameter tuning, and non-interval workflows (AIP-83). -- **Support for Non-Data-Interval DAGs (AIP-83)**: Enables inference DAGs and hyperparameter tuning runs by removing the uniqueness constraint on execution dates. +- **Removal of Legacy Features**: SLAs, SubDAGs, DAG and Xcom pickling, and several internal context variables have been removed. Use the upgrade tools to detect deprecated usage. -Breaking Changes -^^^^^^^^^^^^^^^^ +- **Split CLI and API Changes**: The CLI has been split into ``airflow`` and ``airflowctl`` (AIP-81), and REST API now defaults to ``logical_date=None`` when triggering a new DAG run. -See the :doc:`Upgrade Guide ` for a full list of changes and migration recommendations. Major breaking changes include: +- **Modern React UI**: A complete UI overhaul built on React and FastAPI includes version-aware views, backfill management, and improved DAG and task introspection (AIP-38, AIP-84). -Metadata Database Access -"""""""""""""""""""""""" +- **Migration Tooling**: Use **ruff** and **airflow config update** to validate DAGs and configurations. Upgrade requires Airflow 2.7 or later and Python 3.9–3.12. + +Significant Changes +^^^^^^^^^^^^^^^^^^^ + +Airflow 3.0 introduces the most significant set of changes since the 2.0 release, including architectural shifts, new +execution models, and improvements to DAG authoring and scheduling. + +Task Execution API & Task SDK (AIP-72) +"""""""""""""""""""""""""""""""""""""" -- Direct access to the metadata DB from task code is no longer supported. Use the :doc:`REST API ` instead. +Airflow now supports a service-oriented architecture, enabling tasks to be executed remotely via a new Task Execution +API. This API decouples task execution from the scheduler and introduces a stable contract for running tasks outside of +Airflow's traditional runtime environment. -Scheduling Changes -"""""""""""""""""" +To support this, Airflow introduces the Task SDK — a lightweight runtime environment for running Airflow tasks in +external systems such as containers, edge environments, or other runtimes. This lays the groundwork for +language-agnostic task execution and brings improved isolation, portability, and extensibility to Airflow-based +workflows. -- New default: ``schedule=None``, ``catchup=False`` -- ``schedule_interval`` and ``timetable`` are removed; use ``schedule`` exclusively. -- Raw cron strings now use ``CronTriggerTimetable`` instead of ``CronDataIntervalTimetable``. +Airflow 3.0 also introduces a new ``airflow.sdk`` namespace that exposes the core authoring interfaces for defining DAGs +and tasks. DAG authors should now import objects like ``DAG``, ``@dag``, and ``@task`` from ``airflow.sdk`` rather than +internal modules. This new namespace provides a stable, forward-compatible interface for DAG authoring across future +versions of Airflow. -Context and Parameters +Edge Executor (AIP-69) """""""""""""""""""""" -- Several context variables removed (``conf``, ``execution_date``, ``dag_run.external_trigger``, etc) -- ``fail_stop`` renamed to ``fail_fast`` -- ``.airflowignore`` now uses glob syntax by default +Airflow 3.0 introduces the **Edge Executor** as a generally available feature, enabling execution of tasks in +distributed or remote compute environments. Designed for event-driven and edge-compute use cases, the Edge Executor +integrates with the Task Execution API to support task orchestration beyond the traditional Airflow runtime. This +advancement facilitates hybrid and cross-environment orchestration patterns, allowing task workers to operate closer to +data or application layers. -Deprecated and Removed Features -""""""""""""""""""""""""""""""" +Scheduler-Managed Backfills (AIP-78) +"""""""""""""""""""""""""""""""""""" -+-----------------------------+----------------------------------------------------------+ -| **Feature** | **Replacement** | -+=============================+==========================================================+ -| SubDAGs | Task Groups | -+-----------------------------+----------------------------------------------------------+ -| SLAs | Deadline Alerts (planned post-3.0) | -+-----------------------------+----------------------------------------------------------+ -| ``EmailOperator`` (core) | SMTP provider's ``EmailOperator`` | -+-----------------------------+----------------------------------------------------------+ -| ``dummy`` trigger rule | ``always`` | -+-----------------------------+----------------------------------------------------------+ -| ``none_failed_or_skipped`` | ``none_failed_min_one_success`` | -+-----------------------------+----------------------------------------------------------+ -| XCom pickling | Use a custom XCom backend | -+-----------------------------+----------------------------------------------------------+ +Backfills are now fully managed by the scheduler, rather than being launched as separate command-line jobs. This change +unifies backfill logic with regular DAG execution and ensures that backfill runs follow the same scheduling, versioning, +and observability models as other DAG runs. -Upgrade Process -^^^^^^^^^^^^^^^ +Airflow 3.0 also introduces native UI and REST API support for initiating and monitoring backfills, making them more +accessible and easier to integrate into automated workflows. These improvements lay the foundation for smarter, safer +historical reprocessing — now available directly through the Airflow UI and API. -Airflow 3 was designed with migration in mind. Many Airflow 2 DAGs will work without changes. Use these tools: +DAG Versioning (AIP-66) +""""""""""""""""""""""" -- ``ruff check --preview --select AIR30 --fix``: Flag and auto-fix DAG-level changes -- ``airflow config lint``: Identify outdated or removed config options +Airflow 3.0 introduces native DAG versioning. DAG structure changes (e.g., renamed tasks, dependency shifts) are now +tracked directly in the metadata database. This allows users to inspect historical DAG structures through the UI and API, +and lays the foundation for safer backfills, improved observability, and runtime-determined DAG logic. -**Minimum version required to upgrade**: Airflow 2.7 +React UI Rewrite (AIP-38, AIP-84) +""""""""""""""""""""""""""""""""" -We recommend upgrading to the latest Airflow 2.10.x release before migrating to Airflow 3.0 to benefit from deprecation warnings. Check :doc:`Upgrade Guide ` for more details. +Airflow 3.0 ships with a completely redesigned user interface built on React and FastAPI. This modern architecture +improves responsiveness, enables more consistent navigation across views, and unlocks new UI capabilities — including +support for DAG versioning, asset-centric DAG definitions, and more intuitive filtering and search. -Resources -^^^^^^^^^ +The new UI replaces the legacy Flask-based frontend and introduces a foundation for future extensibility and community +contributions. -- :doc:`Upgrade Guide ` -- `Airflow AIPs `_ +Asset-Based Scheduling & Terminology Alignment (AIP-74, AIP-75) +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Airflow 2.10.5 (2025-02-10) ---------------------------- +The concept of **Datasets** has been renamed to **Assets**, unifying terminology with common practices in the modern +data ecosystem. The internal model has also been reworked to better support future features like asset partitions and +validations. -Significant Changes -^^^^^^^^^^^^^^^^^^^ +The ``@asset`` decorator and related changes to the DAG parser enable clearer, asset-centric DAG definitions, allowing +Airflow to more naturally support event-driven and data-aware scheduling patterns. -Ensure teardown tasks are executed when DAG run is set to failed (#45530) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +This renaming impacts modules, classes, functions, configuration keys, and internal models. Key changes include: -Previously when a DAG run was manually set to "failed" or to "success" state the terminal state was set to all tasks. -But this was a gap for cases when setup- and teardown tasks were defined: If teardown was used to clean-up infrastructure -or other resources, they were also skipped and thus resources could stay allocated. +- ``Dataset`` → ``Asset`` +- ``DatasetEvent`` → ``AssetEvent`` +- ``DatasetAlias`` → ``AssetAlias`` +- ``airflow.datasets.*`` → ``airflow.sdk.*`` +- ``airflow.timetables.simple.DatasetTriggeredTimetable`` → ``airflow.timetables.simple.AssetTriggeredTimetable`` +- ``airflow.timetables.datasets.DatasetOrTimeSchedule`` → ``airflow.timetables.assets.AssetOrTimeSchedule`` +- ``airflow.listeners.spec.dataset.on_dataset_created`` → ``airflow.listeners.spec.asset.on_asset_created`` +- ``airflow.listeners.spec.dataset.on_dataset_changed`` → ``airflow.listeners.spec.asset.on_asset_changed`` +- ``core.dataset_manager_class`` → ``core.asset_manager_class`` +- ``core.dataset_manager_kwargs`` → ``core.asset_manager_kwargs`` -As of now when setup tasks had been executed before and the DAG is manually set to "failed" or "success" then teardown -tasks are executed. Teardown tasks are skipped if the setup was also skipped. +Unified Scheduling Field +"""""""""""""""""""""""" -As a side effect this means if the DAG contains teardown tasks, then the manual marking of DAG as "failed" or "success" -will need to keep the DAG in running state to ensure that teardown tasks will be scheduled. They would not be scheduled -if the DAG is directly set to "failed" or "success". +Airflow 3.0 removes the legacy ``schedule_interval`` and ``timetable`` parameters. DAGs must now use the unified +``schedule`` field for all time- and event-based scheduling logic. This simplifies DAG definition and improves +consistency across scheduling paradigms. +Updated Scheduling Defaults +""""""""""""""""""""""""""" -Bug Fixes -""""""""" +Airflow 3.0 changes the default behavior for new DAGs by setting ``catchup_by_default = False`` in the configuration +file. This means DAGs that do not explicitly set ``catchup=...`` will no longer backfill missed intervals by default. +This change reduces confusion for new users and better reflects the growing use of on-demand and event-driven workflows. -- Prevent using ``trigger_rule=TriggerRule.ALWAYS`` in a task-generated mapping within bare tasks (#44751) -- Fix ShortCircuitOperator mapped tasks (#44912) -- Fix premature evaluation of tasks with certain trigger rules (e.g. ``ONE_DONE``) in a mapped task group (#44937) -- Fix task_id validation in BaseOperator (#44938) (#44938) -- Allow fetching XCom with forward slash from the API and escape it in the UI (#45134) -- Fix ``FileTaskHandler`` only read from default executor (#46000) -- Fix empty task instance for log (#45702) (#45703) -- Remove ``skip_if`` and ``run_if`` decorators before TaskFlow virtualenv tasks are run (#41832) (#45680) -- Fix request body for json requests in event log (#45546) (#45560) -- Ensure teardown tasks are executed when DAG run is set to failed (#45530) (#45581) -- Do not update DR on TI update after task execution (#45348) -- Fix object and array DAG params that have a None default (#45313) (#45315) -- Fix endless sensor rescheduling (#45224) (#45250) -- Evaluate None in SQLAlchemy's extended JSON type decorator (#45119) (#45120) -- Allow dynamic tasks to be filtered by ``rendered_map_index`` (#45109) (#45122) -- Handle relative paths when sanitizing URLs (#41995) (#45080) -- Set Autocomplete Off on Login Form (#44929) (#44940) -- Add Webserver parameters ``max_form_parts``, ``max_form_memory_size`` (#46243) (#45749) -- Fixed accessing thread local variable in BaseOperators ``execute`` safeguard mechanism (#44646) (#46280) -- Add map_index parameter to extra links API (#46337) +The default DAG schedule has been changed to ``None`` from ``@once``. +Restricted Metadata Database Access +""""""""""""""""""""""""""""""""""" -Miscellaneous -""""""""""""" +Task code can no longer directly access the metadata database. Interactions with DAG state, task history, or DAG runs +must be performed via the Airflow REST API or exposed context. This change improves architectural separation and enables +remote execution. -- Add traceback log output when SIGTERMs was sent (#44880) (#45077) -- Removed the ability for Operators to specify their own "scheduling deps" (#45713) (#45742) -- Deprecate ``conf`` from Task Context (#44993) +Future Logical Dates No Longer Supported +""""""""""""""""""""""""""""""""""""""""" +Airflow no longer supports triggering DAG runs with a logical date in the future. This change aligns with the logical +execution model and removes ambiguity in backfills and event-driven DAGs. Use ``logical_date=None`` to trigger runs with +the current timestamp. -Airflow 2.10.4 (2024-12-16) ---------------------------- +Context Behavior for Asset and Manually Triggered DAGs +"""""""""""""""""""""""""""""""""""""""""""""""""""""" -Significant Changes -^^^^^^^^^^^^^^^^^^^ +For DAG runs triggered by an Asset event or through the REST API without specifying a ``logical_date``, Airflow now sets +``logical_date=None`` by default. These DAG runs do not have a data interval, and attempting to access +``data_interval_start``, ``data_interval_end``, or ``logical_date`` from the task context will raise a ``KeyError``. -TaskInstance ``priority_weight`` is capped in 32-bit signed integer ranges (#43611) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +DAG authors should use ``dag_run.logical_date`` and perform appropriate checks or fallbacks if supporting multiple +trigger types. This change improves consistency with event-driven semantics but may require updates to existing DAGs +that assume these values are always present. -Some database engines are limited to 32-bit integer values. As some users reported errors in -weight rolled-over to negative values, we decided to cap the value to the 32-bit integer. Even -if internally in python smaller or larger values to 64 bit are supported, ``priority_weight`` is -capped and only storing values from -2147483648 to 2147483647. +Improved Callback Behavior +"""""""""""""""""""""""""" -Bug Fixes -^^^^^^^^^ +Airflow 3.0 refines task callback behavior to improve clarity and consistency. In particular, ``on_success_callback`` is +no longer executed when a task is marked as ``SKIPPED``, aligning it more closely with expected semantics. -- Fix stats of dynamic mapped tasks after automatic retries of failed tasks (#44300) -- Fix wrong display of multi-line messages in the log after filtering (#44457) -- Allow "/" in metrics validator (#42934) (#44515) -- Fix gantt flickering (#44488) (#44517) -- Fix problem with inability to remove fields from Connection form (#40421) (#44442) -- Check pool_slots on partial task import instead of execution (#39724) (#42693) -- Avoid grouping task instance stats by try_number for dynamic mapped tasks (#44300) (#44319) -- Re-queue task when they are stuck in queued (#43520) (#44158) -- Suppress the warnings where we check for sensitive values (#44148) (#44167) -- Fix get_task_instance_try_details to return appropriate schema (#43830) (#44133) -- Log message source details are grouped (#43681) (#44070) -- Fix duplication of Task tries in the UI (#43891) (#43950) -- Add correct mime-type in OpenAPI spec (#43879) (#43901) -- Disable extra links button if link is null or empty (#43844) (#43851) -- Disable XCom list ordering by execution_date (#43680) (#43696) -- Fix venv numpy example which needs to be 1.26 at least to be working in Python 3.12 (#43659) -- Fix Try Selector in Mapped Tasks also on Index 0 (#43590) (#43591) -- Prevent using ``trigger_rule="always"`` in a dynamic mapped task (#43810) -- Prevent using ``trigger_rule=TriggerRule.ALWAYS`` in a task-generated mapping within bare tasks (#44751) +Updated Default Configuration +""""""""""""""""""""""""""""" -Doc Only Changes -"""""""""""""""" -- Update XCom docs around containers/helm (#44570) (#44573) +Several default configuration values have been updated in Airflow 3.0 to better reflect modern usage patterns and +simplify onboarding: -Miscellaneous -""""""""""""" -- Raise deprecation warning when accessing inlet or outlet events through str (#43922) +- ``catchup_by_default`` is now set to ``False`` by default. DAGs will not automatically backfill unless explicitly configured to do so. +- ``create_cron_data_intervals`` is now set to ``False`` by default. As a result, cron expressions will be interpreted using the ``CronTriggerTimetable`` instead of the legacy ``CronDataIntervalTimetable``. +- ``SimpleAuthManager`` is now the default ``auth_manager``. To continue using Flask AppBuilder-based authentication, install the ``apache-airflow-providers-flask-appbuilder`` provider and explicitly set ``auth_manager = airflow.providers.fab.auth_manager.FabAuthManager``. +These changes represent the most significant evolution of the Airflow platform since the release of 2.0 — setting the +stage for more scalable, event-driven, and language-agnostic orchestration in the years ahead. -Airflow 2.10.3 (2024-11-05) ---------------------------- +Executor & Scheduler Updates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Significant Changes -^^^^^^^^^^^^^^^^^^^ +Airflow 3.0 introduces several important improvements and behavior changes in how DAGs and tasks are scheduled, +prioritized, and executed. -No significant changes. +Standalone DAG Processor Required +""""""""""""""""""""""""""""""""" -Bug Fixes -""""""""" -- Improves the handling of value masking when setting Airflow variables for enhanced security. (#43123) (#43278) -- Adds support for task_instance_mutation_hook to handle mapped operators with index 0. (#42661) (#43089) -- Fixes executor cleanup to properly handle zombie tasks when task instances are terminated. (#43065) -- Adds retry logic for HTTP 502 and 504 errors in internal API calls to handle webserver startup issues. (#42994) (#43044) -- Restores the use of separate sessions for writing and deleting RTIF data to prevent StaleDataError. (#42928) (#43012) -- Fixes PythonOperator error by replacing hyphens with underscores in DAG names. (#42993) -- Improving validation of task retries to handle None values (#42532) (#42915) -- Fixes error handling in dataset managers when resolving dataset aliases into new datasets (#42733) -- Enables clicking on task names in the DAG Graph View to correctly select the corresponding task. (#38782) (#42697) -- Prevent redirect loop on /home with tags/last run filters (#42607) (#42609) (#42628) -- Support of host.name in OTEL metrics and usage of OTEL_RESOURCE_ATTRIBUTES in metrics (#42428) (#42604) -- Reduce eyestrain in dark mode with reduced contrast and saturation (#42567) (#42583) -- Handle ENTER key correctly in trigger form and allow manual JSON (#42525) (#42535) -- Ensure DAG trigger form submits with updated parameters upon keyboard submit (#42487) (#42499) -- Do not attempt to provide not ``stringified`` objects to UI via xcom if pickling is active (#42388) (#42486) -- Fix the span link of task instance to point to the correct span in the scheduler_job_loop (#42430) (#42480) -- Bugfix task execution from runner in Windows (#42426) (#42478) -- Allows overriding the hardcoded OTEL_SERVICE_NAME with an environment variable (#42242) (#42441) -- Improves trigger performance by using ``selectinload`` instead of ``joinedload`` (#40487) (#42351) -- Suppress warnings when masking sensitive configs (#43335) (#43337) -- Masking configuration values irrelevant to DAG author (#43040) (#43336) -- Execute templated bash script as file in BashOperator (#43191) -- Fixes schedule_downstream_tasks to include upstream tasks for one_success trigger rule (#42582) (#43299) -- Add retry logic in the scheduler for updating trigger timeouts in case of deadlocks. (#41429) (#42651) -- Mark all tasks as skipped when failing a dag_run manually (#43572) -- Fix ``TrySelector`` for Mapped Tasks in Logs and Details Grid Panel (#43566) -- Conditionally add OTEL events when processing executor events (#43558) (#43567) -- Fix broken stat ``scheduler_loop_duration`` (#42886) (#43544) -- Ensure total_entries in /api/v1/dags (#43377) (#43429) -- Include limit and offset in request body schema for List task instances (batch) endpoint (#43479) -- Don't raise a warning in ExecutorSafeguard when execute is called from an extended operator (#42849) (#43577) +Airflow 3.0 now requires the standalone DAG processor to parse DAGs. This dedicated process improves scheduler +performance, isolation, and observability. It also simplifies architecture by clearly separating DAG parsing from +scheduling logic. This change may affect custom deployments that previously used embedded DAG parsing. -Miscellaneous -""""""""""""" -- Deprecate session auth backend (#42911) -- Removed unicodecsv dependency for providers with Airflow version 2.8.0 and above (#42765) (#42970) -- Remove the referrer from Webserver to Scarf (#42901) (#42942) -- Bump ``dompurify`` from 2.2.9 to 2.5.6 in /airflow/www (#42263) (#42270) -- Correct docstring format in _get_template_context (#42244) (#42272) -- Backport: Bump Flask-AppBuilder to ``4.5.2`` (#43309) (#43318) -- Check python version that was used to install pre-commit venvs (#43282) (#43310) -- Resolve warning in Dataset Alias migration (#43425) +Priority Weight Capped by Pool Slots +""""""""""""""""""""""""""""""""""""" -Doc Only Changes -"""""""""""""""" -- Clarifying PLUGINS_FOLDER permissions by DAG authors (#43022) (#43029) -- Add templating info to TaskFlow tutorial (#42992) -- Airflow local settings no longer importable from dags folder (#42231) (#42603) -- Fix documentation for cpu and memory usage (#42147) (#42256) -- Fix instruction for docker compose (#43119) (#43321) -- Updates documentation to reflect that dag_warnings is returned instead of import_errors. (#42858) (#42888) +The ``priority_weight`` value on a task is now capped by the number of available pool slots. This ensures that resource +availability remains the primary constraint in task execution order, preventing high-priority tasks from starving others +when resource contention exists. +Teardown Task Handling During DAG Termination +""""""""""""""""""""""""""""""""""""""""""""" -Airflow 2.10.2 (2024-09-18) ---------------------------- +Teardown tasks will now be executed even when a DAG run is terminated early. This ensures that cleanup logic is +respected, improving reliability for workflows that use teardown tasks to manage ephemeral infrastructure, temporary +files, or downstream notifications. -Significant Changes -^^^^^^^^^^^^^^^^^^^ +Improved Scheduler Fault Tolerance +"""""""""""""""""""""""""""""""""" -No significant changes. +Scheduler components now use ``run_with_db_retries`` to handle transient database issues more gracefully. This enhances +Airflow's fault tolerance in high-volume environments and reduces the likelihood of scheduler restarts due to temporary +database connection problems. -Bug Fixes -""""""""" -- Revert "Fix: DAGs are not marked as stale if the dags folder change" (#42220, #42217) -- Add missing open telemetry span and correct scheduled slots documentation (#41985) -- Fix require_confirmation_dag_change (#42063) (#42211) -- Only treat null/undefined as falsy when rendering XComEntry (#42199) (#42213) -- Add extra and ``renderedTemplates`` as keys to skip ``camelCasing`` (#42206) (#42208) -- Do not ``camelcase`` xcom entries (#42182) (#42187) -- Fix task_instance and dag_run links from list views (#42138) (#42143) -- Support multi-line input for Params of type string in trigger UI form (#40414) (#42139) -- Fix details tab log url detection (#42104) (#42114) -- Add new type of exception to catch timeout (#42064) (#42078) -- Rewrite how DAG to dataset / dataset alias are stored (#41987) (#42055) -- Allow dataset alias to add more than one dataset events (#42189) (#42247) +Mapped Task Stats Accuracy +""""""""""""""""""""""""""" -Miscellaneous -""""""""""""" -- Limit universal-pathlib below ``0.2.4`` as it breaks our integration (#42101) -- Auto-fix default deferrable with ``LibCST`` (#42089) -- Deprecate ``--tree`` flag for ``tasks list`` cli command (#41965) +Airflow 3.0 fixes a bug that caused incorrect task statistics to be reported for dynamic task mapping. Stats now +accurately reflect the number of mapped task instances and their statuses, improving observability and debugging for +dynamic workflows. -Doc Only Changes -"""""""""""""""" -- Update ``security_model.rst`` to clear unauthenticated endpoints exceptions (#42085) -- Add note about dataclasses and attrs to XComs page (#42056) -- Improve docs on markdown docs in DAGs (#42013) -- Add warning that listeners can be dangerous (#41968) +``SequentialExecutor`` has been removed +""""""""""""""""""""""""""""""""""""""" +``SequentialExecutor`` was primarily used for local testing but is now redundant, as ``LocalExecutor`` +supports SQLite with WAL mode and provides better performance with parallel execution. +Users should switch to ``LocalExecutor`` or ``CeleryExecutor`` as alternatives. -Airflow 2.10.1 (2024-09-05) ---------------------------- +DAG Authoring Enhancements +^^^^^^^^^^^^^^^^^^^^^^^^^^ -Significant Changes -^^^^^^^^^^^^^^^^^^^ +Airflow 3.0 includes several changes that improve consistency, clarity, and long-term stability for DAG authors. -No significant changes. +New Stable DAG Authoring Interface: ``airflow.sdk`` +""""""""""""""""""""""""""""""""""""""""""""""""""" -Bug Fixes -""""""""" -- Handle Example dags case when checking for missing files (#41874) -- Fix logout link in "no roles" error page (#41845) -- Set end_date and duration for triggers completed with end_from_trigger as True. (#41834) -- DAGs are not marked as stale if the dags folder change (#41829) -- Fix compatibility with FAB provider versions <1.3.0 (#41809) -- Don't Fail LocalTaskJob on heartbeat (#41810) -- Remove deprecation warning for cgitb in Plugins Manager (#41793) -- Fix log for notifier(instance) without ``__name__`` (#41699) -- Splitting syspath preparation into stages (#41694) -- Adding url sanitization for extra links (#41680) -- Fix InletEventsAccessors type stub (#41607) -- Fix UI rendering when XCom is INT, FLOAT, BOOL or NULL (#41605) -- Fix try selector refresh (#41503) -- Incorrect try number subtraction producing invalid span id for OTEL airflow (#41535) -- Add WebEncoder for trigger page rendering to avoid render failure (#41485) -- Adding ``tojson`` filter to example_inlet_event_extra example dag (#41890) -- Add backward compatibility check for executors that don't inherit BaseExecutor (#41927) +Airflow 3.0 introduces a new, stable public API for DAG authoring under the ``airflow.sdk`` namespace, +available via the ``apache-airflow-task-sdk`` package. + +The goal of this change is to **decouple DAG authoring from Airflow internals** (Scheduler, API Server, etc.), +providing a **forward-compatible, stable interface** for writing and maintaining DAGs across Airflow versions. + +DAG authors should now import core constructs from ``airflow.sdk`` rather than internal modules. + +**Key Imports from** ``airflow.sdk``: + +- Classes: + + - ``Asset`` + - ``BaseNotifier`` + - ``BaseOperator`` + - ``BaseOperatorLink`` + - ``BaseSensorOperator`` + - ``Connection`` + - ``Context`` + - ``DAG`` + - ``EdgeModifier`` + - ``Label`` + - ``ObjectStoragePath`` + - ``Param`` + - ``TaskGroup`` + - ``Variable`` + +- Decorators and Functions: + + - ``@asset`` + - ``@dag`` + - ``@setup`` + - ``@task`` + - ``@task_group`` + - ``@teardown`` + - ``chain`` + - ``chain_linear`` + - ``cross_downstream`` + - ``get_current_context`` + - ``get_parsing_context`` + +For an exhaustive list of available classes, decorators, and functions, check ``airflow.sdk.__all__``. + +All DAGs should update imports to use ``airflow.sdk`` instead of referencing internal Airflow modules directly. +Legacy import paths (e.g., ``airflow.models.dag.DAG``, ``airflow.decorator.task``) are **deprecated** and +will be **removed** in a future Airflow version. Some additional utilities and helper functions +that DAGs sometimes use from ``airflow.utils.*`` and others will be progressively migrated to the Task SDK in future +minor releases. + +These future changes aim to **complete the decoupling** of DAG authoring constructs +from internal Airflow services. DAG authors should expect continued improvements +to ``airflow.sdk`` with no backwards-incompatible changes to existing constructs. + +For example, update: -Miscellaneous -""""""""""""" -- Bump webpack from 5.76.0 to 5.94.0 in /airflow/www (#41879) -- Adding rel property to hyperlinks in logs (#41783) -- Field Deletion Warning when editing Connections (#41504) -- Make Scarf usage reporting in major+minor versions and counters in buckets (#41900) -- Lower down universal-pathlib minimum to 0.2.2 (#41943) -- Protect against None components of universal pathlib xcom backend (#41938) +.. code-block:: python -Doc Only Changes -"""""""""""""""" -- Remove Debian bullseye support (#41569) -- Add an example for auth with ``keycloak`` (#41791) + # Old (Airflow 2.x) + from airflow.models import DAG + from airflow.decorators import task + # New (Airflow 3.x) + from airflow.sdk import DAG, task -Airflow 2.10.0 (2024-08-15) ---------------------------- +Renamed Parameter: ``fail_stop`` → ``fail_fast`` +""""""""""""""""""""""""""""""""""""""""""""""""" -Significant Changes -^^^^^^^^^^^^^^^^^^^ +The DAG argument ``fail_stop`` has been renamed to ``fail_fast`` for improved clarity. This parameter controls whether a +DAG run should immediately stop execution when a task fails. DAG authors should update any code referencing +``fail_stop`` to use the new name. -Scarf based telemetry: Airflow now collect telemetry data (#39510) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Airflow integrates Scarf to collect basic usage data during operation. Deployments can opt-out of data collection by -setting the ``[usage_data_collection]enabled`` option to ``False``, or the ``SCARF_ANALYTICS=false`` environment variable. +Context Cleanup and Parameter Removal +""""""""""""""""""""""""""""""""""""" -Datasets no longer trigger inactive DAGs (#38891) -""""""""""""""""""""""""""""""""""""""""""""""""" +Several legacy context variables have been removed or may no longer be available in certain types of DAG runs, +including: -Previously, when a DAG is paused or removed, incoming dataset events would still -trigger it, and the DAG would run when it is unpaused or added back in a DAG -file. This has been changed; a DAG's dataset schedule can now only be satisfied -by events that occur when the DAG is active. While this is a breaking change, -the previous behavior is considered a bug. +- ``conf`` +- ``execution_date`` +- ``dag_run.external_trigger`` -The behavior of time-based scheduling is unchanged, including the timetable part -of ``DatasetOrTimeSchedule``. +In asset-triggered and manually triggered DAG runs with ``logical_date=None``, data interval fields such as +``data_interval_start`` and ``data_interval_end`` may not be present in the task context. DAG authors should use +explicit references such as ``dag_run.logical_date`` and conditionally check for the presence of interval-related fields +where applicable. -``try_number`` is no longer incremented during task execution (#39336) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Task Context Utilities Moved +"""""""""""""""""""""""""""" -Previously, the try number (``try_number``) was incremented at the beginning of task execution on the worker. This was problematic for many reasons. -For one it meant that the try number was incremented when it was not supposed to, namely when resuming from reschedule or deferral. And it also resulted in -the try number being "wrong" when the task had not yet started. The workarounds for these two issues caused a lot of confusion. +Internal task context functions such as ``get_parsing_context`` have been moved to a more appropriate location (e.g., +``airflow.models.taskcontext``). DAG authors using these utilities directly should update import paths accordingly. -Now, instead, the try number for a task run is determined at the time the task is scheduled, and does not change in flight, and it is never decremented. -So after the task runs, the observed try number remains the same as it was when the task was running; only when there is a "new try" will the try number be incremented again. +Trigger Rule Restrictions +""""""""""""""""""""""""" -One consequence of this change is, if users were "manually" running tasks (e.g. by calling ``ti.run()`` directly, or command line ``airflow tasks run``), -try number will no longer be incremented. Airflow assumes that tasks are always run after being scheduled by the scheduler, so we do not regard this as a breaking change. +The ``TriggerRule.ALWAYS`` rule can no longer be used with teardown tasks or tasks that are expected to honor upstream +dependency semantics. DAG authors should ensure that teardown logic is defined with the appropriate trigger rules for +consistent task resolution behavior. -``/logout`` endpoint in FAB Auth Manager is now CSRF protected (#40145) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Asset Aliases for Reusability +""""""""""""""""""""""""""""" -The ``/logout`` endpoint's method in FAB Auth Manager has been changed from ``GET`` to ``POST`` in all existing -AuthViews (``AuthDBView``, ``AuthLDAPView``, ``AuthOAuthView``, ``AuthOIDView``, ``AuthRemoteUserView``), and -now includes CSRF protection to enhance security and prevent unauthorized logouts. +A new utility function, ``create_asset_aliases()``, allows DAG authors to define reusable aliases for frequently +referenced Assets. This improves modularity and reuse across DAG files and is particularly helpful for teams adopting +asset-centric DAGs. -OpenTelemetry Traces for Apache Airflow (#37948). -""""""""""""""""""""""""""""""""""""""""""""""""" -This new feature adds capability for Apache Airflow to emit 1) airflow system traces of scheduler, -triggerer, executor, processor 2) DAG run traces for deployed DAG runs in OpenTelemetry format. Previously, only metrics were supported which emitted metrics in OpenTelemetry. -This new feature will add richer data for users to use OpenTelemetry standard to emit and send their trace data to OTLP compatible endpoints. +Operator Links interface changed +"""""""""""""""""""""""""""""""" -Decorator for Task Flow ``(@skip_if, @run_if)`` to make it simple to apply whether or not to skip a Task. (#41116) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This feature adds a decorator to make it simple to skip a Task. +The Operator Extra links, which can be defined either via plugins or custom operators +now do not execute any user code in the Airflow UI, but instead push the "full" +links to XCom backend and the link is fetched from the XCom backend when viewing +task details, for example from grid view. -Using Multiple Executors Concurrently (#40701) -"""""""""""""""""""""""""""""""""""""""""""""" -Previously known as hybrid executors, this new feature allows Airflow to use multiple executors concurrently. DAGs, or even individual tasks, can be configured -to use a specific executor that suits its needs best. A single DAG can contain tasks all using different executors. Please see the Airflow documentation for -more details. Note: This feature is still experimental. See `documentation on Executor `_ for a more detailed description. +Example for users with custom links class: -New Features -"""""""""""" -- AIP-61 Hybrid Execution (`AIP-61 `_) -- AIP-62 Getting Lineage from Hook Instrumentation (`AIP-62 `_) -- AIP-64 TaskInstance Try History (`AIP-64 `_) -- AIP-44 Internal API (`AIP-44 `_) -- Enable ending the task directly from the triggerer without going into the worker. (#40084) -- Extend dataset dependencies (#40868) -- Feature/add token authentication to internal api (#40899) -- Add DatasetAlias to support dynamic Dataset Event Emission and Dataset Creation (#40478) -- Add example DAGs for inlet_events (#39893) -- Implement ``accessors`` to read dataset events defined as inlet (#39367) -- Decorator for Task Flow, to make it simple to apply whether or not to skip a Task. (#41116) -- Add start execution from triggerer support to dynamic task mapping (#39912) -- Add try_number to log table (#40739) -- Added ds_format_locale method in macros which allows localizing datetime formatting using Babel (#40746) -- Add DatasetAlias to support dynamic Dataset Event Emission and Dataset Creation (#40478, #40723, #40809, #41264, #40830, #40693, #41302) -- Use sentinel to mark dag as removed on re-serialization (#39825) -- Add parameter for the last number of queries to the DB in DAG file processing stats (#40323) -- Add prototype version dark mode for Airflow UI (#39355) -- Add ability to mark some tasks as successful in ``dag test`` (#40010) -- Allow use of callable for template_fields (#37028) -- Filter running/failed and active/paused dags on the home page(#39701) -- Add metrics about task CPU and memory usage (#39650) -- UI changes for DAG Re-parsing feature (#39636) -- Add Scarf based telemetry (#39510, #41318) -- Add dag re-parsing request endpoint (#39138) -- Redirect to new DAGRun after trigger from Grid view (#39569) -- Display ``endDate`` in task instance tooltip. (#39547) -- Implement ``accessors`` to read dataset events defined as inlet (#39367, #39893) -- Add color to log lines in UI for error and warnings based on keywords (#39006) -- Add Rendered k8s pod spec tab to ti details view (#39141) -- Make audit log before/after filterable (#39120) -- Consolidate grid collapse actions to a single full screen toggle (#39070) -- Implement Metadata to emit runtime extra (#38650) -- Add executor field to the DB and parameter to the operators (#38474) -- Implement context accessor for DatasetEvent extra (#38481) -- Add dataset event info to dag graph (#41012) -- Add button to toggle datasets on/off in dag graph (#41200) -- Add ``run_if`` & ``skip_if`` decorators (#41116) -- Add dag_stats rest api endpoint (#41017) -- Add listeners for Dag import errors (#39739) -- Allowing DateTimeSensorAsync, FileSensor and TimeSensorAsync to start execution from trigger during dynamic task mapping (#41182) +.. code-block:: python + @attr.s(auto_attribs=True) + class CustomBaseIndexOpLink(BaseOperatorLink): + """Custom Operator Link for Google BigQuery Console.""" -Improvements -"""""""""""" -- Allow set Dag Run resource into Dag Level permission: extends Dag's access_control feature to allow Dag Run resource permissions. (#40703) -- Improve security and error handling for the internal API (#40999) -- Datasets UI Improvements (#40871) -- Change DAG Audit log tab to Event Log (#40967) -- Make standalone dag file processor works in DB isolation mode (#40916) -- Show only the source on the consumer DAG page and only triggered DAG run in the producer DAG page (#41300) -- Update metrics names to allow multiple executors to report metrics (#40778) -- Format DAG run count (#39684) -- Update styles for ``renderedjson`` component (#40964) -- Improve ATTRIBUTE_REMOVED sentinel to use class and more context (#40920) -- Make XCom display as react json (#40640) -- Replace usages of task context logger with the log table (#40867) -- Rollback for all retry exceptions (#40882) (#40883) -- Support rendering ObjectStoragePath value (#40638) -- Add try_number and map_index as params for log event endpoint (#40845) -- Rotate fernet key in batches to limit memory usage (#40786) -- Add gauge metric for 'last_num_of_db_queries' parameter (#40833) -- Set parallelism log messages to warning level for better visibility (#39298) -- Add error handling for encoding the dag runs (#40222) -- Use params instead of dag_run.conf in example DAG (#40759) -- Load Example Plugins with Example DAGs (#39999) -- Stop deferring TimeDeltaSensorAsync task when the target_dttm is in the past (#40719) -- Send important executor logs to task logs (#40468) -- Open external links in new tabs (#40635) -- Attempt to add ReactJSON view to rendered templates (#40639) -- Speeding up regex match time for custom warnings (#40513) -- Refactor DAG.dataset_triggers into the timetable class (#39321) -- add next_kwargs to StartTriggerArgs (#40376) -- Improve UI error handling (#40350) -- Remove double warning in CLI when config value is deprecated (#40319) -- Implement XComArg concat() (#40172) -- Added ``get_extra_dejson`` method with nested parameter which allows you to specify if you want the nested json as string to be also deserialized (#39811) -- Add executor field to the task instance API (#40034) -- Support checking for db path absoluteness on Windows (#40069) -- Introduce StartTriggerArgs and prevent start trigger initialization in scheduler (#39585) -- Add task documentation to details tab in grid view (#39899) -- Allow executors to be specified with only the class name of the Executor (#40131) -- Remove obsolete conditional logic related to try_number (#40104) -- Allow Task Group Ids to be passed as branches in BranchMixIn (#38883) -- Javascript connection form will apply CodeMirror to all textarea's dynamically (#39812) -- Determine needs_expansion at time of serialization (#39604) -- Add indexes on dag_id column in referencing tables to speed up deletion of dag records (#39638) -- Add task failed dependencies to details page (#38449) -- Remove webserver try_number adjustment (#39623) -- Implement slicing in lazy sequence (#39483) -- Unify lazy db sequence implementations (#39426) -- Add ``__getattr__`` to task decorator stub (#39425) -- Allow passing labels to FAB Views registered via Plugins (#39444) -- Simpler error message when trying to offline migrate with sqlite (#39441) -- Add soft_fail to TriggerDagRunOperator (#39173) -- Rename "dataset event" in context to use "outlet" (#39397) -- Resolve ``RemovedIn20Warning`` in ``airflow task`` command (#39244) -- Determine fail_stop on client side when db isolated (#39258) -- Refactor cloudpickle support in Python operators/decorators (#39270) -- Update trigger kwargs migration to specify existing_nullable (#39361) -- Allowing tasks to start execution directly from triggerer without going to worker (#38674) -- Better ``db migrate`` error messages (#39268) -- Add stacklevel into the ``suppress_and_warn`` warning (#39263) -- Support searching by dag_display_name (#39008) -- Allow sort by on all fields in MappedInstances.tsx (#38090) -- Expose count of scheduled tasks in metrics (#38899) -- Use ``declarative_base`` from ``sqlalchemy.orm`` instead of ``sqlalchemy.ext.declarative`` (#39134) -- Add example DAG to demonstrate emitting approaches (#38821) -- Give ``on_task_instance_failed`` access to the error that caused the failure (#38155) -- Simplify dataset serialization (#38694) -- Add heartbeat recovery message to jobs (#34457) -- Remove select_column option in TaskInstance.get_task_instance (#38571) -- Don't create session in get_dag if not reading dags from database (#38553) -- Add a migration script for encrypted trigger kwargs (#38358) -- Implement render_templates on TaskInstancePydantic (#38559) -- Handle optional session in _refresh_from_db (#38572) -- Make type annotation less confusing in task_command.py (#38561) -- Use fetch_dagrun directly to avoid session creation (#38557) -- Added ``output_processor`` parameter to ``BashProcessor`` (#40843) -- Improve serialization for Database Isolation Mode (#41239) -- Only orphan non-orphaned Datasets (#40806) -- Adjust gantt width based on task history dates (#41192) -- Enable scrolling on legend with high number of elements. (#41187) + index: int = attr.ib() -Bug Fixes -""""""""" -- Bugfix for get_parsing_context() when ran with LocalExecutor (#40738) -- Validating provider documentation urls before displaying in views (#40933) -- Move import to make PythonOperator working on Windows (#40424) -- Fix dataset_with_extra_from_classic_operator example DAG (#40747) -- Call listener on_task_instance_failed() after ti state is changed (#41053) -- Add ``never_fail`` in BaseSensor (#40915) -- Fix tasks API endpoint when DAG doesn't have ``start_date`` (#40878) -- Fix and adjust URL generation for UI grid and older runs (#40764) -- Rotate fernet key optimization (#40758) -- Fix class instance vs. class type in validate_database_executor_compatibility() call (#40626) -- Clean up dark mode (#40466) -- Validate expected types for args for DAG, BaseOperator and TaskGroup (#40269) -- Exponential Backoff Not Functioning in BaseSensorOperator Reschedule Mode (#39823) -- local task job: add timeout, to not kill on_task_instance_success listener prematurely (#39890) -- Move Post Execution Log Grouping behind Exception Print (#40146) -- Fix triggerer race condition in HA setting (#38666) -- Pass triggered or existing DAG Run logical date to DagStateTrigger (#39960) -- Passing ``external_task_group_id`` to ``WorkflowTrigger`` (#39617) -- ECS Executor: Set tasks to RUNNING state once active (#39212) -- Only heartbeat if necessary in backfill loop (#39399) -- Fix trigger kwarg encryption migration (#39246) -- Fix decryption of trigger kwargs when downgrading. (#38743) -- Fix wrong link in TriggeredDagRuns (#41166) -- Pass MapIndex to LogLink component for external log systems (#41125) -- Add NonCachingRotatingFileHandler for worker task (#41064) -- Add argument include_xcom in method resolve an optional value (#41062) -- Sanitizing file names in example_bash_decorator DAG (#40949) -- Show dataset aliases in dependency graphs (#41128) -- Render Dataset Conditions in DAG Graph view (#41137) -- Add task duration plot across dagruns (#40755) -- Add start execution from trigger support for existing core sensors (#41021) -- add example dag for dataset_alias (#41037) -- Add dataset alias unique constraint and remove wrong dataset alias removing logic (#41097) -- Set "has_outlet_datasets" to true if "dataset alias" exists (#41091) -- Make HookLineageCollector group datasets by (#41034) -- Enhance start_trigger_args serialization (#40993) -- Refactor ``BaseSensorOperator`` introduce ``skip_policy`` parameter (#40924) -- Fix viewing logs from triggerer when task is deferred (#41272) -- Refactor how triggered dag run url is replaced (#41259) -- Added support for additional sql alchemy session args (#41048) -- Allow empty list in TriggerDagRun failed_state (#41249) -- Clean up the exception handler when run_as_user is the airflow user (#41241) -- Collapse docs when click and folded (#41214) -- Update updated_at when saving to db as session.merge does not trigger on-update (#40782) -- Fix query count statistics when parsing DAF file (#41149) -- Method Resolution Order in operators without ``__init__`` (#41086) -- Ensure try_number incremented for empty operator (#40426) + @property + def name(self) -> str: + return f"BigQuery Console #{self.index + 1}" -Miscellaneous -""""""""""""" -- Remove the Experimental flag from ``OTel`` Traces (#40874) -- Bump packaging version to 23.0 in order to fix issue with older otel (#40865) -- Simplify _auth_manager_is_authorized_map function (#40803) -- Use correct unknown executor exception in scheduler job (#40700) -- Add D1 ``pydocstyle`` rules to pyproject.toml (#40569) -- Enable enforcing ``pydocstyle`` rule D213 in ruff. (#40448, #40464) -- Update ``Dag.test()`` to run with an executor if desired (#40205) -- Update jest and babel minor versions (#40203) -- Refactor BashOperator and Bash decorator for consistency and simplicity (#39871) -- Add ``AirflowInternalRuntimeError`` for raise ``non catchable`` errors (#38778) -- ruff version bump 0.4.5 (#39849) -- Bump ``pytest`` to 8.0+ (#39450) -- Remove stale comment about TI index (#39470) -- Configure ``back_populates`` between ``DagScheduleDatasetReference.dag`` and ``DagModel.schedule_dataset_references`` (#39392) -- Remove deprecation warnings in endpoints.py (#39389) -- Fix SQLA deprecations in Airflow core (#39211) -- Use class-bound attribute directly in SA (#39198, #39195) -- Fix stacklevel for TaskContextLogger (#39142) -- Capture warnings during collect DAGs (#39109) -- Resolve ``B028`` (no-explicit-stacklevel) in core (#39123) -- Rename model ``ImportError`` to ``ParseImportError`` for avoid shadowing with builtin exception (#39116) -- Add option to support cloudpickle in PythonVenv/External Operator (#38531) -- Suppress ``SubDagOperator`` examples warnings (#39057) -- Add log for running callback (#38892) -- Use ``model_dump`` instead of ``dict`` for serialize Pydantic V2 model (#38933) -- Widen cheat sheet column to avoid wrapping commands (#38888) -- Update ``hatchling`` to latest version (1.22.5) (#38780) -- bump uv to 0.1.29 (#38758) -- Add missing serializations found during provider tests fixing (#41252) -- Bump ``ws`` from 7.5.5 to 7.5.10 in /airflow/www (#40288) -- Improve typing for allowed/failed_states in TriggerDagRunOperator (#39855) + @property + def xcom_key(self) -> str: + return f"bigquery_{self.index + 1}" -Doc Only Changes -"""""""""""""""" -- Add ``filesystems`` and ``dataset-uris`` to "how to create your own provider" page (#40801) -- Fix (TM) to (R) in Airflow repository (#40783) -- Set ``otel_on`` to True in example airflow.cfg (#40712) -- Add warning for _AIRFLOW_PATCH_GEVENT (#40677) -- Update multi-team diagram proposal after Airflow 3 discussions (#40671) -- Add stronger warning that MSSQL is not supported and no longer functional (#40565) -- Fix misleading mac menu structure in howto (#40440) -- Update k8s supported version in docs (#39878) -- Add compatibility note for Listeners (#39544) -- Update edge label image in documentation example with the new graph view (#38802) -- Update UI doc screenshots (#38680) -- Add section "Manipulating queued dataset events through REST API" (#41022) -- Add information about lack of security guarantees for docker compose (#41072) -- Add links to example dags in use params section (#41031) -- Change ``task_id`` from ``send_email`` to ``send_email_notification`` in ``taskflow.rst`` (#41060) -- Remove unnecessary nginx redirect rule from reverse proxy documentation (#38953) + def get_link(self, operator, *, ti_key): + search_queries = XCom.get_one( + task_id=ti_key.task_id, dag_id=ti_key.dag_id, run_id=ti_key.run_id, key="search_query" + ) + return f"https://console.cloud.google.com/bigquery?j={search_query}" +The link has an ``xcom_key`` defined, which is how it will be stored in the XCOM backend, with key as xcom_key and +value as the entire link, this case: ``https://console.cloud.google.com/bigquery?j=search`` +Plugins no longer support adding executors, operators & hooks +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Airflow 2.9.3 (2024-07-15) --------------------------- +Operator (including Sensors), Executors & Hooks can no longer be registered or imported via Airflow's plugin mechanism. These types of classes +are just treated as plain Python classes by Airflow, so there is no need to register them with Airflow. They +can be imported directly from their respective provider packages. -Significant Changes -^^^^^^^^^^^^^^^^^^^ +Before: -Time unit for ``scheduled_duration`` and ``queued_duration`` changed (#37936) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.. code-block:: python -``scheduled_duration`` and ``queued_duration`` metrics are now emitted in milliseconds instead of seconds. + from airflow.hooks.my_plugin import MyHook -By convention all statsd metrics should be emitted in milliseconds, this is later expected in e.g. ``prometheus`` statsd-exporter. +You should instead import it as: +.. code-block:: python -Support for OpenTelemetry Metrics is no longer "Experimental" (#40286) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + from my_plugin import MyHook -Experimental support for OpenTelemetry was added in 2.7.0 since then fixes and improvements were added and now we announce the feature as stable. +Support for ML & AI Use Cases (AIP-83) +""""""""""""""""""""""""""""""""""""""" +Airflow 3.0 expands the types of DAGs that can be expressed by removing the constraint that each DAG run must correspond +to a unique data interval. This change, introduced in AIP-83, enables support for workflows that don't operate on a +fixed schedule — such as model training, hyperparameter tuning, and inference tasks. +These ML- and AI-oriented DAGs often run ad hoc, are triggered by external systems, or need to execute multiple times +with different parameters over the same dataset. By allowing multiple DAG runs with ``logical_date=None``, Airflow now +supports these scenarios natively without requiring workarounds. -Bug Fixes -""""""""" -- Fix calendar view scroll (#40458) -- Validating provider description for urls in provider list view (#40475) -- Fix compatibility with old MySQL 8.0 (#40314) -- Fix dag (un)pausing won't work on environment where dag files are missing (#40345) -- Extra being passed to SQLalchemy (#40391) -- Handle unsupported operand int + str when value of tag is int (job_id) (#40407) -- Fix TriggeredDagRunOperator triggered link (#40336) -- Add ``[webserver]update_fab_perms`` to deprecated configs (#40317) -- Swap dag run link from legacy graph to grid with graph tab (#40241) -- Change ``httpx`` to ``requests`` in ``file_task_handler`` (#39799) -- Fix import future annotations in venv jinja template (#40208) -- Ensures DAG params order regardless of backend (#40156) -- Use a join for TI notes in TI batch API endpoint (#40028) -- Improve trigger UI for string array format validation (#39993) -- Disable jinja2 rendering for doc_md (#40522) -- Skip checking sub dags list if taskinstance state is skipped (#40578) -- Recognize quotes when parsing urls in logs (#40508) +Config & Interface Changes +^^^^^^^^^^^^^^^^^^^^^^^^^^ -Doc Only Changes -"""""""""""""""" -- Add notes about passing secrets via environment variables (#40519) -- Revamp some confusing log messages (#40334) -- Add more precise description of masking sensitive field names (#40512) -- Add slightly more detailed guidance about upgrading to the docs (#40227) -- Metrics allow_list complete example (#40120) -- Add warning to deprecated api docs that access control isn't applied (#40129) -- Simpler command to check local scheduler is alive (#40074) -- Add a note and an example clarifying the usage of DAG-level params (#40541) -- Fix highlight of example code in dags.rst (#40114) -- Add warning about the PostgresOperator being deprecated (#40662) -- Updating airflow download links to CDN based links (#40618) -- Fix import statement for DatasetOrTimetable example (#40601) -- Further clarify triage process (#40536) -- Fix param order in PythonOperator docstring (#40122) -- Update serializers.rst to mention that bytes are not supported (#40597) +Airflow 3.0 introduces several configuration and interface updates that improve consistency, clarify ownership of core +utilities, and remove legacy behaviors that were no longer aligned with modern usage patterns. -Miscellaneous -""""""""""""" -- Upgrade build installers and dependencies (#40177) -- Bump braces from 3.0.2 to 3.0.3 in /airflow/www (#40180) -- Upgrade to another version of trove-classifier (new CUDA classifiers) (#40564) -- Rename "try_number" increments that are unrelated to the airflow concept (#39317) -- Update trove classifiers to the latest version as build dependency (#40542) -- Upgrade to latest version of ``hatchling`` as build dependency (#40387) -- Fix bug in ``SchedulerJobRunner._process_executor_events`` (#40563) -- Remove logging for "blocked" events (#40446) +Default Value Handling +"""""""""""""""""""""" +Airflow no longer silently updates configuration options that retain deprecated default values. Users are now required +to explicitly set any config values that differ from the current defaults. This change improves transparency and +prevents unintentional behavior changes during upgrades. +Refactored Config Defaults +""""""""""""""""""""""""""" -Airflow 2.9.2 (2024-06-10) --------------------------- +Several configuration defaults have changed in Airflow 3.0 to better reflect modern usage patterns: -Significant Changes -^^^^^^^^^^^^^^^^^^^ +- The default value of ``catchup_by_default`` is now ``False``. DAGs will not backfill missed intervals unless explicitly configured to do so. +- The default value of ``create_cron_data_intervals`` is now ``False``. Cron expressions are now interpreted using the ``CronTriggerTimetable`` instead of the legacy ``CronDataIntervalTimetable``. This change simplifies interval logic and aligns with the future direction of Airflow's scheduling system. -No significant changes. +Refactored Internal Utilities +""""""""""""""""""""""""""""" -Bug Fixes -""""""""" -- Fix bug that makes ``AirflowSecurityManagerV2`` leave transactions in the ``idle in transaction`` state (#39935) -- Fix alembic auto-generation and rename mismatching constraints (#39032) -- Add the existing_nullable to the downgrade side of the migration (#39374) -- Fix Mark Instance state buttons stay disabled if user lacks permission (#37451). (#38732) -- Use SKIP LOCKED instead of NOWAIT in mini scheduler (#39745) -- Remove DAG Run Add option from FAB view (#39881) -- Add max_consecutive_failed_dag_runs in API spec (#39830) -- Fix example_branch_operator failing in python 3.12 (#39783) -- Fetch served logs also when task attempt is up for retry and no remote logs available (#39496) -- Change dataset URI validation to raise warning instead of error in Airflow 2.9 (#39670) -- Visible DAG RUN doesn't point to the same dag run id (#38365) -- Refactor ``SafeDogStatsdLogger`` to use ``get_validator`` to enable pattern matching (#39370) -- Fix custom actions in security manager ``has_access`` (#39421) -- Fix HTTP 500 Internal Server Error if DAG is triggered with bad params (#39409) -- Fix static file caching is disabled in Airflow Webserver. (#39345) -- Fix TaskHandlerWithCustomFormatter now adds prefix only once (#38502) -- Do not provide deprecated ``execution_date`` in ``@apply_lineage`` (#39327) -- Add missing conn_id to string representation of ObjectStoragePath (#39313) -- Fix ``sql_alchemy_engine_args`` config example (#38971) -- Add Cache-Control "no-store" to all dynamically generated content (#39550) +Several core components have been moved to more intuitive or stable locations: -Miscellaneous -""""""""""""" -- Limit ``yandex`` provider to avoid ``mypy`` errors (#39990) -- Warn on mini scheduler failures instead of debug (#39760) -- Change type definition for ``provider_info_cache`` decorator (#39750) -- Better typing for BaseOperator ``defer`` (#39742) -- More typing in TimeSensor and TimeSensorAsync (#39696) -- Re-raise exception from strict dataset URI checks (#39719) -- Fix stacklevel for _log_state helper (#39596) -- Resolve SA warnings in migrations scripts (#39418) -- Remove unused index ``idx_last_scheduling_decision`` on ``dag_run`` table (#39275) +- The ``SecretsMasker`` class has been relocated to ``airflow.sdk.execution_time.secrets_masker``. +- The ``ObjectStoragePath`` utility previously located under ``airflow.io`` is now available via ``airflow.sdk``. -Doc Only Changes -"""""""""""""""" -- Provide extra tip on labeling DynamicTaskMapping (#39977) -- Improve visibility of links / variables / other configs in Configuration Reference (#39916) -- Remove 'legacy' definition for ``CronDataIntervalTimetable`` (#39780) -- Update plugins.rst examples to use pyproject.toml over setup.py (#39665) -- Fix nit in pg set-up doc (#39628) -- Add Matomo to Tracking User Activity docs (#39611) -- Fix Connection.get -> Connection. get_connection_from_secrets (#39560) -- Adding note for provider dependencies (#39512) -- Update docker-compose command (#39504) -- Update note about restarting triggerer process (#39436) -- Updating S3LogLink with an invalid bucket link (#39424) -- Update testing_packages.rst (#38996) -- Add multi-team diagrams (#38861) +These changes simplify imports and reflect broader efforts to stabilize utility interfaces across the Airflow codebase. +Improved ``inlet_events``, ``outlet_events``, and ``triggering_asset_events`` +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Asset event mappings in the task context are improved to better support asset use cases, including new features introduced in AIP-74. -Airflow 2.9.1 (2024-05-03) --------------------------- +Events of an asset or asset alias are now accessed directly by a concrete object to avoid ambiguity. Using a ``str`` to access events is +no longer supported. Use an ``Asset`` or ``AssetAlias`` object, or ``Asset.ref`` to refer to an entity explicitly instead, such as:: -Significant Changes -^^^^^^^^^^^^^^^^^^^ + outlet_events[Asset.ref(name="myasset")] # Get events for asset named "myasset". + outlet_events[AssetAlias(name="myalias")] # Get events for asset alias named "myalias". -Stackdriver logging bugfix requires Google provider ``10.17.0`` or later (#38071) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Alternatively, two helpers ``for_asset`` and ``for_asset_alias`` are added as shortcuts:: -If you use Stackdriver logging, you must use Google provider version ``10.17.0`` or later. Airflow ``2.9.1`` now passes ``gcp_log_name`` to the ``StackdriverTaskHandler`` instead of ``name``, and this will fail on earlier provider versions. + outlet_events.for_asset(name="myasset") # Get events for asset named "myasset". + outlet_events.for_asset_alias(name="myalias") # Get events for asset alias named "myalias". -This fixes a bug where the log name configured in ``[logging] remove_base_log_folder`` was overridden when Airflow configured logging, resulting in task logs going to the wrong destination. +The internal representation of asset event triggers now also includes an explicit ``uri`` field, simplifying traceability and +aligning with the broader asset-aware execution model introduced in Airflow 3.0. DAG authors interacting directly with +``inlet_events`` may need to update logic that assumes the previous structure. +Behaviour change in ``xcom_pull`` +""""""""""""""""""""""""""""""""" +In Airflow 2, the ``xcom_pull()`` method allowed pulling XComs by key without specifying task_ids, despite the fact that the underlying +DB model defines task_id as part of the XCom primary key. This created ambiguity: if two tasks pushed XComs with the same key, +``xcom_pull()`` would pull whichever one happened to be first, leading to unpredictable behavior. -Bug Fixes -""""""""" -- Make task log messages include run_id (#39280) -- Copy menu_item ``href`` for nav bar (#39282) -- Fix trigger kwarg encryption migration (#39246, #39361, #39374) -- Add workaround for datetime-local input in ``firefox`` (#39261) -- Add Grid button to Task Instance view (#39223) -- Get served logs when remote or executor logs not available for non-running task try (#39177) -- Fixed side effect of menu filtering causing disappearing menus (#39229) -- Use grid view for Task Instance's ``log_url`` (#39183) -- Improve task filtering ``UX`` (#39119) -- Improve rendered_template ``ux`` in react dag page (#39122) -- Graph view improvements (#38940) -- Check that the dataset<>task exists before trying to render graph (#39069) -- Hostname was "redacted", not "redact"; remove it when there is no context (#39037) -- Check whether ``AUTH_ROLE_PUBLIC`` is set in ``check_authentication`` (#39012) -- Move rendering of ``map_index_template`` so it renders for failed tasks as long as it was defined before the point of failure (#38902) -- ``Undeprecate`` ``BaseXCom.get_one`` method for now (#38991) -- Add ``inherit_cache`` attribute for ``CreateTableAs`` custom SA Clause (#38985) -- Don't wait for DagRun lock in mini scheduler (#38914) -- Fix calendar view with no DAG Run (#38964) -- Changed the background color of external task in graph (#38969) -- Fix dag run selection (#38941) -- Fix ``SAWarning`` 'Coercing Subquery object into a select() for use in IN()' (#38926) -- Fix implicit ``cartesian`` product in AirflowSecurityManagerV2 (#38913) -- Fix problem that links in legacy log view can not be clicked (#38882) -- Fix dag run link params (#38873) -- Use async db calls in WorkflowTrigger (#38689) -- Fix audit log events filter (#38719) -- Use ``methodtools.lru_cache`` instead of ``functools.lru_cache`` in class methods (#37757) -- Raise deprecated warning in ``airflow dags backfill`` only if ``-I`` / ``--ignore-first-depends-on-past`` provided (#38676) +Airflow 3 resolves this inconsistency by requiring ``task_ids`` when pulling by key. This change aligns with the task-scoped nature of +XComs as defined by the schema, ensuring predictable and consistent behavior. -Miscellaneous -""""""""""""" -- ``TriggerDagRunOperator`` deprecate ``execution_date`` in favor of ``logical_date`` (#39285) -- Force to use Airflow Deprecation warnings categories on ``@deprecated`` decorator (#39205) -- Add warning about run/import Airflow under the Windows (#39196) -- Update ``is_authorized_custom_view`` from auth manager to handle custom actions (#39167) -- Add in Trove classifiers Python 3.12 support (#39004) -- Use debug level for ``minischeduler`` skip (#38976) -- Bump ``undici`` from ``5.28.3 to 5.28.4`` in ``/airflow/www`` (#38751) +DAG Authors should update their dags to use ``task_ids`` if their dags used ``xcom_pull`` without ``task_ids`` such as:: + kwargs["ti"].xcom_pull(key="key") -Doc Only Changes -"""""""""""""""" -- Fix supported k8s version in docs (#39172) -- Dynamic task mapping ``PythonOperator`` op_kwargs (#39242) -- Add link to ``user`` and ``role`` commands (#39224) -- Add ``k8s 1.29`` to supported version in docs (#39168) -- Data aware scheduling docs edits (#38687) -- Update ``DagBag`` class docstring to include all params (#38814) -- Correcting an example taskflow example (#39015) -- Remove decorator from rendering fields example (#38827) +Should be updated to:: + kwargs["ti"].xcom_pull(task_ids="task1", key="key") -Airflow 2.9.0 (2024-04-08) --------------------------- +Removed Configuration Keys +""""""""""""""""""""""""""" -Significant Changes -^^^^^^^^^^^^^^^^^^^ +As part of the deprecation cleanup, several legacy configuration options have been removed. These include: -Following Listener API methods are considered stable and can be used for production system (were experimental feature in older Airflow versions) (#36376): -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Lifecycle events: +- ``[scheduler] allow_trigger_in_future`` +- ``[scheduler] use_job_schedule`` +- ``[scheduler] use_local_tz`` +- ``[scheduler] processor_poll_interval`` +- ``[logging] dag_processor_manager_log_location`` +- ``[logging] dag_processor_manager_log_stdout`` +- ``[logging] log_processor_filename_template`` -- ``on_starting`` -- ``before_stopping`` +All the webserver configurations have also been removed since API server now replaces webserver, so +the configurations like below have no effect: -DagRun State Change Events: +- ``[webserver] allow_raw_html_descriptions`` +- ``[webserver] cookie_samesite`` +- ``[webserver] error_logfile`` +- ``[webserver] access_logformat`` +- ``[webserver] web_server_master_timeout`` +- etc -- ``on_dag_run_running`` -- ``on_dag_run_success`` -- ``on_dag_run_failed`` +Several configuration options previously located under the ``[webserver]`` section have +been **moved to the new ``[api]`` section**. The following configuration keys have been moved: -TaskInstance State Change Events: +- ``[webserver] web_server_host`` → ``[api] host`` +- ``[webserver] web_server_port`` → ``[api] port`` +- ``[webserver] workers`` → ``[api] workers`` +- ``[webserver] web_server_worker_timeout`` → ``[api] worker_timeout`` +- ``[webserver] web_server_ssl_cert`` → ``[api] ssl_cert`` +- ``[webserver] web_server_ssl_key`` → ``[api] ssl_key`` +- ``[webserver] access_logfile`` → ``[api] access_logfile`` -- ``on_task_instance_running`` -- ``on_task_instance_success`` -- ``on_task_instance_failed`` +Users should review their ``airflow.cfg`` files or use the ``airflow config lint`` command to identify outdated or +removed options. -Support for Microsoft SQL-Server for Airflow Meta Database has been removed (#36514) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Upgrade Tooling +"""""""""""""""" -After `discussion `__ -and a `voting process `__, -the Airflow's PMC members and Committers have reached a resolution to no longer maintain MsSQL as a -supported Database Backend. +Airflow 3.0 includes improved support for upgrade validation. Use the following tools to proactively catch incompatible +configs or deprecated usage patterns: -As of Airflow 2.9.0 support of MsSQL has been removed for Airflow Database Backend. +- ``airflow config lint``: Identifies removed or invalid config keys +- ``ruff check --select AIR30 --preview``: Flags removed interfaces and common migration issues -A migration script which can help migrating the database *before* upgrading to Airflow 2.9.0 is available in -`airflow-mssql-migration repo on Github `_. -Note that the migration script is provided without support and warranty. +CLI & API Changes +^^^^^^^^^^^^^^^^^ -This does not affect the existing provider packages (operators and hooks), DAGs can still access and process data from MsSQL. +Airflow 3.0 introduces changes to both the CLI and REST API interfaces to better align with service-oriented deployments +and event-driven workflows. -Dataset URIs are now validated on input (#37005) -"""""""""""""""""""""""""""""""""""""""""""""""" +Split CLI Architecture (AIP-81) +""""""""""""""""""""""""""""""" -Datasets must use a URI that conform to rules laid down in AIP-60, and the value -will be automatically normalized when the DAG file is parsed. See -`documentation on Datasets `_ for -a more detailed description on the rules. +The Airflow CLI has been split into two distinct interfaces: -You may need to change your Dataset identifiers if they look like a URI, but are -used in a less mainstream way, such as relying on the URI's auth section, or -have a case-sensitive protocol name. +- The core ``airflow`` CLI now handles only local functionality (e.g., ``airflow tasks test``, ``airflow dags list``). +- Remote functionality, including triggering DAGs or managing connections in service-mode environments, is now handled by a separate CLI called ``airflowctl``, distributed via the ``apache-airflow-client`` package. -The method ``get_permitted_menu_items`` in ``BaseAuthManager`` has been renamed ``filter_permitted_menu_items`` (#37627) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +This change improves security and modularity for deployments that use Airflow in a distributed or API-first context. -Add REST API actions to Audit Log events (#37734) -""""""""""""""""""""""""""""""""""""""""""""""""" +REST API v2 replaces v1 +""""""""""""""""""""""" -The Audit Log ``event`` name for REST API events will be prepended with ``api.`` or ``ui.``, depending on if it came from the Airflow UI or externally. +The legacy REST API v1, previously built with Connexion and Marshmallow, has been replaced by a modern FastAPI-based REST API v2. -Official support for Python 3.12 (#38025) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -There are a few caveats though: +This new implementation improves performance, aligns more closely with web standards, and provides a consistent developer experience across the API and UI. -* Pendulum2 does not support Python 3.12. For Python 3.12 you need to use - `Pendulum 3 `_ +Key changes include stricter validation (422 errors instead of 400), the removal of the ``execution_date`` parameter in favor of ``logical_date``, and more consistent query parameter handling. -* Minimum SQLAlchemy version supported when Pandas is installed for Python 3.12 is ``1.4.36`` released in - April 2022. Airflow 2.9.0 increases the minimum supported version of SQLAlchemy to ``1.4.36`` for all - Python versions. +The v2 API is now the stable, fully supported interface for programmatic access to Airflow, and also powers the new UI - achieving full feature parity between the UI and API. -Not all Providers support Python 3.12. At the initial release of Airflow 2.9.0 the following providers -are released without support for Python 3.12: +For details, see the :doc:`Airflow REST API v2 ` documentation. - * ``apache.beam`` - pending on `Apache Beam support for 3.12 `_ - * ``papermill`` - pending on Releasing Python 3.12 compatible papermill client version - `including this merged issue `_ +REST API: DAG Trigger Behavior Updated +"""""""""""""""""""""""""""""""""""""" -Prevent large string objects from being stored in the Rendered Template Fields (#38094) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -There's now a limit to the length of data that can be stored in the Rendered Template Fields. -The limit is set to 4096 characters. If the data exceeds this limit, it will be truncated. You can change this limit -by setting the ``[core]max_template_field_length`` configuration option in your airflow config. +The behavior of the ``POST /dags/{dag_id}/dagRuns`` endpoint has changed. If a ``logical_date`` is not explicitly +provided when triggering a DAG via the REST API, it now defaults to ``None``. -Change xcom table column value type to longblob for MySQL backend (#38401) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Xcom table column ``value`` type has changed from ``blob`` to ``longblob``. This will allow you to store relatively big data in Xcom but process can take a significant amount of time if you have a lot of large data stored in Xcom. +This aligns with event-driven DAGs and manual runs in Airflow 3.0, but may break backward compatibility with scripts or +tools that previously relied on Airflow auto-generating a timestamped ``logical_date``. -To downgrade from revision: ``b4078ac230a1``, ensure that you don't have Xcom values larger than 65,535 bytes. Otherwise, you'll need to clean those rows or run ``airflow db clean xcom`` to clean the Xcom table. +Removed CLI Flags and Commands +"""""""""""""""""""""""""""""" -Stronger validation for key parameter defaults in taskflow context variables (#38015) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Several deprecated CLI arguments and commands that were marked for removal in earlier versions have now been cleaned up +in Airflow 3.0. Run ``airflow --help`` to review the current set of available commands and arguments. -As for the taskflow implementation in conjunction with context variable defaults invalid parameter orders can be -generated, it is now not accepted anymore (and validated) that taskflow functions are defined with defaults -other than ``None``. If you have done this before you most likely will see a broken DAG and a error message like -``Error message: Context key parameter my_param can't have a default other than None``. +- Deprecated ``--ignore-depends-on-past`` cli option is replaced by ``--depends-on-past ignore``. -New Features -"""""""""""" -- Allow users to write dag_id and task_id in their national characters, added display name for dag / task (v2) (#38446) -- Prevent large objects from being stored in the RTIF (#38094) -- Use current time to calculate duration when end date is not present. (#38375) -- Add average duration mark line in task and dagrun duration charts. (#38214, #38434) -- Add button to manually create dataset events (#38305) -- Add ``Matomo`` as an option for analytics_tool. (#38221) -- Experimental: Support custom weight_rule implementation to calculate the TI priority_weight (#38222) -- Adding ability to automatically set DAG to off after X times it failed sequentially (#36935) -- Add dataset conditions to next run datasets modal (#38123) -- Add task log grouping to UI (#38021) -- Add dataset_expression to grid dag details (#38121) -- Introduce mechanism to support multiple executor configuration (#37635) -- Add color formatting for ANSI chars in logs from task executions (#37985) -- Add the dataset_expression as part of DagModel and DAGDetailSchema (#37826) -- Allow longer rendered_map_index (#37798) -- Inherit the run_ordering from DatasetTriggeredTimetable for DatasetOrTimeSchedule (#37775) -- Implement AIP-60 Dataset URI formats (#37005) -- Introducing Logical Operators for dataset conditional logic (#37101) -- Add post endpoint for dataset events (#37570) -- Show custom instance names for a mapped task in UI (#36797) -- Add excluded/included events to get_event_logs api (#37641) -- Add datasets to dag graph (#37604) -- Show dataset events above task/run details in grid view (#37603) -- Introduce new config variable to control whether DAG processor outputs to stdout (#37439) -- Make Datasets ``hashable`` (#37465) -- Add conditional logic for dataset triggering (#37016) -- Implement task duration page in react. (#35863) -- Add ``queuedEvent`` endpoint to get/delete DatasetDagRunQueue (#37176) -- Support multiple XCom output in the BaseOperator (#37297) -- AIP-58: Add object storage backend for xcom (#37058) -- Introduce ``DatasetOrTimeSchedule`` (#36710) -- Add ``on_skipped_callback`` to ``BaseOperator`` (#36374) -- Allow override of hovered navbar colors (#36631) -- Create new Metrics with Tagging (#36528) -- Add support for openlineage to AFS and common.io (#36410) -- Introduce ``@task.bash`` TaskFlow decorator (#30176, #37875) +- ``--tree`` flag for ``airflow tasks list`` command is removed. The format of the output with that flag can be + expensive to generate and extremely large, depending on the DAG. ``airflow dag show`` is a better way to + visualize the relationship of tasks in a DAG. -Improvements -"""""""""""" -- More human friendly "show tables" output for db cleanup (#38654) -- Improve trigger assign_unassigned by merging alive_triggerer_ids and get_sorted_triggers queries (#38664) -- Add exclude/include events filters to audit log (#38506) -- Clean up unused triggers in a single query for all dialects except MySQL (#38663) -- Update Confirmation Logic for Config Changes on Sensitive Environments Like Production (#38299) -- Improve datasets graph UX (#38476) -- Only show latest dataset event timestamp after last run (#38340) -- Add button to clear only failed tasks in a dagrun. (#38217) -- Delete all old dag pages and redirect to grid view (#37988) -- Check task attribute before use in sentry.add_tagging() (#37143) -- Mysql change xcom value col type for MySQL backend (#38401) -- ``ExternalPythonOperator`` use version from ``sys.version_info`` (#38377) -- Replace too broad exceptions into the Core (#38344) -- Add CLI support for bulk pause and resume of DAGs (#38265) -- Implement methods on TaskInstancePydantic and DagRunPydantic (#38295, #38302, #38303, #38297) -- Made filters bar collapsible and add a full screen toggle (#38296) -- Encrypt all trigger attributes (#38233, #38358, #38743) -- Upgrade react-table package. Use with Audit Log table (#38092) -- Show if dag page filters are active (#38080) -- Add try number to mapped instance (#38097) -- Add retries to job heartbeat (#37541) -- Add REST API events to Audit Log (#37734) -- Make current working directory as templated field in BashOperator (#37968) -- Add calendar view to react (#37909) -- Add ``run_id`` column to log table (#37731) -- Add ``tryNumber`` to grid task instance tooltip (#37911) -- Session is not used in _do_render_template_fields (#37856) -- Improve MappedOperator property types (#37870) -- Remove provide_session decorator from TaskInstancePydantic methods (#37853) -- Ensure the "airflow.task" logger used for TaskInstancePydantic and TaskInstance (#37857) -- Better error message for internal api call error (#37852) -- Increase tooltip size of dag grid view (#37782) (#37805) -- Use named loggers instead of root logger (#37801) -- Add Run Duration in React (#37735) -- Avoid non-recommended usage of logging (#37792) -- Improve DateTimeTrigger typing (#37694) -- Make sure all unique run_ids render a task duration bar (#37717) -- Add Dag Audit Log to React (#37682) -- Add log event for auto pause (#38243) -- Better message for exception for templated base operator fields (#37668) -- Clean up webserver endpoints adding to audit log (#37580) -- Filter datasets graph by dag_id (#37464) -- Use new exception type inheriting BaseException for SIGTERMs (#37613) -- Refactor dataset class inheritance (#37590) -- Simplify checks for package versions (#37585) -- Filter Datasets by associated dag_ids (GET /datasets) (#37512) -- Enable "airflow tasks test" to run deferrable operator (#37542) -- Make datasets list/graph width adjustable (#37425) -- Speedup determine installed airflow version in ``ExternalPythonOperator`` (#37409) -- Add more task details from rest api (#37394) -- Add confirmation dialog box for DAG run actions (#35393) -- Added shutdown color to the STATE_COLORS (#37295) -- Remove legacy dag details page and redirect to grid (#37232) -- Order XCom entries by map index in API (#37086) -- Add data_interval_start and data_interval_end in dagrun create API endpoint (#36630) -- Making links in task logs as hyperlinks by preventing HTML injection (#36829) -- Improve ExternalTaskSensor Async Implementation (#36916) -- Make Datasets ``Pathlike`` (#36947) -- Simplify query for orphaned tasks (#36566) -- Add deferrable param in FileSensor (#36840) -- Run Trigger Page: Configurable number of recent configs (#36878) -- Merge ``nowait`` and skip_locked into with_row_locks (#36889) -- Return the specified field when get ``dag/dagRun`` in the REST API (#36641) -- Only iterate over the items if debug is enabled for DagFileProcessorManager (#36761) -- Add a fuzzy/regex pattern-matching for metric allow and block list (#36250) -- Allow custom columns in cli dags list (#35250) -- Make it possible to change the default cron timetable (#34851) -- Some improvements to Airflow IO code (#36259) -- Improve TaskInstance typing hints (#36487) -- Remove dependency of ``Connexion`` from auth manager interface (#36209) -- Refactor ExternalDagLink to not create ad hoc TaskInstances (#36135) +- Changing ``dag_id`` from flag (``-d``, ``--dag-id``) to a positional argument in the ``dags list-runs`` CLI command. -Bug Fixes -""""""""" -- Load providers configuration when gunicorn workers start (#38795) -- Fix grid header rendering (#38720) -- Add a task instance dependency for mapped dependencies (#37498) -- Improve stability of remove_task_decorator function (#38649) -- Mark more fields on API as dump-only (#38616) -- Fix ``total_entries`` count on the event logs endpoint (#38625) -- Add padding to bottom of log block. (#38610) -- Properly serialize nested attrs classes (#38591) -- Fixing the ``tz`` in next run ID info (#38482) -- Show abandoned tasks in Grid View (#38511) -- Apply task instance mutation hook consistently (#38440) -- Override ``chakra`` styles to keep ``dropdowns`` in filter bar (#38456) -- Store duration in seconds and scale to handle case when a value in the series has a larger unit than the preceding durations. (#38374) -- Don't allow defaults other than None in context parameters, and improve error message (#38015) -- Make postgresql default engine args comply with SA 2.0 (#38362) -- Add return statement to yield within a while loop in triggers (#38389) -- Ensure ``__exit__`` is called in decorator context managers (#38383) -- Make the method ``BaseAuthManager.is_authorized_custom_view`` abstract (#37915) -- Add upper limit to planned calendar events calculation (#38310) -- Fix Scheduler in daemon mode doesn't create PID at the specified location (#38117) -- Properly serialize TaskInstancePydantic and DagRunPydantic (#37855) -- Fix graph task state border color (#38084) -- Add back methods removed in security manager (#37997) -- Don't log "403" from worker serve-logs as "Unknown error". (#37933) -- Fix execution data validation error in ``/get_logs_with_metadata`` endpoint (#37756) -- Fix task duration selection (#37630) -- Refrain from passing ``encoding`` to the SQL engine in SQLAlchemy v2 (#37545) -- Fix 'implicitly coercing SELECT object to scalar subquery' in latest dag run statement (#37505) -- Clean up typing with max_execution_date query builder (#36958) -- Optimize max_execution_date query in single dag case (#33242) -- Fix list dags command for get_dagmodel is None (#36739) -- Load ``consuming_dags`` attr eagerly before dataset listener (#36247) +- The ``airflow db init`` and ``airflow db upgrade`` commands have been removed. Use ``airflow db migrate`` instead + to initialize or migrate the metadata database. If you would like to create default connections use + ``airflow connections create-default-connections``. -Miscellaneous -""""""""""""" -- Remove display of param from the UI (#38660) -- Update log level to debug from warning about scheduled_duration metric (#38180) -- Use ``importlib_metadata`` with compat to Python 3.10/3.12 ``stdlib`` (#38366) -- Refactored ``__new__`` magic method of BaseOperatorMeta to avoid bad mixing classic and decorated operators (#37937) -- Use ``sys.version_info`` for determine Python Major.Minor (#38372) -- Add missing deprecated Fab auth manager (#38376) -- Remove unused loop variable from airflow package (#38308) -- Adding max consecutive failed dag runs info in UI (#38229) -- Bump minimum version of ``blinker`` add where it requires (#38140) -- Bump follow-redirects from 1.15.4 to 1.15.6 in /airflow/www (#38156) -- Bump Cryptography to ``> 39.0.0`` (#38112) -- Add Python 3.12 support (#36755, #38025, #36595) -- Avoid use of ``assert`` outside of the tests (#37718) -- Update ObjectStoragePath for universal_pathlib>=v0.2.2 (#37930) -- Resolve G004: Logging statement uses f-string (#37873) -- Update build and install dependencies. (#37910) -- Bump sanitize-html from 2.11.0 to 2.12.1 in /airflow/www (#37833) -- Update to latest installer versions. (#37754) -- Deprecate smtp configs in airflow settings / local_settings (#37711) -- Deprecate PY* constants into the airflow module (#37575) -- Remove usage of deprecated ``flask._request_ctx_stack`` (#37522) -- Remove redundant ``login`` attribute in ``airflow.__init__.py`` (#37565) -- Upgrade to FAB 4.3.11 (#37233) -- Remove SCHEDULED_DEPS which is no longer used anywhere since 2.0.0 (#37140) -- Replace ``datetime.datetime.utcnow`` by ``airflow.utils.timezone.utcnow`` in core (#35448) -- Bump aiohttp min version to avoid CVE-2024-23829 and CVE-2024-23334 (#37110) -- Move config related to FAB auth manager to FAB provider (#36232) -- Remove MSSQL support form Airflow core (#36514) -- Remove ``is_authorized_cluster_activity`` from auth manager (#36175) -- Create FAB provider and move FAB auth manager in it (#35926) +- ``airflow api-server`` has replaced ``airflow webserver`` cli command. -Doc Only Changes -"""""""""""""""" -- Improve timetable documentation (#38505) -- Reorder OpenAPI Spec tags alphabetically (#38717) -- Update UI screenshots in the documentation (#38680, #38403, #38438, #38435) -- Remove section as it's no longer true with dataset expressions PR (#38370) -- Refactor DatasetOrTimeSchedule timetable docs (#37771) -- Migrate executor docs to respective providers (#37728) -- Add directive to render a list of URI schemes (#37700) -- Add doc page with providers deprecations (#37075) -- Add a cross reference to security policy (#37004) -- Improve AIRFLOW__WEBSERVER__BASE_URL docs (#37003) -- Update faq.rst with (hopefully) clearer description of start_date (#36846) -- Update public interface doc re operators (#36767) -- Add ``exception`` to templates ref list (#36656) -- Add auth manager interface as public interface (#36312) -- Reference fab provider documentation in Airflow documentation (#36310) -- Create auth manager documentation (#36211) -- Update permission docs (#36120) -- Docstring improvement to _covers_every_hour (#36081) -- Add note that task instance, dag and lifecycle listeners are non-experimental (#36376) +Provider Refactor & Standardization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Airflow 2.8.4 (2024-03-25) --------------------------- +Airflow 3.0 completes the migration of several core operators, sensors, and hooks into the new +``apache-airflow-providers-standard`` package. This package now includes commonly used components such as: -Significant Changes -^^^^^^^^^^^^^^^^^^^ +- ``PythonOperator`` +- ``BashOperator`` +- ``EmailOperator`` +- ``SimpleHttpOperator`` +- ``ShortCircuitOperator`` -No significant changes. +These operators were previously bundled inside ``airflow-core`` but are now treated as provider-managed components to +improve modularity, testability, and lifecycle independence. -Bug Fixes -""""""""" -- Fix incorrect serialization of ``FixedTimezone`` (#38139) -- Fix excessive permission changing for log task handler (#38164) -- Fix task instances list link (#38096) -- Fix a bug where scheduler heartrate parameter was not used (#37992) -- Add padding to prevent grid horizontal scroll overlapping tasks (#37942) -- Fix hash caching in ``ObjectStoragePath`` (#37769) +This change enables more consistent versioning across providers and prepares Airflow for a future where all integrations +— including "standard" ones — follow the same interface model. -Miscellaneous +To maintain compatibility with existing DAGs, the ``apache-airflow-providers-standard`` package is installable on both +Airflow 2.x and 3.x. Users upgrading from Airflow 2.x are encouraged to begin updating import paths and testing provider +installation in advance of the upgrade. + +Legacy imports such as ``airflow.operators.python.PythonOperator`` are deprecated and will be removed soon. They should be +replaced with: + +.. code-block:: python + + from airflow.providers.standard.operators.python import PythonOperator + +UI & Usability Improvements +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Airflow 3.0 introduces a modernized user experience that complements the new React-based UI architecture (see +Significant Changes). Several areas of the interface have been enhanced to improve visibility, consistency, and +navigability. + +New Home Page """"""""""""" -- Limit ``importlib_resources`` as it breaks ``pytest_rewrites`` (#38095, #38139) -- Limit ``pandas`` to ``<2.2`` (#37748) -- Bump ``croniter`` to fix an issue with 29 Feb cron expressions (#38198) -Doc Only Changes -"""""""""""""""" -- Tell users what to do if their scanners find issues in the image (#37652) -- Add a section about debugging in Docker Compose with PyCharm (#37940) -- Update deferrable docs to clarify kwargs when trigger resumes operator (#38122) +The Airflow Home page now provides a high-level operational overview of your environment. It includes health checks for +core components (Scheduler, Triggerer, DAG Processor), summary stats for DAG and task instance states, and a real-time +feed of asset-triggered events. This view helps users quickly identify pipeline health, recent activity, and potential +failures. + +Unified DAG List View +"""""""""""""""""""""" +The DAG List page has been refreshed with a cleaner layout and improved responsiveness. Users can browse DAGs by name, +tags, or owners. While full-text search has not yet been integrated, filters and navigation have been refined for +clarity in large deployments. -Airflow 2.8.3 (2024-03-11) --------------------------- +Version-Aware Graph and Grid Views +""""""""""""""""""""""""""""""""""" -Significant Changes -^^^^^^^^^^^^^^^^^^^ +The Graph and Grid views now display task information in the context of the DAG version that was used at runtime. This +improves traceability for DAGs that evolve over time and provides more accurate debugging of historical runs. -The smtp provider is now pre-installed when you install Airflow. (#37713) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Expanded DAG Graph Visualization +"""""""""""""""""""""""""""""""" -Bug Fixes -""""""""" -- Add "MENU" permission in auth manager (#37881) -- Fix external_executor_id being overwritten (#37784) -- Make more MappedOperator members modifiable (#37828) -- Set parsing context dag_id in dag test command (#37606) +The Graph view now supports visualizing the full chain of asset and task dependencies, including assets consumed or +produced across DAG boundaries. This allows users to inspect upstream and downstream lineage in a unified view, making +it easier to trace data flows, debug triggering behavior, and understand conditional dependencies between assets and +tasks. -Miscellaneous +DAG Code View """"""""""""" -- Remove useless methods from security manager (#37889) -- Improve code coverage for TriggerRuleDep (#37680) -- The SMTP provider is now preinstalled when installing Airflow (#37713) -- Bump min versions of openapi validators (#37691) -- Properly include ``airflow_pre_installed_providers.txt`` artifact (#37679) -Doc Only Changes -"""""""""""""""" -- Clarify lack of sync between workers and scheduler (#37913) -- Simplify some docs around airflow_local_settings (#37835) -- Add section about local settings configuration (#37829) -- Fix docs of ``BranchDayOfWeekOperator`` (#37813) -- Write to secrets store is not supported by design (#37814) -- ``ERD`` generating doc improvement (#37808) -- Update incorrect config value (#37706) -- Update security model to clarify Connection Editing user's capabilities (#37688) -- Fix ImportError on examples dags (#37571) +The "Code" tab now displays the exact DAG source as parsed by the scheduler for the selected DAG version. This allows +users to inspect the precise code that was executed, even for historical runs, and helps debug issues related to +versioned DAG changes. +Improved Task Log Access +""""""""""""""""""""""""" -Airflow 2.8.2 (2024-02-26) --------------------------- +Task log access has been streamlined across views. Logs are now easier to access from both the Grid and Task Instance +pages, with cleaner formatting and reduced visual noise. -Significant Changes -^^^^^^^^^^^^^^^^^^^ +Enhanced Asset and Backfill Views +"""""""""""""""""""""""""""""""""" -The ``allowed_deserialization_classes`` flag now follows a glob pattern (#36147). -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +New UI components support asset-centric DAGs and backfill workflows: -For example if one wants to add the class ``airflow.tests.custom_class`` to the -``allowed_deserialization_classes`` list, it can be done by writing the full class -name (``airflow.tests.custom_class``) or a pattern such as the ones used in glob -search (e.g., ``airflow.*``, ``airflow.tests.*``). +- Asset definitions are now visible from the DAG details page, allowing users to inspect upstream and downstream asset relationships. +- Backfills can be triggered and monitored directly from the UI, including support for scheduler-managed backfills introduced in Airflow 3.0. -If you currently use a custom regexp path make sure to rewrite it as a glob pattern. +These improvements make Airflow more accessible to operators, data engineers, and stakeholders working across both +time-based and event-driven workflows. -Alternatively, if you still wish to match it as a regexp pattern, add it under the new -list ``allowed_deserialization_classes_regexp`` instead. +Deprecations & Removals +^^^^^^^^^^^^^^^^^^^^^^^^ -The audit_logs permissions have been updated for heightened security (#37501). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +A number of deprecated features, modules, and interfaces have been removed in Airflow 3.0, completing long-standing +migrations and cleanups. -This was done under the policy that we do not want users like Viewer, Ops, -and other users apart from Admin to have access to audit_logs. The intention behind -this change is to restrict users with less permissions from viewing user details -like First Name, Email etc. from the audit_logs when they are not permitted to. +Users are encouraged to review the following removals to ensure compatibility: -The impact of this change is that the existing users with non admin rights won't be able -to view or access the audit_logs, both from the Browse tab or from the DAG run. +- **SubDag support has been removed** entirely, including the ``SubDagOperator``, related CLI and API interfaces. TaskGroups are now the recommended alternative for nested DAG structures. -``AirflowTimeoutError`` is no longer ``except`` by default through ``Exception`` (#35653). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +- **SLAs have been removed**: The legacy SLA feature, including SLA callbacks and metrics, has been removed. A more flexible replacement mechanism, ``DeadlineAlerts``, is planned for a future version of Airflow. Users who relied on SLA-based notifications should consider implementing custom alerting using task-level success/failure hooks or external monitoring integrations. -The ``AirflowTimeoutError`` is now inheriting ``BaseException`` instead of -``AirflowException``->``Exception``. -See https://docs.python.org/3/library/exceptions.html#exception-hierarchy +- **Pickling support has been removed**: All legacy features related to DAG pickling have been fully removed. This includes the ``PickleDag`` CLI/API, as well as implicit behaviors around ``store_serialized_dags = False``. DAGs must now be serialized using the JSON-based serialization system. Ensure any custom Python objects used in DAGs are JSON-serializable. -This prevents code catching ``Exception`` from accidentally -catching ``AirflowTimeoutError`` and continuing to run. -``AirflowTimeoutError`` is an explicit intent to cancel the task, and should not -be caught in attempts to handle the error and return some default value. +- **Context parameter cleanup**: Several previously available context variables have been removed from the task execution context, including ``conf``, ``execution_date``, and ``dag_run.external_trigger``. These values are either no longer applicable or have been renamed (e.g., use ``dag_run.logical_date`` instead of ``execution_date``). DAG authors should ensure that templated fields and Python callables do not reference these deprecated keys. -Catching ``AirflowTimeoutError`` is still possible by explicitly ``except``ing -``AirflowTimeoutError`` or ``BaseException``. -This is discouraged, as it may allow the code to continue running even after -such cancellation requests. -Code that previously depended on performing strict cleanup in every situation -after catching ``Exception`` is advised to use ``finally`` blocks or -context managers. To perform only the cleanup and then automatically -re-raise the exception. -See similar considerations about catching ``KeyboardInterrupt`` in -https://docs.python.org/3/library/exceptions.html#KeyboardInterrupt +- **Deprecated core imports** have been fully removed. Any use of ``airflow.operators.*``, ``airflow.hooks.*``, or similar legacy import paths should be updated to import from their respective providers. +- **Configuration cleanup**: Several legacy config options have been removed, including: -Bug Fixes -""""""""" -- Sort dag processing stats by last_runtime (#37302) -- Allow pre-population of trigger form values via URL parameters (#37497) -- Base date for fetching dag grid view must include selected run_id (#34887) -- Check permissions for ImportError (#37468) -- Move ``IMPORT_ERROR`` from DAG related permissions to view related permissions (#37292) -- Change ``AirflowTaskTimeout`` to inherit ``BaseException`` (#35653) -- Revert "Fix future DagRun rarely triggered by race conditions when max_active_runs reached its upper limit. (#31414)" (#37596) -- Change margin to padding so first task can be selected (#37527) -- Fix Airflow serialization for ``namedtuple`` (#37168) -- Fix bug with clicking url-unsafe tags (#37395) -- Set deterministic and new getter for ``Treeview`` function (#37162) -- Fix permissions of parent folders for log file handler (#37310) -- Fix permission check on DAGs when ``access_entity`` is specified (#37290) -- Fix the value of ``dateTimeAttrFormat`` constant (#37285) -- Resolve handler close race condition at triggerer shutdown (#37206) -- Fixing status icon alignment for various views (#36804) -- Remove superfluous ``@Sentry.enrich_errors`` (#37002) -- Use execution_date= param as a backup to base date for grid view (#37018) -- Handle SystemExit raised in the task. (#36986) -- Revoking audit_log permission from all users except admin (#37501) -- Fix broken regex for allowed_deserialization_classes (#36147) -- Fix the bug that affected the DAG end date. (#36144) -- Adjust node width based on task name length (#37254) -- fix: PythonVirtualenvOperator crashes if any python_callable function is defined in the same source as DAG (#37165) -- Fix collapsed grid width, line up selected bar with gantt (#37205) -- Adjust graph node layout (#37207) -- Revert the sequence of initializing configuration defaults (#37155) -- Displaying "actual" try number in TaskInstance view (#34635) -- Bugfix Triggering DAG with parameters is mandatory when show_trigger_form_if_no_params is enabled (#37063) -- Secret masker ignores passwords with special chars (#36692) -- Fix DagRuns with UPSTREAM_FAILED tasks get stuck in the backfill. (#36954) -- Disable ``dryrun`` auto-fetch (#36941) -- Fix copy button on a DAG run's config (#36855) -- Fix bug introduced by replacing spaces by + in run_id (#36877) -- Fix webserver always redirecting to home page if user was not logged in (#36833) -- REST API set description on POST to ``/variables`` endpoint (#36820) -- Sanitize the conn_id to disallow potential script execution (#32867) -- Fix task id copy button copying wrong id (#34904) -- Fix security manager inheritance in fab provider (#36538) -- Avoid ``pendulum.from_timestamp`` usage (#37160) + - ``scheduler.allow_trigger_in_future``: DAG runs can no longer be triggered with a future logical date. Use ``logical_date=None`` instead. + - ``scheduler.use_job_schedule`` and ``scheduler.use_local_tz`` have also been removed. These options were deprecated and no longer had any effect. -Miscellaneous -""""""""""""" -- Install latest docker ``CLI`` instead of specific one (#37651) -- Bump ``undici`` from ``5.26.3`` to ``5.28.3`` in ``/airflow/www`` (#37493) -- Add Python ``3.12`` exclusions in ``providers/pyproject.toml`` (#37404) -- Remove ``markdown`` from core dependencies (#37396) -- Remove unused ``pageSize`` method. (#37319) -- Add more-itertools as dependency of common-sql (#37359) -- Replace other ``Python 3.11`` and ``3.12`` deprecations (#37478) -- Include ``airflow_pre_installed_providers.txt`` into ``sdist`` distribution (#37388) -- Turn Pydantic into an optional dependency (#37320) -- Limit ``universal-pathlib to < 0.2.0`` (#37311) -- Allow running airflow against sqlite in-memory DB for tests (#37144) -- Add description to ``queue_when`` (#36997) -- Updated ``config.yml`` for environment variable ``sql_alchemy_connect_args`` (#36526) -- Bump min version of ``Alembic to 1.13.1`` (#36928) -- Limit ``flask-session`` to ``<0.6`` (#36895) +- **Deprecated utility methods** such as those in ``airflow.utils.helpers``, ``airflow.utils.process_utils``, and ``airflow.utils.timezone`` have been removed. Equivalent functionality can now be found in the standard Python library or Airflow provider modules. -Doc Only Changes -"""""""""""""""" -- Fix upgrade docs to reflect true ``CLI`` flags available (#37231) -- Fix a bug in fundamentals doc (#37440) -- Add redirect for deprecated page (#37384) -- Fix the ``otel`` config descriptions (#37229) -- Update ``Objectstore`` tutorial with ``prereqs`` section (#36983) -- Add more precise description on avoiding generic ``package/module`` names (#36927) -- Add airflow version substitution into Docker Compose Howto (#37177) -- Add clarification about DAG author capabilities to security model (#37141) -- Move docs for cron basics to Authoring and Scheduling section (#37049) -- Link to release notes in the upgrade docs (#36923) -- Prevent templated field logic checks in ``__init__`` of operators automatically (#33786) +- **Removal of deprecated CLI flags and behavior**: Several CLI entrypoints and arguments that were marked for removal in earlier versions have been cleaned up. +To assist with the upgrade, tools like ``ruff`` (e.g., rule ``AIR302``) and ``airflow config lint`` can help identify +obsolete imports and configuration keys. These utilities are recommended for locating and resolving common +incompatibilities during migration. Please see :doc:`Upgrade Guide ` for more +information. -Airflow 2.8.1 (2024-01-19) --------------------------- +Summary of Removed Features +""""""""""""""""""""""""""" -Significant Changes -^^^^^^^^^^^^^^^^^^^ +The following table summarizes user-facing features removed in 3.0 and their recommended replacements. Not all of these +are called out individually above. -Target version for core dependency ``pendulum`` package set to 3 (#36281). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Support for pendulum 2.1.2 will be saved for a while, presumably until the next feature version of Airflow. -It is advised to upgrade user code to use pendulum 3 as soon as possible. ++-------------------------------------------+----------------------------------------------------------+ +| **Feature** | **Replacement / Notes** | ++===========================================+==========================================================+ +| SubDagOperator / SubDAGs | Use TaskGroups | ++-------------------------------------------+----------------------------------------------------------+ +| SLA callbacks / metrics | Deadline Alerts (planned post-3.0) | ++-------------------------------------------+----------------------------------------------------------+ +| DAG Pickling | Use JSON serialization; pickling is no longer supported | ++-------------------------------------------+----------------------------------------------------------+ +| Xcom Pickling | Use custom Xcom backend; pickling is no longer supported | ++-------------------------------------------+----------------------------------------------------------+ +| ``execution_date`` context var | Use ``dag_run.logical_date`` | ++-------------------------------------------+----------------------------------------------------------+ +| ``conf`` and ``dag_run.external_trigger`` | Removed from context; use DAG params or ``dag_run`` APIs | ++-------------------------------------------+----------------------------------------------------------+ +| Core ``EmailOperator`` | Use ``EmailOperator`` from the ``smtp`` provider | ++-------------------------------------------+----------------------------------------------------------+ +| ``none_failed_or_skipped`` rule | Use ``none_failed_min_one_success`` | ++-------------------------------------------+----------------------------------------------------------+ +| ``dummy`` trigger rule | Use ``always`` | ++-------------------------------------------+----------------------------------------------------------+ +| ``fail_stop`` argument | Use ``fail_fast`` | ++-------------------------------------------+----------------------------------------------------------+ +| ``store_serialized_dags=False`` | DAGs are always serialized; config has no effect | ++-------------------------------------------+----------------------------------------------------------+ +| Deprecated core imports | Import from appropriate provider package | ++-------------------------------------------+----------------------------------------------------------+ +| ``SequentialExecutor`` & ``DebugExecutor``| Use LocalExecutor for testing | ++-------------------------------------------+----------------------------------------------------------+ +| ``.airflowignore`` regex | Uses glob syntax by default | ++-------------------------------------------+----------------------------------------------------------+ -Pendulum 3 introduced some subtle incompatibilities that you might rely on in your code - for example -default rendering of dates is missing ``T`` in the rendered date representation, which is not ISO8601 -compliant. If you rely on the default rendering of dates, you might need to adjust your code to use -``isoformat()`` method to render dates in ISO8601 format. +Migration Tooling & Upgrade Process +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Airflow packaging specification follows modern Python packaging standards (#36537). -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -We standardized Airflow dependency configuration to follow latest development in Python packaging by -using ``pyproject.toml``. Airflow is now compliant with those accepted PEPs: +Airflow 3 was designed with migration in mind. Many Airflow 2 DAGs will work without changes, especially if deprecation +warnings were addressed in earlier releases. To support the upgrade, Airflow 3 includes validation tools such as ``ruff`` +and ``airflow config update``, as well as a simplified startup model. -* `PEP-440 Version Identification and Dependency Specification `__ -* `PEP-517 A build-system independent format for source trees `__ -* `PEP-518 Specifying Minimum Build System Requirements for Python Projects `__ -* `PEP-561 Distributing and Packaging Type Information `__ -* `PEP-621 Storing project metadata in pyproject.toml `__ -* `PEP-660 Editable installs for pyproject.toml based builds (wheel based) `__ -* `PEP-685 Comparison of extra names for optional distribution dependencies `__ +For a step-by-step upgrade process, see the :doc:`Upgrade Guide `. -Also we implement multiple license files support coming from Draft, not yet accepted (but supported by ``hatchling``) PEP: -* `PEP 639 Improving License Clarity with Better Package Metadata `__ +Minimum Supported Versions +""""""""""""""""""""""""""" -This has almost no noticeable impact on users if they are using modern Python packaging and development tools, generally -speaking Airflow should behave as it did before when installing it from PyPI and it should be much easier to install -it for development purposes using ``pip install -e ".[devel]"``. +To upgrade to Airflow 3.0, you must be running **Airflow 2.7 or later**. -The differences from the user side are: +Airflow 3.0 supports the following Python versions: -* Airflow extras now get extras normalized to ``-`` (following PEP-685) instead of ``_`` and ``.`` - (as it was before in some extras). When you install airflow with such extras (for example ``dbt.core`` or - ``all_dbs``) you should use ``-`` instead of ``_`` and ``.``. +- Python 3.9 +- Python 3.10 +- Python 3.11 +- Python 3.12 -In most modern tools this will work in backwards-compatible way, but in some old version of those tools you might need to -replace ``_`` and ``.`` with ``-``. You can also get warnings that the extra you are installing does not exist - but usually -this warning is harmless and the extra is installed anyway. It is, however, recommended to change to use ``-`` in extras in your dependency -specifications for all Airflow extras. +Earlier versions of Airflow or Python are not supported due to architectural changes and updated dependency requirements. -* Released airflow package does not contain ``devel``, ``devel-*``, ``doc`` and ``docs-gen`` extras. - Those extras are only available when you install Airflow from sources in ``--editable`` mode. This is - because those extras are only used for development and documentation building purposes and are not needed - when you install Airflow for production use. Those dependencies had unspecified and varying behaviour for - released packages anyway and you were not supposed to use them in released packages. +DAG Compatibility Checks +""""""""""""""""""""""""" -* The ``all`` and ``all-*`` extras were not always working correctly when installing Airflow using constraints - because they were also considered as development-only dependencies. With this change, those dependencies are - now properly handling constraints and they will install properly with constraints, pulling the right set - of providers and dependencies when constraints are used. +Airflow now includes a Ruff-based linter with custom rules to detect DAG patterns and interfaces that are no longer +compatible with Airflow 3.0. These checks are packaged under the ``AIR30x`` rule series. Example usage: -Graphviz dependency is now an optional one, not required one (#36647). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -The ``graphviz`` dependency has been problematic as Airflow required dependency - especially for -ARM-based installations. Graphviz packages require binary graphviz libraries - which is already a -limitation, but they also require to install graphviz Python bindings to be build and installed. -This does not work for older Linux installation but - more importantly - when you try to install -Graphviz libraries for Python 3.8, 3.9 for ARM M1 MacBooks, the packages fail to install because -Python bindings compilation for M1 can only work for Python 3.10+. +.. code-block:: bash -This is not a breaking change technically - the CLIs to render the DAGs is still there and IF you -already have graphviz installed, it will continue working as it did before. The only problem when it -does not work is where you do not have graphviz installed it will raise an error and inform that you need it. + ruff check dags/ --select AIR301 --preview + ruff check dags/ --select AIR301 --fix --preview -Graphviz will remain to be installed for most users: +These checks can automatically fix many common issues such as renamed arguments, removed imports, or legacy context +variable usage. -* the Airflow Image will still contain graphviz library, because - it is added there as extra -* when previous version of Airflow has been installed already, then - graphviz library is already installed there and Airflow will - continue working as it did +Configuration Migration +""""""""""""""""""""""" -The only change will be a new installation of new version of Airflow from the scratch, where graphviz will -need to be specified as extra or installed separately in order to enable DAG rendering option. +Airflow 3.0 introduces a new utility to validate and upgrade your Airflow configuration file: -Bug Fixes -""""""""" -- Fix airflow-scheduler exiting with code 0 on exceptions (#36800) -- Fix Callback exception when a removed task is the last one in the ``taskinstance`` list (#36693) -- Allow anonymous user edit/show resource when set ``AUTH_ROLE_PUBLIC=admin`` (#36750) -- Better error message when sqlite URL uses relative path (#36774) -- Explicit string cast required to force integer-type run_ids to be passed as strings instead of integers (#36756) -- Add log lookup exception for empty ``op`` subtypes (#35536) -- Remove unused index on task instance (#36737) -- Fix check on subclass for ``typing.Union`` in ``_infer_multiple_outputs`` for Python 3.10+ (#36728) -- Make sure ``multiple_outputs`` is inferred correctly even when using ``TypedDict`` (#36652) -- Add back FAB constant in legacy security manager (#36719) -- Fix AttributeError when using ``Dagrun.update_state`` (#36712) -- Do not let ``EventsTimetable`` schedule past events if ``catchup=False`` (#36134) -- Support encryption for triggers parameters (#36492) -- Fix the type hint for ``tis_query`` in ``_process_executor_events`` (#36655) -- Redirect to index when user does not have permission to access a page (#36623) -- Avoid using dict as default value in ``call_regular_interval`` (#36608) -- Remove option to set a task instance to running state in UI (#36518) -- Fix details tab not showing when using dynamic task mapping (#36522) -- Raise error when ``DagRun`` fails while running ``dag test`` (#36517) -- Refactor ``_manage_executor_state`` by refreshing TIs in batch (#36502) -- Add flask config: ``MAX_CONTENT_LENGTH`` (#36401) -- Fix get_leaves calculation for teardown in nested group (#36456) -- Stop serializing timezone-naive datetime to timezone-aware datetime with UTC tz (#36379) -- Make ``kubernetes`` decorator type annotation consistent with operator (#36405) -- Fix Webserver returning 500 for POST requests to ``api/dag/*/dagrun`` from anonymous user (#36275) -- Fix the required access for get_variable endpoint (#36396) -- Fix datetime reference in ``DAG.is_fixed_time_schedule`` (#36370) -- Fix AirflowSkipException message raised by BashOperator (#36354) -- Allow PythonVirtualenvOperator.skip_on_exit_code to be zero (#36361) -- Increase width of execution_date input in trigger.html (#36278) -- Fix logging for pausing DAG (#36182) -- Stop deserializing pickle when enable_xcom_pickling is False (#36255) -- Check DAG read permission before accessing DAG code (#36257) -- Enable mark task as failed/success always (#36254) -- Create latest log dir symlink as relative link (#36019) -- Fix Python-based decorators templating (#36103) +.. code-block:: bash -Miscellaneous -""""""""""""" -- Rename concurrency label to max active tasks (#36691) -- Restore function scoped ``httpx`` import in file_task_handler for performance (#36753) -- Add support of Pendulum 3 (#36281) -- Standardize airflow build process and switch to ``hatchling`` build backend (#36537) -- Get rid of ``pyarrow-hotfix`` for ``CVE-2023-47248`` (#36697) -- Make ``graphviz`` dependency optional (#36647) -- Announce MSSQL support end in Airflow 2.9.0, add migration script hints (#36509) -- Set min ``pandas`` dependency to 1.2.5 for all providers and airflow (#36698) -- Bump follow-redirects from 1.15.3 to 1.15.4 in ``/airflow/www`` (#36700) -- Provide the logger_name param to base hook in order to override the logger name (#36674) -- Fix run type icon alignment with run type text (#36616) -- Follow BaseHook connection fields method signature in FSHook (#36444) -- Remove redundant ``docker`` decorator type annotations (#36406) -- Straighten typing in workday timetable (#36296) -- Use ``batch_is_authorized_dag`` to check if user has permission to read DAGs (#36279) -- Replace deprecated get_accessible_dag_ids and use get_readable_dags in get_dag_warnings (#36256) + airflow config update + airflow config update --fix -Doc Only Changes -"""""""""""""""" -- Metrics tagging documentation (#36627) -- In docs use logical_date instead of deprecated execution_date (#36654) -- Add section about live-upgrading Airflow (#36637) -- Replace ``numpy`` example with practical exercise demonstrating top-level code (#35097) -- Improve and add more complete description in the architecture diagrams (#36513) -- Improve the error message displayed when there is a webserver error (#36570) -- Update ``dags.rst`` with information on DAG pausing (#36540) -- Update installation prerequisites after upgrading to Debian Bookworm (#36521) -- Add description on the ways how users should approach DB monitoring (#36483) -- Add branching based on mapped task group example to dynamic-task-mapping.rst (#36480) -- Add further details to replacement documentation (#36485) -- Use cards when describing priority weighting methods (#36411) -- Update ``metrics.rst`` for param ``dagrun.schedule_delay`` (#36404) -- Update admonitions in Python operator doc to reflect sentiment (#36340) -- Improve audit_logs.rst (#36213) -- Remove Redshift mention from the list of managed Postgres backends (#36217) +This utility detects removed or deprecated configuration options and, if desired, updates them in-place. -Airflow 2.8.0 (2023-12-18) --------------------------- +Additional validation is available via: + +.. code-block:: bash + + airflow config lint + +This command surfaces obsolete configuration keys and helps align your environment with Airflow 3.0 requirements. + +Metadata Database Upgrade +""""""""""""""""""""""""" + +As with previous major releases, the Airflow 3.0 upgrade includes schema changes to the metadata database. Before +upgrading, it is strongly recommended that you back up your database and optionally run: + +.. code-block:: bash + + airflow db clean + +to remove old task instance, log, or XCom data. To apply the new schema: + +.. code-block:: bash + + airflow db migrate + +Startup Behavior Changes +""""""""""""""""""""""""" + +Airflow components are now started explicitly. For example: + +.. code-block:: bash + + airflow api-server # Replaces airflow webserver + airflow dag-processor # Required in all environments + +These changes reflect Airflow's new service-oriented architecture. + +Resources +^^^^^^^^^ + +- :doc:`Upgrade Guide ` +- `Airflow AIPs `_ + +Airflow 3.0 represents more than a year of collaboration across hundreds of contributors and dozens of organizations. We +thank everyone who helped shape this release through design discussions, code contributions, testing, documentation, and +community feedback. For full details, migration guidance, and upgrade best practices, refer to the official Upgrade +Guide and join the conversation on the Airflow dev and user mailing lists. + +Airflow 2.11.0 (2025-05-20) +--------------------------- Significant Changes ^^^^^^^^^^^^^^^^^^^ -Raw HTML code in DAG docs and DAG params descriptions is disabled by default (#35460) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -To ensure that no malicious javascript can be injected with DAG descriptions or trigger UI forms by DAG authors -a new parameter ``webserver.allow_raw_html_descriptions`` was added with default value of ``False``. -If you trust your DAG authors code and want to allow using raw HTML in DAG descriptions and params, you can restore the previous -behavior by setting the configuration value to ``True``. +``DeltaTriggerTimetable`` for trigger-based scheduling (#47074) +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -To ensure Airflow is secure by default, the raw HTML support in trigger UI has been super-seeded by markdown support via -the ``description_md`` attribute. If you have been using ``description_html`` please migrate to ``description_md``. -The ``custom_html_form`` is now deprecated. +This change introduces DeltaTriggerTimetable, a new built-in timetable that complements the existing suite of +Airflow timetables by supporting delta-based trigger schedules without relying on data intervals. + +Airflow currently has two major types of timetables: + - Data interval-based (e.g., ``CronDataIntervalTimetable``, ``DeltaDataIntervalTimetable``) + - Trigger-based (e.g., ``CronTriggerTimetable``) + +However, there was no equivalent trigger-based option for delta intervals like ``timedelta(days=1)``. +As a result, even simple schedules like ``schedule=timedelta(days=1)`` were interpreted through a data interval +lens—adding unnecessary complexity for users who don't care about upstream/downstream data dependencies. + +This feature is backported to Airflow 2.11.0 to help users begin transitioning before upgrading to Airflow 3.0. + + - In Airflow 2.11, ``schedule=timedelta(...)`` still defaults to ``DeltaDataIntervalTimetable``. + - A new config option ``[scheduler] create_delta_data_intervals`` (default: ``True``) allows opting in to ``DeltaTriggerTimetable``. + - In Airflow 3.0, this config defaults to ``False``, meaning ``DeltaTriggerTimetable`` becomes the default for timedelta schedules. + +By flipping this config in 2.11, users can preview and adopt the new scheduling behavior in advance — minimizing surprises during upgrade. + + +Consistent timing metrics across all backends (#39908, #43966) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Previously, Airflow reported timing metrics in milliseconds for ``StatsD`` but in seconds for other backends +such as ``OpenTelemetry`` and ``Datadog``. This inconsistency made it difficult to interpret or compare +timing metrics across systems. + +Airflow 2.11 introduces a new config option: + + - ``[metrics] timer_unit_consistency`` (default: ``False`` in 2.11, ``True`` and dropped in Airflow 3.0). + +When enabled, all timing metrics are consistently reported in milliseconds, regardless of the backend. + +This setting has become mandatory and always ``True`` in Airflow 3.0 (the config will be removed), so +enabling it in 2.11 allows users to migrate early and avoid surprises during upgrade. + +Ease migration to Airflow 3 +""""""""""""""""""""""""""" +This release introduces several changes to help users prepare for upgrading to Airflow 3: + + - All models using ``execution_date`` now also include a ``logical_date`` field. Airflow 3 drops ``execution_date`` entirely in favor of ``logical_date`` (#44283) + - Added ``airflow config lint`` and ``airflow config update`` commands in 2.11 to help audit and migrate configs for Airflow 3.0. (#45736, #50353, #46757) + +Python 3.8 support removed +"""""""""""""""""""""""""" +Support for Python 3.8 has been removed, as it has reached end-of-life. +Airflow 2.11 requires Python 3.9, 3.10, 3.11, or 3.12. New Features """""""""""" -- AIP-58: Add Airflow ObjectStore (AFS) (`AIP-58 `_) -- Add XCom tab to Grid (#35719) -- Add "literal" wrapper to disable field templating (#35017) -- Add task context logging feature to allow forwarding messages to task logs (#32646, #32693, #35857) -- Add Listener hooks for Datasets (#34418, #36247) -- Allow override of navbar text color (#35505) -- Add lightweight serialization for deltalake tables (#35462) -- Add support for serialization of iceberg tables (#35456) -- ``prev_end_date_success`` method access (#34528) -- Add task parameter to set custom logger name (#34964) -- Add pyspark decorator (#35247) -- Add trigger as a valid option for the db clean command (#34908) -- Add decorators for external and venv python branching operators (#35043) -- Allow PythonVenvOperator using other index url (#33017) -- Add Python Virtualenv Operator Caching (#33355) -- Introduce a generic export for containerized executor logging (#34903) -- Add ability to clear downstream tis in ``List Task Instances`` view (#34529) -- Attribute ``clear_number`` to track DAG run being cleared (#34126) -- Add BranchPythonVirtualenvOperator (#33356) -- Allow PythonVenvOperator using other index url (#33017) -- Add CLI notification commands to providers (#33116) -- Use dropdown instead of buttons when there are more than 10 retries in log tab (#36025) -Improvements -"""""""""""" -- Add ``multiselect`` to run state in grid view (#35403) -- Fix warning message in ``Connection.get_hook`` in case of ImportError (#36005) -- Add processor_subdir to import_error table to handle multiple dag processors (#35956) -- Consolidate the call of change_state to fail or success in the core executors (#35901) -- Relax mandatory requirement for start_date when schedule=None (#35356) -- Use ExitStack to manage mutation of secrets_backend_list in dag.test (#34620) -- improved visibility of tasks in ActionModal for ``taskinstance`` (#35810) -- Create directories based on ``AIRFLOW_CONFIG`` path (#35818) -- Implements ``JSON-string`` connection representation generator (#35723) -- Move ``BaseOperatorLink`` into the separate module (#35032) -- Set mark_end_on_close after set_context (#35761) -- Move external logs links to top of react logs page (#35668) -- Change terminal mode to ``cbreak`` in ``execute_interactive`` and handle ``SIGINT`` (#35602) -- Make raw HTML descriptions configurable (#35460) -- Allow email field to be templated (#35546) -- Hide logical date and run id in trigger UI form (#35284) -- Improved instructions for adding dependencies in TaskFlow (#35406) -- Add optional exit code to list import errors (#35378) -- Limit query result on DB rather than client in ``synchronize_log_template`` function (#35366) -- Allow description to be passed in when using variables CLI (#34791) -- Allow optional defaults in required fields with manual triggered dags (#31301) -- Permitting airflow kerberos to run in different modes (#35146) -- Refactor commands to unify daemon context handling (#34945) -- Add extra fields to plugins endpoint (#34913) -- Add description to pools view (#34862) -- Move cli's Connection export and Variable export command print logic to a separate function (#34647) -- Extract and reuse get_kerberos_principle func from get_kerberos_principle (#34936) -- Change type annotation for ``BaseOperatorLink.operators`` (#35003) -- Optimise and migrate to ``SA2-compatible`` syntax for TaskReschedule (#33720) -- Consolidate the permissions name in SlaMissModelView (#34949) -- Add debug log saying what's being run to ``EventScheduler`` (#34808) -- Increase log reader stream loop sleep duration to 1 second (#34789) -- Resolve pydantic deprecation warnings re ``update_forward_refs`` (#34657) -- Unify mapped task group lookup logic (#34637) -- Allow filtering event logs by attributes (#34417) -- Make connection login and password TEXT (#32815) -- Ban import ``Dataset`` from ``airflow`` package in codebase (#34610) -- Use ``airflow.datasets.Dataset`` in examples and tests (#34605) -- Enhance task status visibility (#34486) -- Simplify DAG trigger UI (#34567) -- Ban import AirflowException from airflow (#34512) -- Add descriptions for airflow resource config parameters (#34438) -- Simplify trigger name expression (#34356) -- Move definition of Pod*Exceptions to pod_generator (#34346) -- Add deferred tasks to the cluster_activity view Pools Slots (#34275) -- heartbeat failure log message fix (#34160) -- Rename variables for dag runs (#34049) -- Clarify new_state in OpenAPI spec (#34056) -- Remove ``version`` top-level element from docker compose files (#33831) -- Remove generic trigger cancelled error log (#33874) -- Use ``NOT EXISTS`` subquery instead of ``tuple_not_in_condition`` (#33527) -- Allow context key args to not provide a default (#33430) -- Order triggers by - TI priority_weight when assign unassigned triggers (#32318) -- Add metric ``triggerer_heartbeat`` (#33320) -- Allow ``airflow variables export`` to print to stdout (#33279) -- Workaround failing deadlock when running backfill (#32991) -- add dag_run_ids and task_ids filter for the batch task instance API endpoint (#32705) -- Configurable health check threshold for triggerer (#33089) -- Rework provider manager to treat Airflow core hooks like other provider hooks (#33051) -- Ensure DAG-level references are filled on unmap (#33083) -- Affix webserver access_denied warning to be configurable (#33022) -- Add support for arrays of different data types in the Trigger Form UI (#32734) -- Add a mechanism to warn if executors override existing CLI commands (#33423) +- Introduce ``DeltaTriggerTimetable`` (#47074) +- Backport ``airflow config update`` and ``airflow config lint`` changes to ease migration to Airflow 3 (#45736, #50353) +- Add link to show task in a DAG in DAG Dependencies view (#47721) +- Align timers and timing metrics (ms) across all metrics loggers (#39908, #43966) Bug Fixes """"""""" -- Account for change in UTC offset when calculating next schedule (#35887) -- Add read access to pools for viewer role (#35352) -- Fix gantt chart queued duration when queued_dttm is greater than start_date for deferred tasks (#35984) -- Avoid crushing container when directory is not found on rm (#36050) -- Update ``reset_user_sessions`` to work from either CLI or web (#36056) -- Fix UI Grid error when DAG has been removed. (#36028) -- Change Trigger UI to use HTTP POST in web ui (#36026) -- Fix airflow db shell needing an extra key press to exit (#35982) -- Change dag grid ``overscroll`` behaviour to auto (#35717) -- Run triggers inline with dag test (#34642) -- Add ``borderWidthRight`` to grid for Firefox ``scrollbar`` (#35346) -- Fix for infinite recursion due to secrets_masker (#35048) -- Fix write ``processor_subdir`` in serialized_dag table (#35661) -- Reload configuration for standalone dag file processor (#35725) -- Long custom operator name overflows in graph view (#35382) -- Add try_number to extra links query (#35317) -- Prevent assignment of non JSON serializable values to DagRun.conf dict (#35096) -- Numeric values in DAG details are incorrectly rendered as timestamps (#35538) -- Fix Scheduler and triggerer crashes in daemon mode when statsd metrics are enabled (#35181) -- Infinite UI redirection loop after deactivating an active user (#35486) -- Bug fix fetch_callback of Partial Subset DAG (#35256) -- Fix DagRun data interval for DeltaDataIntervalTimetable (#35391) -- Fix query in ``get_dag_by_pickle`` util function (#35339) -- Fix TriggerDagRunOperator failing to trigger subsequent runs when reset_dag_run=True (#35429) -- Fix weight_rule property type in ``mappedoperator`` (#35257) -- Bugfix/prevent concurrency with cached venv (#35258) -- Fix dag serialization (#34042) -- Fix py/url-redirection by replacing request.referrer by get_redirect() (#34237) -- Fix updating variables during variable imports (#33932) -- Use Literal from airflow.typing_compat in Airflow core (#33821) -- Always use ``Literal`` from ``typing_extensions`` (#33794) + +- Don't resolve path for DAGs folder (#46877) +- Fix ``ti.log_url`` timestamp format from ``"%Y-%m-%dT%H:%M:%S%z"`` to ``"%Y-%m-%dT%H:%M:%S.%f%z"`` (#50306) +- Ensure that the generated ``airflow.cfg`` contains a random ``fernet_key`` and ``secret_key`` (#47755) +- Fixed setting ``rendered_map_index`` via internal api (#49057) +- Store rendered_map_index from ``TaskInstancePydantic`` into ``TaskInstance`` (#48571) +- Allow using ``log_url`` property on ``TaskInstancePydantic`` (Internal API) (#50560) +- Fix Trigger Form with Empty Object Default (#46872) +- Fix ``TypeError`` when deserializing task with ``execution_timeout`` set to ``None`` (#46822) +- Always populate mapped tasks (#46790) +- Ensure ``check_query_exists`` returns a bool (#46707) +- UI: ``/xcom/list`` got exception when applying filter on the ``value`` column (#46053) +- Allow to set note field via the experimental internal api (#47769) Miscellaneous """"""""""""" -- Change default MySQL client to MariaDB (#36243) -- Mark daskexecutor provider as removed (#35965) -- Bump FAB to ``4.3.10`` (#35991) -- Mark daskexecutor provider as removed (#35965) -- Rename ``Connection.to_json_dict`` to ``Connection.to_dict`` (#35894) -- Upgrade to Pydantic v2 (#35551) -- Bump ``moto`` version to ``>= 4.2.9`` (#35687) -- Use ``pyarrow-hotfix`` to mitigate CVE-2023-47248 (#35650) -- Bump ``axios`` from ``0.26.0 to 1.6.0`` in ``/airflow/www/`` (#35624) -- Make docker decorator's type annotation consistent with operator (#35568) -- Add default to ``navbar_text_color`` and ``rm`` condition in style (#35553) -- Avoid initiating session twice in ``dag_next_execution`` (#35539) -- Work around typing issue in examples and providers (#35494) -- Enable ``TCH004`` and ``TCH005`` rules (#35475) -- Humanize log output about retrieved DAG(s) (#35338) -- Switch from Black to Ruff formatter (#35287) -- Upgrade to Flask Application Builder 4.3.9 (#35085) -- D401 Support (#34932, #34933) -- Use requires_access to check read permission on dag instead of checking it explicitly (#34940) -- Deprecate lazy import ``AirflowException`` from airflow (#34541) -- View util refactoring on mapped stuff use cases (#34638) -- Bump ``postcss`` from ``8.4.25 to 8.4.31`` in ``/airflow/www`` (#34770) -- Refactor Sqlalchemy queries to 2.0 style (#34763, #34665, #32883, #35120) -- Change to lazy loading of io in pandas serializer (#34684) -- Use ``airflow.models.dag.DAG`` in examples (#34617) -- Use airflow.exceptions.AirflowException in core (#34510) -- Check that dag_ids passed in request are consistent (#34366) -- Refactors to make code better (#34278, #34113, #34110, #33838, #34260, #34409, #34377, #34350) -- Suspend qubole provider (#33889) -- Generate Python API docs for Google ADS (#33814) -- Improve importing in modules (#33812, #33811, #33810, #33806, #33807, #33805, #33804, #33803, - #33801, #33799, #33800, #33797, #33798, #34406, #33808) -- Upgrade Elasticsearch to 8 (#33135) + +- Add ``logical_date`` to models using ``execution_date`` (#44283) +- Drop support for Python 3.8 (#49980, #50015) +- Emit warning for deprecated ``BaseOperatorLink.get_link`` signature (#46448) Doc Only Changes """""""""""""""" -- Add support for tabs (and other UX components) to docs (#36041) -- Replace architecture diagram of Airflow with diagrams-generated one (#36035) -- Add the section describing the security model of DAG Author capabilities (#36022) -- Enhance docs for zombie tasks (#35825) -- Reflect drop/add support of DB Backends versions in documentation (#35785) -- More detail on mandatory task arguments (#35740) -- Indicate usage of the ``re2`` regex engine in the .airflowignore documentation. (#35663) -- Update ``best-practices.rst`` (#35692) -- Update ``dag-run.rst`` to mention Airflow's support for extended cron syntax through croniter (#35342) -- Update ``webserver.rst`` to include information of supported OAuth2 providers (#35237) -- Add back dag_run to docs (#35142) -- Fix ``rst`` code block format (#34708) -- Add typing to concrete taskflow examples (#33417) -- Add concrete examples for accessing context variables from TaskFlow tasks (#33296) -- Fix links in security docs (#33329) - +- Unquote executor ``airflow.cfg`` variable (#48084) +- Update ``XCom`` docs to show examples of pushing multiple ``XComs`` (#46284, #47068) -Airflow 2.7.3 (2023-11-06) --------------------------- +Airflow 2.10.5 (2025-02-10) +--------------------------- Significant Changes ^^^^^^^^^^^^^^^^^^^ -No significant changes. +Ensure teardown tasks are executed when DAG run is set to failed (#45530) +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Previously when a DAG run was manually set to "failed" or to "success" state the terminal state was set to all tasks. +But this was a gap for cases when setup- and teardown tasks were defined: If teardown was used to clean-up infrastructure +or other resources, they were also skipped and thus resources could stay allocated. + +As of now when setup tasks had been executed before and the DAG is manually set to "failed" or "success" then teardown +tasks are executed. Teardown tasks are skipped if the setup was also skipped. + +As a side effect this means if the DAG contains teardown tasks, then the manual marking of DAG as "failed" or "success" +will need to keep the DAG in running state to ensure that teardown tasks will be scheduled. They would not be scheduled +if the DAG is directly set to "failed" or "success". + Bug Fixes """"""""" -- Fix pre-mature evaluation of tasks in mapped task group (#34337) -- Add TriggerRule missing value in rest API (#35194) -- Fix Scheduler crash looping when dagrun creation fails (#35135) -- Fix test connection with ``codemirror`` and extra (#35122) -- Fix usage of cron-descriptor since BC in v1.3.0 (#34836) -- Fix ``get_plugin_info`` for class based listeners. (#35022) -- Some improvements/fixes for dag_run and task_instance endpoints (#34942) -- Fix the dags count filter in webserver home page (#34944) -- Return only the TIs of the readable dags when ~ is provided as a dag_id (#34939) -- Fix triggerer thread crash in daemon mode (#34931) -- Fix wrong plugin schema (#34858) -- Use DAG timezone in TimeSensorAsync (#33406) -- Mark tasks with ``all_skipped`` trigger rule as ``skipped`` if any task is in ``upstream_failed`` state (#34392) -- Add read only validation to read only fields (#33413) -Misc/Internal -""""""""""""" -- Improve testing harness to separate DB and non-DB tests (#35160, #35333) -- Add pytest db_test markers to our tests (#35264) -- Add pip caching for faster build (#35026) -- Upper bound ``pendulum`` requirement to ``<3.0`` (#35336) -- Limit ``sentry_sdk`` to ``1.33.0`` (#35298) -- Fix subtle bug in mocking processor_agent in our tests (#35221) -- Bump ``@babel/traverse`` from ``7.16.0 to 7.23.2`` in ``/airflow/www`` (#34988) -- Bump ``undici`` from ``5.19.1 to 5.26.3`` in ``/airflow/www`` (#34971) -- Remove unused set from ``SchedulerJobRunner`` (#34810) -- Remove warning about ``max_tis per query > parallelism`` (#34742) -- Improve modules import in Airflow core by moving some of them into a type-checking block (#33755) -- Fix tests to respond to Python 3.12 handling of utcnow in sentry-sdk (#34946) -- Add ``connexion<3.0`` upper bound (#35218) -- Limit Airflow to ``< 3.12`` (#35123) -- update moto version (#34938) -- Limit WTForms to below ``3.1.0`` (#34943) +- Prevent using ``trigger_rule=TriggerRule.ALWAYS`` in a task-generated mapping within bare tasks (#44751) +- Fix ShortCircuitOperator mapped tasks (#44912) +- Fix premature evaluation of tasks with certain trigger rules (e.g. ``ONE_DONE``) in a mapped task group (#44937) +- Fix task_id validation in BaseOperator (#44938) (#44938) +- Allow fetching XCom with forward slash from the API and escape it in the UI (#45134) +- Fix ``FileTaskHandler`` only read from default executor (#46000) +- Fix empty task instance for log (#45702) (#45703) +- Remove ``skip_if`` and ``run_if`` decorators before TaskFlow virtualenv tasks are run (#41832) (#45680) +- Fix request body for json requests in event log (#45546) (#45560) +- Ensure teardown tasks are executed when DAG run is set to failed (#45530) (#45581) +- Do not update DR on TI update after task execution (#45348) +- Fix object and array DAG params that have a None default (#45313) (#45315) +- Fix endless sensor rescheduling (#45224) (#45250) +- Evaluate None in SQLAlchemy's extended JSON type decorator (#45119) (#45120) +- Allow dynamic tasks to be filtered by ``rendered_map_index`` (#45109) (#45122) +- Handle relative paths when sanitizing URLs (#41995) (#45080) +- Set Autocomplete Off on Login Form (#44929) (#44940) +- Add Webserver parameters ``max_form_parts``, ``max_form_memory_size`` (#46243) (#45749) +- Fixed accessing thread local variable in BaseOperators ``execute`` safeguard mechanism (#44646) (#46280) +- Add map_index parameter to extra links API (#46337) -Doc Only Changes -"""""""""""""""" -- Fix variables substitution in Airflow Documentation (#34462) -- Added example for defaults in ``conn.extras`` (#35165) -- Update datasets.rst issue with running example code (#35035) -- Remove ``mysql-connector-python`` from recommended MySQL driver (#34287) -- Fix syntax error in task dependency ``set_downstream`` example (#35075) -- Update documentation to enable test connection (#34905) -- Update docs errors.rst - Mention sentry "transport" configuration option (#34912) -- Update dags.rst to put SubDag deprecation note right after the SubDag section heading (#34925) -- Add info on getting variables and config in custom secrets backend (#34834) -- Document BaseExecutor interface in more detail to help users in writing custom executors (#34324) -- Fix broken link to ``airflow_local_settings.py`` template (#34826) -- Fixes python_callable function assignment context kwargs example in params.rst (#34759) -- Add missing multiple_outputs=True param in the TaskFlow example (#34812) -- Remove extraneous ``'>'`` in provider section name (#34813) -- Fix imports in extra link documentation (#34547) +Miscellaneous +""""""""""""" + +- Add traceback log output when SIGTERMs was sent (#44880) (#45077) +- Removed the ability for Operators to specify their own "scheduling deps" (#45713) (#45742) +- Deprecate ``conf`` from Task Context (#44993) -Airflow 2.7.2 (2023-10-12) --------------------------- +Airflow 2.10.4 (2024-12-16) +--------------------------- Significant Changes ^^^^^^^^^^^^^^^^^^^ -No significant changes +TaskInstance ``priority_weight`` is capped in 32-bit signed integer ranges (#43611) +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Some database engines are limited to 32-bit integer values. As some users reported errors in +weight rolled-over to negative values, we decided to cap the value to the 32-bit integer. Even +if internally in python smaller or larger values to 64 bit are supported, ``priority_weight`` is +capped and only storing values from -2147483648 to 2147483647. Bug Fixes -""""""""" -- Check if the lower of provided values are sensitives in config endpoint (#34712) -- Add support for ZoneInfo and generic UTC to fix datetime serialization (#34683, #34804) -- Fix AttributeError: 'Select' object has no attribute 'count' during the airflow db migrate command (#34348) -- Make dry run optional for patch task instance (#34568) -- Fix non deterministic datetime deserialization (#34492) -- Use iterative loop to look for mapped parent (#34622) -- Fix is_parent_mapped value by checking if any of the parent ``taskgroup`` is mapped (#34587) -- Avoid top-level airflow import to avoid circular dependency (#34586) -- Add more exemptions to lengthy metric list (#34531) -- Fix dag warning endpoint permissions (#34355) -- Fix task instance access issue in the batch endpoint (#34315) -- Correcting wrong time showing in grid view (#34179) -- Fix www ``cluster_activity`` view not loading due to ``standaloneDagProcessor`` templating (#34274) -- Set ``loglevel=DEBUG`` in 'Not syncing ``DAG-level`` permissions' (#34268) -- Make param validation consistent for DAG validation and triggering (#34248) -- Ensure details panel is shown when any tab is selected (#34136) -- Fix issues related to ``access_control={}`` (#34114) -- Fix not found ``ab_user`` table in the CLI session (#34120) -- Fix FAB-related logging format interpolation (#34139) -- Fix query bug in ``next_run_datasets_summary`` endpoint (#34143) -- Fix for TaskGroup toggles for duplicated labels (#34072) -- Fix the required permissions to clear a TI from the UI (#34123) -- Reuse ``_run_task_session`` in mapped ``render_template_fields`` (#33309) -- Fix scheduler logic to plan new dag runs by ignoring manual runs (#34027) -- Add missing audit logs for Flask actions add, edit and delete (#34090) -- Hide Irrelevant Dag Processor from Cluster Activity Page (#33611) -- Remove infinite animation for pinwheel, spin for 1.5s (#34020) -- Restore rendering of provider configuration with ``version_added`` (#34011) +^^^^^^^^^ + +- Fix stats of dynamic mapped tasks after automatic retries of failed tasks (#44300) +- Fix wrong display of multi-line messages in the log after filtering (#44457) +- Allow "/" in metrics validator (#42934) (#44515) +- Fix gantt flickering (#44488) (#44517) +- Fix problem with inability to remove fields from Connection form (#40421) (#44442) +- Check pool_slots on partial task import instead of execution (#39724) (#42693) +- Avoid grouping task instance stats by try_number for dynamic mapped tasks (#44300) (#44319) +- Re-queue task when they are stuck in queued (#43520) (#44158) +- Suppress the warnings where we check for sensitive values (#44148) (#44167) +- Fix get_task_instance_try_details to return appropriate schema (#43830) (#44133) +- Log message source details are grouped (#43681) (#44070) +- Fix duplication of Task tries in the UI (#43891) (#43950) +- Add correct mime-type in OpenAPI spec (#43879) (#43901) +- Disable extra links button if link is null or empty (#43844) (#43851) +- Disable XCom list ordering by execution_date (#43680) (#43696) +- Fix venv numpy example which needs to be 1.26 at least to be working in Python 3.12 (#43659) +- Fix Try Selector in Mapped Tasks also on Index 0 (#43590) (#43591) +- Prevent using ``trigger_rule="always"`` in a dynamic mapped task (#43810) +- Prevent using ``trigger_rule=TriggerRule.ALWAYS`` in a task-generated mapping within bare tasks (#44751) Doc Only Changes """""""""""""""" -- Clarify audit log permissions (#34815) -- Add explanation for Audit log users (#34814) -- Import ``AUTH_REMOTE_USER`` from FAB in WSGI middleware example (#34721) -- Add information about drop support MsSQL as DB Backend in the future (#34375) -- Document how to use the system's timezone database (#34667) -- Clarify what landing time means in doc (#34608) -- Fix screenshot in dynamic task mapping docs (#34566) -- Fix class reference in Public Interface documentation (#34454) -- Clarify var.value.get and var.json.get usage (#34411) -- Schedule default value description (#34291) -- Docs for triggered_dataset_event (#34410) -- Add DagRun events (#34328) -- Provide tabular overview about trigger form param types (#34285) -- Add link to Amazon Provider Configuration in Core documentation (#34305) -- Add "security infrastructure" paragraph to security model (#34301) -- Change links to SQLAlchemy 1.4 (#34288) -- Add SBOM entry in security documentation (#34261) -- Added more example code for XCom push and pull (#34016) -- Add state utils to Public Airflow Interface (#34059) -- Replace markdown style link with rst style link (#33990) -- Fix broken link to the "UPDATING.md" file (#33583) +- Update XCom docs around containers/helm (#44570) (#44573) -Misc/Internal +Miscellaneous """"""""""""" -- Update min-sqlalchemy version to account for latest features used (#34293) -- Fix SesssionExemptMixin spelling (#34696) -- Restrict ``astroid`` version < 3 (#34658) -- Fail dag test if defer without triggerer (#34619) -- Fix connections exported output (#34640) -- Don't run isort when creating new alembic migrations (#34636) -- Deprecate numeric type python version in PythonVirtualEnvOperator (#34359) -- Refactor ``os.path.splitext`` to ``Path.*`` (#34352, #33669) -- Replace = by is for type comparison (#33983) -- Refactor integer division (#34180) -- Refactor: Simplify comparisons (#34181) -- Refactor: Simplify string generation (#34118) -- Replace unnecessary dict comprehension with dict() in core (#33858) -- Change "not all" to "any" for ease of readability (#34259) -- Replace assert by if...raise in code (#34250, #34249) -- Move default timezone to except block (#34245) -- Combine similar if logic in core (#33988) -- Refactor: Consolidate import and usage of random (#34108) -- Consolidate importing of os.path.* (#34060) -- Replace sequence concatenation by unpacking in Airflow core (#33934) -- Refactor unneeded 'continue' jumps around the repo (#33849, #33845, #33846, #33848, #33839, #33844, #33836, #33842) -- Remove [project] section from ``pyproject.toml`` (#34014) -- Move the try outside the loop when this is possible in Airflow core (#33975) -- Replace loop by any when looking for a positive value in core (#33985) -- Do not create lists we don't need (#33519) -- Remove useless string join from core (#33969) -- Add TCH001 and TCH002 rules to pre-commit to detect and move type checking modules (#33865) -- Add cancel_trigger_ids to to_cancel dequeue in batch (#33944) -- Avoid creating unnecessary list when parsing stats datadog tags (#33943) -- Replace dict.items by dict.values when key is not used in core (#33940) -- Replace lambdas with comprehensions (#33745) -- Improve modules import in Airflow core by some of them into a type-checking block (#33755) -- Refactor: remove unused state - SHUTDOWN (#33746, #34063, #33893) -- Refactor: Use in-place .sort() (#33743) -- Use literal dict instead of calling dict() in Airflow core (#33762) -- remove unnecessary map and rewrite it using list in Airflow core (#33764) -- Replace lambda by a def method in Airflow core (#33758) -- Replace type func by ``isinstance`` in fab_security manager (#33760) -- Replace single quotes by double quotes in all Airflow modules (#33766) -- Merge multiple ``isinstance`` calls for the same object in a single call (#33767) -- Use a single statement with multiple contexts instead of nested statements in core (#33769) -- Refactor: Use f-strings (#33734, #33455) -- Refactor: Use random.choices (#33631) -- Use ``str.splitlines()`` to split lines (#33592) -- Refactor: Remove useless str() calls (#33629) -- Refactor: Improve detection of duplicates and list sorting (#33675) -- Simplify conditions on ``len()`` (#33454) +- Raise deprecation warning when accessing inlet or outlet events through str (#43922) -Airflow 2.7.1 (2023-09-07) --------------------------- +Airflow 2.10.3 (2024-11-05) +--------------------------- Significant Changes ^^^^^^^^^^^^^^^^^^^ -CronTriggerTimetable is now less aggressive when trying to skip a run (#33404) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -When setting ``catchup=False``, CronTriggerTimetable no longer skips a run if -the scheduler does not query the timetable immediately after the previous run -has been triggered. +No significant changes. -This should not affect scheduling in most cases, but can change the behaviour if -a DAG is paused-unpaused to manually skip a run. Previously, the timetable (with -``catchup=False``) would only start a run after a DAG is unpaused, but with this -change, the scheduler would try to look at little bit back to schedule the -previous run that covers a part of the period when the DAG was paused. This -means you will need to keep a DAG paused longer (namely, for the entire cron -period to pass) to really skip a run. +Bug Fixes +""""""""" +- Improves the handling of value masking when setting Airflow variables for enhanced security. (#43123) (#43278) +- Adds support for task_instance_mutation_hook to handle mapped operators with index 0. (#42661) (#43089) +- Fixes executor cleanup to properly handle zombie tasks when task instances are terminated. (#43065) +- Adds retry logic for HTTP 502 and 504 errors in internal API calls to handle webserver startup issues. (#42994) (#43044) +- Restores the use of separate sessions for writing and deleting RTIF data to prevent StaleDataError. (#42928) (#43012) +- Fixes PythonOperator error by replacing hyphens with underscores in DAG names. (#42993) +- Improving validation of task retries to handle None values (#42532) (#42915) +- Fixes error handling in dataset managers when resolving dataset aliases into new datasets (#42733) +- Enables clicking on task names in the DAG Graph View to correctly select the corresponding task. (#38782) (#42697) +- Prevent redirect loop on /home with tags/last run filters (#42607) (#42609) (#42628) +- Support of host.name in OTEL metrics and usage of OTEL_RESOURCE_ATTRIBUTES in metrics (#42428) (#42604) +- Reduce eyestrain in dark mode with reduced contrast and saturation (#42567) (#42583) +- Handle ENTER key correctly in trigger form and allow manual JSON (#42525) (#42535) +- Ensure DAG trigger form submits with updated parameters upon keyboard submit (#42487) (#42499) +- Do not attempt to provide not ``stringified`` objects to UI via xcom if pickling is active (#42388) (#42486) +- Fix the span link of task instance to point to the correct span in the scheduler_job_loop (#42430) (#42480) +- Bugfix task execution from runner in Windows (#42426) (#42478) +- Allows overriding the hardcoded OTEL_SERVICE_NAME with an environment variable (#42242) (#42441) +- Improves trigger performance by using ``selectinload`` instead of ``joinedload`` (#40487) (#42351) +- Suppress warnings when masking sensitive configs (#43335) (#43337) +- Masking configuration values irrelevant to DAG author (#43040) (#43336) +- Execute templated bash script as file in BashOperator (#43191) +- Fixes schedule_downstream_tasks to include upstream tasks for one_success trigger rule (#42582) (#43299) +- Add retry logic in the scheduler for updating trigger timeouts in case of deadlocks. (#41429) (#42651) +- Mark all tasks as skipped when failing a dag_run manually (#43572) +- Fix ``TrySelector`` for Mapped Tasks in Logs and Details Grid Panel (#43566) +- Conditionally add OTEL events when processing executor events (#43558) (#43567) +- Fix broken stat ``scheduler_loop_duration`` (#42886) (#43544) +- Ensure total_entries in /api/v1/dags (#43377) (#43429) +- Include limit and offset in request body schema for List task instances (batch) endpoint (#43479) +- Don't raise a warning in ExecutorSafeguard when execute is called from an extended operator (#42849) (#43577) -Note that this is also the behaviour exhibited by various other cron-based -scheduling tools, such as ``anacron``. +Miscellaneous +""""""""""""" +- Deprecate session auth backend (#42911) +- Removed unicodecsv dependency for providers with Airflow version 2.8.0 and above (#42765) (#42970) +- Remove the referrer from Webserver to Scarf (#42901) (#42942) +- Bump ``dompurify`` from 2.2.9 to 2.5.6 in /airflow/www (#42263) (#42270) +- Correct docstring format in _get_template_context (#42244) (#42272) +- Backport: Bump Flask-AppBuilder to ``4.5.2`` (#43309) (#43318) +- Check python version that was used to install pre-commit venvs (#43282) (#43310) +- Resolve warning in Dataset Alias migration (#43425) -``conf.set()`` becomes case insensitive to match ``conf.get()`` behavior (#33452) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Doc Only Changes +"""""""""""""""" +- Clarifying PLUGINS_FOLDER permissions by DAG authors (#43022) (#43029) +- Add templating info to TaskFlow tutorial (#42992) +- Airflow local settings no longer importable from dags folder (#42231) (#42603) +- Fix documentation for cpu and memory usage (#42147) (#42256) +- Fix instruction for docker compose (#43119) (#43321) +- Updates documentation to reflect that dag_warnings is returned instead of import_errors. (#42858) (#42888) -Also, ``conf.get()`` will now break if used with non-string parameters. -``conf.set(section, key, value)`` used to be case sensitive, i.e. ``conf.set("SECTION", "KEY", value)`` -and ``conf.set("section", "key", value)`` were stored as two distinct configurations. -This was inconsistent with the behavior of ``conf.get(section, key)``, which was always converting the section and key to lower case. +Airflow 2.10.2 (2024-09-18) +--------------------------- -As a result, configuration options set with upper case characters in the section or key were unreachable. -That's why we are now converting section and key to lower case in ``conf.set`` too. +Significant Changes +^^^^^^^^^^^^^^^^^^^ -We also changed a bit the behavior of ``conf.get()``. It used to allow objects that are not strings in the section or key. -Doing this will now result in an exception. For instance, ``conf.get("section", 123)`` needs to be replaced with ``conf.get("section", "123")``. +No significant changes. Bug Fixes """"""""" -- Ensure that tasks wait for running indirect setup (#33903) -- Respect "soft_fail" for core async sensors (#33403) -- Differentiate 0 and unset as a default param values (#33965) -- Raise 404 from Variable PATCH API if variable is not found (#33885) -- Fix ``MappedTaskGroup`` tasks not respecting upstream dependency (#33732) -- Add limit 1 if required first value from query result (#33672) -- Fix UI DAG counts including deleted DAGs (#33778) -- Fix cleaning zombie RESTARTING tasks (#33706) -- ``SECURITY_MANAGER_CLASS`` should be a reference to class, not a string (#33690) -- Add back ``get_url_for_login`` in security manager (#33660) -- Fix ``2.7.0 db`` migration job errors (#33652) -- Set context inside templates (#33645) -- Treat dag-defined access_control as authoritative if defined (#33632) -- Bind engine before attempting to drop archive tables (#33622) -- Add a fallback in case no first name and last name are set (#33617) -- Sort data before ``groupby`` in TIS duration calculation (#33535) -- Stop adding values to rendered templates UI when there is no dagrun (#33516) -- Set strict to True when parsing dates in webserver views (#33512) -- Use ``dialect.name`` in custom SA types (#33503) -- Do not return ongoing dagrun when a ``end_date`` is less than ``utcnow`` (#33488) -- Fix a bug in ``formatDuration`` method (#33486) -- Make ``conf.set`` case insensitive (#33452) -- Allow timetable to slightly miss catchup cutoff (#33404) -- Respect ``soft_fail`` argument when ``poke`` is called (#33401) -- Create a new method used to resume the task in order to implement specific logic for operators (#33424) -- Fix DagFileProcessor interfering with dags outside its ``processor_subdir`` (#33357) -- Remove the unnecessary ``
`` text in Provider's view (#33326) -- Respect ``soft_fail`` argument when ExternalTaskSensor runs in deferrable mode (#33196) -- Fix handling of default value and serialization of Param class (#33141) -- Check if the dynamically-added index is in the table schema before adding (#32731) -- Fix rendering the mapped parameters when using ``expand_kwargs`` method (#32272) -- Fix dependencies for celery and opentelemetry for Python 3.8 (#33579) +- Revert "Fix: DAGs are not marked as stale if the dags folder change" (#42220, #42217) +- Add missing open telemetry span and correct scheduled slots documentation (#41985) +- Fix require_confirmation_dag_change (#42063) (#42211) +- Only treat null/undefined as falsy when rendering XComEntry (#42199) (#42213) +- Add extra and ``renderedTemplates`` as keys to skip ``camelCasing`` (#42206) (#42208) +- Do not ``camelcase`` xcom entries (#42182) (#42187) +- Fix task_instance and dag_run links from list views (#42138) (#42143) +- Support multi-line input for Params of type string in trigger UI form (#40414) (#42139) +- Fix details tab log url detection (#42104) (#42114) +- Add new type of exception to catch timeout (#42064) (#42078) +- Rewrite how DAG to dataset / dataset alias are stored (#41987) (#42055) +- Allow dataset alias to add more than one dataset events (#42189) (#42247) -Misc/Internal +Miscellaneous """"""""""""" -- Bring back ``Pydantic`` 1 compatibility (#34081, #33998) -- Use a trimmed version of README.md for PyPI (#33637) -- Upgrade to ``Pydantic`` 2 (#33956) -- Reorganize ``devel_only`` extra in Airflow's setup.py (#33907) -- Bumping ``FAB`` to ``4.3.4`` in order to fix issues with filters (#33931) -- Add minimum requirement for ``sqlalchemy to 1.4.24`` (#33892) -- Update version_added field for configs in config file (#33509) -- Replace ``OrderedDict`` with plain dict (#33508) -- Consolidate import and usage of itertools (#33479) -- Static check fixes (#33462) -- Import utc from datetime and normalize its import (#33450) -- D401 Support (#33352, #33339, #33337, #33336, #33335, #33333, #33338) -- Fix some missing type hints (#33334) -- D205 Support - Stragglers (#33301, #33298, #33297) -- Refactor: Simplify code (#33160, #33270, #33268, #33267, #33266, #33264, #33292, #33453, #33476, #33567, - #33568, #33480, #33753, #33520, #33623) -- Fix ``Pydantic`` warning about ``orm_mode`` rename (#33220) -- Add MySQL 8.1 to supported versions. (#33576) -- Remove ``Pydantic`` limitation for version < 2 (#33507) +- Limit universal-pathlib below ``0.2.4`` as it breaks our integration (#42101) +- Auto-fix default deferrable with ``LibCST`` (#42089) +- Deprecate ``--tree`` flag for ``tasks list`` cli command (#41965) -Doc only changes -""""""""""""""""" -- Add documentation explaining template_ext (and how to override it) (#33735) -- Explain how users can check if python code is top-level (#34006) -- Clarify that DAG authors can also run code in DAG File Processor (#33920) -- Fix broken link in Modules Management page (#33499) -- Fix secrets backend docs (#33471) -- Fix config description for base_log_folder (#33388) +Doc Only Changes +"""""""""""""""" +- Update ``security_model.rst`` to clear unauthenticated endpoints exceptions (#42085) +- Add note about dataclasses and attrs to XComs page (#42056) +- Improve docs on markdown docs in DAGs (#42013) +- Add warning that listeners can be dangerous (#41968) -Airflow 2.7.0 (2023-08-18) --------------------------- +Airflow 2.10.1 (2024-09-05) +--------------------------- Significant Changes ^^^^^^^^^^^^^^^^^^^ -Remove Python 3.7 support (#30963) -"""""""""""""""""""""""""""""""""" -As of now, Python 3.7 is no longer supported by the Python community. -Therefore, to use Airflow 2.7.0, you must ensure your Python version is -either 3.8, 3.9, 3.10, or 3.11. +No significant changes. -Old Graph View is removed (#32958) -"""""""""""""""""""""""""""""""""" -The old Graph View is removed. The new Graph View is the default view now. +Bug Fixes +""""""""" +- Handle Example dags case when checking for missing files (#41874) +- Fix logout link in "no roles" error page (#41845) +- Set end_date and duration for triggers completed with end_from_trigger as True. (#41834) +- DAGs are not marked as stale if the dags folder change (#41829) +- Fix compatibility with FAB provider versions <1.3.0 (#41809) +- Don't Fail LocalTaskJob on heartbeat (#41810) +- Remove deprecation warning for cgitb in Plugins Manager (#41793) +- Fix log for notifier(instance) without ``__name__`` (#41699) +- Splitting syspath preparation into stages (#41694) +- Adding url sanitization for extra links (#41680) +- Fix InletEventsAccessors type stub (#41607) +- Fix UI rendering when XCom is INT, FLOAT, BOOL or NULL (#41605) +- Fix try selector refresh (#41503) +- Incorrect try number subtraction producing invalid span id for OTEL airflow (#41535) +- Add WebEncoder for trigger page rendering to avoid render failure (#41485) +- Adding ``tojson`` filter to example_inlet_event_extra example dag (#41890) +- Add backward compatibility check for executors that don't inherit BaseExecutor (#41927) -The trigger UI form is skipped in web UI if no parameters are defined in a DAG (#33351) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Miscellaneous +""""""""""""" +- Bump webpack from 5.76.0 to 5.94.0 in /airflow/www (#41879) +- Adding rel property to hyperlinks in logs (#41783) +- Field Deletion Warning when editing Connections (#41504) +- Make Scarf usage reporting in major+minor versions and counters in buckets (#41900) +- Lower down universal-pathlib minimum to 0.2.2 (#41943) +- Protect against None components of universal pathlib xcom backend (#41938) -If you are using ``dag_run.conf`` dictionary and web UI JSON entry to run your DAG you should either: +Doc Only Changes +"""""""""""""""" +- Remove Debian bullseye support (#41569) +- Add an example for auth with ``keycloak`` (#41791) -* `Add params to your DAG `_ -* Enable the new configuration ``show_trigger_form_if_no_params`` to bring back old behaviour -The "db init", "db upgrade" commands and "[database] load_default_connections" configuration options are deprecated (#33136). -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Instead, you should use "airflow db migrate" command to create or upgrade database. This command will not create default connections. -In order to create default connections you need to run "airflow connections create-default-connections" explicitly, -after running "airflow db migrate". +Airflow 2.10.0 (2024-08-15) +--------------------------- -In case of SMTP SSL connection, the context now uses the "default" context (#33070) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -The "default" context is Python's ``default_ssl_contest`` instead of previously used "none". The -``default_ssl_context`` provides a balance between security and compatibility but in some cases, -when certificates are old, self-signed or misconfigured, it might not work. This can be configured -by setting "ssl_context" in "email" configuration of Airflow. +Significant Changes +^^^^^^^^^^^^^^^^^^^ -Setting it to "none" brings back the "none" setting that was used in Airflow 2.6 and before, -but it is not recommended due to security reasons ad this setting disables validation of certificates and allows MITM attacks. +Scarf based telemetry: Airflow now collect telemetry data (#39510) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Airflow integrates Scarf to collect basic usage data during operation. Deployments can opt-out of data collection by +setting the ``[usage_data_collection]enabled`` option to ``False``, or the ``SCARF_ANALYTICS=false`` environment variable. -Disable default allowing the testing of connections in UI, API and CLI(#32052) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -For security reasons, the test connection functionality is disabled by default across Airflow UI, -API and CLI. The availability of the functionality can be controlled by the -``test_connection`` flag in the ``core`` section of the Airflow -configuration (``airflow.cfg``). It can also be controlled by the -environment variable ``AIRFLOW__CORE__TEST_CONNECTION``. +Datasets no longer trigger inactive DAGs (#38891) +""""""""""""""""""""""""""""""""""""""""""""""""" -The following values are accepted for this config param: -1. ``Disabled``: Disables the test connection functionality and -disables the Test Connection button in the UI. +Previously, when a DAG is paused or removed, incoming dataset events would still +trigger it, and the DAG would run when it is unpaused or added back in a DAG +file. This has been changed; a DAG's dataset schedule can now only be satisfied +by events that occur when the DAG is active. While this is a breaking change, +the previous behavior is considered a bug. -This is also the default value set in the Airflow configuration. -2. ``Enabled``: Enables the test connection functionality and -activates the Test Connection button in the UI. +The behavior of time-based scheduling is unchanged, including the timetable part +of ``DatasetOrTimeSchedule``. -3. ``Hidden``: Disables the test connection functionality and -hides the Test Connection button in UI. +``try_number`` is no longer incremented during task execution (#39336) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -For more information on capabilities of users, see the documentation: -https://airflow.apache.org/docs/apache-airflow/stable/security/security_model.html#capabilities-of-authenticated-ui-users -It is strongly advised to **not** enable the feature until you make sure that only -highly trusted UI/API users have "edit connection" permissions. +Previously, the try number (``try_number``) was incremented at the beginning of task execution on the worker. This was problematic for many reasons. +For one it meant that the try number was incremented when it was not supposed to, namely when resuming from reschedule or deferral. And it also resulted in +the try number being "wrong" when the task had not yet started. The workarounds for these two issues caused a lot of confusion. -The ``xcomEntries`` API disables support for the ``deserialize`` flag by default (#32176) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -For security reasons, the ``/dags/*/dagRuns/*/taskInstances/*/xcomEntries/*`` -API endpoint now disables the ``deserialize`` option to deserialize arbitrary -XCom values in the webserver. For backward compatibility, server admins may set -the ``[api] enable_xcom_deserialize_support`` config to *True* to enable the -flag and restore backward compatibility. - -However, it is strongly advised to **not** enable the feature, and perform -deserialization at the client side instead. - -Change of the default Celery application name (#32526) -"""""""""""""""""""""""""""""""""""""""""""""""""""""" -Default name of the Celery application changed from ``airflow.executors.celery_executor`` to ``airflow.providers.celery.executors.celery_executor``. - -You should change both your configuration and Health check command to use the new name: - * in configuration (``celery_app_name`` configuration in ``celery`` section) use ``airflow.providers.celery.executors.celery_executor`` - * in your Health check command use ``airflow.providers.celery.executors.celery_executor.app`` - - -The default value for ``scheduler.max_tis_per_query`` is changed from 512 to 16 (#32572) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This change is expected to make the Scheduler more responsive. - -``scheduler.max_tis_per_query`` needs to be lower than ``core.parallelism``. -If both were left to their default value previously, the effective default value of ``scheduler.max_tis_per_query`` was 32 -(because it was capped at ``core.parallelism``). - -To keep the behavior as close as possible to the old config, one can set ``scheduler.max_tis_per_query = 0``, -in which case it'll always use the value of ``core.parallelism``. +Now, instead, the try number for a task run is determined at the time the task is scheduled, and does not change in flight, and it is never decremented. +So after the task runs, the observed try number remains the same as it was when the task was running; only when there is a "new try" will the try number be incremented again. -Some executors have been moved to corresponding providers (#32767) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -In order to use the executors, you need to install the providers: +One consequence of this change is, if users were "manually" running tasks (e.g. by calling ``ti.run()`` directly, or command line ``airflow tasks run``), +try number will no longer be incremented. Airflow assumes that tasks are always run after being scheduled by the scheduler, so we do not regard this as a breaking change. -* for Celery executors you need to install ``apache-airflow-providers-celery`` package >= 3.3.0 -* for Kubernetes executors you need to install ``apache-airflow-providers-cncf-kubernetes`` package >= 7.4.0 -* For Dask executors you need to install ``apache-airflow-providers-daskexecutor`` package in any version +``/logout`` endpoint in FAB Auth Manager is now CSRF protected (#40145) +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -You can achieve it also by installing airflow with ``[celery]``, ``[cncf.kubernetes]``, ``[daskexecutor]`` extras respectively. +The ``/logout`` endpoint's method in FAB Auth Manager has been changed from ``GET`` to ``POST`` in all existing +AuthViews (``AuthDBView``, ``AuthLDAPView``, ``AuthOAuthView``, ``AuthOIDView``, ``AuthRemoteUserView``), and +now includes CSRF protection to enhance security and prevent unauthorized logouts. -Users who base their images on the ``apache/airflow`` reference image (not slim) should be unaffected - the base -reference image comes with all the three providers installed. +OpenTelemetry Traces for Apache Airflow (#37948). +""""""""""""""""""""""""""""""""""""""""""""""""" +This new feature adds capability for Apache Airflow to emit 1) airflow system traces of scheduler, +triggerer, executor, processor 2) DAG run traces for deployed DAG runs in OpenTelemetry format. Previously, only metrics were supported which emitted metrics in OpenTelemetry. +This new feature will add richer data for users to use OpenTelemetry standard to emit and send their trace data to OTLP compatible endpoints. -Improvement Changes -^^^^^^^^^^^^^^^^^^^ +Decorator for Task Flow ``(@skip_if, @run_if)`` to make it simple to apply whether or not to skip a Task. (#41116) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +This feature adds a decorator to make it simple to skip a Task. -PostgreSQL only improvement: Added index on taskinstance table (#30762) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This index seems to have great positive effect in a setup with tens of millions such rows. +Using Multiple Executors Concurrently (#40701) +"""""""""""""""""""""""""""""""""""""""""""""" +Previously known as hybrid executors, this new feature allows Airflow to use multiple executors concurrently. DAGs, or even individual tasks, can be configured +to use a specific executor that suits its needs best. A single DAG can contain tasks all using different executors. Please see the Airflow documentation for +more details. Note: This feature is still experimental. See `documentation on Executor `_ for a more detailed description. New Features """""""""""" -- Add OpenTelemetry to Airflow (`AIP-49 `_) -- Trigger Button - Implement Part 2 of AIP-50 (#31583) -- Removing Executor Coupling from Core Airflow (`AIP-51 `_) -- Automatic setup and teardown tasks (`AIP-52 `_) -- OpenLineage in Airflow (`AIP-53 `_) -- Experimental: Add a cache to Variable and Connection when called at dag parsing time (#30259) -- Enable pools to consider deferred tasks (#32709) -- Allows to choose SSL context for SMTP connection (#33070) -- New gantt tab (#31806) -- Load plugins from providers (#32692) -- Add ``BranchExternalPythonOperator`` (#32787, #33360) -- Add option for storing configuration description in providers (#32629) -- Introduce Heartbeat Parameter to Allow ``Per-LocalTaskJob`` Configuration (#32313) -- Add Executors discovery and documentation (#32532) -- Add JobState for job state constants (#32549) -- Add config to disable the 'deserialize' XCom API flag (#32176) -- Show task instance in web UI by custom operator name (#31852) -- Add default_deferrable config (#31712) -- Introducing ``AirflowClusterPolicySkipDag`` exception (#32013) -- Use ``reactflow`` for datasets graph (#31775) -- Add an option to load the dags from db for command tasks run (#32038) -- Add version of ``chain`` which doesn't require matched lists (#31927) -- Use operator_name instead of task_type in UI (#31662) -- Add ``--retry`` and ``--retry-delay`` to ``airflow db check`` (#31836) -- Allow skipped task state task_instance_schema.py (#31421) -- Add a new config for celery result_backend engine options (#30426) -- UI Add Cluster Activity Page (#31123, #32446) -- Adding keyboard shortcuts to common actions (#30950) -- Adding more information to kubernetes executor logs (#29929) -- Add support for configuring custom alembic file (#31415) -- Add running and failed status tab for DAGs on the UI (#30429) -- Add multi-select, proposals and labels for trigger form (#31441) -- Making webserver config customizable (#29926) -- Render DAGCode in the Grid View as a tab (#31113) -- Add rest endpoint to get option of configuration (#31056) -- Add ``section`` query param in get config rest API (#30936) -- Create metrics to track ``Scheduled->Queued->Running`` task state transition times (#30612) -- Mark Task Groups as Success/Failure (#30478) -- Add CLI command to list the provider trigger info (#30822) -- Add Fail Fast feature for DAGs (#29406) +- AIP-61 Hybrid Execution (`AIP-61 `_) +- AIP-62 Getting Lineage from Hook Instrumentation (`AIP-62 `_) +- AIP-64 TaskInstance Try History (`AIP-64 `_) +- AIP-44 Internal API (`AIP-44 `_) +- Enable ending the task directly from the triggerer without going into the worker. (#40084) +- Extend dataset dependencies (#40868) +- Feature/add token authentication to internal api (#40899) +- Add DatasetAlias to support dynamic Dataset Event Emission and Dataset Creation (#40478) +- Add example DAGs for inlet_events (#39893) +- Implement ``accessors`` to read dataset events defined as inlet (#39367) +- Decorator for Task Flow, to make it simple to apply whether or not to skip a Task. (#41116) +- Add start execution from triggerer support to dynamic task mapping (#39912) +- Add try_number to log table (#40739) +- Added ds_format_locale method in macros which allows localizing datetime formatting using Babel (#40746) +- Add DatasetAlias to support dynamic Dataset Event Emission and Dataset Creation (#40478, #40723, #40809, #41264, #40830, #40693, #41302) +- Use sentinel to mark dag as removed on re-serialization (#39825) +- Add parameter for the last number of queries to the DB in DAG file processing stats (#40323) +- Add prototype version dark mode for Airflow UI (#39355) +- Add ability to mark some tasks as successful in ``dag test`` (#40010) +- Allow use of callable for template_fields (#37028) +- Filter running/failed and active/paused dags on the home page(#39701) +- Add metrics about task CPU and memory usage (#39650) +- UI changes for DAG Re-parsing feature (#39636) +- Add Scarf based telemetry (#39510, #41318) +- Add dag re-parsing request endpoint (#39138) +- Redirect to new DAGRun after trigger from Grid view (#39569) +- Display ``endDate`` in task instance tooltip. (#39547) +- Implement ``accessors`` to read dataset events defined as inlet (#39367, #39893) +- Add color to log lines in UI for error and warnings based on keywords (#39006) +- Add Rendered k8s pod spec tab to ti details view (#39141) +- Make audit log before/after filterable (#39120) +- Consolidate grid collapse actions to a single full screen toggle (#39070) +- Implement Metadata to emit runtime extra (#38650) +- Add executor field to the DB and parameter to the operators (#38474) +- Implement context accessor for DatasetEvent extra (#38481) +- Add dataset event info to dag graph (#41012) +- Add button to toggle datasets on/off in dag graph (#41200) +- Add ``run_if`` & ``skip_if`` decorators (#41116) +- Add dag_stats rest api endpoint (#41017) +- Add listeners for Dag import errors (#39739) +- Allowing DateTimeSensorAsync, FileSensor and TimeSensorAsync to start execution from trigger during dynamic task mapping (#41182) + Improvements """""""""""" -- Improve graph nesting logic (#33421) -- Configurable health check threshold for triggerer (#33089, #33084) -- add dag_run_ids and task_ids filter for the batch task instance API endpoint (#32705) -- Ensure DAG-level references are filled on unmap (#33083) -- Add support for arrays of different data types in the Trigger Form UI (#32734) -- Always show gantt and code tabs (#33029) -- Move listener success hook to after SQLAlchemy commit (#32988) -- Rename ``db upgrade`` to ``db migrate`` and add ``connections create-default-connections`` (#32810, #33136) -- Remove old gantt chart and redirect to grid views gantt tab (#32908) -- Adjust graph zoom based on selected task (#32792) -- Call listener on_task_instance_running after rendering templates (#32716) -- Display execution_date in graph view task instance tooltip. (#32527) -- Allow configuration to be contributed by providers (#32604, #32755, #32812) -- Reduce default for max TIs per query, enforce ``<=`` parallelism (#32572) -- Store config description in Airflow configuration object (#32669) -- Use ``isdisjoint`` instead of ``not intersection`` (#32616) -- Speed up calculation of leaves and roots for task groups (#32592) -- Kubernetes Executor Load Time Optimizations (#30727) -- Save DAG parsing time if dag is not schedulable (#30911) -- Updates health check endpoint to include ``dag_processor`` status. (#32382) -- Disable default allowing the testing of connections in UI, API and CLI (#32052, #33342) -- Fix config var types under the scheduler section (#32132) -- Allow to sort Grid View alphabetically (#32179) -- Add hostname to triggerer metric ``[triggers.running]`` (#32050) -- Improve DAG ORM cleanup code (#30614) -- ``TriggerDagRunOperator``: Add ``wait_for_completion`` to ``template_fields`` (#31122) -- Open links in new tab that take us away from Airflow UI (#32088) -- Only show code tab when a task is not selected (#31744) -- Add descriptions for celery and dask cert configs (#31822) -- ``PythonVirtualenvOperator`` termination log in alert (#31747) -- Migration of all DAG details to existing grid view dag details panel (#31690) -- Add a diagram to help visualize timer metrics (#30650) -- Celery Executor load time optimizations (#31001) -- Update code style for ``airflow db`` commands to SQLAlchemy 2.0 style (#31486) -- Mark uses of md5 as "not-used-for-security" in FIPS environments (#31171) -- Add pydantic support to serde (#31565) -- Enable search in note column in DagRun and TaskInstance (#31455) -- Save scheduler execution time by adding new Index idea for dag_run (#30827) -- Save scheduler execution time by caching dags (#30704) -- Support for sorting DAGs by Last Run Date in the web UI (#31234) -- Better typing for Job and JobRunners (#31240) -- Add sorting logic by created_date for fetching triggers (#31151) -- Remove DAGs.can_create on access control doc, adjust test fixture (#30862) -- Split Celery logs into stdout/stderr (#30485) -- Decouple metrics clients and ``validators`` into their own modules (#30802) -- Description added for pagination in ``get_log`` api (#30729) -- Optimize performance of scheduling mapped tasks (#30372) -- Add sentry transport configuration option (#30419) -- Better message on deserialization error (#30588) - -Bug Fixes -""""""""" -- Remove user sessions when resetting password (#33347) -- ``Gantt chart:`` Use earliest/oldest ti dates if different than dag run start/end (#33215) -- Fix ``virtualenv`` detection for Python ``virtualenv`` operator (#33223) -- Correctly log when there are problems trying to ``chmod`` ``airflow.cfg`` (#33118) -- Pass app context to webserver_config.py (#32759) -- Skip served logs for non-running task try (#32561) -- Fix reload gunicorn workers (#32102) -- Fix future DagRun rarely triggered by race conditions when ``max_active_runs`` reached its upper limit. (#31414) -- Fix BaseOperator ``get_task_instances`` query (#33054) -- Fix issue with using the various state enum value in logs (#33065) -- Use string concatenation to prepend base URL for log_url (#33063) -- Update graph nodes with operator style attributes (#32822) -- Affix webserver access_denied warning to be configurable (#33022) -- Only load task action modal if user can edit (#32992) -- OpenAPI Spec fix nullable alongside ``$ref`` (#32887) -- Make the decorators of ``PythonOperator`` sub-classes extend its decorator (#32845) -- Fix check if ``virtualenv`` is installed in ``PythonVirtualenvOperator`` (#32939) -- Unwrap Proxy before checking ``__iter__`` in is_container() (#32850) -- Override base log folder by using task handler's base_log_folder (#32781) -- Catch arbitrary exception from run_job to prevent zombie scheduler (#32707) -- Fix depends_on_past work for dynamic tasks (#32397) -- Sort extra_links for predictable order in UI. (#32762) -- Fix prefix group false graph (#32764) -- Fix bad delete logic for dagruns (#32684) -- Fix bug in prune_dict where empty dict and list would be removed even in strict mode (#32573) -- Add explicit browsers list and correct rel for blank target links (#32633) -- Handle returned None when multiple_outputs is True (#32625) -- Fix returned value when ShortCircuitOperator condition is falsy and there is not downstream tasks (#32623) -- Fix returned value when ShortCircuitOperator condition is falsy (#32569) -- Fix rendering of ``dagRunTimeout`` (#32565) -- Fix permissions on ``/blocked`` endpoint (#32571) -- Bugfix, prevent force of unpause on trigger DAG (#32456) -- Fix data interval in ``cli.dags.trigger`` command output (#32548) -- Strip ``whitespaces`` from airflow connections form (#32292) -- Add timedelta support for applicable arguments of sensors (#32515) -- Fix incorrect default on ``readonly`` property in our API (#32510) -- Add xcom map_index as a filter to xcom endpoint (#32453) -- Fix CLI commands when custom timetable is used (#32118) -- Use WebEncoder to encode DagRun.conf in DagRun's list view (#32385) -- Fix logic of the skip_all_except method (#31153) -- Ensure dynamic tasks inside dynamic task group only marks the (#32354) -- Handle the cases that webserver.expose_config is set to non-sensitive-only instead of boolean value (#32261) -- Add retry functionality for handling process termination caused by database network issues (#31998) -- Adapt Notifier for sla_miss_callback (#31887) -- Fix XCOM view (#31807) -- Fix for "Filter dags by tag" flickering on initial load of dags.html (#31578) -- Fix where expanding ``resizer`` would not expanse grid view (#31581) -- Fix MappedOperator-BaseOperator attr sync check (#31520) -- Always pass named ``type_`` arg to drop_constraint (#31306) -- Fix bad ``drop_constraint`` call in migrations (#31302) -- Resolving problems with redesigned grid view (#31232) -- Support ``requirepass`` redis sentinel (#30352) -- Fix webserver crash when calling get ``/config`` (#31057) - -Misc/Internal -""""""""""""" -- Modify pathspec version restriction (#33349) -- Refactor: Simplify code in ``dag_processing`` (#33161) -- For now limit ``Pydantic`` to ``< 2.0.0`` (#33235) -- Refactor: Simplify code in models (#33181) -- Add elasticsearch group to pre-2.7 defaults (#33166) -- Refactor: Simplify dict manipulation in airflow/cli (#33159) -- Remove redundant dict.keys() call (#33158) -- Upgrade ruff to latest 0.0.282 version in pre-commits (#33152) -- Move openlineage configuration to provider (#33124) -- Replace State by TaskInstanceState in Airflow executors (#32627) -- Get rid of Python 2 numeric relics (#33050) -- Remove legacy dag code (#33058) -- Remove legacy task instance modal (#33060) -- Remove old graph view (#32958) -- Move CeleryExecutor to the celery provider (#32526, #32628) -- Move all k8S classes to ``cncf.kubernetes`` provider (#32767, #32891) -- Refactor existence-checking SQL to helper (#32790) -- Extract Dask executor to new daskexecutor provider (#32772) -- Remove atlas configuration definition (#32776) -- Add Redis task handler (#31855) -- Move writing configuration for webserver to main (webserver limited) (#32766) -- Improve getting the query count in Airflow API endpoints (#32630) -- Remove click upper bound (#32634) -- Add D400 ``pydocstyle`` check - core Airflow only (#31297) -- D205 Support (#31742, #32575, #32213, #32212, #32591, #32449, #32450) -- Bump word-wrap from ``1.2.3 to 1.2.4`` in ``/airflow/www`` (#32680) -- Strong-type all single-state enum values (#32537) -- More strong typed state conversion (#32521) -- SQL query improvements in utils/db.py (#32518) -- Bump semver from ``6.3.0 to 6.3.1`` in ``/airflow/www`` (#32506) -- Bump jsonschema version to ``4.18.0`` (#32445) -- Bump ``stylelint`` from ``13.13.1 to 15.10.1`` in ``/airflow/www`` (#32435) -- Bump tough-cookie from ``4.0.0 to 4.1.3`` in ``/airflow/www`` (#32443) -- upgrade flask-appbuilder (#32054) -- Support ``Pydantic`` 2 (#32366) -- Limit click until we fix mypy issues (#32413) -- A couple of minor cleanups (#31890) -- Replace State usages with strong-typed ``enums`` (#31735) -- Upgrade ruff to ``0.272`` (#31966) -- Better error message when serializing callable without name (#31778) -- Improve the views module a bit (#31661) -- Remove ``asynctest`` (#31664) -- Refactor sqlalchemy queries to ``2.0`` style (#31569, #31772, #32350, #32339, #32474, #32645) -- Remove Python ``3.7`` support (#30963) -- Bring back min-airflow-version for preinstalled providers (#31469) -- Docstring improvements (#31375) -- Improve typing in SchedulerJobRunner (#31285) -- Upgrade ruff to ``0.0.262`` (#30809) -- Upgrade to MyPy ``1.2.0`` (#30687) - -Docs only changes -""""""""""""""""" -- Clarify UI user types in security model (#33021) -- Add links to ``DAGRun / DAG / Task`` in templates-ref.rst (#33013) -- Add docs of how to test for DAG Import Errors (#32811) -- Clean-up of our new security page (#32951) -- Cleans up Extras reference page (#32954) -- Update Dag trigger API and command docs (#32696) -- Add deprecation info to the Airflow modules and classes docstring (#32635) -- Formatting installation doc to improve readability (#32502) -- Fix triggerer HA doc (#32454) -- Add type annotation to code examples (#32422) -- Document cron and delta timetables (#32392) -- Update index.rst doc to correct grammar (#32315) -- Fixing small typo in python.py (#31474) -- Separate out and clarify policies for providers (#30657) -- Fix docs: add an "apache" prefix to pip install (#30681) - - -Airflow 2.6.3 (2023-07-10) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Default allowed pattern of a run_id has been changed to ``^[A-Za-z0-9_.~:+-]+$`` (#32293). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Previously, there was no validation on the run_id string. There is now a validation regex that -can be set by configuring ``allowed_run_id_pattern`` in ``scheduler`` section. - -Bug Fixes -""""""""" -- Use linear time regular expressions (#32303) -- Fix triggerers alive check and add a new conf for triggerer heartbeat rate (#32123) -- Catch the exception that triggerer initialization failed (#31999) -- Hide sensitive values from extra in connection edit form (#32309) -- Sanitize ``DagRun.run_id`` and allow flexibility (#32293) -- Add triggerer canceled log (#31757) -- Fix try number shown in the task view (#32361) -- Retry transactions on occasional deadlocks for rendered fields (#32341) -- Fix behaviour of LazyDictWithCache when import fails (#32248) -- Remove ``executor_class`` from Job - fixing backfill for custom executors (#32219) -- Fix bugged singleton implementation (#32218) -- Use ``mapIndex`` to display extra links per mapped task. (#32154) -- Ensure that main triggerer thread exits if the async thread fails (#32092) -- Use ``re2`` for matching untrusted regex (#32060) -- Render list items in rendered fields view (#32042) -- Fix hashing of ``dag_dependencies`` in serialized dag (#32037) -- Return ``None`` if an XComArg fails to resolve in a multiple_outputs Task (#32027) -- Check for DAG ID in query param from url as well as kwargs (#32014) -- Flash an error message instead of failure in ``rendered-templates`` when map index is not found (#32011) -- Fix ``ExternalTaskSensor`` when there is no task group TIs for the current execution date (#32009) -- Fix number param html type in trigger template (#31980, #31946) -- Fix masking nested variable fields (#31964) -- Fix ``operator_extra_links`` property serialization in mapped tasks (#31904) -- Decode old-style nested Xcom value (#31866) -- Add a check for trailing slash in webserver base_url (#31833) -- Fix connection uri parsing when the host includes a scheme (#31465) -- Fix database session closing with ``xcom_pull`` and ``inlets`` (#31128) -- Fix DAG's ``on_failure_callback`` is not invoked when task failed during testing dag. (#30965) -- Fix airflow module version check when using ``ExternalPythonOperator`` and debug logging level (#30367) - -Misc/Internal -""""""""""""" -- Fix ``task.sensor`` annotation in type stub (#31954) -- Limit ``Pydantic`` to ``< 2.0.0`` until we solve ``2.0.0`` incompatibilities (#32312) -- Fix ``Pydantic`` 2 pickiness about model definition (#32307) - -Doc only changes -"""""""""""""""" -- Add explanation about tag creation and cleanup (#32406) -- Minor updates to docs (#32369, #32315, #32310, #31794) -- Clarify Listener API behavior (#32269) -- Add information for users who ask for requirements (#32262) -- Add links to DAGRun / DAG / Task in Templates Reference (#32245) -- Add comment to warn off a potential wrong fix (#32230) -- Add a note that we'll need to restart triggerer to reflect any trigger change (#32140) -- Adding missing hyperlink to the tutorial documentation (#32105) -- Added difference between Deferrable and Non-Deferrable Operators (#31840) -- Add comments explaining need for special "trigger end" log message (#31812) -- Documentation update on Plugin updates. (#31781) -- Fix SemVer link in security documentation (#32320) -- Update security model of Airflow (#32098) -- Update references to restructured documentation from Airflow core (#32282) -- Separate out advanced logging configuration (#32131) -- Add ``™`` to Airflow in prominent places (#31977) - - -Airflow 2.6.2 (2023-06-17) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -No significant changes. - -Bug Fixes -^^^^^^^^^ -- Cascade update of TaskInstance to TaskMap table (#31445) -- Fix Kubernetes executors detection of deleted pods (#31274) -- Use keyword parameters for migration methods for mssql (#31309) -- Control permissibility of driver config in extra from airflow.cfg (#31754) -- Fixing broken links in openapi/v1.yaml (#31619) -- Hide old alert box when testing connection with different value (#31606) -- Add TriggererStatus to OpenAPI spec (#31579) -- Resolving issue where Grid won't un-collapse when Details is collapsed (#31561) -- Fix sorting of tags (#31553) -- Add the missing ``map_index`` to the xcom key when skipping downstream tasks (#31541) -- Fix airflow users delete CLI command (#31539) -- Include triggerer health status in Airflow ``/health`` endpoint (#31529) -- Remove dependency already registered for this task warning (#31502) -- Use kube_client over default CoreV1Api for deleting pods (#31477) -- Ensure min backoff in base sensor is at least 1 (#31412) -- Fix ``max_active_tis_per_dagrun`` for Dynamic Task Mapping (#31406) -- Fix error handling when pre-importing modules in DAGs (#31401) -- Fix dropdown default and adjust tutorial to use 42 as default for proof (#31400) -- Fix crash when clearing run with task from normal to mapped (#31352) -- Make BaseJobRunner a generic on the job class (#31287) -- Fix ``url_for_asset`` fallback and 404 on DAG Audit Log (#31233) -- Don't present an undefined execution date (#31196) -- Added spinner activity while the logs load (#31165) -- Include rediss to the list of supported URL schemes (#31028) -- Optimize scheduler by skipping "non-schedulable" DAGs (#30706) -- Save scheduler execution time during search for queued dag_runs (#30699) -- Fix ExternalTaskSensor to work correctly with task groups (#30742) -- Fix DAG.access_control can't sync when clean access_control (#30340) -- Fix failing get_safe_url tests for latest Python 3.8 and 3.9 (#31766) -- Fix typing for POST user endpoint (#31767) -- Fix wrong update for nested group default args (#31776) -- Fix overriding ``default_args`` in nested task groups (#31608) -- Mark ``[secrets] backend_kwargs`` as a sensitive config (#31788) -- Executor events are not always "exited" here (#30859) -- Validate connection IDs (#31140) - -Misc/Internal -""""""""""""" -- Add Python 3.11 support (#27264) -- Replace unicodecsv with standard csv library (#31693) -- Bring back unicodecsv as dependency of Airflow (#31814) -- Remove found_descendents param from get_flat_relative_ids (#31559) -- Fix typing in external task triggers (#31490) -- Wording the next and last run DAG columns better (#31467) -- Skip auto-document things with :meta private: (#31380) -- Add an example for sql_alchemy_connect_args conf (#31332) -- Convert dask upper-binding into exclusion (#31329) -- Upgrade FAB to 4.3.1 (#31203) -- Added metavar and choices to --state flag in airflow dags list-jobs CLI for suggesting valid state arguments. (#31308) -- Use only one line for tmp dir log (#31170) -- Rephrase comment in setup.py (#31312) -- Add fullname to owner on logging (#30185) -- Make connection id validation consistent across interface (#31282) -- Use single source of truth for sensitive config items (#31820) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Add docstring and signature for _read_remote_logs (#31623) -- Remove note about triggerer being 3.7+ only (#31483) -- Fix version support information (#31468) -- Add missing BashOperator import to documentation example (#31436) -- Fix task.branch error caused by incorrect initial parameter (#31265) -- Update callbacks documentation (errors and context) (#31116) -- Add an example for dynamic task mapping with non-TaskFlow operator (#29762) -- Few doc fixes - links, grammar and wording (#31719) -- Add description in a few more places about adding airflow to pip install (#31448) -- Fix table formatting in docker build documentation (#31472) -- Update documentation for constraints installation (#31882) - -Airflow 2.6.1 (2023-05-16) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Clarifications of the external Health Check mechanism and using ``Job`` classes (#31277). -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -In the past SchedulerJob and other ``*Job`` classes are known to have been used to perform -external health checks for Airflow components. Those are, however, Airflow DB ORM related classes. -The DB models and database structure of Airflow are considered as internal implementation detail, following -`public interface `_). -Therefore, they should not be used for external health checks. Instead, you should use the -``airflow jobs check`` CLI command (introduced in Airflow 2.1) for that purpose. - -Bug Fixes -^^^^^^^^^ -- Fix calculation of health check threshold for SchedulerJob (#31277) -- Fix timestamp parse failure for k8s executor pod tailing (#31175) -- Make sure that DAG processor job row has filled value in ``job_type`` column (#31182) -- Fix section name reference for ``api_client_retry_configuration`` (#31174) -- Ensure the KPO runs pod mutation hooks correctly (#31173) -- Remove worrying log message about redaction from the OpenLineage plugin (#31149) -- Move ``interleave_timestamp_parser`` config to the logging section (#31102) -- Ensure that we check worker for served logs if no local or remote logs found (#31101) -- Fix ``MappedTaskGroup`` import in taskinstance file (#31100) -- Format DagBag.dagbag_report() Output (#31095) -- Mask task attribute on task detail view (#31125) -- Fix template error when iterating None value and fix params documentation (#31078) -- Fix ``apache-hive`` extra so it installs the correct package (#31068) -- Fix issue with zip files in DAGs folder when pre-importing Airflow modules (#31061) -- Move TaskInstanceKey to a separate file to fix circular import (#31033, #31204) -- Fix deleting DagRuns and TaskInstances that have a note (#30987) -- Fix ``airflow providers get`` command output (#30978) -- Fix Pool schema in the OpenAPI spec (#30973) -- Add support for dynamic tasks with template fields that contain ``pandas.DataFrame`` (#30943) -- Use the Task Group explicitly passed to 'partial' if any (#30933) -- Fix ``order_by`` request in list DAG rest api (#30926) -- Include node height/width in center-on-task logic (#30924) -- Remove print from dag trigger command (#30921) -- Improve task group UI in new graph (#30918) -- Fix mapped states in grid view (#30916) -- Fix problem with displaying graph (#30765) -- Fix backfill KeyError when try_number out of sync (#30653) -- Re-enable clear and setting state in the TaskInstance UI (#30415) -- Prevent DagRun's ``state`` and ``start_date`` from being reset when clearing a task in a running DagRun (#30125) - -Misc/Internal -""""""""""""" -- Upper bind dask until they solve a side effect in their test suite (#31259) -- Show task instances affected by clearing in a table (#30633) -- Fix missing models in API documentation (#31021) - -Doc only changes -"""""""""""""""" -- Improve description of the ``dag_processing.processes`` metric (#30891) -- Improve Quick Start instructions (#30820) -- Add section about missing task logs to the FAQ (#30717) -- Mount the ``config`` directory in docker compose (#30662) -- Update ``version_added`` config field for ``might_contain_dag`` and ``metrics_allow_list`` (#30969) - - -Airflow 2.6.0 (2023-04-30) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Default permissions of file task handler log directories and files has been changed to "owner + group" writeable (#29506). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Default setting handles case where impersonation is needed and both users (airflow and the impersonated user) -have the same group set as main group. Previously the default was also other-writeable and the user might choose -to use the other-writeable setting if they wish by configuring ``file_task_handler_new_folder_permissions`` -and ``file_task_handler_new_file_permissions`` in ``logging`` section. - -SLA callbacks no longer add files to the dag processor manager's queue (#30076) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This stops SLA callbacks from keeping the dag processor manager permanently busy. It means reduced CPU, -and fixes issues where SLAs stop the system from seeing changes to existing dag files. Additional metrics added to help track queue state. - -The ``cleanup()`` method in BaseTrigger is now defined as asynchronous (following async/await) pattern (#30152). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -This is potentially a breaking change for any custom trigger implementations that override the ``cleanup()`` -method and uses synchronous code, however using synchronous operations in cleanup was technically wrong, -because the method was executed in the main loop of the Triggerer and it was introducing unnecessary delays -impacting other triggers. The change is unlikely to affect any existing trigger implementations. - -The gauge ``scheduler.tasks.running`` no longer exist (#30374) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -The gauge has never been working and its value has always been 0. Having an accurate -value for this metric is complex so it has been decided that removing this gauge makes -more sense than fixing it with no certainty of the correctness of its value. - -Consolidate handling of tasks stuck in queued under new ``task_queued_timeout`` config (#30375) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Logic for handling tasks stuck in the queued state has been consolidated, and the all configurations -responsible for timing out stuck queued tasks have been deprecated and merged into -``[scheduler] task_queued_timeout``. The configurations that have been deprecated are -``[kubernetes] worker_pods_pending_timeout``, ``[celery] stalled_task_timeout``, and -``[celery] task_adoption_timeout``. If any of these configurations are set, the longest timeout will be -respected. For example, if ``[celery] stalled_task_timeout`` is 1200, and ``[scheduler] task_queued_timeout`` -is 600, Airflow will set ``[scheduler] task_queued_timeout`` to 1200. - -Improvement Changes -^^^^^^^^^^^^^^^^^^^ - -Display only the running configuration in configurations view (#28892) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -The configurations view now only displays the running configuration. Previously, the default configuration -was displayed at the top but it was not obvious whether this default configuration was overridden or not. -Subsequently, the non-documented endpoint ``/configuration?raw=true`` is deprecated and will be removed in -Airflow 3.0. The HTTP response now returns an additional ``Deprecation`` header. The ``/config`` endpoint on -the REST API is the standard way to fetch Airflow configuration programmatically. - -Explicit skipped states list for ExternalTaskSensor (#29933) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -ExternalTaskSensor now has an explicit ``skipped_states`` list - -Miscellaneous Changes -^^^^^^^^^^^^^^^^^^^^^ - -Handle OverflowError on exponential backoff in next_run_calculation (#28172) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Maximum retry task delay is set to be 24h (86400s) by default. You can change it globally via ``core.max_task_retry_delay`` -parameter. - -Move Hive macros to the provider (#28538) -""""""""""""""""""""""""""""""""""""""""" -The Hive Macros (``hive.max_partition``, ``hive.closest_ds_partition``) are available only when Hive Provider is -installed. Please install Hive Provider > 5.1.0 when using those macros. - -Updated app to support configuring the caching hash method for FIPS v2 (#30675) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Various updates for FIPS-compliance when running Airflow in Python 3.9+. This includes a new webserver option, ``caching_hash_method``, -for changing the default flask caching method. - -New Features -^^^^^^^^^^^^ -- AIP-50 Trigger DAG UI Extension with Flexible User Form Concept (#27063,#29376) -- Skip PythonVirtualenvOperator task when it returns a provided exit code (#30690) -- rename skip_exit_code to skip_on_exit_code and allow providing multiple codes (#30692) -- Add skip_on_exit_code also to ExternalPythonOperator (#30738) -- Add ``max_active_tis_per_dagrun`` for Dynamic Task Mapping (#29094) -- Add serializer for pandas dataframe (#30390) -- Deferrable ``TriggerDagRunOperator`` (#30292) -- Add command to get DAG Details via CLI (#30432) -- Adding ContinuousTimetable and support for @continuous schedule_interval (#29909) -- Allow customized rules to check if a file has dag (#30104) -- Add a new Airflow conf to specify a SSL ca cert for Kubernetes client (#30048) -- Bash sensor has an explicit retry code (#30080) -- Add filter task upstream/downstream to grid view (#29885) -- Add testing a connection via Airflow CLI (#29892) -- Support deleting the local log files when using remote logging (#29772) -- ``Blocklist`` to disable specific metric tags or metric names (#29881) -- Add a new graph inside of the grid view (#29413) -- Add database ``check_migrations`` config (#29714) -- add output format arg for ``cli.dags.trigger`` (#29224) -- Make json and yaml available in templates (#28930) -- Enable tagged metric names for existing Statsd metric publishing events | influxdb-statsd support (#29093) -- Add arg --yes to ``db export-archived`` command. (#29485) -- Make the policy functions pluggable (#28558) -- Add ``airflow db drop-archived`` command (#29309) -- Enable individual trigger logging (#27758) -- Implement new filtering options in graph view (#29226) -- Add triggers for ExternalTask (#29313) -- Add command to export purged records to CSV files (#29058) -- Add ``FileTrigger`` (#29265) -- Emit DataDog statsd metrics with metadata tags (#28961) -- Add some statsd metrics for dataset (#28907) -- Add --overwrite option to ``connections import`` CLI command (#28738) -- Add general-purpose "notifier" concept to DAGs (#28569) -- Add a new conf to wait past_deps before skipping a task (#27710) -- Add Flink on K8s Operator (#28512) -- Allow Users to disable SwaggerUI via configuration (#28354) -- Show mapped task groups in graph (#28392) -- Log FileTaskHandler to work with KubernetesExecutor's multi_namespace_mode (#28436) -- Add a new config for adapting masked secrets to make it easier to prevent secret leakage in logs (#28239) -- List specific config section and its values using the cli (#28334) -- KubernetesExecutor multi_namespace_mode can use namespace list to avoid requiring cluster role (#28047) -- Automatically save and allow restore of recent DAG run configs (#27805) -- Added exclude_microseconds to cli (#27640) - -Improvements -"""""""""""" -- Rename most pod_id usage to pod_name in KubernetesExecutor (#29147) -- Update the error message for invalid use of poke-only sensors (#30821) -- Update log level in scheduler critical section edge case (#30694) -- AIP-51 Removing Executor Coupling from Core Airflow (`AIP-51 `__) -- Add multiple exit code handling in skip logic for BashOperator (#30739) -- Updated app to support configuring the caching hash method for FIPS v2 (#30675) -- Preload airflow imports before dag parsing to save time (#30495) -- Improve task & run actions ``UX`` in grid view (#30373) -- Speed up TaskGroups with caching property of group_id (#30284) -- Use the engine provided in the session (#29804) -- Type related import optimization for Executors (#30361) -- Add more type hints to the code base (#30503) -- Always use self.appbuilder.get_session in security managers (#30233) -- Update SQLAlchemy ``select()`` to new style (#30515) -- Refactor out xcom constants from models (#30180) -- Add exception class name to DAG-parsing error message (#30105) -- Rename statsd_allow_list and statsd_block_list to ``metrics_*_list`` (#30174) -- Improve serialization of tuples and sets (#29019) -- Make cleanup method in trigger an async one (#30152) -- Lazy load serialization modules (#30094) -- SLA callbacks no longer add files to the dag_processing manager queue (#30076) -- Add task.trigger rule to grid_data (#30130) -- Speed up log template sync by avoiding ORM (#30119) -- Separate cli_parser.py into two modules (#29962) -- Explicit skipped states list for ExternalTaskSensor (#29933) -- Add task state hover highlighting to new graph (#30100) -- Store grid tabs in url params (#29904) -- Use custom Connexion resolver to load lazily (#29992) -- Delay Kubernetes import in secret masker (#29993) -- Delay ConnectionModelView init until it's accessed (#29946) -- Scheduler, make stale DAG deactivation threshold configurable instead of using dag processing timeout (#29446) -- Improve grid view height calculations (#29563) -- Avoid importing executor during conf validation (#29569) -- Make permissions for FileTaskHandler group-writeable and configurable (#29506) -- Add colors in help outputs of Airflow CLI commands #28789 (#29116) -- Add a param for get_dags endpoint to list only unpaused dags (#28713) -- Expose updated_at filter for dag run and task instance endpoints (#28636) -- Increase length of user identifier columns (#29061) -- Update gantt chart UI to display queued state of tasks (#28686) -- Add index on log.dttm (#28944) -- Display only the running configuration in configurations view (#28892) -- Cap dropdown menu size dynamically (#28736) -- Added JSON linter to connection edit / add UI for field extra. On connection edit screen, existing extra data will be displayed indented (#28583) -- Use labels instead of pod name for pod log read in k8s exec (#28546) -- Use time not tries for queued & running re-checks. (#28586) -- CustomTTYColoredFormatter should inherit TimezoneAware formatter (#28439) -- Improve past depends handling in Airflow CLI tasks.run command (#28113) -- Support using a list of callbacks in ``on_*_callback/sla_miss_callbacks`` (#28469) -- Better table name validation for db clean (#28246) -- Use object instead of array in config.yml for config template (#28417) -- Add markdown rendering for task notes. (#28245) -- Show mapped task groups in grid view (#28208) -- Add ``renamed`` and ``previous_name`` in config sections (#28324) -- Speed up most Users/Role CLI commands (#28259) -- Speed up Airflow role list command (#28244) -- Refactor serialization (#28067, #30819, #30823) -- Allow longer pod names for k8s executor / KPO (#27736) -- Updates health check endpoint to include ``triggerer`` status (#27755) - - -Bug Fixes -""""""""" -- Fix static_folder for cli app (#30952) -- Initialize plugins for cli appbuilder (#30934) -- Fix dag file processor heartbeat to run only if necessary (#30899) -- Fix KubernetesExecutor sending state to scheduler (#30872) -- Count mapped upstream only if all are finished (#30641) -- ExternalTaskSensor: add external_task_group_id to template_fields (#30401) -- Improve url detection for task instance details (#30779) -- Use material icons for dag import error banner (#30771) -- Fix misc grid/graph view UI bugs (#30752) -- Add a collapse grid button (#30711) -- Fix d3 dependencies (#30702) -- Simplify logic to resolve tasks stuck in queued despite stalled_task_timeout (#30375) -- When clearing task instances try to get associated DAGs from database (#29065) -- Fix mapped tasks partial arguments when DAG default args are provided (#29913) -- Deactivate DAGs deleted from within zip files (#30608) -- Recover from ``too old resource version exception`` by retrieving the latest ``resource_version`` (#30425) -- Fix possible race condition when refreshing DAGs (#30392) -- Use custom validator for OpenAPI request body (#30596) -- Fix ``TriggerDagRunOperator`` with deferrable parameter (#30406) -- Speed up dag runs deletion (#30330) -- Do not use template literals to construct html elements (#30447) -- Fix deprecation warning in ``example_sensor_decorator`` DAG (#30513) -- Avoid logging sensitive information in triggerer job log (#30110) -- Add a new parameter for base sensor to catch the exceptions in poke method (#30293) -- Fix dag run conf encoding with non-JSON serializable values (#28777) -- Added fixes for Airflow to be usable on Windows Dask-Workers (#30249) -- Force DAG last modified time to UTC (#30243) -- Fix EmptySkipOperator in example dag (#30269) -- Make the webserver startup respect update_fab_perms (#30246) -- Ignore error when changing log folder permissions (#30123) -- Disable ordering DagRuns by note (#30043) -- Fix reading logs from finished KubernetesExecutor worker pod (#28817) -- Mask out non-access bits when comparing file modes (#29886) -- Remove Run task action from UI (#29706) -- Fix log tailing issues with legacy log view (#29496) -- Fixes to how DebugExecutor handles sensors (#28528) -- Ensure that pod_mutation_hook is called before logging the pod name (#28534) -- Handle OverflowError on exponential backoff in next_run_calculation (#28172) - -Misc/Internal -""""""""""""" -- Make eager upgrade additional dependencies optional (#30811) -- Upgrade to pip 23.1.1 (#30808) -- Remove protobuf limitation from eager upgrade (#30182) -- Remove protobuf limitation from eager upgrade (#30182) -- Deprecate ``skip_exit_code`` in ``BashOperator`` (#30734) -- Remove gauge ``scheduler.tasks.running`` (#30374) -- Bump json5 to 1.0.2 and eslint-plugin-import to 2.27.5 in ``/airflow/www`` (#30568) -- Add tests to PythonOperator (#30362) -- Add asgiref as a core dependency (#30527) -- Discovery safe mode toggle comment clarification (#30459) -- Upgrade moment-timezone package to fix Tehran tz (#30455) -- Bump loader-utils from 2.0.0 to 2.0.4 in ``/airflow/www`` (#30319) -- Bump babel-loader from 8.1.0 to 9.1.0 in ``/airflow/www`` (#30316) -- DagBag: Use ``dag.fileloc`` instead of ``dag.full_filepath`` in exception message (#30610) -- Change log level of serialization information (#30239) -- Minor DagRun helper method cleanup (#30092) -- Improve type hinting in stats.py (#30024) -- Limit ``importlib-metadata`` backport to < 5.0.0 (#29924) -- Align cncf provider file names with AIP-21 (#29905) -- Upgrade FAB to 4.3.0 (#29766) -- Clear ExecutorLoader cache in tests (#29849) -- Lazy load Task Instance logs in UI (#29827) -- added warning log for max page limit exceeding api calls (#29788) -- Aggressively cache entry points in process (#29625) -- Don't use ``importlib.metadata`` to get Version for speed (#29723) -- Upgrade Mypy to 1.0 (#29468) -- Rename ``db export-cleaned`` to ``db export-archived`` (#29450) -- listener: simplify API by replacing SQLAlchemy event-listening by direct calls (#29289) -- No multi-line log entry for bash env vars (#28881) -- Switch to ruff for faster static checks (#28893) -- Remove horizontal lines in TI logs (#28876) -- Make allowed_deserialization_classes more intuitive (#28829) -- Propagate logs to stdout when in k8s executor pod (#28440, #30860) -- Fix code readability, add docstrings to json_client (#28619) -- AIP-51 - Misc. Compatibility Checks (#28375) -- Fix is_local for LocalKubernetesExecutor (#28288) -- Move Hive macros to the provider (#28538) -- Rerun flaky PinotDB integration test (#28562) -- Add pre-commit hook to check session default value (#28007) -- Refactor get_mapped_group_summaries for web UI (#28374) -- Add support for k8s 1.26 (#28320) -- Replace ``freezegun`` with time-machine (#28193) -- Completed D400 for ``airflow/kubernetes/*`` (#28212) -- Completed D400 for multiple folders (#27969) -- Drop k8s 1.21 and 1.22 support (#28168) -- Remove unused task_queue attr from k8s scheduler class (#28049) -- Completed D400 for multiple folders (#27767, #27768) - - -Doc only changes -"""""""""""""""" -- Add instructions on how to avoid accidental airflow upgrade/downgrade (#30813) -- Add explicit information about how to write task logs (#30732) -- Better explanation on how to log from tasks (#30746) -- Use correct import path for Dataset (#30617) -- Create ``audit_logs.rst`` (#30405) -- Adding taskflow API example for sensors (#30344) -- Add clarification about timezone aware dags (#30467) -- Clarity params documentation (#30345) -- Fix unit for task duration metric (#30273) -- Update dag-run.rst for dead links of cli commands (#30254) -- Add Write efficient Python code section to Reducing DAG complexity (#30158) -- Allow to specify which connection, variable or config are being looked up in the backend using ``*_lookup_pattern`` parameters (#29580) -- Add Documentation for notification feature extension (#29191) -- Clarify that executor interface is public but instances are not (#29200) -- Add Public Interface description to Airflow documentation (#28300) -- Add documentation for task group mapping (#28001) -- Some fixes to metrics doc (#30290) - - -Airflow 2.5.3 (2023-04-01) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -No significant changes. - -Bug Fixes -^^^^^^^^^ -- Fix DagProcessorJob integration for standalone dag-processor (#30278) -- Fix proper termination of gunicorn when it hangs (#30188) -- Fix XCom.get_one exactly one exception text (#30183) -- Correct the VARCHAR size to 250. (#30178) -- Revert fix for on_failure_callback when task receives a SIGTERM (#30165) -- Move read only property to DagState to fix generated docs (#30149) -- Ensure that ``dag.partial_subset`` doesn't mutate task group properties (#30129) -- Fix inconsistent returned value of ``airflow dags next-execution`` cli command (#30117) -- Fix www/utils.dag_run_link redirection (#30098) -- Fix ``TriggerRuleDep`` when the mapped tasks count is 0 (#30084) -- Dag processor manager, add retry_db_transaction to _fetch_callbacks (#30079) -- Fix db clean command for mysql db (#29999) -- Avoid considering EmptyOperator in mini scheduler (#29979) -- Fix some long known Graph View UI problems (#29971, #30355, #30360) -- Fix dag docs toggle icon initial angle (#29970) -- Fix tags selection in DAGs UI (#29944) -- Including airflow/example_dags/sql/sample.sql in MANIFEST.in (#29883) -- Fixing broken filter in /taskinstance/list view (#29850) -- Allow generic param dicts (#29782) -- Fix update_mask in patch variable route (#29711) -- Strip markup from app_name if instance_name_has_markup = True (#28894) - -Misc/Internal -^^^^^^^^^^^^^ -- Revert "Also limit importlib on Python 3.9 (#30069)" (#30209) -- Add custom_operator_name to @task.sensor tasks (#30131) -- Bump webpack from 5.73.0 to 5.76.0 in /airflow/www (#30112) -- Formatted config (#30103) -- Remove upper bound limit of astroid (#30033) -- Remove accidentally merged vendor daemon patch code (#29895) -- Fix warning in airflow tasks test command regarding absence of data_interval (#27106) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Adding more information regarding top level code (#30040) -- Update workday example (#30026) -- Fix some typos in the DAGs docs (#30015) -- Update set-up-database.rst (#29991) -- Fix some typos on the kubernetes documentation (#29936) -- Fix some punctuation and grammar (#29342) - - -Airflow 2.5.2 (2023-03-15) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -The date-time fields passed as API parameters or Params should be RFC3339-compliant (#29395) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -In case of API calls, it was possible that "+" passed as part of the date-time fields were not URL-encoded, and -such date-time fields could pass validation. Such date-time parameters should now be URL-encoded (as ``%2B``). - -In case of parameters, we still allow IS8601-compliant date-time (so for example it is possible that -' ' was used instead of ``T`` separating date from time and no timezone was specified) but we raise -deprecation warning. - -Default for ``[webserver] expose_hostname`` changed to ``False`` (#29547) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -The default for ``[webserver] expose_hostname`` has been set to ``False``, instead of ``True``. This means administrators must opt-in to expose webserver hostnames to end users. - -Bug Fixes -^^^^^^^^^ -- Fix validation of date-time field in API and Parameter schemas (#29395) -- Fix grid logs for large logs (#29390) -- Fix on_failure_callback when task receives a SIGTERM (#29743) -- Update min version of python-daemon to fix containerd file limits (#29916) -- POST ``/dagRuns`` API should 404 if dag not active (#29860) -- DAG list sorting lost when switching page (#29756) -- Fix Scheduler crash when clear a previous run of a normal task that is now a mapped task (#29645) -- Convert moment with timezone to UTC instead of raising an exception (#29606) -- Fix clear dag run ``openapi`` spec responses by adding additional return type (#29600) -- Don't display empty rendered attrs in Task Instance Details page (#29545) -- Remove section check from get-value command (#29541) -- Do not show version/node in UI traceback for unauthenticated user (#29501) -- Make ``prev_logical_date`` variable offset-aware (#29454) -- Fix nested fields rendering in mapped operators (#29451) -- Datasets, next_run_datasets, remove unnecessary timestamp filter (#29441) -- ``Edgemodifier`` refactoring w/ labels in TaskGroup edge case (#29410) -- Fix Rest API update user output (#29409) -- Ensure Serialized DAG is deleted (#29407) -- Persist DAG and task doc values in TaskFlow API if explicitly set (#29399) -- Redirect to the origin page with all the params (#29212) -- Fixing Task Duration view in case of manual DAG runs only (#22015) (#29195) -- Remove poke method to fall back to parent implementation (#29146) -- PR: Introduced fix to run tasks on Windows systems (#29107) -- Fix warning in migrations about old config. (#29092) -- Emit dagrun failed duration when timeout (#29076) -- Handling error on cluster policy itself (#29056) -- Fix kerberos authentication for the REST API. (#29054) -- Fix leak sensitive field via V1EnvVar on exception (#29016) -- Sanitize url_for arguments before they are passed (#29039) -- Fix dag run trigger with a note. (#29228) -- Write action log to DB when DAG run is triggered via API (#28998) -- Resolve all variables in pickled XCom iterator (#28982) -- Allow URI without authority and host blocks in ``airflow connections add`` (#28922) -- Be more selective when adopting pods with KubernetesExecutor (#28899) -- KubenetesExecutor sends state even when successful (#28871) -- Annotate KubernetesExecutor pods that we don't delete (#28844) -- Throttle streaming log reads (#28818) -- Introduce dag processor job (#28799) -- Fix #28391 manual task trigger from UI fails for k8s executor (#28394) -- Logging poke info when external dag is not none and task_id and task_ids are none (#28097) -- Fix inconsistencies in checking edit permissions for a DAG (#20346) - -Misc/Internal -^^^^^^^^^^^^^ -- Add a check for not templateable fields (#29821) -- Removed continue for not in (#29791) -- Move extra links position in grid view (#29703) -- Bump ``undici`` from ``5.9.1`` to ``5.19.1`` (#29583) -- Change expose_hostname default to false (#29547) -- Change permissions of config/password files created by airflow (#29495) -- Use newer setuptools ``v67.2.0`` (#29465) -- Increase max height for grid view elements (#29367) -- Clarify description of worker control config (#29247) -- Bump ``ua-parser-js`` from ``0.7.31`` to ``0.7.33`` in ``/airflow/www`` (#29172) -- Remove upper bound limitation for ``pytest`` (#29086) -- Check for ``run_id`` url param when linking to ``graph/gantt`` views (#29066) -- Clarify graph view dynamic task labels (#29042) -- Fixing import error for dataset (#29007) -- Update how PythonSensor returns values from ``python_callable`` (#28932) -- Add dep context description for better log message (#28875) -- Bump ``swagger-ui-dist`` from ``3.52.0`` to ``4.1.3`` in ``/airflow/www`` (#28824) -- Limit ``importlib-metadata`` backport to ``< 5.0.0`` (#29924, #30069) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Update pipeline.rst - Fix query in ``merge_data()`` task (#29158) -- Correct argument name of Workday timetable in timetable.rst (#29896) -- Update ref anchor for env var link in Connection how-to doc (#29816) -- Better description for limit in api (#29773) -- Description of dag_processing.last_duration (#29740) -- Update docs re: template_fields typing and subclasses (#29725) -- Fix formatting of Dataset inlet/outlet note in TaskFlow concepts (#29678) -- Specific use-case: adding packages via requirements.txt in compose (#29598) -- Detect is 'docker-compose' existing (#29544) -- Add Landing Times entry to UI docs (#29511) -- Improve health checks in example docker-compose and clarify usage (#29408) -- Remove ``notes`` param from TriggerDagRunOperator docstring (#29298) -- Use ``schedule`` param rather than ``timetable`` in Timetables docs (#29255) -- Add trigger process to Airflow Docker docs (#29203) -- Update set-up-database.rst (#29104) -- Several improvements to the Params doc (#29062) -- Email Config docs more explicit env var examples (#28845) -- Listener plugin example added (#27905) - - -Airflow 2.5.1 (2023-01-20) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Trigger gevent ``monkeypatching`` via environment variable (#28283) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -If you are using gevent for your webserver deployment and used local settings to ``monkeypatch`` gevent, -you might want to replace local settings patching with an ``_AIRFLOW_PATCH_GEVENT`` environment variable -set to 1 in your webserver. This ensures gevent patching is done as early as possible. - -Bug Fixes -^^^^^^^^^ -- Fix masking of non-sensitive environment variables (#28802) -- Remove swagger-ui extra from connexion and install ``swagger-ui-dist`` via npm package (#28788) -- Fix ``UIAlert`` should_show when ``AUTH_ROLE_PUBLIC`` set (#28781) -- Only patch single label when adopting pod (#28776) -- Update CSRF token to expire with session (#28730) -- Fix "airflow tasks render" cli command for mapped task instances (#28698) -- Allow XComArgs for ``external_task_ids`` of ExternalTaskSensor (#28692) -- Row-lock TIs to be removed during mapped task expansion (#28689) -- Handle ConnectionReset exception in Executor cleanup (#28685) -- Fix description of output redirection for access_log for gunicorn (#28672) -- Add back join to zombie query that was dropped in #28198 (#28544) -- Fix calendar view for CronTriggerTimeTable dags (#28411) -- After running the DAG the employees table is empty. (#28353) -- Fix ``DetachedInstanceError`` when finding zombies in Dag Parsing process (#28198) -- Nest header blocks in ``divs`` to fix ``dagid`` copy nit on dag.html (#28643) -- Fix UI caret direction (#28624) -- Guard not-yet-expanded ti in trigger rule dep (#28592) -- Move TI ``setNote`` endpoints under TaskInstance in OpenAPI (#28566) -- Consider previous run in ``CronTriggerTimetable`` (#28532) -- Ensure correct log dir in file task handler (#28477) -- Fix bad pods pickled in executor_config (#28454) -- Add ``ensure_ascii=False`` in trigger dag run API (#28451) -- Add setters to MappedOperator on_*_callbacks (#28313) -- Fix ``ti._try_number`` for deferred and up_for_reschedule tasks (#26993) -- separate ``callModal`` from dag.js (#28410) -- A manual run can't look like a scheduled one (#28397) -- Dont show task/run durations when there is no start_date (#28395) -- Maintain manual scroll position in task logs (#28386) -- Correctly select a mapped task's "previous" task (#28379) -- Trigger gevent ``monkeypatching`` via environment variable (#28283) -- Fix db clean warnings (#28243) -- Make arguments 'offset' and 'length' not required (#28234) -- Make live logs reading work for "other" k8s executors (#28213) -- Add custom pickling hooks to ``LazyXComAccess`` (#28191) -- fix next run datasets error (#28165) -- Ensure that warnings from ``@dag`` decorator are reported in dag file (#28153) -- Do not warn when airflow dags tests command is used (#28138) -- Ensure the ``dagbag_size`` metric decreases when files are deleted (#28135) -- Improve run/task grid view actions (#28130) -- Make BaseJob.most_recent_job favor "running" jobs (#28119) -- Don't emit FutureWarning when code not calling old key (#28109) -- Add ``airflow.api.auth.backend.session`` to backend sessions in compose (#28094) -- Resolve false warning about calling conf.get on moved item (#28075) -- Return list of tasks that will be changed (#28066) -- Handle bad zip files nicely when parsing DAGs. (#28011) -- Prevent double loading of providers from local paths (#27988) -- Fix deadlock when chaining multiple empty mapped tasks (#27964) -- fix: current_state method on TaskInstance doesn't filter by map_index (#27898) -- Don't log CLI actions if db not initialized (#27851) -- Make sure we can get out of a faulty scheduler state (#27834) -- dagrun, ``next_dagruns_to_examine``, add MySQL index hint (#27821) -- Handle DAG disappearing mid-flight when dag verification happens (#27720) -- fix: continue checking sla (#26968) -- Allow generation of connection URI to work when no conn type (#26765) - -Misc/Internal -^^^^^^^^^^^^^ -- Remove limit for ``dnspython`` after eventlet got fixed (#29004) -- Limit ``dnspython`` to < ``2.3.0`` until eventlet incompatibility is solved (#28962) -- Add automated version replacement in example dag indexes (#28090) -- Cleanup and do housekeeping with plugin examples (#28537) -- Limit ``SQLAlchemy`` to below ``2.0`` (#28725) -- Bump ``json5`` from ``1.0.1`` to ``1.0.2`` in ``/airflow/www`` (#28715) -- Fix some docs on using sensors with taskflow (#28708) -- Change Architecture and OperatingSystem classes into ``Enums`` (#28627) -- Add doc-strings and small improvement to email util (#28634) -- Fix ``Connection.get_extra`` type (#28594) -- navbar, cap dropdown size, and add scroll bar (#28561) -- Emit warnings for ``conf.get*`` from the right source location (#28543) -- Move MyPY plugins of ours to dev folder (#28498) -- Add retry to ``purge_inactive_dag_warnings`` (#28481) -- Re-enable Plyvel on ARM as it now builds cleanly (#28443) -- Add SIGUSR2 handler for LocalTaskJob and workers to aid debugging (#28309) -- Convert ``test_task_command`` to Pytest and ``unquarantine`` tests in it (#28247) -- Make invalid characters exception more readable (#28181) -- Bump decode-uri-component from ``0.2.0`` to ``0.2.2`` in ``/airflow/www`` (#28080) -- Use asserts instead of exceptions for executor not started (#28019) -- Simplify dataset ``subgraph`` logic (#27987) -- Order TIs by ``map_index`` (#27904) -- Additional info about Segmentation Fault in ``LocalTaskJob`` (#27381) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Mention mapped operator in cluster policy doc (#28885) -- Slightly improve description of Dynamic DAG generation preamble (#28650) -- Restructure Docs (#27235) -- Update scheduler docs about low priority tasks (#28831) -- Clarify that versioned constraints are fixed at release time (#28762) -- Clarify about docker compose (#28729) -- Adding an example dag for dynamic task mapping (#28325) -- Use docker compose v2 command (#28605) -- Add AIRFLOW_PROJ_DIR to docker-compose example (#28517) -- Remove outdated Optional Provider Feature outdated documentation (#28506) -- Add documentation for [core] mp_start_method config (#27993) -- Documentation for the LocalTaskJob return code counter (#27972) -- Note which versions of Python are supported (#27798) - - -Airflow 2.5.0 (2022-12-02) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -``airflow dags test`` no longer performs a backfill job (#26400) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -In order to make ``airflow dags test`` more useful as a testing and debugging tool, we no -longer run a backfill job and instead run a "local task runner". Users can still backfill -their DAGs using the ``airflow dags backfill`` command. - -Airflow config section ``kubernetes`` renamed to ``kubernetes_executor`` (#26873) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -KubernetesPodOperator no longer considers any core kubernetes config params, so this section now only applies to kubernetes executor. Renaming it reduces potential for confusion. - -``AirflowException`` is now thrown as soon as any dependent tasks of ExternalTaskSensor fails (#27190) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -``ExternalTaskSensor`` no longer hangs indefinitely when ``failed_states`` is set, an ``execute_date_fn`` is used, and some but not all of the dependent tasks fail. -Instead, an ``AirflowException`` is thrown as soon as any of the dependent tasks fail. -Any code handling this failure in addition to timeouts should move to caching the ``AirflowException`` ``BaseClass`` and not only the ``AirflowSensorTimeout`` subclass. - -The Airflow config option ``scheduler.deactivate_stale_dags_interval`` has been renamed to ``scheduler.parsing_cleanup_interval`` (#27828). -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -The old option will continue to work but will issue deprecation warnings, and will be removed entirely in Airflow 3. - -New Features -^^^^^^^^^^^^ -- ``TaskRunner``: notify of component start and finish (#27855) -- Add DagRun state change to the Listener plugin system(#27113) -- Metric for raw task return codes (#27155) -- Add logic for XComArg to pull specific map indexes (#27771) -- Clear TaskGroup (#26658, #28003) -- Add critical section query duration metric (#27700) -- Add: #23880 :: Audit log for ``AirflowModelViews(Variables/Connection)`` (#24079, #27994, #27923) -- Add postgres 15 support (#27444) -- Expand tasks in mapped group at run time (#27491) -- reset commits, clean submodules (#27560) -- scheduler_job, add metric for scheduler loop timer (#27605) -- Allow datasets to be used in taskflow (#27540) -- Add expanded_ti_count to ti context (#27680) -- Add user comment to task instance and dag run (#26457, #27849, #27867) -- Enable copying DagRun JSON to clipboard (#27639) -- Implement extra controls for SLAs (#27557) -- add dag parsed time in DAG view (#27573) -- Add max_wait for exponential_backoff in BaseSensor (#27597) -- Expand tasks in mapped group at parse time (#27158) -- Add disable retry flag on backfill (#23829) -- Adding sensor decorator (#22562) -- Api endpoint update ti (#26165) -- Filtering datasets by recent update events (#26942) -- Support ``Is /not`` Null filter for value is None on ``webui`` (#26584) -- Add search to datasets list (#26893) -- Split out and handle 'params' in mapped operator (#26100) -- Add authoring API for TaskGroup mapping (#26844) -- Add ``one_done`` trigger rule (#26146) -- Create a more efficient airflow dag test command that also has better local logging (#26400) -- Support add/remove permissions to roles commands (#26338) -- Auto tail file logs in Web UI (#26169) -- Add triggerer info to task instance in API (#26249) -- Flag to deserialize value on custom XCom backend (#26343) - -Improvements -^^^^^^^^^^^^ -- Allow depth-first execution (#27827) -- UI: Update offset height if data changes (#27865) -- Improve TriggerRuleDep typing and readability (#27810) -- Make views requiring session, keyword only args (#27790) -- Optimize ``TI.xcom_pull()`` with explicit task_ids and map_indexes (#27699) -- Allow hyphens in pod id used by k8s executor (#27737) -- optimise task instances filtering (#27102) -- Use context managers to simplify log serve management (#27756) -- Fix formatting leftovers (#27750) -- Improve task deadlock messaging (#27734) -- Improve "sensor timeout" messaging (#27733) -- Replace urlparse with ``urlsplit`` (#27389) -- Align TaskGroup semantics to AbstractOperator (#27723) -- Add new files to parsing queue on every loop of dag processing (#27060) -- Make Kubernetes Executor & Scheduler resilient to error during PMH execution (#27611) -- Separate dataset deps into individual graphs (#27356) -- Use log.exception where more economical than log.error (#27517) -- Move validation ``branch_task_ids`` into ``SkipMixin`` (#27434) -- Coerce LazyXComAccess to list when pushed to XCom (#27251) -- Update cluster-policies.rst docs (#27362) -- Add warning if connection type already registered within the provider (#27520) -- Activate debug logging in commands with --verbose option (#27447) -- Add classic examples for Python Operators (#27403) -- change ``.first()`` to ``.scalar()`` (#27323) -- Improve reset_dag_run description (#26755) -- Add examples and ``howtos`` about sensors (#27333) -- Make grid view widths adjustable (#27273) -- Sorting plugins custom menu links by category before name (#27152) -- Simplify DagRun.verify_integrity (#26894) -- Add mapped task group info to serialization (#27027) -- Correct the JSON style used for Run config in Grid View (#27119) -- No ``extra__conn_type__`` prefix required for UI behaviors (#26995) -- Improve dataset update blurb (#26878) -- Rename kubernetes config section to kubernetes_executor (#26873) -- decode params for dataset searches (#26941) -- Get rid of the DAGRun details page & rely completely on Grid (#26837) -- Fix scheduler ``crashloopbackoff`` when using ``hostname_callable`` (#24999) -- Reduce log verbosity in KubernetesExecutor. (#26582) -- Don't iterate tis list twice for no reason (#26740) -- Clearer code for PodGenerator.deserialize_model_file (#26641) -- Don't import kubernetes unless you have a V1Pod (#26496) -- Add updated_at column to DagRun and Ti tables (#26252) -- Move the deserialization of custom XCom Backend to 2.4.0 (#26392) -- Avoid calculating all elements when one item is needed (#26377) -- Add ``__future__``.annotations automatically by isort (#26383) -- Handle list when serializing expand_kwargs (#26369) -- Apply PEP-563 (Postponed Evaluation of Annotations) to core airflow (#26290) -- Add more weekday operator and sensor examples #26071 (#26098) -- Align TaskGroup semantics to AbstractOperator (#27723) - -Bug Fixes -^^^^^^^^^ -- Gracefully handle whole config sections being renamed (#28008) -- Add allow list for imports during deserialization (#27887) -- Soft delete datasets that are no longer referenced in DAG schedules or task outlets (#27828) -- Redirect to home view when there are no valid tags in the URL (#25715) -- Refresh next run datasets info in dags view (#27839) -- Make MappedTaskGroup depend on its expand inputs (#27876) -- Make DagRun state updates for paused DAGs faster (#27725) -- Don't explicitly set include_examples to False on task run command (#27813) -- Fix menu border color (#27789) -- Fix backfill queued task getting reset to scheduled state. (#23720) -- Fix clearing child dag mapped tasks from parent dag (#27501) -- Handle json encoding of ``V1Pod`` in task callback (#27609) -- Fix ExternalTaskSensor can't check zipped dag (#27056) -- Avoid re-fetching DAG run in TriggerDagRunOperator (#27635) -- Continue on exception when retrieving metadata (#27665) -- External task sensor fail fix (#27190) -- Add the default None when pop actions (#27537) -- Display parameter values from serialized dag in trigger dag view. (#27482, #27944) -- Move TriggerDagRun conf check to execute (#27035) -- Resolve trigger assignment race condition (#27072) -- Update google_analytics.html (#27226) -- Fix some bug in web ui dags list page (auto-refresh & jump search null state) (#27141) -- Fixed broken URL for docker-compose.yaml (#26721) -- Fix xcom arg.py .zip bug (#26636) -- Fix 404 ``taskInstance`` errors and split into two tables (#26575) -- Fix browser warning of improper thread usage (#26551) -- template rendering issue fix (#26390) -- Clear ``autoregistered`` DAGs if there are any import errors (#26398) -- Fix ``from airflow import version`` lazy import (#26239) -- allow scroll in triggered dag runs modal (#27965) - -Misc/Internal -^^^^^^^^^^^^^ -- Remove ``is_mapped`` attribute (#27881) -- Simplify FAB table resetting (#27869) -- Fix old-style typing in Base Sensor (#27871) -- Switch (back) to late imports (#27730) -- Completed D400 for multiple folders (#27748) -- simplify notes accordion test (#27757) -- completed D400 for ``airflow/callbacks/* airflow/cli/*`` (#27721) -- Completed D400 for ``airflow/api_connexion/* directory`` (#27718) -- Completed D400 for ``airflow/listener/* directory`` (#27731) -- Completed D400 for ``airflow/lineage/* directory`` (#27732) -- Update API & Python Client versions (#27642) -- Completed D400 & D401 for ``airflow/api/*`` directory (#27716) -- Completed D400 for multiple folders (#27722) -- Bump ``minimatch`` from ``3.0.4 to 3.0.8`` in ``/airflow/www`` (#27688) -- Bump loader-utils from ``1.4.1 to 1.4.2 ``in ``/airflow/www`` (#27697) -- Disable nested task mapping for now (#27681) -- bump alembic minimum version (#27629) -- remove unused code.html (#27585) -- Enable python string normalization everywhere (#27588) -- Upgrade dependencies in order to avoid backtracking (#27531) -- Strengthen a bit and clarify importance of triaging issues (#27262) -- Deduplicate type hints (#27508) -- Add stub 'yield' to ``BaseTrigger.run`` (#27416) -- Remove upper-bound limit to dask (#27415) -- Limit Dask to under ``2022.10.1`` (#27383) -- Update old style typing (#26872) -- Enable string normalization for docs (#27269) -- Slightly faster up/downgrade tests (#26939) -- Deprecate use of core get_kube_client in PodManager (#26848) -- Add ``memray`` files to ``gitignore / dockerignore`` (#27001) -- Bump sphinx and ``sphinx-autoapi`` (#26743) -- Simplify ``RTIF.delete_old_records()`` (#26667) -- migrate last react files to typescript (#26112) -- Work around ``pyupgrade`` edge cases (#26384) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Document dag_file_processor_timeouts metric as deprecated (#27067) -- Drop support for PostgreSQL 10 (#27594) -- Update index.rst (#27529) -- Add note about pushing the lazy XCom proxy to XCom (#27250) -- Fix BaseOperator link (#27441) -- [docs] best-practices add use variable with template example. (#27316) -- docs for custom view using plugin (#27244) -- Update graph view and grid view on overview page (#26909) -- Documentation fixes (#26819) -- make consistency on markup title string level (#26696) -- Add documentation to dag test function (#26713) -- Fix broken URL for ``docker-compose.yaml`` (#26726) -- Add a note against use of top level code in timetable (#26649) -- Fix example_datasets dag names (#26495) -- Update docs: zip-like effect is now possible in task mapping (#26435) -- changing to task decorator in docs from classic operator use (#25711) - -Airflow 2.4.3 (2022-11-14) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Make ``RotatingFilehandler`` used in ``DagProcessor`` non-caching (#27223) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -In case you want to decrease cache memory when ``CONFIG_PROCESSOR_MANAGER_LOGGER=True``, and you have your local settings created before, -you can update ``processor_manager_handler`` to use ``airflow.utils.log.non_caching_file_handler.NonCachingRotatingFileHandler`` handler instead of ``logging.RotatingFileHandler``. - -Bug Fixes -^^^^^^^^^ -- Fix double logging with some task logging handler (#27591) -- Replace FAB url filtering function with Airflow's (#27576) -- Fix mini scheduler expansion of mapped task (#27506) -- ``SLAMiss`` is nullable and not always given back when pulling task instances (#27423) -- Fix behavior of ``_`` when searching for DAGs (#27448) -- Fix getting the ``dag/task`` ids from BaseExecutor (#27550) -- Fix SQLAlchemy primary key black-out error on DDRQ (#27538) -- Fix IntegrityError during webserver startup (#27297) -- Add case insensitive constraint to username (#27266) -- Fix python external template keys (#27256) -- Reduce extraneous task log requests (#27233) -- Make ``RotatingFilehandler`` used in ``DagProcessor`` non-caching (#27223) -- Listener: Set task on SQLAlchemy TaskInstance object (#27167) -- Fix dags list page auto-refresh & jump search null state (#27141) -- Set ``executor.job_id`` to ``BackfillJob.id`` for backfills (#27020) - -Misc/Internal -^^^^^^^^^^^^^ -- Bump loader-utils from ``1.4.0`` to ``1.4.1`` in ``/airflow/www`` (#27552) -- Reduce log level for k8s ``TCP_KEEPALIVE`` etc warnings (#26981) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Use correct executable in docker compose docs (#27529) -- Fix wording in DAG Runs description (#27470) -- Document that ``KubernetesExecutor`` overwrites container args (#27450) -- Fix ``BaseOperator`` links (#27441) -- Correct timer units to seconds from milliseconds. (#27360) -- Add missed import in the Trigger Rules example (#27309) -- Update SLA wording to reflect it is relative to ``Dag Run`` start. (#27111) -- Add ``kerberos`` environment variables to the docs (#27028) - -Airflow 2.4.2 (2022-10-23) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Default for ``[webserver] expose_stacktrace`` changed to ``False`` (#27059) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -The default for ``[webserver] expose_stacktrace`` has been set to ``False``, instead of ``True``. This means administrators must opt-in to expose tracebacks to end users. - -Bug Fixes -^^^^^^^^^ -- Make tracebacks opt-in (#27059) -- Add missing AUTOINC/SERIAL for FAB tables (#26885) -- Add separate error handler for 405(Method not allowed) errors (#26880) -- Don't re-patch pods that are already controlled by current worker (#26778) -- Handle mapped tasks in task duration chart (#26722) -- Fix task duration cumulative chart (#26717) -- Avoid 500 on dag redirect (#27064) -- Filter dataset dependency data on webserver (#27046) -- Remove double collection of dags in ``airflow dags reserialize`` (#27030) -- Fix auto refresh for graph view (#26926) -- Don't overwrite connection extra with invalid json (#27142) -- Fix next run dataset modal links (#26897) -- Change dag audit log sort by date from asc to desc (#26895) -- Bump min version of jinja2 (#26866) -- Add missing colors to ``state_color_mapping`` jinja global (#26822) -- Fix running debuggers inside ``airflow tasks test`` (#26806) -- Fix warning when using xcomarg dependencies (#26801) -- demote Removed state in priority for displaying task summaries (#26789) -- Ensure the log messages from operators during parsing go somewhere (#26779) -- Add restarting state to TaskState Enum in REST API (#26776) -- Allow retrieving error message from data.detail (#26762) -- Simplify origin string cleaning (#27143) -- Remove DAG parsing from StandardTaskRunner (#26750) -- Fix non-hidden cumulative chart on duration view (#26716) -- Remove TaskFail duplicates check (#26714) -- Fix airflow tasks run --local when dags_folder differs from that of processor (#26509) -- Fix yarn warning from d3-color (#27139) -- Fix version for a couple configurations (#26491) -- Revert "No grid auto-refresh for backfill dag runs (#25042)" (#26463) -- Retry on Airflow Schedule DAG Run DB Deadlock (#26347) - -Misc/Internal -^^^^^^^^^^^^^ -- Clean-ups around task-mapping code (#26879) -- Move user-facing string to template (#26815) -- add icon legend to datasets graph (#26781) -- Bump ``sphinx`` and ``sphinx-autoapi`` (#26743) -- Simplify ``RTIF.delete_old_records()`` (#26667) -- Bump FAB to ``4.1.4`` (#26393) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Fixed triple quotes in task group example (#26829) -- Documentation fixes (#26819) -- make consistency on markup title string level (#26696) -- Add a note against use of top level code in timetable (#26649) -- Fix broken URL for ``docker-compose.yaml`` (#26726) - - -Airflow 2.4.1 (2022-09-30) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -No significant changes. - -Bug Fixes -^^^^^^^^^ - -- When rendering template, unmap task in context (#26702) -- Fix scroll overflow for ConfirmDialog (#26681) -- Resolve deprecation warning re ``Table.exists()`` (#26616) -- Fix XComArg zip bug (#26636) -- Use COALESCE when ordering runs to handle NULL (#26626) -- Check user is active (#26635) -- No missing user warning for public admin (#26611) -- Allow MapXComArg to resolve after serialization (#26591) -- Resolve warning about DISTINCT ON query on dags view (#26608) -- Log warning when secret backend kwargs is invalid (#26580) -- Fix grid view log try numbers (#26556) -- Template rendering issue in passing ``templates_dict`` to task decorator (#26390) -- Fix Deferrable stuck as ``scheduled`` during backfill (#26205) -- Suppress SQLALCHEMY_TRACK_MODIFICATIONS warning in db init (#26617) -- Correctly set ``json_provider_class`` on Flask app so it uses our encoder (#26554) -- Fix WSGI root app (#26549) -- Fix deadlock when mapped task with removed upstream is rerun (#26518) -- ExecutorConfigType should be ``cacheable`` (#26498) -- Fix proper joining of the path for logs retrieved from celery workers (#26493) -- DAG Deps extends ``base_template`` (#26439) -- Don't update backfill run from the scheduler (#26342) - -Doc only changes -^^^^^^^^^^^^^^^^ - -- Clarify owner links document (#26515) -- Fix invalid RST in dataset concepts doc (#26434) -- Document the ``non-sensitive-only`` option for ``expose_config`` (#26507) -- Fix ``example_datasets`` dag names (#26495) -- Zip-like effect is now possible in task mapping (#26435) -- Use task decorator in docs instead of classic operators (#25711) - -Airflow 2.4.0 (2022-09-19) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Data-aware Scheduling and ``Dataset`` concept added to Airflow -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -New to this release of Airflow is the concept of Datasets to Airflow, and with it a new way of scheduling dags: -data-aware scheduling. - -This allows DAG runs to be automatically created as a result of a task "producing" a dataset. In some ways -this can be thought of as the inverse of ``TriggerDagRunOperator``, where instead of the producing DAG -controlling which DAGs get created, the consuming DAGs can "listen" for changes. - -A dataset is identified by a URI: - -.. code-block:: python - - from airflow import Dataset - - # The URI doesn't have to be absolute - dataset = Dataset(uri="my-dataset") - # Or you can use a scheme to show where it lives. - dataset2 = Dataset(uri="s3://bucket/prefix") - -To create a DAG that runs whenever a Dataset is updated use the new ``schedule`` parameter (see below) and -pass a list of 1 or more Datasets: - -.. code-block:: python - - with DAG(dag_id='dataset-consumer', schedule=[dataset]): - ... - -And to mark a task as producing a dataset pass the dataset(s) to the ``outlets`` attribute: - -.. code-block:: python - - @task(outlets=[dataset]) - def my_task(): ... - - - # Or for classic operators - BashOperator(task_id="update-ds", bash_command=..., outlets=[dataset]) - -If you have the producer and consumer in different files you do not need to use the same Dataset object, two -``Dataset()``\s created with the same URI are equal. - -Datasets represent the abstract concept of a dataset, and (for now) do not have any direct read or write -capability - in this release we are adding the foundational feature that we will build upon. - -For more info on Datasets please see `Datasets documentation `_. - -Expanded dynamic task mapping support -""""""""""""""""""""""""""""""""""""" - -Dynamic task mapping now includes support for ``expand_kwargs``, ``zip`` and ``map``. - -For more info on dynamic task mapping please see :doc:`/authoring-and-scheduling/dynamic-task-mapping`. - -DAGS used in a context manager no longer need to be assigned to a module variable (#23592) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -Previously you had to assign a DAG to a module-level variable in order for Airflow to pick it up. For example this - - -.. code-block:: python - - with DAG(dag_id="example") as dag: - ... - - - @dag - def dag_maker(): ... - - - dag2 = dag_maker() - - -can become - -.. code-block:: python - - with DAG(dag_id="example"): - ... - - - @dag - def dag_maker(): ... - - - dag_maker() - -If you want to disable the behaviour for any reason then set ``auto_register=False`` on the dag: - -.. code-block:: python - - # This dag will not be picked up by Airflow as it's not assigned to a variable - with DAG(dag_id="example", auto_register=False): - ... - -Deprecation of ``schedule_interval`` and ``timetable`` arguments (#25410) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -We added new DAG argument ``schedule`` that can accept a cron expression, timedelta object, *timetable* object, or list of dataset objects. Arguments ``schedule_interval`` and ``timetable`` are deprecated. - -If you previously used the ``@daily`` cron preset, your DAG may have looked like this: - -.. code-block:: python - - with DAG( - dag_id="my_example", - start_date=datetime(2021, 1, 1), - schedule_interval="@daily", - ): - ... - -Going forward, you should use the ``schedule`` argument instead: - -.. code-block:: python - - with DAG( - dag_id="my_example", - start_date=datetime(2021, 1, 1), - schedule="@daily", - ): - ... - -The same is true if you used a custom timetable. Previously you would have used the ``timetable`` argument: - -.. code-block:: python - - with DAG( - dag_id="my_example", - start_date=datetime(2021, 1, 1), - timetable=EventsTimetable(event_dates=[pendulum.datetime(2022, 4, 5)]), - ): - ... - -Now you should use the ``schedule`` argument: - -.. code-block:: python - - with DAG( - dag_id="my_example", - start_date=datetime(2021, 1, 1), - schedule=EventsTimetable(event_dates=[pendulum.datetime(2022, 4, 5)]), - ): - ... - -Removal of experimental Smart Sensors (#25507) -"""""""""""""""""""""""""""""""""""""""""""""" - -Smart Sensors were added in 2.0 and deprecated in favor of Deferrable operators in 2.2, and have now been removed. - -``airflow.contrib`` packages and deprecated modules are dynamically generated (#26153, #26179, #26167) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -The ``airflow.contrib`` packages and deprecated modules from Airflow 1.10 in ``airflow.hooks``, ``airflow.operators``, ``airflow.sensors`` packages are now dynamically generated modules and while users can continue using the deprecated contrib classes, they are no longer visible for static code check tools and will be reported as missing. It is recommended for the users to move to the non-deprecated classes. - -``DBApiHook`` and ``SQLSensor`` have moved (#24836) -""""""""""""""""""""""""""""""""""""""""""""""""""" - -``DBApiHook`` and ``SQLSensor`` have been moved to the ``apache-airflow-providers-common-sql`` provider. - -DAG runs sorting logic changed in grid view (#25090) -"""""""""""""""""""""""""""""""""""""""""""""""""""" - -The ordering of DAG runs in the grid view has been changed to be more "natural". -The new logic generally orders by data interval, but a custom ordering can be -applied by setting the DAG to use a custom timetable. - - -New Features -^^^^^^^^^^^^ -- Add Data-aware Scheduling (`AIP-48 `_) -- Add ``@task.short_circuit`` TaskFlow decorator (#25752) -- Make ``execution_date_or_run_id`` optional in ``tasks test`` command (#26114) -- Automatically register DAGs that are used in a context manager (#23592, #26398) -- Add option of sending DAG parser logs to stdout. (#25754) -- Support multiple ``DagProcessors`` parsing files from different locations. (#25935) -- Implement ``ExternalPythonOperator`` (#25780) -- Make execution_date optional for command ``dags test`` (#26111) -- Implement ``expand_kwargs()`` against a literal list (#25925) -- Add trigger rule tooltip (#26043) -- Add conf parameter to CLI for airflow dags test (#25900) -- Include scheduled slots in pools view (#26006) -- Add ``output`` property to ``MappedOperator`` (#25604) -- Add roles delete command to cli (#25854) -- Add Airflow specific warning classes (#25799) -- Add support for ``TaskGroup`` in ``ExternalTaskSensor`` (#24902) -- Add ``@task.kubernetes`` taskflow decorator (#25663) -- Add a way to import Airflow without side-effects (#25832) -- Let timetables control generated run_ids. (#25795) -- Allow per-timetable ordering override in grid view (#25633) -- Grid logs for mapped instances (#25610, #25621, #25611) -- Consolidate to one ``schedule`` param (#25410) -- DAG regex flag in backfill command (#23870) -- Adding support for owner links in the Dags view UI (#25280) -- Ability to clear a specific DAG Run's task instances via REST API (#23516) -- Possibility to document DAG with a separate markdown file (#25509) -- Add parsing context to DAG Parsing (#25161) -- Implement ``CronTriggerTimetable`` (#23662) -- Add option to mask sensitive data in UI configuration page (#25346) -- Create new databases from the ORM (#24156) -- Implement ``XComArg.zip(*xcom_args)`` (#25176) -- Introduce ``sla_miss`` metric (#23402) -- Implement ``map()`` semantic (#25085) -- Add override method to TaskGroupDecorator (#25160) -- Implement ``expand_kwargs()`` (#24989) -- Add parameter to turn off SQL query logging (#24570) -- Add ``DagWarning`` model, and a check for missing pools (#23317) -- Add Task Logs to Grid details panel (#24249) -- Added small health check server and endpoint in scheduler(#23905) -- Add built-in External Link for ``ExternalTaskMarker`` operator (#23964) -- Add default task retry delay config (#23861) -- Add clear DagRun endpoint. (#23451) -- Add support for timezone as string in cron interval timetable (#23279) -- Add auto-refresh to dags home page (#22900, #24770) - -Improvements -^^^^^^^^^^^^ - -- Add more weekday operator and sensor examples #26071 (#26098) -- Add subdir parameter to dags reserialize command (#26170) -- Update zombie message to be more descriptive (#26141) -- Only send an ``SlaCallbackRequest`` if the DAG is scheduled (#26089) -- Promote ``Operator.output`` more (#25617) -- Upgrade API files to typescript (#25098) -- Less ``hacky`` double-rendering prevention in mapped task (#25924) -- Improve Audit log (#25856) -- Remove mapped operator validation code (#25870) -- More ``DAG(schedule=...)`` improvements (#25648) -- Reduce ``operator_name`` dupe in serialized JSON (#25819) -- Make grid view group/mapped summary UI more consistent (#25723) -- Remove useless statement in ``task_group_to_grid`` (#25654) -- Add optional data interval to ``CronTriggerTimetable`` (#25503) -- Remove unused code in ``/grid`` endpoint (#25481) -- Add and document description fields (#25370) -- Improve Airflow logging for operator Jinja template processing (#25452) -- Update core example DAGs to use ``@task.branch`` decorator (#25242) -- Update DAG ``audit_log`` route (#25415) -- Change stdout and stderr access mode to append in commands (#25253) -- Remove ``getTasks`` from Grid view (#25359) -- Improve taskflow type hints with ParamSpec (#25173) -- Use tables in grid details panes (#25258) -- Explicitly list ``@dag`` arguments (#25044) -- More typing in ``SchedulerJob`` and ``TaskInstance`` (#24912) -- Patch ``getfqdn`` with more resilient version (#24981) -- Replace all ``NBSP`` characters by ``whitespaces`` (#24797) -- Re-serialize all DAGs on ``airflow db upgrade`` (#24518) -- Rework contract of try_adopt_task_instances method (#23188) -- Make ``expand()`` error vague so it's not misleading (#24018) -- Add enum validation for ``[webserver]analytics_tool`` (#24032) -- Add ``dttm`` searchable field in audit log (#23794) -- Allow more parameters to be piped through via ``execute_in_subprocess`` (#23286) -- Use ``func.count`` to count rows (#23657) -- Remove stale serialized dags (#22917) -- AIP45 Remove dag parsing in airflow run local (#21877) -- Add support for queued state in DagRun update endpoint. (#23481) -- Add fields to dagrun endpoint (#23440) -- Use ``sql_alchemy_conn`` for celery result backend when ``result_backend`` is not set (#24496) - -Bug Fixes -^^^^^^^^^ - -- Have consistent types between the ORM and the migration files (#24044, #25869) -- Disallow any dag tags longer than 100 char (#25196) -- Add the dag_id to ``AirflowDagCycleException`` message (#26204) -- Properly build URL to retrieve logs independently from system (#26337) -- For worker log servers only bind to IPV6 when dual stack is available (#26222) -- Fix ``TaskInstance.task`` not defined before ``handle_failure`` (#26040) -- Undo secrets backend config caching (#26223) -- Fix faulty executor config serialization logic (#26191) -- Show ``DAGs`` and ``Datasets`` menu links based on role permission (#26183) -- Allow setting ``TaskGroup`` tooltip via function docstring (#26028) -- Fix RecursionError on graph view of a DAG with many tasks (#26175) -- Fix backfill occasional deadlocking (#26161) -- Fix ``DagRun.start_date`` not set during backfill with ``--reset-dagruns`` True (#26135) -- Use label instead of id for dynamic task labels in graph (#26108) -- Don't fail DagRun when leaf ``mapped_task`` is SKIPPED (#25995) -- Add group prefix to decorated mapped task (#26081) -- Fix UI flash when triggering with dup logical date (#26094) -- Fix Make items nullable for ``TaskInstance`` related endpoints to avoid API errors (#26076) -- Fix ``BranchDateTimeOperator`` to be ``timezone-awreness-insensitive`` (#25944) -- Fix legacy timetable schedule interval params (#25999) -- Fix response schema for ``list-mapped-task-instance`` (#25965) -- Properly check the existence of missing mapped TIs (#25788) -- Fix broken auto-refresh on grid view (#25950) -- Use per-timetable ordering in grid UI (#25880) -- Rewrite recursion when parsing DAG into iteration (#25898) -- Find cross-group tasks in ``iter_mapped_dependants`` (#25793) -- Fail task if mapping upstream fails (#25757) -- Support ``/`` in variable get endpoint (#25774) -- Use cfg default_wrap value for grid logs (#25731) -- Add origin request args when triggering a run (#25729) -- Operator name separate from class (#22834) -- Fix incorrect data interval alignment due to assumption on input time alignment (#22658) -- Return None if an ``XComArg`` fails to resolve (#25661) -- Correct ``json`` arg help in ``airflow variables set`` command (#25726) -- Added MySQL index hint to use ``ti_state`` on ``find_zombies`` query (#25725) -- Only excluded actually expanded fields from render (#25599) -- Grid, fix toast for ``axios`` errors (#25703) -- Fix UI redirect (#26409) -- Require dag_id arg for dags list-runs (#26357) -- Check for queued states for dags auto-refresh (#25695) -- Fix upgrade code for the ``dag_owner_attributes`` table (#25579) -- Add map index to task logs api (#25568) -- Ensure that zombie tasks for dags with errors get cleaned up (#25550) -- Make extra link work in UI (#25500) -- Sync up plugin API schema and definition (#25524) -- First/last names can be empty (#25476) -- Refactor DAG pages to be consistent (#25402) -- Check ``expand_kwargs()`` input type before unmapping (#25355) -- Filter XCOM by key when calculating map lengths (#24530) -- Fix ``ExternalTaskSensor`` not working with dynamic task (#25215) -- Added exception catching to send default email if template file raises any exception (#24943) -- Bring ``MappedOperator`` members in sync with ``BaseOperator`` (#24034) - - -Misc/Internal -^^^^^^^^^^^^^ - -- Add automatically generated ``ERD`` schema for the ``MetaData`` DB (#26217) -- Mark serialization functions as internal (#26193) -- Remove remaining deprecated classes and replace them with ``PEP562`` (#26167) -- Move ``dag_edges`` and ``task_group_to_dict`` to corresponding util modules (#26212) -- Lazily import many modules to improve import speed (#24486, #26239) -- FIX Incorrect typing information (#26077) -- Add missing contrib classes to deprecated dictionaries (#26179) -- Re-configure/connect the ``ORM`` after forking to run a DAG processor (#26216) -- Remove cattrs from lineage processing. (#26134) -- Removed deprecated contrib files and replace them with ``PEP-562`` getattr (#26153) -- Make ``BaseSerialization.serialize`` "public" to other classes. (#26142) -- Change the template to use human readable task_instance description (#25960) -- Bump ``moment-timezone`` from ``0.5.34`` to ``0.5.35`` in ``/airflow/www`` (#26080) -- Fix Flask deprecation warning (#25753) -- Add ``CamelCase`` to generated operations types (#25887) -- Fix migration issues and tighten the CI upgrade/downgrade test (#25869) -- Fix type annotations in ``SkipMixin`` (#25864) -- Workaround setuptools editable packages path issue (#25848) -- Bump ``undici`` from ``5.8.0 to 5.9.1`` in /airflow/www (#25801) -- Add custom_operator_name attr to ``_BranchPythonDecoratedOperator`` (#25783) -- Clarify ``filename_template`` deprecation message (#25749) -- Use ``ParamSpec`` to replace ``...`` in Callable (#25658) -- Remove deprecated modules (#25543) -- Documentation on task mapping additions (#24489) -- Remove Smart Sensors (#25507) -- Fix ``elasticsearch`` test config to avoid warning on deprecated template (#25520) -- Bump ``terser`` from ``4.8.0 to 4.8.1`` in /airflow/ui (#25178) -- Generate ``typescript`` types from rest ``API`` docs (#25123) -- Upgrade utils files to ``typescript`` (#25089) -- Upgrade remaining context file to ``typescript``. (#25096) -- Migrate files to ``ts`` (#25267) -- Upgrade grid Table component to ``ts.`` (#25074) -- Skip mapping against mapped ``ti`` if it returns None (#25047) -- Refactor ``js`` file structure (#25003) -- Move mapped kwargs introspection to separate type (#24971) -- Only assert stuff for mypy when type checking (#24937) -- Bump ``moment`` from ``2.29.3 to 2.29.4`` in ``/airflow/www`` (#24885) -- Remove "bad characters" from our codebase (#24841) -- Remove ``xcom_push`` flag from ``BashOperator`` (#24824) -- Move Flask hook registration to end of file (#24776) -- Upgrade more javascript files to ``typescript`` (#24715) -- Clean up task decorator type hints and docstrings (#24667) -- Preserve original order of providers' connection extra fields in UI (#24425) -- Rename ``charts.css`` to ``chart.css`` (#24531) -- Rename ``grid.css`` to ``chart.css`` (#24529) -- Misc: create new process group by ``set_new_process_group`` utility (#24371) -- Airflow UI fix Prototype Pollution (#24201) -- Bump ``moto`` version (#24222) -- Remove unused ``[github_enterprise]`` from ref docs (#24033) -- Clean up ``f-strings`` in logging calls (#23597) -- Add limit for ``JPype1`` (#23847) -- Simply json responses (#25518) -- Add min attrs version (#26408) - -Doc only changes -^^^^^^^^^^^^^^^^ -- Add url prefix setting for ``Celery`` Flower (#25986) -- Updating deprecated configuration in examples (#26037) -- Fix wrong link for taskflow tutorial (#26007) -- Reorganize tutorials into a section (#25890) -- Fix concept doc for dynamic task map (#26002) -- Update code examples from "classic" operators to taskflow (#25845, #25657) -- Add instructions on manually fixing ``MySQL`` Charset problems (#25938) -- Prefer the local Quick Start in docs (#25888) -- Fix broken link to ``Trigger Rules`` (#25840) -- Improve docker documentation (#25735) -- Correctly link to Dag parsing context in docs (#25722) -- Add note on ``task_instance_mutation_hook`` usage (#25607) -- Note that TaskFlow API automatically passes data between tasks (#25577) -- Update DAG run to clarify when a DAG actually runs (#25290) -- Update tutorial docs to include a definition of operators (#25012) -- Rewrite the Airflow documentation home page (#24795) -- Fix ``task-generated mapping`` example (#23424) -- Add note on subtle logical date change in ``2.2.0`` (#24413) -- Add missing import in best-practices code example (#25391) - - - -Airflow 2.3.4 (2022-08-23) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -Added new config ``[logging]log_formatter_class`` to fix timezone display for logs on UI (#24811) -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -If you are using a custom Formatter subclass in your ``[logging]logging_config_class``, please inherit from ``airflow.utils.log.timezone_aware.TimezoneAware`` instead of ``logging.Formatter``. -For example, in your ``custom_config.py``: - -.. code-block:: python - - from airflow.utils.log.timezone_aware import TimezoneAware - - - # before - class YourCustomFormatter(logging.Formatter): ... - - - # after - class YourCustomFormatter(TimezoneAware): ... - - - AIRFLOW_FORMATTER = LOGGING_CONFIG["formatters"]["airflow"] - AIRFLOW_FORMATTER["class"] = "somewhere.your.custom_config.YourCustomFormatter" - # or use TimezoneAware class directly. If you don't have custom Formatter. - AIRFLOW_FORMATTER["class"] = "airflow.utils.log.timezone_aware.TimezoneAware" - -Bug Fixes -^^^^^^^^^ - -- Disable ``attrs`` state management on ``MappedOperator`` (#24772) -- Serialize ``pod_override`` to JSON before pickling ``executor_config`` (#24356) -- Fix ``pid`` check (#24636) -- Rotate session id during login (#25771) -- Fix mapped sensor with reschedule mode (#25594) -- Cache the custom secrets backend so the same instance gets reused (#25556) -- Add right padding (#25554) -- Fix reducing mapped length of a mapped task at runtime after a clear (#25531) -- Fix ``airflow db reset`` when dangling tables exist (#25441) -- Change ``disable_verify_ssl`` behaviour (#25023) -- Set default task group in dag.add_task method (#25000) -- Removed interfering force of index. (#25404) -- Remove useless logging line (#25347) -- Adding mysql index hint to use index on ``task_instance.state`` in critical section query (#25673) -- Configurable umask to all daemonized processes. (#25664) -- Fix the errors raised when None is passed to template filters (#25593) -- Allow wildcarded CORS origins (#25553) -- Fix "This Session's transaction has been rolled back" (#25532) -- Fix Serialization error in ``TaskCallbackRequest`` (#25471) -- fix - resolve bash by absolute path (#25331) -- Add ``__repr__`` to ParamsDict class (#25305) -- Only load distribution of a name once (#25296) -- convert ``TimeSensorAsync`` ``target_time`` to utc on call time (#25221) -- call ``updateNodeLabels`` after ``expandGroup`` (#25217) -- Stop SLA callbacks gazumping other callbacks and DOS'ing the ``DagProcessorManager`` queue (#25147) -- Fix ``invalidateQueries`` call (#25097) -- ``airflow/www/package.json``: Add name, version fields. (#25065) -- No grid auto-refresh for backfill dag runs (#25042) -- Fix tag link on dag detail page (#24918) -- Fix zombie task handling with multiple schedulers (#24906) -- Bind log server on worker to ``IPv6`` address (#24755) (#24846) -- Add ``%z`` for ``%(asctime)s`` to fix timezone for logs on UI (#24811) -- ``TriggerDagRunOperator.operator_extra_links`` is attr (#24676) -- Send DAG timeout callbacks to processor outside of ``prohibit_commit`` (#24366) -- Don't rely on current ORM structure for db clean command (#23574) -- Clear next method when clearing TIs (#23929) -- Two typing fixes (#25690) - -Doc only changes -^^^^^^^^^^^^^^^^ - -- Update set-up-database.rst (#24983) -- Fix syntax in mysql setup documentation (#24893 (#24939) -- Note how DAG policy works with default_args (#24804) -- Update PythonVirtualenvOperator Howto (#24782) -- Doc: Add hyperlinks to Github PRs for Release Notes (#24532) - -Misc/Internal -^^^^^^^^^^^^^ - -- Remove depreciation warning when use default remote tasks logging handlers (#25764) -- clearer method name in scheduler_job.py (#23702) -- Bump cattrs version (#25689) -- Include missing mention of ``external_executor_id`` in ``sql_engine_collation_for_ids`` docs (#25197) -- Refactor ``DR.task_instance_scheduling_decisions`` (#24774) -- Sort operator extra links (#24992) -- Extends ``resolve_xcom_backend`` function level documentation (#24965) -- Upgrade FAB to 4.1.3 (#24884) -- Limit Flask to <2.3 in the wake of 2.2 breaking our tests (#25511) -- Limit astroid version to < 2.12 (#24982) -- Move javascript compilation to host (#25169) -- Bump typing-extensions and mypy for ParamSpec (#25088) - - -Airflow 2.3.3 (2022-07-09) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ - -We've upgraded Flask App Builder to a major version 4.* (#24399) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -Flask App Builder is one of the important components of Airflow Webserver, as -it uses a lot of dependencies that are essential to run the webserver and integrate it -in enterprise environments - especially authentication. - -The FAB 4.* upgrades a number of dependencies to major releases, which upgrades them to versions -that have a number of security issues fixed. A lot of tests were performed to bring the dependencies -in a backwards-compatible way, however the dependencies themselves implement breaking changes in their -internals so it might be that some of those changes might impact the users in case they are using the -libraries for their own purposes. - -One important change that you likely will need to apply to Oauth configuration is to add -``server_metadata_url`` or ``jwks_uri`` and you can read about it more -in `this issue `_. - -Here is the list of breaking changes in dependencies that comes together with FAB 4: - - * ``Flask`` from 1.X to 2.X `breaking changes `__ - - * ``flask-jwt-extended`` 3.X to 4.X `breaking changes: `__ - - * ``Jinja2`` 2.X to 3.X `breaking changes: `__ - - * ``Werkzeug`` 1.X to 2.X `breaking changes `__ - - * ``pyJWT`` 1.X to 2.X `breaking changes: `__ - - * ``Click`` 7.X to 8.X `breaking changes: `__ - - * ``itsdangerous`` 1.X to 2.X `breaking changes `__ - -Bug Fixes -^^^^^^^^^ - -- Fix exception in mini task scheduler (#24865) -- Fix cycle bug with attaching label to task group (#24847) -- Fix timestamp defaults for ``sensorinstance`` (#24638) -- Move fallible ``ti.task.dag`` assignment back inside ``try/except`` block (#24533) (#24592) -- Add missing types to ``FSHook`` (#24470) -- Mask secrets in ``stdout`` for ``airflow tasks test`` (#24362) -- ``DebugExecutor`` use ``ti.run()`` instead of ``ti._run_raw_task`` (#24357) -- Fix bugs in ``URI`` constructor for ``MySQL`` connection (#24320) -- Missing ``scheduleinterval`` nullable true added in ``openapi`` (#24253) -- Unify ``return_code`` interface for task runner (#24093) -- Handle occasional deadlocks in trigger with retries (#24071) -- Remove special serde logic for mapped ``op_kwargs`` (#23860) -- ``ExternalTaskSensor`` respects ``soft_fail`` if the external task enters a ``failed_state`` (#23647) -- Fix ``StatD`` timing metric units (#21106) -- Add ``cache_ok`` flag to sqlalchemy TypeDecorators. (#24499) -- Allow for ``LOGGING_LEVEL=DEBUG`` (#23360) -- Fix grid date ticks (#24738) -- Debounce status highlighting in Grid view (#24710) -- Fix Grid vertical scrolling (#24684) -- don't try to render child rows for closed groups (#24637) -- Do not calculate grid root instances (#24528) -- Maintain grid view selection on filtering upstream (#23779) -- Speed up ``grid_data`` endpoint by 10x (#24284) -- Apply per-run log templates to log handlers (#24153) -- Don't crash scheduler if exec config has old k8s objects (#24117) -- ``TI.log_url`` fix for ``map_index`` (#24335) -- Fix migration ``0080_2_0_2`` - Replace null values before setting column not null (#24585) -- Patch ``sql_alchemy_conn`` if old Postgres schemes used (#24569) -- Seed ``log_template`` table (#24511) -- Fix deprecated ``log_id_template`` value (#24506) -- Fix toast messages (#24505) -- Add indexes for CASCADE deletes for ``task_instance`` (#24488) -- Return empty dict if Pod JSON encoding fails (#24478) -- Improve grid rendering performance with a custom tooltip (#24417, #24449) -- Check for ``run_id`` for grid group summaries (#24327) -- Optimize calendar view for cron scheduled DAGs (#24262) -- Use ``get_hostname`` instead of ``socket.getfqdn`` (#24260) -- Check that edge nodes actually exist (#24166) -- Fix ``useTasks`` crash on error (#24152) -- Do not fail re-queued TIs (#23846) -- Reduce grid view API calls (#24083) -- Rename Permissions to Permission Pairs. (#24065) -- Replace ``use_task_execution_date`` with ``use_task_logical_date`` (#23983) -- Grid fix details button truncated and small UI tweaks (#23934) -- Add TaskInstance State ``REMOVED`` to finished states and success states (#23797) -- Fix mapped task immutability after clear (#23667) -- Fix permission issue for dag that has dot in name (#23510) -- Fix closing connection ``dbapi.get_pandas_df`` (#23452) -- Check bag DAG ``schedule_interval`` match timetable (#23113) -- Parse error for task added to multiple groups (#23071) -- Fix flaky order of returned dag runs (#24405) -- Migrate ``jsx`` files that affect run/task selection to ``tsx`` (#24509) -- Fix links to sources for examples (#24386) -- Set proper ``Content-Type`` and ``chartset`` on ``grid_data`` endpoint (#24375) - -Doc only changes -^^^^^^^^^^^^^^^^ - -- Update templates doc to mention ``extras`` and format Airflow ``Vars`` / ``Conns`` (#24735) -- Document built in Timetables (#23099) -- Alphabetizes two tables (#23923) -- Clarify that users should not use Maria DB (#24556) -- Add imports to deferring code samples (#24544) -- Add note about image regeneration in June 2022 (#24524) -- Small cleanup of ``get_current_context()`` chapter (#24482) -- Fix default 2.2.5 ``log_id_template`` (#24455) -- Update description of installing providers separately from core (#24454) -- Mention context variables and logging (#24304) - -Misc/Internal -^^^^^^^^^^^^^ - -- Remove internet explorer support (#24495) -- Removing magic status code numbers from ``api_connexion`` (#24050) -- Upgrade FAB to ``4.1.2`` (#24619) -- Switch Markdown engine to ``markdown-it-py`` (#19702) -- Update ``rich`` to latest version across the board. (#24186) -- Get rid of ``TimedJSONWebSignatureSerializer`` (#24519) -- Update flask-appbuilder ``authlib``/ ``oauth`` dependency (#24516) -- Upgrade to ``webpack`` 5 (#24485) -- Add ``typescript`` (#24337) -- The JWT claims in the request to retrieve logs have been standardized: we use ``nbf`` and ``aud`` claims for - maturity and audience of the requests. Also "filename" payload field is used to keep log name. (#24519) -- Address all ``yarn`` test warnings (#24722) -- Upgrade to react 18 and chakra 2 (#24430) -- Refactor ``DagRun.verify_integrity`` (#24114) -- Upgrade FAB to ``4.1.1`` (#24399) -- We now need at least ``Flask-WTF 0.15`` (#24621) - - -Airflow 2.3.2 (2022-06-04) --------------------------- - -No significant changes. - -Bug Fixes -^^^^^^^^^ - -- Run the ``check_migration`` loop at least once -- Fix grid view for mapped tasks (#24059) -- Icons in grid view for different DAG run types (#23970) -- Faster grid view (#23951) -- Disallow calling expand with no arguments (#23463) -- Add missing ``is_mapped`` field to Task response. (#23319) -- DagFileProcessorManager: Start a new process group only if current process not a session leader (#23872) -- Mask sensitive values for not-yet-running TIs (#23807) -- Add cascade to ``dag_tag`` to ``dag`` foreign key (#23444) -- Use ``--subdir`` argument value for standalone dag processor. (#23864) -- Highlight task states by hovering on legend row (#23678) -- Fix and speed up grid view (#23947) -- Prevent UI from crashing if grid task instances are null (#23939) -- Remove redundant register exit signals in ``dag-processor`` command (#23886) -- Add ``__wrapped__`` property to ``_TaskDecorator`` (#23830) -- Fix UnboundLocalError when ``sql`` is empty list in DbApiHook (#23816) -- Enable clicking on DAG owner in autocomplete dropdown (#23804) -- Simplify flash message for ``_airflow_moved`` tables (#23635) -- Exclude missing tasks from the gantt view (#23627) - -Doc only changes -^^^^^^^^^^^^^^^^ - -- Add column names for DB Migration Reference (#23853) - -Misc/Internal -^^^^^^^^^^^^^ - -- Remove pinning for xmltodict (#23992) - - -Airflow 2.3.1 (2022-05-25) --------------------------- - -Significant Changes -^^^^^^^^^^^^^^^^^^^ -No significant changes. - -Bug Fixes -^^^^^^^^^ - -- Automatically reschedule stalled queued tasks in ``CeleryExecutor`` (#23690) -- Fix expand/collapse all buttons (#23590) -- Grid view status filters (#23392) -- Expand/collapse all groups (#23487) -- Fix retrieval of deprecated non-config values (#23723) -- Fix secrets rendered in UI when task is not executed. (#22754) -- Fix provider import error matching (#23825) -- Fix regression in ignoring symlinks (#23535) -- Fix ``dag-processor`` fetch metadata database config (#23575) -- Fix auto upstream dep when expanding non-templated field (#23771) -- Fix task log is not captured (#23684) -- Add ``reschedule`` to the serialized fields for the ``BaseSensorOperator`` (#23674) -- Modify db clean to also catch the ProgrammingError exception (#23699) -- Remove titles from link buttons (#23736) -- Fix grid details header text overlap (#23728) -- Ensure ``execution_timeout`` as timedelta (#23655) -- Don't run pre-migration checks for downgrade (#23634) -- Add index for event column in log table (#23625) -- Implement ``send_callback`` method for ``CeleryKubernetesExecutor`` and ``LocalKubernetesExecutor`` (#23617) -- Fix ``PythonVirtualenvOperator`` templated_fields (#23559) -- Apply specific ID collation to ``root_dag_id`` too (#23536) -- Prevent ``KubernetesJobWatcher`` getting stuck on resource too old (#23521) -- Fix scheduler crash when expanding with mapped task that returned none (#23486) -- Fix broken dagrun links when many runs start at the same time (#23462) -- Fix: Exception when parsing log #20966 (#23301) -- Handle invalid date parsing in webserver views. (#23161) -- Pools with negative open slots should not block other pools (#23143) -- Move around overflow, position and padding (#23044) -- Change approach to finding bad rows to LEFT OUTER JOIN. (#23528) -- Only count bad refs when ``moved`` table exists (#23491) -- Visually distinguish task group summary (#23488) -- Remove color change for highly nested groups (#23482) -- Optimize 2.3.0 pre-upgrade check queries (#23458) -- Add backward compatibility for ``core__sql_alchemy_conn__cmd`` (#23441) -- Fix literal cross product expansion (#23434) -- Fix broken task instance link in xcom list (#23367) -- Fix connection test button (#23345) -- fix cli ``airflow dags show`` for mapped operator (#23339) -- Hide some task instance attributes (#23338) -- Don't show grid actions if server would reject with permission denied (#23332) -- Use run_id for ``ti.mark_success_url`` (#23330) -- Fix update user auth stats (#23314) -- Use ``