diff --git a/.asf.yaml b/.asf.yaml
index 3130630e80c6b..fac7a10c87f7e 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -20,13 +20,13 @@
github:
description: "Apache Airflow - A platform to programmatically author, schedule, and monitor workflows"
homepage: https://airflow.apache.org/
- # Social media preview image is not supported by Github API/asf.yaml, need to be uploaded
- # manually in Github repository --> Settings --> click "Edit" in "Social preview"
+ # Social media preview image is not supported by GitHub API/asf.yaml, need to be uploaded
+ # manually in GitHub repository --> Settings --> click "Edit" in "Social preview"
# See also:
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/customizing-your-repositorys-social-media-preview
# social_media_preview: docs/apache-airflow/img/logos/github_repository_social_image.png
labels:
- # Note that Github only supports <=20 labels/topics per repo! Pipeline will fail if you add more.
+ # Note that GitHub only supports <=20 labels/topics per repo! Pipeline will fail if you add more.
- airflow
- apache
- apache-airflow
@@ -62,6 +62,12 @@ github:
merge: false
rebase: false
+ pull_requests:
+ # allow auto-merge
+ allow_auto_merge: false
+ # auto-delete head branches after being merged
+ del_branch_on_merge: true
+
protected_branches:
main:
required_pull_request_reviews:
@@ -128,11 +134,15 @@ github:
required_approving_review_count: 1
required_linear_history: true
required_signatures: false
- v2-10-test:
+ v2-11-stable:
+ required_pull_request_reviews:
+ required_approving_review_count: 1
+ required_linear_history: true
+ required_signatures: false
+ v3-0-stable:
required_pull_request_reviews:
required_approving_review_count: 1
required_linear_history: true
- required_conversation_resolution: true
required_signatures: false
providers-fab/v1-5:
required_pull_request_reviews:
@@ -152,6 +162,7 @@ github:
- cmarteepants
- karenbraganz
- gyli
+ - jroachgolf84
notifications:
jobs: jobs@airflow.apache.org
diff --git a/.dockerignore b/.dockerignore
index c50ed5ae24ee6..96c42ac203186 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -38,6 +38,7 @@
!providers/
!task-sdk/
!airflow-ctl/
+!go-sdk/
# Add all "test" distributions
!tests
@@ -45,6 +46,8 @@
!docker-tests
!helm-tests
!kubernetes-tests
+!task-sdk-tests
+!shared/
# Add scripts so that we can use them inside the container
!scripts
diff --git a/.editorconfig b/.editorconfig
index b3084d3f3aa07..bdaedb2630b0b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -58,3 +58,7 @@ indent_size = 2
[*.json]
indent_size = 4
+
+[*.go]
+indent_style = tab
+max_line_length = 110
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..e42a7f52d1694 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,20 @@
/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/es/ @bbovenzi # + @aoelvp94
+airflow-core/src/airflow/ui/public/i18n/locales/he/ @eladkal @shahar1 @romsharon98 # +@Dev-iL
+airflow-core/src/airflow/ui/public/i18n/locales/ko/ @jscheffl @potiuk # + @choo121600 @kgw7401 @0ne-stone
+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 +82,7 @@
/providers/edge3/ @jscheffl
/providers/fab/ @vincbeck
/providers/hashicorp/ @hussein-awala
+/providers/keycloak/ @vincbeck @bugraoz93
/providers/openlineage/ @mobuchowski
/providers/slack/ @eladkal
/providers/smtp/ @hussein-awala
@@ -77,7 +91,8 @@
# Dev tools
/.github/workflows/ @potiuk @ashb @gopidesupavan
-/dev/ @potiuk @ashb @jedcunningham @gopidesupavan
+/dev/ @potiuk @ashb @jedcunningham @gopidesupavan @amoghrajesh
+/dev/react-plugin-tools/ @pierrejeambrun @bbovenzi
/docker-tests/ @potiuk @ashb @gopidesupavan @jason810496
/kubernetes-tests/ @potiuk @ashb @gopidesupavan @jason810496
/helm-tests/ @dstandish @jedcunningham
@@ -109,4 +124,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/1-airflow_bug_report.yml b/.github/ISSUE_TEMPLATE/1-airflow_bug_report.yml
new file mode 100644
index 0000000000000..fcb1e7b5d23c6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/1-airflow_bug_report.yml
@@ -0,0 +1,144 @@
+---
+name: Airflow Bug report
+description: Problems and issues with code in Apache Airflow core
+labels: ["kind:bug", "area:core", "needs-triage"]
+body:
+ - type: markdown
+ attributes:
+ # yamllint disable rule:line-length
+ value: "
+
+ Thank you for finding the time to report the problem!
+
+ We really appreciate the community's efforts to improve Airflow.
+
+ Note, you do not need to create an issue if you have a change ready to submit!
+
+ You can open a [pull request](https://github.com/apache/airflow/pulls) immediately instead.
+ "
+ # yamllint enable rule:line-length
+ - type: dropdown
+ attributes:
+ label: Apache Airflow version
+ description: >
+ What Apache Airflow version are you using? If you do not see your version, please (ideally) test on
+ the latest release or main to see if the issue is fixed before reporting it.
+ multiple: false
+ options:
+ - "3.0.4"
+ - "2.11.0"
+ - "main (development)"
+ - "Other Airflow 2 version (please specify below)"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: If "Other Airflow 2 version" selected, which one?
+ # yamllint disable rule:line-length
+ description: >
+ On what 2.X version of Airflow are you currently experiencing the issue? Remember, you are encouraged to
+ test with the latest release or on the main branch to verify your issue still exists, especially if
+ your version is at least a minor version older than the [current stable release](https://airflow.apache.org/docs/apache-airflow/stable/installation/supported-versions.html#version-life-cycle).
+ # yamllint enable rule:line-length
+ - type: textarea
+ attributes:
+ label: What happened?
+ description: Describe what happened.
+ placeholder: >
+ Please provide the context in which the problem occurred and explain what happened
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: What you think should happen instead?
+ description: What do you think went wrong?
+ placeholder: >
+ Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy&paste
+ the fragment of logs showing the exact error messages or wrong behaviour and screenshots for
+ UI problems or YouTube link to a video of you demonstrating the problem. You can include files by
+ dragging and dropping them here.
+ - type: textarea
+ attributes:
+ label: How to reproduce
+ description: >
+ What should we do to reproduce the problem? If you are not able to provide a reproducible case,
+ please open a [discussion](https://github.com/apache/airflow/discussions) instead.
+ placeholder: >
+ Please make sure you provide a reproducible step-by-step case of how to reproduce the problem
+ as minimally and precisely as possible. Keep in mind we do not have access to your cluster or DAGs.
+ Remember that non-reproducible issues will be closed! Opening a discussion is recommended as a
+ first step.
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: Operating System
+ description: What Operating System are you using?
+ placeholder: "You can get it via `cat /etc/os-release` for example"
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Versions of Apache Airflow Providers
+ description: What Apache Airflow Providers versions are you using?
+ placeholder: You can use `pip freeze | grep apache-airflow-providers` (you can leave only relevant ones)
+ - type: dropdown
+ attributes:
+ label: Deployment
+ description: >
+ What kind of deployment do you have? If you use a Managed Service, consider first using regular
+ channels of reporting issues for the service.
+ multiple: false
+ options:
+ - "Official Apache Airflow Helm Chart"
+ - "Other 3rd-party Helm chart"
+ - "Docker-Compose"
+ - "Other Docker-based deployment"
+ - "Virtualenv installation"
+ - "Astronomer"
+ - "Google Cloud Composer"
+ - "Amazon (AWS) MWAA"
+ - "Microsoft ADF Managed Airflow"
+ - "Other"
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Deployment details
+ description: Additional description of your deployment.
+ placeholder: >
+ Enter any relevant details of your deployment. Especially version of your tools,
+ software (docker-compose, helm, k8s, etc.), any customisation and configuration you added.
+ - type: textarea
+ attributes:
+ label: Anything else?
+ description: Anything else we need to know?
+ placeholder: >
+ How often does this problem occur? (Once? Every time? Only when certain conditions are met?)
+ Any relevant logs to include? Put them here inside fenced
+ ``` ``` blocks or inside a foldable details tag if it's long:
+ x.log lots of stuff
+ - type: checkboxes
+ attributes:
+ label: Are you willing to submit PR?
+ description: >
+ This is absolutely not required, but we are happy to guide you in the contribution process
+ especially if you already have a good understanding of how to implement the fix.
+ Airflow is a community-managed project and we love to bring new contributors in.
+ Find us in #new-contributors on Slack!
+ options:
+ - label: Yes I am willing to submit a PR!
+ - type: checkboxes
+ attributes:
+ label: Code of Conduct
+ description: >
+ The Code of Conduct helps create a safe space for everyone. We require
+ that everyone agrees to it.
+ options:
+ - label: >
+ I agree to follow this project's
+ [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
+ required: true
+ - type: markdown
+ attributes:
+ value: "Thanks for completing our form!"
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/3-airflow_providers_bug_report.yml b/.github/ISSUE_TEMPLATE/3-airflow_providers_bug_report.yml
new file mode 100644
index 0000000000000..844ea18ea4d89
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/3-airflow_providers_bug_report.yml
@@ -0,0 +1,232 @@
+---
+name: Airflow Providers Bug report
+description: Problems and issues with code in Apache Airflow Providers
+labels: ["kind:bug", "area:providers", "needs-triage"]
+body:
+ - type: markdown
+ attributes:
+ # yamllint disable rule:line-length
+ value: "
+
+ Thank you for finding the time to report a problem!
+
+ We really appreciate the community's efforts to improve Airflow.
+
+ Note, you do not need to create an issue if you have a change ready to submit!
+
+ You can open a [pull request](https://github.com/apache/airflow/pulls) immediately instead.
+ "
+ # yamllint enable rule:line-length
+ - type: dropdown
+ attributes:
+ label: Apache Airflow Provider(s)
+ description: Provider(s) that the issue report is about (you can choose more than one)
+ multiple: true
+ options:
+ - airbyte
+ - alibaba
+ - amazon
+ - apache-beam
+ - apache-cassandra
+ - apache-drill
+ - apache-druid
+ - apache-flink
+ - apache-hdfs
+ - apache-hive
+ - apache-iceberg
+ - apache-impala
+ - apache-kafka
+ - apache-kylin
+ - apache-livy
+ - apache-pig
+ - apache-pinot
+ - apache-spark
+ - apache-tinkerpop
+ - apprise
+ - arangodb
+ - asana
+ - atlassian-jira
+ - celery
+ - cloudant
+ - cncf-kubernetes
+ - cohere
+ - common-compat
+ - common-io
+ - common-messaging
+ - common-sql
+ - databricks
+ - datadog
+ - dbt-cloud
+ - dingding
+ - discord
+ - docker
+ - edge3
+ - elasticsearch
+ - exasol
+ - fab
+ - facebook
+ - ftp
+ - git
+ - github
+ - google
+ - grpc
+ - hashicorp
+ - http
+ - imap
+ - influxdb
+ - jdbc
+ - jenkins
+ - keycloak
+ - microsoft-azure
+ - microsoft-mssql
+ - microsoft-psrp
+ - microsoft-winrm
+ - mongo
+ - mysql
+ - neo4j
+ - odbc
+ - openai
+ - openfaas
+ - openlineage
+ - opensearch
+ - opsgenie
+ - oracle
+ - pagerduty
+ - papermill
+ - pgvector
+ - pinecone
+ - postgres
+ - presto
+ - qdrant
+ - redis
+ - salesforce
+ - samba
+ - segment
+ - sendgrid
+ - sftp
+ - singularity
+ - slack
+ - smtp
+ - snowflake
+ - sqlite
+ - ssh
+ - standard
+ - tableau
+ - telegram
+ - teradata
+ - trino
+ - vertica
+ - weaviate
+ - yandex
+ - ydb
+ - zendesk
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Versions of Apache Airflow Providers
+ description: What Apache Airflow Providers versions are you using?
+ placeholder: You can use `pip freeze | grep apache-airflow-providers` (you can leave only relevant ones)
+ - type: input
+ attributes:
+ label: Apache Airflow version
+ description: >
+ What Apache Airflow version are you using?
+ [Only Airflow 2 is supported](https://github.com/apache/airflow#version-life-cycle) for bugs.
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: Operating System
+ description: What Operating System are you using?
+ placeholder: "You can get it via `cat /etc/os-release` for example"
+ validations:
+ required: true
+ - type: dropdown
+ attributes:
+ label: Deployment
+ description: >
+ What kind of deployment do you have? If you use a Managed Service, consider first using regular
+ channels of reporting issues for the service.
+ multiple: false
+ options:
+ - "Official Apache Airflow Helm Chart"
+ - "Other 3rd-party Helm chart"
+ - "Docker-Compose"
+ - "Other Docker-based deployment"
+ - "Virtualenv installation"
+ - "Astronomer"
+ - "Google Cloud Composer"
+ - "Amazon (AWS) MWAA"
+ - "Microsoft ADF Managed Airflow"
+ - "Other"
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Deployment details
+ description: Additional description of your deployment.
+ placeholder: >
+ Enter any relevant details of your deployment. Especially version of your tools,
+ software (docker-compose, helm, k8s, etc.), any customisation and configuration you added.
+ - type: textarea
+ attributes:
+ label: What happened
+ description: Describe what happened.
+ placeholder: >
+ Please provide the context in which the problem occurred and explain what happened
+ - type: textarea
+ attributes:
+ label: What you think should happen instead
+ description: What do you think went wrong?
+ placeholder: >
+ Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy&paste
+ the fragment of logs showing the exact error messages or wrong behaviour and screenshots for
+ UI problems or YouTube link to a video of you demonstrating the problem. You can include files by
+ dragging and dropping them here.
+ - type: textarea
+ attributes:
+ label: How to reproduce
+ description: >
+ What should we do to reproduce the problem? If you are not able to provide a reproducible case,
+ please open a [Discussion](https://github.com/apache/airflow/discussions) instead.
+ placeholder: >
+ Please make sure you provide a reproducible step-by-step case of how to reproduce the problem
+ as minimally and precisely as possible. Keep in mind we do not have access to your cluster or
+ DAGs. Remember that non-reproducible issues will be closed! Opening a discussion is
+ recommended as a first step.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Anything else
+ description: Anything else we need to know?
+ placeholder: >
+ How often does this problem occur? (Once? Every time? Only when certain conditions are met?)
+ Any relevant logs to include? Put them here inside fenced
+ ``` ``` blocks or inside a foldable details tag if it's long:
+ x.log lots of stuff
+ - type: checkboxes
+ attributes:
+ label: Are you willing to submit PR?
+ description: >
+ This is absolutely not required, but we are happy to guide you in the contribution process
+ especially if you already have a good understanding of how to implement the fix.
+ Airflow is a community-managed project and we love to bring new contributors in.
+ Find us in #new-contributors on Slack!
+ options:
+ - label: Yes I am willing to submit a PR!
+ - type: checkboxes
+ attributes:
+ label: Code of Conduct
+ description: >
+ The Code of Conduct helps create a safe space for everyone. We require
+ that everyone agrees to it.
+ options:
+ - label: >
+ I agree to follow this project's
+ [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
+ required: true
+ - type: markdown
+ attributes:
+ value: "Thanks for completing our form!"
diff --git a/.github/ISSUE_TEMPLATE/4-airflow_helmchart_bug_report.yml b/.github/ISSUE_TEMPLATE/4-airflow_helmchart_bug_report.yml
new file mode 100644
index 0000000000000..64efe5ac16a3d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/4-airflow_helmchart_bug_report.yml
@@ -0,0 +1,144 @@
+---
+name: Airflow Helm Chart Bug report
+description: Problems and issues with the Apache Airflow Official Helm Chart
+labels: ["kind:bug", "area:helm-chart", "needs-triage"]
+body:
+ - type: markdown
+ attributes:
+ # yamllint disable rule:line-length
+ value: "
+
+ Thank you for finding the time to report the problem!
+
+ We really appreciate the community's efforts to improve Airflow.
+
+ Note that this issue is only for the
+ [Official Apache Airflow Helm Chart](https://airflow.apache.org/docs/helm-chart/stable/index.html).
+ If you use another 3rd-party Chart, you should report your issue in the repo of that chart instead.
+
+ Note, you do not need to create an issue if you have a change ready to submit!
+
+ You can open a [pull request](https://github.com/apache/airflow/pulls) immediately instead.
+ "
+ # yamllint enable rule:line-length
+ - type: dropdown
+ attributes:
+ label: Official Helm Chart version
+ description: >
+ What Apache Airflow Helm Chart version are you using?
+ multiple: false
+ options:
+ - "1.18.0 (latest released)"
+ - "1.17.0"
+ - "1.16.0"
+ - "1.15.0"
+ - "1.14.0"
+ - "1.13.1"
+ - "1.13.0"
+ - "1.12.0"
+ - "1.11.0"
+ - "1.10.0"
+ - "1.9.0"
+ - "1.8.0"
+ - "1.7.0"
+ - "1.6.0"
+ - "1.5.0"
+ - "1.4.0"
+ - "1.3.0"
+ - "1.2.0"
+ - "1.1.0"
+ - "1.0.0"
+ - "main (development)"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: Apache Airflow version
+ description: >
+ What Apache Airflow version are you using?
+ [Only Airflow 2 is supported](https://github.com/apache/airflow#version-life-cycle) for bugs.
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: Kubernetes Version
+ description: Which Kubernetes Version do you use?
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Helm Chart configuration
+ description: Additional description of your Helm Chart configuration.
+ placeholder: >
+ Enter any relevant details of your Helm Chart configuration. Maybe you can
+ paste your `values.yaml` or important parts of it here? Make sure to surround the code
+ you paste with ``` ```.
+ - type: textarea
+ attributes:
+ label: Docker Image customizations
+ description: What are the specific modification you've made in your image?
+ placeholder: >
+ Did you extend or customise the official Airflow image? Did you add any packages? Maybe
+ you can share a link to your image, or copy the Dockerfile and `docker build` commands
+ you used to build the image? Make sure to surround the code you paste with ``` ```.
+ - type: textarea
+ attributes:
+ label: What happened
+ description: Describe what happened.
+ placeholder: >
+ Please provide the context in which the problem occurred and explain what happened
+ - type: textarea
+ attributes:
+ label: What you think should happen instead
+ description: What do you think went wrong?
+ placeholder: >
+ Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy&paste
+ the fragment of logs showing the exact error messages or wrong behaviour and screenshots for
+ UI problems or YouTube link to a video of you demonstrating the problem. You can include files by
+ dragging and dropping them here.
+ - type: textarea
+ attributes:
+ label: How to reproduce
+ description: >
+ What should we do to reproduce the problem? If you are not able to provide a reproducible case,
+ please open a [Discussion](https://github.com/apache/airflow/discussions) instead.
+ placeholder: >
+ Please make sure you provide a reproducible step-by-step case of how to reproduce the problem
+ as minimally and precisely as possible. Keep in mind we do not have access to your cluster or DAGs.
+ Remember that non-reproducible issues will be closed! Opening a discussion is recommended as a
+ first step.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Anything else
+ description: Anything else we need to know?
+ placeholder: >
+ How often does this problem occur? (Once? Every time? Only when certain conditions are met?)
+ Any relevant logs to include? Put them here inside fenced
+ ``` ``` blocks or inside a foldable details tag if it's long:
+ x.log lots of stuff
+ - type: checkboxes
+ attributes:
+ label: Are you willing to submit PR?
+ description: >
+ This is absolutely not required, but we are happy to guide you in the contribution process
+ especially if you already have a good understanding of how to implement the fix.
+ Airflow is a community-managed project and we love to bring new contributors in.
+ Find us in #new-contributors on Slack!
+ options:
+ - label: Yes I am willing to submit a PR!
+ - type: checkboxes
+ attributes:
+ label: Code of Conduct
+ description: >
+ The Code of Conduct helps create a safe space for everyone. We require
+ that everyone agrees to it.
+ options:
+ - label: >
+ I agree to follow this project's
+ [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
+ required: true
+ - type: markdown
+ attributes:
+ value: "Thanks for completing our form!"
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/ISSUE_TEMPLATE/airflow_bug_report.yml b/.github/ISSUE_TEMPLATE/airflow_bug_report.yml
deleted file mode 100644
index 25fb14cba10e4..0000000000000
--- a/.github/ISSUE_TEMPLATE/airflow_bug_report.yml
+++ /dev/null
@@ -1,144 +0,0 @@
----
-name: Airflow Bug report
-description: Problems and issues with code in Apache Airflow core
-labels: ["kind:bug", "area:core", "needs-triage"]
-body:
- - type: markdown
- attributes:
- # yamllint disable rule:line-length
- value: "
-
- Thank you for finding the time to report the problem!
-
- We really appreciate the community's efforts to improve Airflow.
-
- Note, you do not need to create an issue if you have a change ready to submit!
-
- You can open a [pull request](https://github.com/apache/airflow/pulls) immediately instead.
- "
- # yamllint enable rule:line-length
- - type: dropdown
- attributes:
- label: Apache Airflow version
- description: >
- What Apache Airflow version are you using? If you do not see your version, please (ideally) test on
- the latest release or main to see if the issue is fixed before reporting it.
- multiple: false
- options:
- - "2.10.5"
- - "3.0.0"
- - "main (development)"
- - "Other Airflow 2 version (please specify below)"
- validations:
- required: true
- - type: input
- attributes:
- label: If "Other Airflow 2 version" selected, which one?
- # yamllint disable rule:line-length
- description: >
- On what 2.X version of Airflow are you currently experiencing the issue? Remember, you are encouraged to
- test with the latest release or on the main branch to verify your issue still exists, especially if
- your version is at least a minor version older than the [current stable release](https://airflow.apache.org/docs/apache-airflow/stable/installation/supported-versions.html#version-life-cycle).
- # yamllint enable rule:line-length
- - type: textarea
- attributes:
- label: What happened?
- description: Describe what happened.
- placeholder: >
- Please provide the context in which the problem occurred and explain what happened
- validations:
- required: true
- - type: textarea
- attributes:
- label: What you think should happen instead?
- description: What do you think went wrong?
- placeholder: >
- Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy&paste
- the fragment of logs showing the exact error messages or wrong behaviour and screenshots for
- UI problems or YouTube link to a video of you demonstrating the problem. You can include files by
- dragging and dropping them here.
- - type: textarea
- attributes:
- label: How to reproduce
- description: >
- What should we do to reproduce the problem? If you are not able to provide a reproducible case,
- please open a [discussion](https://github.com/apache/airflow/discussions) instead.
- placeholder: >
- Please make sure you provide a reproducible step-by-step case of how to reproduce the problem
- as minimally and precisely as possible. Keep in mind we do not have access to your cluster or DAGs.
- Remember that non-reproducible issues will be closed! Opening a discussion is recommended as a
- first step.
- validations:
- required: true
- - type: input
- attributes:
- label: Operating System
- description: What Operating System are you using?
- placeholder: "You can get it via `cat /etc/os-release` for example"
- validations:
- required: true
- - type: textarea
- attributes:
- label: Versions of Apache Airflow Providers
- description: What Apache Airflow Providers versions are you using?
- placeholder: You can use `pip freeze | grep apache-airflow-providers` (you can leave only relevant ones)
- - type: dropdown
- attributes:
- label: Deployment
- description: >
- What kind of deployment do you have? If you use a Managed Service, consider first using regular
- channels of reporting issues for the service.
- multiple: false
- options:
- - "Official Apache Airflow Helm Chart"
- - "Other 3rd-party Helm chart"
- - "Docker-Compose"
- - "Other Docker-based deployment"
- - "Virtualenv installation"
- - "Astronomer"
- - "Google Cloud Composer"
- - "Amazon (AWS) MWAA"
- - "Microsoft ADF Managed Airflow"
- - "Other"
- validations:
- required: true
- - type: textarea
- attributes:
- label: Deployment details
- description: Additional description of your deployment.
- placeholder: >
- Enter any relevant details of your deployment. Especially version of your tools,
- software (docker-compose, helm, k8s, etc.), any customisation and configuration you added.
- - type: textarea
- attributes:
- label: Anything else?
- description: Anything else we need to know?
- placeholder: >
- How often does this problem occur? (Once? Every time? Only when certain conditions are met?)
- Any relevant logs to include? Put them here inside fenced
- ``` ``` blocks or inside a foldable details tag if it's long:
- x.log lots of stuff
- - type: checkboxes
- attributes:
- label: Are you willing to submit PR?
- description: >
- This is absolutely not required, but we are happy to guide you in the contribution process
- especially if you already have a good understanding of how to implement the fix.
- Airflow is a community-managed project and we love to bring new contributors in.
- Find us in #new-contributors on Slack!
- options:
- - label: Yes I am willing to submit a PR!
- - type: checkboxes
- attributes:
- label: Code of Conduct
- description: >
- The Code of Conduct helps create a safe space for everyone. We require
- that everyone agrees to it.
- options:
- - label: >
- I agree to follow this project's
- [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
- required: true
- - type: markdown
- attributes:
- value: "Thanks for completing our form!"
diff --git a/.github/ISSUE_TEMPLATE/airflow_helmchart_bug_report.yml b/.github/ISSUE_TEMPLATE/airflow_helmchart_bug_report.yml
deleted file mode 100644
index 3c8b7e68a82bf..0000000000000
--- a/.github/ISSUE_TEMPLATE/airflow_helmchart_bug_report.yml
+++ /dev/null
@@ -1,142 +0,0 @@
----
-name: Airflow Helm Chart Bug report
-description: Problems and issues with the Apache Airflow Official Helm Chart
-labels: ["kind:bug", "area:helm-chart", "needs-triage"]
-body:
- - type: markdown
- attributes:
- # yamllint disable rule:line-length
- value: "
-
- Thank you for finding the time to report the problem!
-
- We really appreciate the community's efforts to improve Airflow.
-
- Note that this issue is only for the
- [Official Apache Airflow Helm Chart](https://airflow.apache.org/docs/helm-chart/stable/index.html).
- If you use another 3rd-party Chart, you should report your issue in the repo of that chart instead.
-
- Note, you do not need to create an issue if you have a change ready to submit!
-
- You can open a [pull request](https://github.com/apache/airflow/pulls) immediately instead.
- "
- # yamllint enable rule:line-length
- - type: dropdown
- attributes:
- label: Official Helm Chart version
- description: >
- What Apache Airflow Helm Chart version are you using?
- multiple: false
- options:
- - "1.16.0 (latest released)"
- - "1.15.0"
- - "1.14.0"
- - "1.13.1"
- - "1.13.0"
- - "1.12.0"
- - "1.11.0"
- - "1.10.0"
- - "1.9.0"
- - "1.8.0"
- - "1.7.0"
- - "1.6.0"
- - "1.5.0"
- - "1.4.0"
- - "1.3.0"
- - "1.2.0"
- - "1.1.0"
- - "1.0.0"
- - "main (development)"
- validations:
- required: true
- - type: input
- attributes:
- label: Apache Airflow version
- description: >
- What Apache Airflow version are you using?
- [Only Airflow 2 is supported](https://github.com/apache/airflow#version-life-cycle) for bugs.
- validations:
- required: true
- - type: input
- attributes:
- label: Kubernetes Version
- description: Which Kubernetes Version do you use?
- validations:
- required: true
- - type: textarea
- attributes:
- label: Helm Chart configuration
- description: Additional description of your Helm Chart configuration.
- placeholder: >
- Enter any relevant details of your Helm Chart configuration. Maybe you can
- paste your `values.yaml` or important parts of it here? Make sure to surround the code
- you paste with ``` ```.
- - type: textarea
- attributes:
- label: Docker Image customizations
- description: What are the specific modification you've made in your image?
- placeholder: >
- Did you extend or customise the official Airflow image? Did you add any packages? Maybe
- you can share a link to your image, or copy the Dockerfile and `docker build` commands
- you used to build the image? Make sure to surround the code you paste with ``` ```.
- - type: textarea
- attributes:
- label: What happened
- description: Describe what happened.
- placeholder: >
- Please provide the context in which the problem occurred and explain what happened
- - type: textarea
- attributes:
- label: What you think should happen instead
- description: What do you think went wrong?
- placeholder: >
- Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy&paste
- the fragment of logs showing the exact error messages or wrong behaviour and screenshots for
- UI problems or YouTube link to a video of you demonstrating the problem. You can include files by
- dragging and dropping them here.
- - type: textarea
- attributes:
- label: How to reproduce
- description: >
- What should we do to reproduce the problem? If you are not able to provide a reproducible case,
- please open a [Discussion](https://github.com/apache/airflow/discussions) instead.
- placeholder: >
- Please make sure you provide a reproducible step-by-step case of how to reproduce the problem
- as minimally and precisely as possible. Keep in mind we do not have access to your cluster or DAGs.
- Remember that non-reproducible issues will be closed! Opening a discussion is recommended as a
- first step.
- validations:
- required: true
- - type: textarea
- attributes:
- label: Anything else
- description: Anything else we need to know?
- placeholder: >
- How often does this problem occur? (Once? Every time? Only when certain conditions are met?)
- Any relevant logs to include? Put them here inside fenced
- ``` ``` blocks or inside a foldable details tag if it's long:
- x.log lots of stuff
- - type: checkboxes
- attributes:
- label: Are you willing to submit PR?
- description: >
- This is absolutely not required, but we are happy to guide you in the contribution process
- especially if you already have a good understanding of how to implement the fix.
- Airflow is a community-managed project and we love to bring new contributors in.
- Find us in #new-contributors on Slack!
- options:
- - label: Yes I am willing to submit a PR!
- - type: checkboxes
- attributes:
- label: Code of Conduct
- description: >
- The Code of Conduct helps create a safe space for everyone. We require
- that everyone agrees to it.
- options:
- - label: >
- I agree to follow this project's
- [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
- required: true
- - type: markdown
- attributes:
- value: "Thanks for completing our form!"
diff --git a/.github/ISSUE_TEMPLATE/airflow_providers_bug_report.yml b/.github/ISSUE_TEMPLATE/airflow_providers_bug_report.yml
deleted file mode 100644
index a2461de6285e7..0000000000000
--- a/.github/ISSUE_TEMPLATE/airflow_providers_bug_report.yml
+++ /dev/null
@@ -1,230 +0,0 @@
----
-name: Airflow Providers Bug report
-description: Problems and issues with code in Apache Airflow Providers
-labels: ["kind:bug", "area:providers", "needs-triage"]
-body:
- - type: markdown
- attributes:
- # yamllint disable rule:line-length
- value: "
-
- Thank you for finding the time to report a problem!
-
- We really appreciate the community's efforts to improve Airflow.
-
- Note, you do not need to create an issue if you have a change ready to submit!
-
- You can open a [pull request](https://github.com/apache/airflow/pulls) immediately instead.
- "
- # yamllint enable rule:line-length
- - type: dropdown
- attributes:
- label: Apache Airflow Provider(s)
- description: Provider(s) that the issue report is about (you can choose more than one)
- multiple: true
- options:
- - airbyte
- - alibaba
- - amazon
- - apache-beam
- - apache-cassandra
- - apache-drill
- - apache-druid
- - apache-flink
- - apache-hdfs
- - apache-hive
- - apache-iceberg
- - apache-impala
- - apache-kafka
- - apache-kylin
- - apache-livy
- - apache-pig
- - apache-pinot
- - apache-spark
- - apprise
- - arangodb
- - asana
- - atlassian-jira
- - celery
- - cloudant
- - cncf-kubernetes
- - cohere
- - common-compat
- - common-io
- - common-messaging
- - common-sql
- - databricks
- - datadog
- - dbt-cloud
- - dingding
- - discord
- - docker
- - edge3
- - elasticsearch
- - exasol
- - fab
- - facebook
- - ftp
- - git
- - github
- - google
- - grpc
- - hashicorp
- - http
- - imap
- - influxdb
- - jdbc
- - jenkins
- - microsoft-azure
- - microsoft-mssql
- - microsoft-psrp
- - microsoft-winrm
- - mongo
- - mysql
- - neo4j
- - odbc
- - openai
- - openfaas
- - openlineage
- - opensearch
- - opsgenie
- - oracle
- - pagerduty
- - papermill
- - pgvector
- - pinecone
- - postgres
- - presto
- - qdrant
- - redis
- - salesforce
- - samba
- - segment
- - sendgrid
- - sftp
- - singularity
- - slack
- - smtp
- - snowflake
- - sqlite
- - ssh
- - standard
- - tableau
- - telegram
- - teradata
- - trino
- - vertica
- - weaviate
- - yandex
- - ydb
- - zendesk
- validations:
- required: true
- - type: textarea
- attributes:
- label: Versions of Apache Airflow Providers
- description: What Apache Airflow Providers versions are you using?
- placeholder: You can use `pip freeze | grep apache-airflow-providers` (you can leave only relevant ones)
- - type: input
- attributes:
- label: Apache Airflow version
- description: >
- What Apache Airflow version are you using?
- [Only Airflow 2 is supported](https://github.com/apache/airflow#version-life-cycle) for bugs.
- validations:
- required: true
- - type: input
- attributes:
- label: Operating System
- description: What Operating System are you using?
- placeholder: "You can get it via `cat /etc/os-release` for example"
- validations:
- required: true
- - type: dropdown
- attributes:
- label: Deployment
- description: >
- What kind of deployment do you have? If you use a Managed Service, consider first using regular
- channels of reporting issues for the service.
- multiple: false
- options:
- - "Official Apache Airflow Helm Chart"
- - "Other 3rd-party Helm chart"
- - "Docker-Compose"
- - "Other Docker-based deployment"
- - "Virtualenv installation"
- - "Astronomer"
- - "Google Cloud Composer"
- - "Amazon (AWS) MWAA"
- - "Microsoft ADF Managed Airflow"
- - "Other"
- validations:
- required: true
- - type: textarea
- attributes:
- label: Deployment details
- description: Additional description of your deployment.
- placeholder: >
- Enter any relevant details of your deployment. Especially version of your tools,
- software (docker-compose, helm, k8s, etc.), any customisation and configuration you added.
- - type: textarea
- attributes:
- label: What happened
- description: Describe what happened.
- placeholder: >
- Please provide the context in which the problem occurred and explain what happened
- - type: textarea
- attributes:
- label: What you think should happen instead
- description: What do you think went wrong?
- placeholder: >
- Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy&paste
- the fragment of logs showing the exact error messages or wrong behaviour and screenshots for
- UI problems or YouTube link to a video of you demonstrating the problem. You can include files by
- dragging and dropping them here.
- - type: textarea
- attributes:
- label: How to reproduce
- description: >
- What should we do to reproduce the problem? If you are not able to provide a reproducible case,
- please open a [Discussion](https://github.com/apache/airflow/discussions) instead.
- placeholder: >
- Please make sure you provide a reproducible step-by-step case of how to reproduce the problem
- as minimally and precisely as possible. Keep in mind we do not have access to your cluster or
- DAGs. Remember that non-reproducible issues will be closed! Opening a discussion is
- recommended as a first step.
- validations:
- required: true
- - type: textarea
- attributes:
- label: Anything else
- description: Anything else we need to know?
- placeholder: >
- How often does this problem occur? (Once? Every time? Only when certain conditions are met?)
- Any relevant logs to include? Put them here inside fenced
- ``` ``` blocks or inside a foldable details tag if it's long:
- x.log lots of stuff
- - type: checkboxes
- attributes:
- label: Are you willing to submit PR?
- description: >
- This is absolutely not required, but we are happy to guide you in the contribution process
- especially if you already have a good understanding of how to implement the fix.
- Airflow is a community-managed project and we love to bring new contributors in.
- Find us in #new-contributors on Slack!
- options:
- - label: Yes I am willing to submit a PR!
- - type: checkboxes
- attributes:
- label: Code of Conduct
- description: >
- The Code of Conduct helps create a safe space for everyone. We require
- that everyone agrees to it.
- options:
- - label: >
- I agree to follow this project's
- [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
- required: true
- - type: markdown
- attributes:
- value: "Thanks for completing our form!"
diff --git a/.github/actions/breeze/action.yml b/.github/actions/breeze/action.yml
index 39e87cd7d8b52..a7fff7dc397fe 100644
--- a/.github/actions/breeze/action.yml
+++ b/.github/actions/breeze/action.yml
@@ -21,10 +21,7 @@ description: 'Sets up Python and Breeze'
inputs:
python-version:
description: 'Python version to use'
- default: "3.9"
- use-uv:
- description: 'Whether to use uv tool'
- required: true
+ default: "3.10"
outputs:
host-python-version:
description: Python version used in host
@@ -41,6 +38,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..f2ee5868aa96c 100644
--- a/.github/actions/install-pre-commit/action.yml
+++ b/.github/actions/install-pre-commit/action.yml
@@ -21,16 +21,19 @@ description: 'Installs pre-commit and related packages'
inputs:
python-version:
description: 'Python version to use'
- default: "3.9"
+ default: "3.10"
uv-version:
description: 'uv version to use'
- default: "0.6.13" # Keep this comment to allow automatic replacement of uv version
+ default: "0.8.9" # 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
+ default: "4.3.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..93e966de8a847 100644
--- a/.github/actions/migration_tests/action.yml
+++ b/.github/actions/migration_tests/action.yml
@@ -18,18 +18,23 @@
---
name: 'Run migration tests'
description: 'Runs migration tests'
+inputs:
+ python-version:
+ description: "Python version to run the tests on"
+ required: true
runs:
using: "composite"
steps:
- 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 "${AIRFLOW_2_CMD}" --use-airflow-version 2.11.0 --answer y &&
+ breeze shell "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${DB_MANGERS}
+ ${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
@@ -37,63 +42,77 @@ runs:
airflow db migrate --to-revision heads &&
airflow db downgrade -n 2.7.0 -y &&
airflow db migrate
- if: env.BACKEND != 'sqlite'
+ # migration tests cannot be run with Python 3.13 now - currently we have no FAB and no FABDBManager -
+ # and airflow (correctly) refuses to migrate things to Airflow 2 when there is no "ab_user"
+ # table created. So migration tests for now will have to be excluded for Python 3.13 until
+ # we start working on 3.2 (with migration to 3.1) or until FAB is supported in 3.13 (FAB 5)
+ # TODO(potiuk) bring migration tests back for Python 3.13 when one of the two conditions are fulfilled
+ if: env.BACKEND != 'sqlite' && inputs.python-version != '3.13'
- name: "Bring composer down"
shell: bash
run: breeze down
env:
COMPOSE_PROJECT_NAME: "docker-compose"
+ if: inputs.python-version != '3.13'
- 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 "${AIRFLOW_2_CMD}" --use-airflow-version 2.11.0 --answer y &&
+ breeze shell "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${DB_MANGERS}
+ ${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: >-
airflow db migrate --to-revision heads &&
airflow db downgrade -n 2.7.0 -y &&
airflow db migrate
- if: env.BACKEND != 'sqlite'
+ if: env.BACKEND != 'sqlite' && inputs.python-version != '3.13'
- name: "Bring compose down again"
shell: bash
run: breeze down
env:
COMPOSE_PROJECT_NAME: "docker-compose"
+ if: inputs.python-version != '3.13'
- name: "Test ORM migration ${{env.BACKEND}}"
shell: bash
run: >
- breeze shell "airflow db reset -y &&
+ breeze shell "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${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"
+ if: inputs.python-version != '3.13'
- name: "Bring compose down again"
shell: bash
run: breeze down
env:
COMPOSE_PROJECT_NAME: "docker-compose"
+ if: inputs.python-version != '3.13'
- name: "Test offline migration ${{env.BACKEND}}"
shell: bash
run: >
- breeze shell "airflow db reset -y &&
+ breeze shell
+ "export AIRFLOW__DATABASE__EXTERNAL_DB_MANAGERS=${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"
- if: env.BACKEND != 'sqlite'
+ DB_MANAGERS: "airflow.providers.fab.auth_manager.models.db.FABDBManager"
+ if: env.BACKEND != 'sqlite' && inputs.python-version != '3.13'
- name: "Bring any containers left down"
shell: bash
run: breeze down
env:
COMPOSE_PROJECT_NAME: "docker-compose"
+ if: inputs.python-version != '3.13'
- name: "Dump logs on failure ${{env.BACKEND}}"
shell: bash
run: docker ps -q | xargs docker logs
diff --git a/.github/actions/post_tests_success/action.yml b/.github/actions/post_tests_success/action.yml
index b7b00a6fc0df3..234cde900e4d8 100644
--- a/.github/actions/post_tests_success/action.yml
+++ b/.github/actions/post_tests_success/action.yml
@@ -44,10 +44,12 @@ 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'
+ if: >
+ env.ENABLE_COVERAGE == 'true' && env.TEST_TYPES != 'Helm' && inputs.python-version != '3.12'
+ && inputs.python-version != '3.13'
with:
name: coverage-${{env.JOB_ID}}
flags: python-${{ env.PYTHON_MAJOR_MINOR_VERSION }},${{ env.BACKEND }}-${{ env.BACKEND_VERSION }}
diff --git a/.github/actions/prepare_all_ci_images/action.yml b/.github/actions/prepare_all_ci_images/action.yml
index 76c00a72a3998..7e2e8395636eb 100644
--- a/.github/actions/prepare_all_ci_images/action.yml
+++ b/.github/actions/prepare_all_ci_images/action.yml
@@ -34,14 +34,9 @@ runs:
# TODO: Currently we cannot loop through the list of python versions and have dynamic list of
# tasks. Instead we hardcode all possible python versions and they - but
# this should be implemented in stash action as list of keys to download.
- # That includes 3.8 - 3.12 as we are backporting it to v2-10-test branch
+ # That includes 3.9 - 3.12 as we are backporting it to v3-0-test branch
# This is captured in https://github.com/apache/airflow/issues/45268
- - name: "Restore CI docker image ${{ inputs.platform }}:3.8"
- uses: ./.github/actions/prepare_single_ci_image
- with:
- platform: ${{ inputs.platform }}
- python: "3.8"
- python-versions-list-as-string: ${{ inputs.python-versions-list-as-string }}
+ # So we actually need 3.9 even if 3.9 support on main is dropped!
- name: "Restore CI docker image ${{ inputs.platform }}:3.9"
uses: ./.github/actions/prepare_single_ci_image
with:
@@ -66,3 +61,9 @@ runs:
platform: ${{ inputs.platform }}
python: "3.12"
python-versions-list-as-string: ${{ inputs.python-versions-list-as-string }}
+ - name: "Restore CI docker image ${{ inputs.platform }}:3.13"
+ uses: ./.github/actions/prepare_single_ci_image
+ with:
+ platform: ${{ inputs.platform }}
+ python: "3.13"
+ python-versions-list-as-string: ${{ inputs.python-versions-list-as-string }}
diff --git a/.github/actions/prepare_breeze_and_image/action.yml b/.github/actions/prepare_breeze_and_image/action.yml
index 3254254a86516..0724167cda519 100644
--- a/.github/actions/prepare_breeze_and_image/action.yml
+++ b/.github/actions/prepare_breeze_and_image/action.yml
@@ -38,14 +38,17 @@ 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..1bfdfafef6c41 100644
--- a/.github/boring-cyborg.yml
+++ b/.github/boring-cyborg.yml
@@ -72,6 +72,9 @@ labelPRBasedOnFilePath:
provider:apache-spark:
- providers/apache/spark/**
+ provider:apache-tinkerpop:
+ - providers/apache/tinkerpop/**
+
provider:apprise:
- providers/apprise/**
@@ -108,9 +111,6 @@ labelPRBasedOnFilePath:
provider:common-sql:
- providers/common/sql/**
- provider:standard:
- - providers/standard/**
-
provider:databricks:
- providers/databricks/**
@@ -177,6 +177,9 @@ labelPRBasedOnFilePath:
provider:jenkins:
- providers/jenkins/**
+ provider:keycloak:
+ - providers/keycloak/**
+
provider:microsoft-azure:
- providers/microsoft/azure/**
@@ -216,7 +219,7 @@ labelPRBasedOnFilePath:
provider:opsgenie:
- providers/opsgenie/**
- provider:Oracle:
+ provider:oracle:
- providers/oracle/**
provider:pagerduty:
@@ -276,6 +279,9 @@ labelPRBasedOnFilePath:
provider:ssh:
- providers/ssh/**
+ provider:standard:
+ - providers/standard/**
+
provider:tableau:
- providers/tableau/**
@@ -326,6 +332,24 @@ labelPRBasedOnFilePath:
- .rat-excludes
- .readthedocs.yml
+ # 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/**/*
@@ -341,6 +365,39 @@ labelPRBasedOnFilePath:
- airflow-core/docs/ui.rst
- airflow-core/src/airflow/ui/**/*
+ area:translations:
+ - airflow-core/src/airflow/ui/public/i18n/**/*
+
+ translation:default:
+ - airflow-core/src/airflow/ui/public/i18n/locales/en/*
+
+ translation:ar:
+ - airflow-core/src/airflow/ui/public/i18n/locales/ar/*
+
+ translation:de:
+ - airflow-core/src/airflow/ui/public/i18n/locales/de/*
+
+ translation:es:
+ - airflow-core/src/airflow/ui/public/i18n/locales/es/*
+
+ translation:fr:
+ - airflow-core/src/airflow/ui/public/i18n/locales/fr/*
+
+ translation:he:
+ - airflow-core/src/airflow/ui/public/i18n/locales/he/*
+
+ translation:ko:
+ - airflow-core/src/airflow/ui/public/i18n/locales/ko/*
+
+ translation:nl:
+ - airflow-core/src/airflow/ui/public/i18n/locales/nl/*
+
+ translation:pl:
+ - airflow-core/src/airflow/ui/public/i18n/locales/pl/*
+
+ translation:zh-TW:
+ - airflow-core/src/airflow/ui/public/i18n/locales/zh-TW/*
+
area:CLI:
- airflow-core/src/airflow/cli/**/*.py
- airflow-core/tests/unit/cli/**/*.py
@@ -353,11 +410,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
@@ -423,6 +485,9 @@ labelPRBasedOnFilePath:
area:task-sdk:
- task-sdk/**/*
+ area:go-sdk:
+ - go-sdk/**/*
+
area:db-migrations:
- airflow-core/src/airflow/migrations/versions/*
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..f3982389301e6 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,66 +111,36 @@ 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
+ timeout-minutes: 17
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:
- use-uv: ${{ inputs.use-uv }}
- - name: "Login to ghcr.io"
- env:
- actor: ${{ github.actor }}
- 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 900 --platform "${PLATFORM}"
diff --git a/.github/workflows/additional-prod-image-tests.yml b/.github/workflows/additional-prod-image-tests.yml
index e656f48a5a300..0820b1deb3664 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,17 +144,47 @@ 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 }}
id: breeze
- name: "Test docker-compose quick start"
run: breeze testing docker-compose-tests
+
+ task-sdk-integration-tests:
+ timeout-minutes: 60
+ name: "Task SDK integration tests with PROD image"
+ runs-on: ${{ fromJSON(inputs.runners) }}
+ env:
+ PYTHON_MAJOR_MINOR_VERSION: "${{ inputs.default-python-version }}"
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_USERNAME: ${{ github.actor }}
+ 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@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: ${{ inputs.platform }}
+ image-type: "prod"
+ python: ${{ env.PYTHON_MAJOR_MINOR_VERSION }}
+ use-uv: ${{ inputs.use-uv }}
+ id: breeze
+ - name: "Run Task SDK integration tests"
+ run: breeze testing task-sdk-integration-tests
diff --git a/.github/workflows/airflow-distributions-tests.yml b/.github/workflows/airflow-distributions-tests.yml
index c7071c5f34d7c..98203e47b3ebc 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,41 @@ 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
+ 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..42f8178868267 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
@@ -70,8 +70,8 @@ jobs:
TARGET_BRANCH: ${{ inputs.target-branch }}
COMMIT_SHA: ${{ inputs.commit-sha }}
run: |
- git config --global user.email "name@example.com"
- git config --global user.name "Your Name"
+ git config --global user.email "bot@airflow.apache.org"
+ git config --global user.name "Your friendly bot"
set +e
{
echo 'cherry_picker_output<
pre-commit run
@@ -280,7 +280,7 @@ 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
@@ -288,10 +288,13 @@ jobs:
if: always()
env:
UPGRADE_UV: "true"
+ UPGRADE_PYTHON: "false"
+ UPGRADE_GOLANG: "true"
UPGRADE_PIP: "false"
UPGRADE_PRE_COMMIT: "false"
UPGRADE_NODE_LTS: "false"
- - name: "Run automated upgrade for pip, pre-commit and node"
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - 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
@@ -299,14 +302,17 @@ jobs:
if: always()
env:
UPGRADE_UV: "false"
+ UPGRADE_PYTHON: "true"
+ UPGRADE_GOLANG: "false"
UPGRADE_PIP: "true"
UPGRADE_PRE_COMMIT: "true"
UPGRADE_NODE_LTS: "true"
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
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,42 +325,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: "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:
- use-uv: ${{ inputs.use-uv }}
- name: "Cleanup dist files"
run: rm -fv ./dist/*
- name: Setup git for tagging
run: |
- git config --global user.email "name@example.com"
- git config --global user.name "Your Name"
+ git config --global user.email "bot@airflow.apache.org"
+ git config --global user.name "Your friendly bot"
- name: Install twine
run: pip install twine
- name: "Check Airflow create minor branch command"
- run: |
- ./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-and-airflow-releases
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: "Fetch all git tags for origin"
run: git fetch --tags >/dev/null 2>&1 || true
- name: "Test airflow core issue generation automatically"
run: |
- ./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-amd.yml b/.github/workflows/ci-amd.yml
new file mode 100644
index 0000000000000..13d45625c35dc
--- /dev/null
+++ b/.github/workflows/ci-amd.yml
@@ -0,0 +1,986 @@
+# 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 AMD
+on: # yamllint disable-line rule:truthy
+ schedule:
+ - cron: '28 1,7,13,19 * * *'
+ push:
+ branches:
+ - v[0-9]+-[0-9]+-test
+ - providers-[a-z]+-?[a-z]*/v[0-9]+-[0-9]+
+ pull_request:
+ branches:
+ - main
+ - v[0-9]+-[0-9]+-test
+ - v[0-9]+-[0-9]+-stable
+ - providers-[a-z]+-?[a-z]*/v[0-9]+-[0-9]+
+ types: [opened, reopened, synchronize, ready_for_review]
+ 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-amd-${{ 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.head-repo }}
+ source-head-ref: ${{ steps.source-run-info.outputs.head-ref }}
+ 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
+ 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) }}
+
+ 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.8.9" # Keep this comment to allow automatic replacement of uv version
+ PRE_COMMIT_VERSION: "4.3.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:
+ 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 }}"
+ 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.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 }}
+ 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.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 }}"
+ 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.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 }}
+ debug-resources: ${{ needs.build-info.outputs.debug-resources }}
+ use-uv: ${{ needs.build-info.outputs.use-uv }}
+
+ ci-image-checks:
+ name: "CI image checks"
+ needs: [build-info, build-ci-images]
+ uses: ./.github/workflows/ci-image-checks.yml
+ permissions:
+ id-token: write
+ contents: read
+ with:
+ 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 }}"
+ 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 }}
+ 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 }}
+ docs-build: ${{ needs.build-info.outputs.docs-build }}
+ needs-api-codegen: ${{ needs.build-info.outputs.needs-api-codegen }}
+ default-postgres-version: ${{ needs.build-info.outputs.default-postgres-version }}
+ run-coverage: ${{ needs.build-info.outputs.run-coverage }}
+ use-uv: ${{ needs.build-info.outputs.use-uv }}
+ source-head-repo: ${{ needs.build-info.outputs.source-head-repo }}
+ source-head-ref: ${{ needs.build-info.outputs.source-head-ref }}
+ secrets:
+ DOCS_AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_AWS_ACCESS_KEY_ID }}
+ DOCS_AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_AWS_SECRET_ACCESS_KEY }}
+
+ 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' &&
+ needs.build-info.outputs.run-tests == 'true'
+ with:
+ 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 }}"
+ 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.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 }}"
+ 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.amd-runners }}
+ platform: "linux/amd64"
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+
+ 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.amd-runners }}
+ platform: "linux/amd64"
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ if: needs.build-info.outputs.run-tests == 'true'
+
+ tests-mysql-core:
+ name: "MySQL 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.amd-runners }}
+ platform: "linux/amd64"
+ backend: "mysql"
+ test-name: "MySQL"
+ test-scope: "DB"
+ test-group: "core"
+ python-versions: ${{ needs.build-info.outputs.python-versions }}
+ backend-versions: ${{ needs.build-info.outputs.mysql-versions }}
+ excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }}
+ excludes: ${{ needs.build-info.outputs.mysql-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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ if: needs.build-info.outputs.run-tests == 'true'
+
+ tests-mysql-providers:
+ name: "MySQL 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.amd-runners }}
+ platform: "linux/amd64"
+ backend: "mysql"
+ test-name: "MySQL"
+ test-scope: "DB"
+ test-group: "providers"
+ python-versions: ${{ needs.build-info.outputs.python-versions }}
+ backend-versions: ${{ needs.build-info.outputs.mysql-versions }}
+ excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }}
+ excludes: ${{ needs.build-info.outputs.mysql-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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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.amd-runners }}
+ platform: "linux/amd64"
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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.amd-runners }}
+ platform: "linux/amd64"
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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.amd-runners }}
+ platform: "linux/amd64"
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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.amd-runners }}
+ platform: "linux/amd64"
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ if: needs.build-info.outputs.run-tests == 'true'
+
+ tests-special:
+ name: "Special tests"
+ uses: ./.github/workflows/special-tests.yml
+ needs: [build-info, build-ci-images]
+ permissions:
+ contents: read
+ packages: read
+ if: >
+ needs.build-info.outputs.run-tests == 'true' &&
+ (needs.build-info.outputs.canary-run == 'true' ||
+ needs.build-info.outputs.upgrade-to-newer-dependencies != 'false' ||
+ needs.build-info.outputs.full-tests-needed == 'true')
+ with:
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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 }}"
+ 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 }}
+ canary-run: ${{ needs.build-info.outputs.canary-run }}
+ upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }}
+ include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }}
+ skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }}
+ debug-resources: ${{ needs.build-info.outputs.debug-resources }}
+ use-uv: ${{ needs.build-info.outputs.use-uv }}
+
+ tests-integration-system:
+ name: Integration and System Tests
+ needs: [build-info, build-ci-images]
+ uses: ./.github/workflows/integration-system-tests.yml
+ permissions:
+ contents: read
+ packages: read
+ with:
+ 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-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 }}
+ 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-with-lowest-direct-resolution-core:
+ name: "Low dep tests:core"
+ needs: [build-info, build-ci-images]
+ uses: ./.github/workflows/run-unit-tests.yml
+ permissions:
+ contents: read
+ packages: read
+ if: >
+ needs.build-info.outputs.run-tests == 'true'
+ with:
+ runners: ${{ needs.build-info.outputs.amd-runners }}
+ platform: "linux/amd64"
+ test-name: "LowestDeps"
+ force-lowest-dependencies: "true"
+ test-scope: "All"
+ test-group: "core"
+ backend: "sqlite"
+ python-versions: ${{ needs.build-info.outputs.python-versions }}
+ backend-versions: "['${{ needs.build-info.outputs.default-postgres-version }}']"
+ excluded-providers-as-string: ""
+ excludes: "[]"
+ 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 }}
+ monitor-delay-time-in-seconds: 120
+ skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }}
+ use-uv: ${{ needs.build-info.outputs.use-uv }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+
+ tests-with-lowest-direct-resolution-providers:
+ name: "Low dep tests: providers"
+ needs: [build-info, build-ci-images]
+ uses: ./.github/workflows/run-unit-tests.yml
+ permissions:
+ contents: read
+ packages: read
+ if: needs.build-info.outputs.run-tests == 'true'
+ with:
+ runners: ${{ needs.build-info.outputs.amd-runners }}
+ platform: "linux/amd64"
+ test-name: "LowestDeps"
+ force-lowest-dependencies: "true"
+ test-scope: "All"
+ test-group: "providers"
+ backend: "sqlite"
+ python-versions: ${{ needs.build-info.outputs.python-versions }}
+ backend-versions: "['${{ needs.build-info.outputs.default-postgres-version }}']"
+ excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }}
+ excludes: "[]"
+ test-types-as-strings-in-json: >
+ ${{ needs.build-info.outputs.individual-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 }}
+ monitor-delay-time-in-seconds: 120
+ skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }}
+ use-uv: ${{ needs.build-info.outputs.use-uv }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+
+ 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.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 }}"
+ 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 }}
+
+ additional-prod-image-tests:
+ name: "Additional PROD image tests"
+ needs: [build-info, build-prod-images, generate-constraints]
+ uses: ./.github/workflows/additional-prod-image-tests.yml
+ with:
+ 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 }}
+ 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 }}"
+ 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'
+
+ 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.amd-runners }}
+ platform: "linux/amd64"
+ 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-task-sdk:
+ name: "Task SDK tests"
+ uses: ./.github/workflows/airflow-distributions-tests.yml
+ needs: [build-info, build-ci-images]
+ 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: "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-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
+
+ # keep this in sync with go.mod in go-sdk/
+ - name: Setup Gotestsum
+ shell: bash
+ run: |
+ go install gotest.tools/gotestsum@ddd0b05a6878e2e8257a2abe6e7df66cebc53d0e # v1.12.3
+ gotestsum --version
+
+ - name: "Cleanup dist files"
+ run: rm -fv ./dist/*
+
+ - name: Run Go tests
+ working-directory: ./go-sdk
+ run: gotestsum --format testname ./...
+
+ 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'
+ test-timeout: 20
+ 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
+ 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
+ - additional-prod-image-tests
+ - basic-tests
+ - build-info
+ - build-prod-images
+ - ci-image-checks
+ - generate-constraints
+ - providers
+ - tests-helm
+ - tests-integration-system
+ - tests-kubernetes
+ - tests-mysql-core
+ - tests-mysql-providers
+ - tests-non-db-core
+ - tests-non-db-providers
+ - 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:
+ 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 }}"
+ 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: "🚨🕒 Failure Alert: Scheduled CI (AMD) on branch *${{ github.ref_name }}* 🕒🚨\n\n*Details:* "
+ blocks:
+ - type: "section"
+ text:
+ type: "mrkdwn"
+ text: "🚨🕒 Failure Alert: Scheduled CI (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..89014e80f6742
--- /dev/null
+++ b/.github/workflows/ci-arm.yml
@@ -0,0 +1,614 @@
+# 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
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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 }}
+ default-branch: ${{ needs.build-info.outputs.default-branch }}
+ 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: "🚨🕒 Failure Alert: Scheduled CI (ARM) on branch *${{ github.ref_name }}* 🕒🚨\n\n*Details:* "
+ blocks:
+ - type: "section"
+ text:
+ type: "mrkdwn"
+ text: "🚨🕒 Failure Alert: Scheduled CI (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..e716f85c5ad79 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,15 +117,13 @@ 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:
- use-uv: ${{ inputs.use-uv }}
- name: "Restore ci-cache mount image ${{ inputs.platform }}:${{ env.PYTHON_MAJOR_MINOR_VERSION }}"
uses: apache/infrastructure-actions/stash/restore@1c35b5ccf8fba5d4c3fdf25a045ca91aa0cbc468
with:
diff --git a/.github/workflows/ci-image-checks.yml b/.github/workflows/ci-image-checks.yml
index 3e7a3bba9088a..7fd13495aa827 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
@@ -108,6 +104,14 @@ on: # yamllint disable-line rule:truthy
description: "Whether to use uv to build the image (true/false)"
required: true
type: string
+ source-head-repo:
+ description: "The source head repository to use for back-references"
+ default: "apache/airflow"
+ type: string
+ source-head-ref:
+ description: "The source head ref to use for back-references"
+ default: "main"
+ type: string
secrets:
DOCS_AWS_ACCESS_KEY_ID:
required: true
@@ -121,7 +125,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,14 +135,12 @@ 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'
- name: "Install Breeze"
uses: ./.github/actions/breeze
- with:
- use-uv: ${{ inputs.use-uv }}
id: breeze
if: inputs.canary-run == 'true'
- name: "Install pre-commit"
@@ -165,7 +167,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 +179,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 +199,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 +207,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 +222,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 +241,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 +251,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 +270,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'
@@ -310,12 +311,12 @@ jobs:
publish-docs:
timeout-minutes: 150
- name: "Publish documentation"
+ name: "Publish documentation and validate versions"
permissions:
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 +325,35 @@ 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'
+ HEAD_REPO: "${{ inputs.source-head-repo }}"
+ HEAD_REF: "${{ inputs.source-head-ref }}"
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 +361,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"
@@ -370,6 +370,11 @@ jobs:
run: breeze release-management add-back-references docker-stack
- name: "Generate back references for helm-chart"
run: breeze release-management add-back-references helm-chart
+ - name: "Validate published doc versions"
+ id: validate-docs-versions
+ run: cd ./dev/breeze && uv run ./src/airflow_breeze/utils/docs_version_validation.py
+ env:
+ AIRFLOW_SITE_DIRECTORY: /mnt/airflow-site/airflow-site
- name: Install AWS CLI v2
run: |
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
@@ -377,19 +382,28 @@ jobs:
rm /tmp/awscliv2.zip
sudo /tmp/aws/install --update
rm -rf /tmp/aws/
+ if: >
+ inputs.canary-run == 'true' &&
+ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
- 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: eu-central-1
+ if: >
+ inputs.canary-run == 'true' &&
+ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
- name: "Upload documentation to AWS S3"
run: aws s3 sync --delete ./generated/_build s3://apache-airflow-docs
+ if: >
+ inputs.canary-run == 'true' &&
+ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
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 +421,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 +435,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/ci-notification.yml b/.github/workflows/ci-notification.yml
new file mode 100644
index 0000000000000..60c2476c2dd81
--- /dev/null
+++ b/.github/workflows/ci-notification.yml
@@ -0,0 +1,82 @@
+# 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: "CI Notification"
+on: # yamllint disable-line rule:truthy
+ schedule:
+ - cron: '0 6,17 * * *'
+ 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"
+
+jobs:
+
+ workflow-status:
+ strategy:
+ matrix:
+ branch: ["v3-0-test"]
+ workflow-id: ["ci-amd.yml", "ci-arm.yml"]
+ runs-on: ubuntu-latest
+ 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
+
+ - name: "Find workflow run status"
+ id: find-workflow-run-status
+ run: |
+ python3 -m pip install uv
+ uv run ./dev/breeze/src/airflow_breeze/utils/workflow_status.py
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ workflow_branch: ${{ matrix.branch }}
+ workflow_id: ${{ matrix.workflow-id }}
+
+ - name: "Send Slack notification"
+ if: steps.find-workflow-run-status.outputs.conclusion == 'failure'
+ 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: "🚨🕒 Failure Alert: ${{ env.workflow_id }} on branch *${{ env.branch }}* 🕒🚨\n\n*Details:* <${{ env.run_url }}|View the failure log>"
+ blocks:
+ - type: "section"
+ text:
+ type: "mrkdwn"
+ text: "🚨🕒 Failure Alert: ${{ env.workflow_id }} ${{ env.branch }} 🕒🚨\n\n*Details:* <${{ env.run_url }}|View the failure log>"
+ env:
+ run_url: ${{ steps.find-workflow-run-status.outputs.run-url }}
+ branch: ${{ matrix.branch }}
+ workflow_id: ${{ matrix.workflow-id }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 406132c3a0b73..0000000000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,851 +0,0 @@
-# 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
-on: # yamllint disable-line rule:truthy
- schedule:
- - cron: '28 1,7,13,19 * * *'
- push:
- branches:
- - v[0-9]+-[0-9]+-test
- - providers-[a-z]+-?[a-z]*/v[0-9]+-[0-9]+
- pull_request:
- branches:
- - main
- - v[0-9]+-[0-9]+-test
- - v[0-9]+-[0-9]+-stable
- - providers-[a-z]+-?[a-z]*/v[0-9]+-[0-9]+
- types: [opened, reopened, synchronize, ready_for_review]
- 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-${{ 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 }}
- 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 }}
- 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 }}
- 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 }}
- 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-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 }}
- 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@v4
- with:
- persist-credentials: false
- - name: "Cleanup docker"
- run: ./scripts/ci/cleanup_docker.sh
- - name: Fetch incoming commit ${{ github.sha }} with its parent
- uses: actions/checkout@v4
- 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:
- runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }}
- 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:
- 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 }}
- 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 }}
- 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'
-
- 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
- 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 }}
- 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:
- runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }}
- python-versions-list-as-string: ${{ needs.build-info.outputs.python-versions-list-as-string }}
- # 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 }}
-
- ci-image-checks:
- name: "CI image checks"
- needs: [build-info, build-ci-images]
- uses: ./.github/workflows/ci-image-checks.yml
- permissions:
- 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 }}
- 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 }}
- 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 }}
- docs-build: ${{ needs.build-info.outputs.docs-build }}
- needs-api-codegen: ${{ needs.build-info.outputs.needs-api-codegen }}
- default-postgres-version: ${{ needs.build-info.outputs.default-postgres-version }}
- run-coverage: ${{ needs.build-info.outputs.run-coverage }}
- use-uv: ${{ needs.build-info.outputs.use-uv }}
- secrets:
- DOCS_AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_AWS_ACCESS_KEY_ID }}
- DOCS_AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_AWS_SECRET_ACCESS_KEY }}
-
- 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:
- runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
- 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:
- 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 }}
- 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:
- runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
- 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:
- runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
- 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-mysql-core:
- name: "MySQL tests: core"
- uses: ./.github/workflows/run-unit-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 }}
- backend: "mysql"
- test-name: "MySQL"
- test-scope: "DB"
- test-group: "core"
- python-versions: ${{ needs.build-info.outputs.python-versions }}
- backend-versions: ${{ needs.build-info.outputs.mysql-versions }}
- excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }}
- excludes: ${{ needs.build-info.outputs.mysql-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-mysql-providers:
- name: "MySQL tests: providers"
- uses: ./.github/workflows/run-unit-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 }}
- backend: "mysql"
- test-name: "MySQL"
- test-scope: "DB"
- test-group: "providers"
- python-versions: ${{ needs.build-info.outputs.python-versions }}
- backend-versions: ${{ needs.build-info.outputs.mysql-versions }}
- excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }}
- excludes: ${{ needs.build-info.outputs.mysql-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-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:
- runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
- 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:
- runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
- 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:
- runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
- 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:
- runs-on-as-json-default: ${{ needs.build-info.outputs.runs-on-as-json-default }}
- 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'
-
- tests-special:
- name: "Special tests"
- uses: ./.github/workflows/special-tests.yml
- needs: [build-info, build-ci-images]
- permissions:
- contents: read
- packages: read
- if: >
- needs.build-info.outputs.run-tests == 'true' &&
- (needs.build-info.outputs.canary-run == 'true' ||
- needs.build-info.outputs.upgrade-to-newer-dependencies != 'false' ||
- 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 }}
- 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 }}
- 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 }}
- canary-run: ${{ needs.build-info.outputs.canary-run }}
- upgrade-to-newer-dependencies: ${{ needs.build-info.outputs.upgrade-to-newer-dependencies }}
- include-success-outputs: ${{ needs.build-info.outputs.include-success-outputs }}
- skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }}
- debug-resources: ${{ needs.build-info.outputs.debug-resources }}
- use-uv: ${{ needs.build-info.outputs.use-uv }}
-
- tests-integration-system:
- name: Integration and System Tests
- needs: [build-info, build-ci-images]
- uses: ./.github/workflows/integration-system-tests.yml
- permissions:
- contents: read
- packages: read
- with:
- runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }}
- 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-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 }}
- 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-with-lowest-direct-resolution-core:
- name: "Low dep tests:core"
- needs: [build-info, build-ci-images]
- uses: ./.github/workflows/run-unit-tests.yml
- permissions:
- contents: read
- 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 }}
- test-name: "LowestDeps"
- force-lowest-dependencies: "true"
- test-scope: "All"
- test-group: "core"
- backend: "sqlite"
- python-versions: ${{ needs.build-info.outputs.python-versions }}
- backend-versions: "['${{ needs.build-info.outputs.default-postgres-version }}']"
- excluded-providers-as-string: ""
- excludes: "[]"
- 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 }}
- monitor-delay-time-in-seconds: 120
- skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }}
- use-uv: ${{ needs.build-info.outputs.use-uv }}
-
- tests-with-lowest-direct-resolution-providers:
- name: "Low dep tests: providers"
- needs: [build-info, build-ci-images]
- uses: ./.github/workflows/run-unit-tests.yml
- permissions:
- contents: read
- 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 }}
- test-name: "LowestDeps"
- force-lowest-dependencies: "true"
- test-scope: "All"
- test-group: "providers"
- backend: "sqlite"
- python-versions: ${{ needs.build-info.outputs.python-versions }}
- backend-versions: "['${{ needs.build-info.outputs.default-postgres-version }}']"
- excluded-providers-as-string: ${{ needs.build-info.outputs.excluded-providers-as-string }}
- excludes: "[]"
- test-types-as-strings-in-json: >
- ${{ needs.build-info.outputs.individual-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 }}
- monitor-delay-time-in-seconds: 120
- skip-providers-tests: ${{ needs.build-info.outputs.skip-providers-tests }}
- use-uv: ${{ needs.build-info.outputs.use-uv }}
-
- 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:
- runs-on-as-json-public: ${{ needs.build-info.outputs.runs-on-as-json-public }}
- build-type: "Regular"
- platform: "linux/amd64"
- 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 }}
- 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 }}
- prod-image-build: ${{ needs.build-info.outputs.prod-image-build }}
-
- additional-prod-image-tests:
- name: "Additional PROD image tests"
- 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 }}
- 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 }}
- 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'
-
- tests-kubernetes:
- name: "Kubernetes tests"
- uses: ./.github/workflows/k8s-tests.yml
- needs: [build-info, build-prod-images]
- permissions:
- contents: read
- packages: read
- with:
- 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 }}
- 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-task-sdk:
- name: "Task SDK 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: "task-sdk"
- distribution-cmd-format: "prepare-task-sdk-distributions"
- test-type: "task-sdk-tests"
- 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')
-
- 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:
- - build-info
- - generate-constraints
- - ci-image-checks
- - tests-sqlite-core
- - tests-sqlite-providers
- - 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
- 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 }}
- 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:
- - 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"]
- 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 🕒🚨\n\n*Details:* "
- blocks:
- - type: "section"
- text:
- type: "mrkdwn"
- text: "🚨🕒 Scheduled CI Failure Alert 🕒🚨\n\n*Details:* "
- # yamllint enable rule:line-length
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..4fdbc777f22c8 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,4 @@ 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 != 'pull_request'
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..46e91cf9cf1db 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,27 +85,26 @@ 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}}"
+ 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@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:
- use-uv: ${{ inputs.use-uv }}
- name: Setup git for tagging
run: |
- git config --global user.email "name@example.com"
- git config --global user.name "Your Name"
+ git config --global user.email "bot@airflow.apache.org"
+ git config --global user.name "Your friendly bot"
- name: "Remove old artifacts"
run: rm -rf dist/*
- name: "Setup k8s/helm environment"
@@ -130,13 +129,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..6a075c9d52169 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
@@ -145,28 +136,23 @@ jobs:
if: inputs.upload-package-artifact == 'true'
- name: "Install Breeze"
uses: ./.github/actions/breeze
- 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 +169,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 +184,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 +192,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,34 +202,45 @@ 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:
- use-uv: ${{ inputs.use-uv }}
- name: "Cleanup dist and context file"
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 +263,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..7d6a35cfbe52a
--- /dev/null
+++ b/.github/workflows/publish-docs-to-s3.yml
@@ -0,0 +1,369 @@
+# 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
+ airflow-base-version:
+ required: false
+ description: "Override the Airflow Base Version to use for the docs build"
+ type: string
+ airflow-version:
+ required: false
+ description: "Override the Airflow Version to use for the docs build"
+ type: string
+ apply-commits:
+ required: false
+ description: "Optionally apply commit hashes before building - to patch the docs (coma separated)"
+ type: string
+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 }}
+ AIRFLOW_BASE_VERSION: ${{ inputs.airflow-base-version || '' }}
+ AIRFLOW_VERSION: ${{ inputs.airflow-version || '' }}
+ APPLY_COMMITS: ${{ inputs.apply-commits || '' }}
+ 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}'"
+ echo "Airflow Base Version: '${AIRFLOW_BASE_VERSION}'"
+ echo "Airflow Version: '${AIRFLOW_VERSION}'"
+ echo "Apply commits: '${APPLY_COMMITS}'"
+ 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
+ if [[ ${AIRFLOW_BASE_VERSION=} == "" && ${AIRFLOW_VERSION=} == "" ]]; then
+ echo "No Airflow Versions provided, using ${REF} to determine it."
+ AIRFLOW_VERSION="${REF}"
+ set +e
+ AIRFLOW_BASE_VERSION=$(echo "${REF}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
+ set -e
+ if [[ ${AIRFLOW_BASE_VERSION=} == "" ]]; then
+ echo
+ echo "No Airflow Base Version found in ${REF}"
+ echo "You need to force airflow version and airflow base version in the workflow."
+ echo
+ exit 1
+ fi
+ fi
+ 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 }}
+ APPLY_COMMITS: ${{ inputs.apply-commits || '' }}
+ 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: "Apply patch commits if provided"
+ run: |
+ if [[ "${APPLY_COMMITS}" != "" ]]; then
+ git config --global user.email "bot@airflow.apache.org"
+ git config --global user.name "Your friendly bot"
+ echo "Applying commits ${APPLY_COMMITS} to the docs"
+ # Split APPLY_COMMITS by comma and apply each commit
+ IFS=',' read -ra COMMIT_ARRAY <<< "${APPLY_COMMITS}"
+ for APPLY_COMMIT in "${COMMIT_ARRAY[@]}"; do
+ echo "Applying commit ${APPLY_COMMIT}"
+ git fetch origin "${APPLY_COMMIT}"
+ git cherry-pick "${APPLY_COMMIT}"
+ done
+ else
+ echo "No commits provided to apply, skipping."
+ fi
+ - name: "Install Breeze from the ${{ inputs.ref }} reference"
+ uses: ./.github/actions/breeze
+ with:
+ 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' }}
+ # if the regular breeze ci-image build fails, we will try to build the image using docker buildx
+ # This is needed for the case when we are building an old image which tries to use main as
+ # a cache and it fails because the main branch has changed and does not have the same pyproject.toml
+ # Structure as the one we are trying to build.
+ run: >
+ breeze ci-image build ||
+ docker buildx build --load --builder default --progress=auto --pull
+ --build-arg AIRFLOW_EXTRAS=devel-ci --build-arg AIRFLOW_PRE_CACHED_PIP_PACKAGES=false
+ --build-arg AIRFLOW_USE_UV=true --build-arg UV_HTTP_TIMEOUT=300
+ --build-arg BUILD_PROGRESS=auto --build-arg INSTALL_MYSQL_CLIENT_TYPE=mariadb
+ --build-arg VERSION_SUFFIX_FOR_PYPI=dev0
+ -t ghcr.io/apache/airflow/main/ci/python3.9:latest --target main .
+ -f Dockerfile.ci --platform linux/amd64
+ - 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
+ - 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..eccd176096137 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,21 +108,18 @@ 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:
- use-uv: ${{ inputs.use-uv }}
- name: Login to ghcr.io
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -159,11 +148,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,26 +176,23 @@ 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:
- use-uv: ${{ inputs.use-uv }}
- 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 0afeb8e143e90..dbe38567c5cb0 100644
--- a/.github/workflows/release_dockerhub_image.yml
+++ b/.github/workflows/release_dockerhub_image.yml
@@ -21,12 +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.'
+ amdOnly:
+ type: boolean
+ description: 'Limit to amd64 images'
+ default: false
+ limitPythonVersions:
+ type: string
+ description: 'Force python versions (e.g. "3.10 3.11")'
default: ''
- required: false
permissions:
contents: read
packages: read
@@ -40,46 +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' }}
- 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",
@@ -91,132 +69,80 @@ 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
+ - 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 r00 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.rc0
+ 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 rc0 ${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 }}
+ 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 }}
- 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 }}
- 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..991ac35b13924
--- /dev/null
+++ b/.github/workflows/release_single_dockerhub_image.yml
@@ -0,0 +1,238 @@
+# 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.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
+ - 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
+ - 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..bde6c8fbb7945 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:
@@ -88,6 +92,11 @@ on: # yamllint disable-line rule:truthy
required: false
default: "false"
type: string
+ upgrade-sqlalchemy:
+ description: "Whether to upgrade SQLAlchemy or not (true/false)"
+ required: false
+ default: "false"
+ type: string
upgrade-boto:
description: "Whether to upgrade boto or not (true/false)"
required: false
@@ -116,16 +125,23 @@ on: # yamllint disable-line rule:truthy
description: "Whether to use uv"
required: true
type: string
+ default-branch:
+ description: "The default branch of the repository"
+ required: true
+ type: string
permissions:
contents: read
jobs:
tests:
- timeout-minutes: 120
+ timeout-minutes: 65
+ # yamllint disable rule:line-length
name: "\
- ${{ inputs.test-scope }}-${{ inputs.test-group }}:\
+ ${{ inputs.test-scope == 'All' && '' || inputs.test-scope == 'Quarantined' && 'Qrnt' || inputs.test-scope }}\
+ ${{ inputs.test-scope == 'All' && '' || '-' }}\
+ ${{ inputs.test-group == 'providers' && 'prov' || 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 +163,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"
@@ -154,26 +171,31 @@ jobs:
PARALLEL_TEST_TYPES: ${{ matrix.test-types.test_types }}
PYTHON_MAJOR_MINOR_VERSION: "${{ matrix.python-version }}"
UPGRADE_BOTO: "${{ inputs.upgrade-boto }}"
+ UPGRADE_SQLALCHEMY: "${{ inputs.upgrade-sqlalchemy }}"
AIRFLOW_MONITOR_DELAY_TIME_IN_SECONDS: "${{inputs.monitor-delay-time-in-seconds}}"
VERBOSE: "true"
+ DEFAULT_BRANCH: "${{ inputs.default-branch }}"
+ TOTAL_TEST_TIMEOUT: "3600" # 60 minutes in seconds
if: inputs.test-group == 'core' || inputs.skip-providers-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: "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: >
Migration Tests: ${{ matrix.python-version }}:${{ env.PARALLEL_TEST_TYPES }}
uses: ./.github/actions/migration_tests
+ with:
+ python-version: ${{ matrix.python-version }}
if: inputs.run-migration-tests == 'true' && inputs.test-group == 'core'
- name: >
${{ inputs.test-group }}:${{ inputs.test-scope }} Tests ${{ inputs.test-name }} ${{ matrix.backend-version }}
diff --git a/.github/workflows/special-tests.yml b/.github/workflows/special-tests.yml
index d47907f923f54..d410375f4054d 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"
@@ -105,6 +110,7 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
+ default-branch: ${{ inputs.default-branch }}
tests-min-sqlalchemy-providers:
name: "Min SQLAlchemy test: providers"
@@ -113,7 +119,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"
@@ -128,66 +135,77 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
+ default-branch: ${{ inputs.default-branch }}
- tests-boto-core:
- name: "Latest Boto test: core"
+ tests-latest-sqlalchemy:
+ name: "Latest SQLAlchemy 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 }}
- upgrade-boto: "true"
- test-name: "LatestBoto-Postgres"
- test-scope: "All"
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
+ upgrade-sqlalchemy: "true"
+ test-name: "LatestSQLAlchemy-Postgres"
+ test-scope: "DB"
test-group: "core"
backend: "postgres"
- python-versions: "['${{ inputs.default-python-version }}']"
+ # The python version constraint is a TEMPORARY WORKAROUND to exclude all FAB tests. It should be
+ # removed after upgrading FAB to v5 (PR #50960). The setting below should be:
+ # "['${{ inputs.default-python-version }}']"
+ python-versions: "['3.13']"
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 }}
+ default-branch: ${{ inputs.default-branch }}
+ if: contains(fromJSON(inputs.python-versions), '3.13') # Remove this line after upgrading FAB to v5
- tests-boto-providers:
- name: "Latest Boto test: providers"
+ tests-latest-sqlalchemy-providers:
+ name: "Latest SQLAlchemy 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 }}
- upgrade-boto: "true"
- test-name: "LatestBoto-Postgres"
- test-scope: "All"
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
+ upgrade-sqlalchemy: "true"
+ test-name: "LatestSQLAlchemy-Postgres"
+ test-scope: "DB"
test-group: "providers"
backend: "postgres"
- python-versions: "['${{ inputs.default-python-version }}']"
+ # The python version constraint is a TEMPORARY WORKAROUND to exclude all FAB tests. It should be
+ # removed after upgrading FAB to v5 (PR #50960). The setting below should be:
+ # "['${{ inputs.default-python-version }}']"
+ python-versions: "['3.13']"
backend-versions: "['${{ inputs.default-postgres-version }}']"
excluded-providers-as-string: ${{ inputs.excluded-providers-as-string }}
excludes: "[]"
test-types-as-strings-in-json: ${{ inputs.providers-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 }}
+ default-branch: ${{ inputs.default-branch }}
+ if: contains(fromJSON(inputs.python-versions), '3.13') # Remove this line after upgrading FAB to v5
-
- tests-pendulum-2-core:
- name: "Pendulum2 test: core"
+ tests-boto-core:
+ name: "Latest Boto 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 }}
- downgrade-pendulum: "true"
- test-name: "Pendulum2-Postgres"
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
+ upgrade-boto: "true"
+ test-name: "LatestBoto-Postgres"
test-scope: "All"
test-group: "core"
backend: "postgres"
@@ -201,17 +219,19 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
+ default-branch: ${{ inputs.default-branch }}
- tests-pendulum-2-providers:
- name: "Pendulum2 test: providers"
+ tests-boto-providers:
+ name: "Latest Boto 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 }}
- downgrade-pendulum: "true"
- test-name: "Pendulum2-Postgres"
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
+ upgrade-boto: "true"
+ test-name: "LatestBoto-Postgres"
test-scope: "All"
test-group: "providers"
backend: "postgres"
@@ -225,17 +245,20 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
+ default-branch: ${{ inputs.default-branch }}
- tests-quarantined-core:
- name: "Quarantined test: core"
+ tests-pendulum-2-core:
+ name: "Pendulum2 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: "Quarantined"
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
+ downgrade-pendulum: "true"
+ test-name: "Pendulum2-Postgres"
+ test-scope: "All"
test-group: "core"
backend: "postgres"
python-versions: "['${{ inputs.default-python-version }}']"
@@ -248,17 +271,20 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
+ default-branch: ${{ inputs.default-branch }}
- tests-quarantined-providers:
- name: "Quarantined test: providers"
+ tests-pendulum-2-providers:
+ name: "Pendulum2 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: "Quarantined"
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
+ downgrade-pendulum: "true"
+ test-name: "Pendulum2-Postgres"
+ test-scope: "All"
test-group: "providers"
backend: "postgres"
python-versions: "['${{ inputs.default-python-version }}']"
@@ -271,18 +297,19 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
+ default-branch: ${{ inputs.default-branch }}
-
- tests-arm-collection-core:
- name: "ARM Collection test: core"
+ tests-quarantined-core:
+ name: "Quarantined 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 }}
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
test-name: "Postgres"
- test-scope: "ARM collection"
+ test-scope: "Quarantined"
test-group: "core"
backend: "postgres"
python-versions: "['${{ inputs.default-python-version }}']"
@@ -295,32 +322,32 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
- if: ${{ inputs.default-branch == 'main' }}
+ default-branch: ${{ inputs.default-branch }}
- tests-arm-collection-providers:
- name: "ARM Collection test: providers"
+ tests-quarantined-providers:
+ name: "Quarantined 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 }}
+ runners: ${{ inputs.runners }}
+ platform: ${{ inputs.platform }}
test-name: "Postgres"
- test-scope: "ARM collection"
+ test-scope: "Quarantined"
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 }}
+ test-types-as-strings-in-json: ${{ inputs.providers-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' }}
-
+ default-branch: ${{ inputs.default-branch }}
tests-system-core:
name: "System test: ${{ matrix.test-group }}"
@@ -329,7 +356,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"
@@ -344,3 +372,4 @@ jobs:
debug-resources: ${{ inputs.debug-resources }}
skip-providers-tests: ${{ inputs.skip-providers-tests }}
use-uv: ${{ inputs.use-uv }}
+ default-branch: ${{ inputs.default-branch }}
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..3c187c42a0746 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: |
@@ -122,10 +126,6 @@ jobs:
breeze release-management generate-issue-content-providers
--only-available-in-dist --disable-progress
if: matrix.package-format == 'wheel'
- - name: Remove Python 3.9-incompatible provider distributions
- run: |
- echo "Removing Python 3.9-incompatible provider: cloudant"
- rm -vf dist/*cloudant*
- name: "Generate source constraints from CI image"
shell: bash
run: >
@@ -134,7 +134,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 +164,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 +176,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 +184,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 +198,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..f7358b05f30e9 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
@@ -127,6 +128,9 @@ ENV/
.idea/
*.iml
+# Cursor
+.cursor/
+
# vim
*.swp
@@ -267,3 +271,6 @@ airflow-build-dockerfile*
*.zip
_api/
+
+#while running go tests inside the go-sdk, it can generate log files for dags, ignore all logs
+go-sdk/**/*.log
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 503814fbf5c77..e41cd56e95879 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.18.0
+ golang: 1.24.0
minimum_pre_commit_version: '3.2.0'
exclude: ^.*/.*_vendor/
repos:
@@ -30,17 +31,26 @@ repos:
- id: check-hooks-apply
name: Check if all hooks apply to the repository
- repo: https://github.com/thlorenz/doctoc.git
- rev: v2.2.0
+ rev: 70fdcd39ef919754011a827bd25f23a0b141c3c3 # frozen: v2.2.0
hooks:
- 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"
- repo: https://github.com/Lucas-C/pre-commit-hooks
- rev: v1.5.5
+ # replace hash with version once PR #103 merged comes in a release
+ rev: abdd8b62891099da34162217ecb3872d22184a51
hooks:
- id: insert-license
name: Add license for all SQL files
@@ -96,7 +106,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 +135,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:
@@ -155,6 +172,18 @@ repos:
- --fuzzy-match-generates-todo
files: >
\.cfg$|\.conf$|\.ini$|\.ldif$|\.properties$|\.service$|\.tf$|Dockerfile.*$
+ - id: insert-license
+ name: Add license for all Go files
+ types: [go]
+ exclude: mocks/.*\.go$
+ args:
+ - --comment-style
+ - "|//|"
+ - --license-filepath
+ - scripts/ci/license-templates/LICENSE.txt
+ - --insert-license-after-regex
+ # We need this 'generated by' line at the top for `golines` to not format it
+ - '// Code generated by .*'
- repo: local
hooks:
- id: check-min-python-version
@@ -163,13 +192,6 @@ repos:
language: python
additional_dependencies: ['rich>=12.4.4']
require_serial: true
- - id: check-imports-in-providers
- name: Check imports in providers
- entry: ./scripts/ci/pre_commit/check_imports_in_providers.py
- language: python
- additional_dependencies: ['rich>=12.4.4', 'ruff==0.11.2']
- files: ^providers/.*/src/airflow/providers/.*\.py$
- require_serial: true
- id: update-black-version
name: Update black versions everywhere (manual)
entry: ./scripts/ci/pre_commit/update_black_version.py
@@ -184,10 +206,14 @@ repos:
entry: ./scripts/ci/pre_commit/update_installers_and_pre_commit.py
stages: ['manual']
language: python
- files: ^\.pre-commit-config\.yaml$|^scripts/ci/pre_commit/update_installers_and_pre_commit\.py$
+ files: >
+ (?x)
+ ^\.pre-commit-config\.yaml$|
+ ^\.github/\.pre-commit-config\.yaml$|
+ ^scripts/ci/pre_commit/update_installers_and_pre_commit\.py$
pass_filenames: false
require_serial: true
- additional_dependencies: ['pyyaml>=6.0.2', 'rich>=12.4.4', 'requests>=2.31.0']
+ additional_dependencies: ['pyyaml>=6.0.2', 'rich>=12.4.4', 'requests>=2.31.0',"packaging>=25"]
- id: update-chart-dependencies
name: Update chart dependencies to latest (manual)
entry: ./scripts/ci/pre_commit/update_chart_dependencies.py
@@ -210,23 +236,23 @@ 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
+ additional_dependencies: ['libcst>=1.8.1']
files: ^(providers/.*/)?airflow/.*/(sensors|operators)/.*\.py$
- repo: https://github.com/asottile/blacken-docs
- rev: 1.19.1
+ rev: 78a9dcbecf4f755f65d1f3dec556bc249d723600 # frozen: 1.19.1
hooks:
- id: blacken-docs
name: Run black on docs
args:
- --line-length=110
- - --target-version=py39
- --target-version=py310
- --target-version=py311
- --target-version=py312
alias: blacken-docs
additional_dependencies: ['black==24.10.0']
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v5.0.0
+ rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-merge-conflict
name: Check that merge conflicts are not being committed
@@ -239,20 +265,30 @@ 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.*$
- - id: fix-encoding-pragma
- name: Remove encoding header from Python files
- args:
- - --remove
+ exclude: >
+ (?x)
+ ^airflow-core/docs/img/.*\.dot$|
+ ^dev/breeze/doc/images/output.*$|
+ ^.*/openapi-gen/.*$|
+ ^airflow-ctl/docs/images/.*\.svg$
- id: pretty-format-json
name: Format JSON files
args:
@@ -263,14 +299,14 @@ repos:
files: ^chart/values\.schema\.json$|^chart/values_schema\.schema\.json$
pass_filenames: true
- repo: https://github.com/pre-commit/pygrep-hooks
- rev: v1.10.0
+ rev: 3a6eb0fadf60b3cccfd80bad9dbb6fae7e47b316 # frozen: v1.10.0
hooks:
- id: rst-backticks
name: Check if RST files use double backticks for code
- 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: 79a6b2b1392eaf49cdd32ac4f14be1a809bbd8f7 # frozen: v1.37.1
hooks:
- id: yamllint
name: Check YAML files with yamllint
@@ -281,13 +317,14 @@ 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$|
^.*reproducible_build\.yaml$|
^.*pnpm-lock\.yaml$
- repo: https://github.com/ikamensh/flynt
- rev: '1.0.1'
+ rev: '97be693bf18bc2f050667dd282d243e2824b81e2' # frozen: 1.0.6
hooks:
- id: flynt
name: Run flynt string format converter for Python
@@ -298,7 +335,7 @@ repos:
- --line-length
- '99999'
- repo: https://github.com/codespell-project/codespell
- rev: v2.4.1
+ rev: 63c8f8312b7559622c0d82815639671ae42132ac # frozen: v2.4.1
hooks:
- id: codespell
name: Run codespell
@@ -308,13 +345,22 @@ 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/public/i18n/locales/(?!en/).+/
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: 807e9d4c61778a1c3082413cf4ff50629483d8bb # frozen: v1.12.0
hooks:
- id: zizmor
name: Run zizmor to check for github workflow syntax errors
@@ -338,6 +384,20 @@ repos:
always_run: true
pass_filenames: false
additional_dependencies: ['rich>=12.4.4', 'pyyaml>=6.0.2', 'tomli>=2.0.1']
+ - id: check-shared-distributions-structure
+ name: Check shared distributions structure
+ entry: ./scripts/ci/pre_commit/check_shared_distributions_structure.py
+ language: python
+ additional_dependencies: ['rich>=12.4.4', 'tomli>=2.0.1']
+ pass_filenames: false
+ files: ^shared/.*$
+ - id: check-shared-distributions-usage
+ name: Check shared distributions usage
+ entry: ./scripts/ci/pre_commit/check_shared_distributions_usage.py
+ language: python
+ additional_dependencies: ['rich>=12.4.4', 'tomli>=2.0.1']
+ pass_filenames: false
+ files: ^shared/.*$|^.*/pyproject.toml$|^.*/_shared/.*$
- id: validate-operators-init
name: No templated field logic checks in operator __init__
description: Prevent templated field logic checks in operators' __init__
@@ -362,6 +422,13 @@ repos:
^airflow_breeze/templates/PROVIDER_README_TEMPLATE\.rst\.jinja2$
additional_dependencies: ['rich>=12.4.4','requests>=2.31.0']
require_serial: true
+ - id: check-airflow-v-imports-in-tests
+ name: Check AIRFLOW_V imports in tests
+ language: python
+ entry: ./scripts/ci/pre_commit/check_airflow_v_imports_in_tests.py
+ pass_filenames: true
+ files: ^providers/.*/tests/.+\.py$
+ additional_dependencies: ['rich>=12.4.4']
- id: ruff
name: Run 'ruff' for extremely fast Python linting
description: "Run 'ruff' for extremely fast Python linting"
@@ -370,7 +437,7 @@ repos:
types_or: [python, pyi]
args: [--fix]
require_serial: true
- additional_dependencies: ['ruff==0.11.2']
+ additional_dependencies: ['ruff==0.12.8']
exclude: ^airflow-core/tests/unit/dags/test_imports\.py$|^performance/tests/test_.*\.py$
- id: ruff-format
name: Run 'ruff format'
@@ -380,14 +447,14 @@ repos:
types_or: [python, pyi]
args: []
require_serial: true
- additional_dependencies: ['ruff==0.11.2']
+ additional_dependencies: ['ruff==0.12.8']
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$|^airflow-core/src/airflow/ui/openapi-gen/|.*/dist/.*|\.go$|/go\.(mod|sum)$
additional_dependencies: ['rich>=12.4.4']
- id: lint-dockerfile
name: Lint Dockerfile
@@ -422,7 +489,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']
@@ -456,7 +523,7 @@ repos:
entry: ./scripts/ci/pre_commit/check_common_sql_dependency.py
language: python
files: ^providers/.*/src/airflow/providers/.*/hooks/.*\.py$
- additional_dependencies: ['rich>=12.4.4', 'pyyaml>=6.0.2', 'packaging>=23.2']
+ additional_dependencies: ['rich>=12.4.4', 'pyyaml>=6.0.2', 'packaging>=25']
- id: check-extra-packages-references
name: Checks setup extra packages
description: Checks if all the extras defined in hatch_build.py are listed in extra-packages-ref.rst file
@@ -476,7 +543,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
@@ -487,6 +557,16 @@ repos:
pass_filenames: false
require_serial: true
additional_dependencies: ['rich>=12.4.4']
+ - id: prevent-deprecated-sqlalchemy-usage
+ name: Prevent deprecated sqlalchemy usage
+ entry: ./scripts/ci/pre_commit/prevent_deprecated_sqlalchemy_usage.py
+ language: python
+ additional_dependencies: ['rich>=12.4.4']
+ files: >
+ (?x)
+ ^airflow-ctl.*\.py$|
+ ^task_sdk.*\.py$
+ pass_filenames: true
- id: update-supported-versions
name: Updates supported versions in documentation
entry: ./scripts/ci/pre_commit/supported_versions.py
@@ -506,12 +586,12 @@ repos:
^providers/fab/src/airflow/providers/fab/migrations/versions/.*$|^providers/fab/src/airflow/providers/fab/migrations/versions|
^airflow-core/src/airflow/utils/db\.py$|
^providers/fab/src/airflow/providers/fab/auth_manager/models/db\.py$
- additional_dependencies: ['packaging>=23.2', 'rich>=12.4.4']
+ additional_dependencies: ['packaging>=25', 'rich>=12.4.4']
- id: update-version
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
@@ -520,6 +600,60 @@ repos:
entry: "pydevd.*settrace\\("
pass_filenames: true
files: \.py$
+ - id: check-pytest-mark-db-test-in-providers
+ language: pygrep
+ name: Check pytest.mark.db_test use in providers
+ entry: pytest\.mark\.db_test
+ pass_filenames: true
+ # Here we should add providers that are already free from the pytest.mark.db_test
+ # and we want to keep them clean and only use non-db-tests
+ files: >
+ (?x)
+ ^providers/airbyte/.*\.py$|
+ ^providers/apache/beam/.*\.py$|
+ ^providers/apache/flink/.*\.py$|
+ ^providers/apache/iceberg/.*\.py$|
+ ^providers/apache/kafka/.*\.py$|
+ ^providers/arangodb/.*\.py$|
+ ^providers/asana/.*\.py$|
+ ^providers/cloudant/.*\.py$|
+ ^providers/cohere/.*\.py$|
+ ^providers/common/compat/.*\.py$|
+ ^providers/common/messaging/.*\.py$|
+ ^providers/datadog/.*\.py$|
+ ^providers/dingding/.*\.py$|
+ ^providers/discord/.*\.py$|
+ ^providers/exasol/.*\.py$|
+ ^providers/facebook/.*\.py$|
+ ^providers/ftp/.*\.py$|
+ ^providers/grpc/.*\.py$|
+ ^providers/hashicorp/.*\.py$|
+ ^providers/imap/.*\.py$|
+ ^providers/influxdb/.*\.py$|
+ ^providers/jdbc/.*\.py$|
+ ^providers/jenkins/.*\.py$|
+ ^providers/mongo/.*\.py$|
+ ^providers/microsoft/psrp/.*\.py$|
+ ^providers/microsoft/winrm/.*\.py$|
+ ^providers/neo4j/.*\.py$|
+ ^providers/odbc/.*\.py$|
+ ^providers/openai/.*\.py$|
+ ^providers/openfaas/.*\.py$|
+ ^providers/oracle/.*\.py$|
+ ^providers/pagerduty/.*\.py$|
+ ^providers/pgvector/.*\.py$|
+ ^providers/pinecone/.*\.py$|
+ ^providers/postgres/.*\.py$|
+ ^providers/presto/.*\.py$|
+ ^providers/segment/.*\.py$|
+ ^providers/sendgrid/.*\.py$|
+ ^providers/singularity/.*\.py$|
+ ^providers/tableau/.*\.py$|
+ ^providers/teradata/.*\.py$|
+ ^providers/trino/.*\.py$|
+ ^providers/vertica/.*\.py$|
+ ^providers/yandex/.*\.py$|
+ ^providers/zendesk/.*\.py$
- id: check-links-to-example-dags-do-not-use-hardcoded-versions
name: Verify no hard-coded version in example dags
description: The links to example dags should use |version| as version specification
@@ -583,8 +717,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/public/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 +741,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 +755,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$|
@@ -633,6 +770,7 @@ repos:
^.*/conf_constants\.py$|
^.*/provider_conf\.py$|
^devel-common/src/sphinx_exts/removemarktransform\.py|
+ ^devel-common/src/tests_common/test_utils/db\.py|
^airflow-core/newsfragments/41761.significant\.rst$|
^scripts/ci/pre_commit/vendor_k8s_json_schema\.py$|
^scripts/ci/docker-compose/integration-keycloak\.yml$|
@@ -645,7 +783,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$|
@@ -707,7 +845,7 @@ repos:
files: >
(?x)
^providers/.*/src/airflow/providers/.*\.py$
- exclude: providers/standard/.*/.*\.py$
+ exclude: ^providers/standard/.*/.*\.py$
- id: check-get-lineage-collector-providers
language: python
name: Check providers import hook lineage code from compat
@@ -731,7 +869,7 @@ repos:
name: Verify usage of Airflow deprecation classes in core
entry: category=DeprecationWarning|category=PendingDeprecationWarning
files: \.py$
- exclude: ^airflow-core/src/airflow/configuration\.py$|airflow-core/tests/.*$|^providers/.*/src/airflow/providers/|^scripts/in_container/verify_providers\.py$|providers/.*/tests/.*$|^devel-common/
+ exclude: ^airflow-core/src/airflow/configuration\.py$|^airflow-core/tests/.*$|^providers/.*/src/airflow/providers/|^scripts/in_container/verify_providers\.py$|^providers/.*/tests/.*$|^devel-common/
pass_filenames: true
- id: check-provide-create-sessions-imports
language: pygrep
@@ -746,12 +884,6 @@ repos:
entry: "LoggingMixin\\(\\)"
files: \.py$
pass_filenames: true
- - id: check-daysago-import-from-utils
- language: pygrep
- name: days_ago imported from airflow.utils.dates
- entry: "(airflow\\.){0,1}utils\\.dates\\.days_ago"
- files: \.py$
- pass_filenames: true
- id: check-start-date-not-used-in-defaults
language: pygrep
name: start_date not in default_args
@@ -808,6 +940,13 @@ repos:
files: ^chart
require_serial: true
additional_dependencies: ['rich>=12.4.4','requests>=2.31.0']
+ - id: validate-chart-annotations
+ name: Validate chart annotations
+ entry: ./scripts/ci/pre_commit/validate_chart_annotations.py
+ language: python
+ pass_filenames: false
+ files: ^chart/Chart\.yaml$
+ additional_dependencies: ['pyyaml>=6.0.2', 'rich>=12.4.4']
- id: kubeconform
name: Kubeconform check on our helm chart
entry: ./scripts/ci/pre_commit/check_kubeconform.py
@@ -834,9 +973,8 @@ 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
+ entry: ./scripts/ci/pre_commit/compile_provider_assets.py fab
pass_filenames: false
additional_dependencies: ['yarn@1.22.21']
- id: compile-ui-assets-dev
@@ -886,10 +1024,15 @@ 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: >
+ (?x)
+ ^.*/pyproject\.toml$|
+ ^scripts/ci/pre_commit/update_airflow_pyproject_toml\.py$|
+ ^providers/.*/pyproject\.toml$|
+ ^providers/.*/provider\.yaml$
pass_filenames: false
require_serial: true
- additional_dependencies: ['rich>=12.4.4', 'tomli>=2.0.1', 'packaging>=23.2' ]
+ additional_dependencies: ['rich>=12.4.4', 'tomli>=2.0.1', 'packaging>=25' ]
- id: update-reproducible-source-date-epoch
name: Update Source Date Epoch for reproducible builds
language: python
@@ -970,6 +1113,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']
@@ -1084,7 +1228,7 @@ repos:
name: Check significant newsfragments are valid
# Significant newsfragments follows a special format so that we can group information easily.
language: python
- files: airflow-core/newsfragments/.*\.rst$
+ files: ^airflow-core/newsfragments/.*\.rst$
entry: ./scripts/ci/pre_commit/significant_newsfragments_checker.py
pass_filenames: false
additional_dependencies: ['docutils>=0.21.2', 'pygments>=2.19.1', 'jinja2>=3.1.5']
@@ -1207,7 +1351,71 @@ repos:
pass_filenames: true
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
+ ^airflow-core/src/airflow/migrations/versions/0028_3_0_0_drop_ab_user_id_foreign_key.py$
+ - id: go-mockery
+ name: Generate mocks for go
+ entry: -w /src/go-sdk vektra/mockery:3
+ files: ^go-sdk/
+ exclude: mocks/.*\.go$
+ types: [go]
+ pass_filenames: false
+ language: docker_image
+ - id: go-mod-tidy
+ name: Run go mod tidy
+ entry: bash -c "cd go-sdk && go mod tidy"
+ files: ^go-sdk/
+ exclude: mocks/.*\.go$
+ pass_filenames: false
+ language: system
+ - id: gofmt
+ name: Format go code
+ entry: golines --base-formatter=gofumpt --write-output --max-len=100 --chain-split-dots
+ additional_dependencies: [github.com/segmentio/golines@latest, mvdan.cc/gofumpt@v0.8.0]
+ files: ^go-sdk/
+ types: [go]
+ language: golang
+ - id: gci
+ name: Consistent import ordering for Go files
+ # Since this is invoked from the root folder, not go-sdk/, gci can't auto-detect the prefix
+ entry: gci write --skip-generated -s standard -s default -s "prefix(github.com/apache/airflow)"
+ additional_dependencies: [github.com/daixiang0/gci@v0.13.6]
+ files: ^go-sdk/
+ types: [go]
+ language: golang
+ - 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/.*\.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
@@ -1230,7 +1438,7 @@ repos:
name: Run mypy for airflow-core
language: python
entry: ./scripts/ci/pre_commit/mypy.py
- files: airflow-core/.*\.py$
+ files: ^airflow-core/.*\.py$
require_serial: true
additional_dependencies: ['rich>=12.4.4']
- id: mypy-airflow-core
@@ -1239,7 +1447,7 @@ repos:
language: python
entry: ./scripts/ci/pre_commit/mypy_folder.py airflow-core
pass_filenames: false
- files: airflow-core/.*\.py$
+ files: ^airflow-core/.*\.py$
require_serial: true
additional_dependencies: ['rich>=12.4.4']
- id: mypy-providers
@@ -1295,6 +1503,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,24 +1518,32 @@ 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', '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: ^providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/.*\.py$
+ additional_dependencies: ['rich>=12.4.4', 'openapi-spec-validator>=0.7.1']
+ - id: generate-openapi-spec-keycloak
+ name: Generate the FastAPI API spec for Keycloak
+ language: python
+ entry: ./scripts/ci/pre_commit/generate_openapi_spec_keycloak.py
+ pass_filenames: false
+ files: ^providers/keycloak/src/airflow/providers/keycloak/auth_manager/.*\.py$
+ additional_dependencies: [ 'rich>=12.4.4', 'openapi-spec-validator>=0.7.1' ]
+ - id: check-i18n-json
+ name: Check i18n files validity
+ description: Check i18n files are valid json, have no TODOs, and auto-format them
+ language: python
+ files: ^airflow-core/src/airflow/ui/public/i18n/locales/.*\.json$
+ entry: ./scripts/ci/pre_commit/check_i18n_json.py
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']
pass_filenames: false
- id: check-provider-yaml-valid
name: Validate provider.yaml files
@@ -1353,10 +1570,20 @@ repos:
- id: generate-tasksdk-datamodels
name: Generate Datamodels for TaskSDK client
language: python
- entry: uv run -p 3.12 --no-dev --no-progress --active --group codegen --project apache-airflow-task-sdk --directory task-sdk -s dev/generate_task_sdk_models.py
+ entry: uv run -p 3.12 --no-progress --active --group codegen --project apache-airflow-task-sdk --directory task-sdk -s dev/generate_task_sdk_models.py
pass_filenames: false
files: ^airflow-core/src/airflow/api_fastapi/execution_api/.*\.py$
require_serial: true
+ - id: generate-airflowctl-datamodels
+ name: Generate Datamodels for AirflowCTL
+ language: python
+ entry: >
+ bash -c '
+ uv run -p 3.12 --no-dev --no-progress --active --group codegen --project apache-airflow-ctl --directory airflow-ctl/ datamodel-codegen &&
+ uv run -p 3.12 --no-dev --no-progress --active --group codegen --project apache-airflow-ctl --directory airflow-ctl/ datamodel-codegen --input="../airflow-core/src/airflow/api_fastapi/auth/managers/simple/openapi/v2-simple-auth-manager-generated.yaml" --output="src/airflowctl/api/datamodels/auth_generated.py"'
+ pass_filenames: false
+ files: ^airflow-core/src/airflow/api_fastapi/core_api/datamodels/.*\.py$|^airflow-core/src/airflow/api_fastapi/auth/managers/simple/(datamodels|routes|services|openapi)/.*\.py$
+ require_serial: true
- id: update-er-diagram
name: Update ER diagram
language: python
@@ -1372,4 +1599,138 @@ repos:
require_serial: true
pass_filenames: false
files: ^airflow-core/src/airflow/config_templates/config\.yml$
+ - id: generate-airflowctl-help-images
+ name: Generate SVG from Airflow CTL Commands
+ entry: ./scripts/ci/pre_commit/capture_airflowctl_help.py
+ language: python
+ pass_filenames: false
+ files:
+ ^airflow-ctl/src/airflowctl/api/operations.py|airflow-ctl/src/airflowctl/ctl/commands/.*\.py$
+ additional_dependencies: ['rich>=12.4.4', 'argcomplete>=1.10']
+ - id: check-imports-in-providers
+ name: Check imports in providers
+ entry: ./scripts/ci/pre_commit/check_imports_in_providers.py
+ language: python
+ additional_dependencies: ['rich>=12.4.4', 'ruff==0.12.8']
+ files: ^providers/.*/src/airflow/providers/.*version_compat.*\.py$
+ require_serial: true
+ - id: provider-version-compat
+ name: Check for correct version_compat imports in providers
+ entry: ./scripts/ci/pre_commit/check_provider_version_compat.py
+ language: python
+ types: [python]
+ files: ^providers/.*/src/airflow/providers/.*\.py$
+ require_serial: true
+ - id: check-airflow-version-checks-in-core
+ language: pygrep
+ name: No AIRFLOW_V_* imports in airflow-core
+ entry: "import AIRFLOW_V_"
+ files: ^airflow-core/.*\.py$
+ pass_filenames: true
+ # TODO (@amoghrajesh): revisit last few in this list as they all rely on versioned secrets masker imports
+ exclude: >
+ (?x)
+ ^airflow-core/tests/integration/otel/dags/otel_test_dag_with_pause_between_tasks\.py$|
+ ^airflow-core/tests/integration/otel/dags/otel_test_dag_with_pause_in_task\.py$|
+ ^airflow-core/tests/integration/otel/test_otel\.py$|
+ ^airflow-core/tests/unit/core/test_configuration\.py$|
+ ^airflow-core/tests/unit/models/test_renderedtifields\.py$|
+ ^airflow-core/tests/unit/models/test_variable\.py$
+ - id: check-sdk-imports
+ name: Check for SDK imports in core files
+ entry: ./scripts/ci/pre_commit/check_sdk_imports.py
+ language: python
+ types: [python]
+ files: ^airflow-core/src/airflow/
+ exclude: |
+ (?x)
+ # Allow SDK imports in these legitimate locations
+ ^airflow-core/src/airflow/example_dags/.*\.py$|
+
+ # TODO: These files need to be refactored to remove SDK coupling
+ ^airflow-core/src/airflow/__init__\.py$|
+ ^airflow-core/src/airflow/models/__init__\.py$|
+ ^airflow-core/src/airflow/api/common/mark_tasks\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/datamodels/assets\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/datamodels/connections\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/services/public/connections\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/datamodels/hitl\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/datamodels/variables\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/routes/ui/structure\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/services/ui/connections\.py$|
+ ^airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid\.py$|
+ ^airflow-core/src/airflow/api_fastapi/execution_api/routes/hitl\.py$|
+ ^airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances\.py$|
+ ^airflow-core/src/airflow/api_fastapi/logging/decorators\.py$|
+ ^airflow-core/src/airflow/assets/evaluation\.py$|
+ ^airflow-core/src/airflow/assets/manager\.py$|
+ ^airflow-core/src/airflow/cli/commands/connection_command\.py$|
+ ^airflow-core/src/airflow/cli/commands/task_command\.py$|
+ ^airflow-core/src/airflow/configuration\.py$|
+ ^airflow-core/src/airflow/dag_processing/collection\.py$|
+ ^airflow-core/src/airflow/dag_processing/manager\.py$|
+ ^airflow-core/src/airflow/dag_processing/processor\.py$|
+ ^airflow-core/src/airflow/datasets/metadata\.py$|
+ ^airflow-core/src/airflow/exceptions\.py$|
+ ^airflow-core/src/airflow/executors/local_executor\.py$|
+ ^airflow-core/src/airflow/jobs/triggerer_job_runner\.py$|
+ ^airflow-core/src/airflow/lineage/hook\.py$|
+ ^airflow-core/src/airflow/listeners/spec/asset\.py$|
+ ^airflow-core/src/airflow/listeners/spec/taskinstance\.py$|
+ ^airflow-core/src/airflow/logging/remote\.py$|
+ ^airflow-core/src/airflow/models/asset\.py$|
+ ^airflow-core/src/airflow/models/baseoperator\.py$|
+ ^airflow-core/src/airflow/models/connection\.py$|
+ ^airflow-core/src/airflow/models/dag\.py$|
+ ^airflow-core/src/airflow/models/deadline\.py$|
+ ^airflow-core/src/airflow/models/dagbag\.py$|
+ ^airflow-core/src/airflow/models/dagrun\.py$|
+ ^airflow-core/src/airflow/models/mappedoperator\.py$|
+ ^airflow-core/src/airflow/models/operator\.py$|
+ ^airflow-core/src/airflow/models/param\.py$|
+ ^airflow-core/src/airflow/models/serialized_dag\.py$|
+ ^airflow-core/src/airflow/models/taskinstance\.py$|
+ ^airflow-core/src/airflow/models/taskinstancekey\.py$|
+ ^airflow-core/src/airflow/models/taskmap\.py$|
+ ^airflow-core/src/airflow/models/taskreschedule\.py$|
+ ^airflow-core/src/airflow/models/variable\.py$|
+ ^airflow-core/src/airflow/operators/subdag\.py$|
+ ^airflow-core/src/airflow/serialization/dag\.py$|
+ ^airflow-core/src/airflow/serialization/enums\.py$|
+ ^airflow-core/src/airflow/serialization/serialized_objects\.py$|
+ ^airflow-core/src/airflow/task/task_runner/bash_task_runner\.py$|
+ ^airflow-core/src/airflow/task/task_runner/standard_task_runner\.py$|
+ ^airflow-core/src/airflow/utils/dag_cycle_tester\.py$|
+ ^airflow-core/src/airflow/utils/dag_parsing_context\.py$|
+ ^airflow-core/src/airflow/utils/decorators\.py$|
+ ^airflow-core/src/airflow/utils/operator_helpers\.py$|
+ ^airflow-core/src/airflow/utils/session\.py$|
+ ^airflow-core/src/airflow/utils/task_group\.py$|
+ ^airflow-core/src/airflow/utils/trigger_rule\.py$|
+ ^airflow-core/src/airflow/utils/xcom\.py$|
+ ^airflow-core/src/airflow/providers_manager\.py$|
+ ^airflow-core/src/airflow/timetables/assets\.py$|
+ ^airflow-core/src/airflow/ti_deps/deps/prev_dagrun_dep\.py$|
+ ^airflow-core/src/airflow/utils/context\.py$|
+ ^airflow-core/src/airflow/models/taskmixin\.py$|
+ ^airflow-core/src/airflow/utils/edgemodifier\.py$|
+ ^airflow-core/src/airflow/utils/email\.py$|
+ ^airflow-core/src/airflow/ti_deps/deps/trigger_rule_dep\.py$|
+ ^airflow-core/src/airflow/utils/helpers\.py$|
+ ^airflow-core/src/airflow/ti_deps/deps/mapped_task_upstream_dep\.py$|
+ ^airflow-core/src/airflow/utils/types\.py$|
+ ^airflow-core/src/airflow/utils/dag_edges\.py$|
+ ^airflow-core/src/airflow/utils/cli\.py$|
+ ^airflow-core/src/airflow/timetables/base\.py$|
+ ^airflow-core/src/airflow/utils/dot_renderer\.py$|
+ ^airflow-core/src/airflow/models/xcom_arg\.py$|
+ ^airflow-core/src/airflow/plugins_manager\.py$|
+ ^airflow-core/src/airflow/models/xcom\.py$|
+ ^airflow-core/src/airflow/timetables/simple\.py$|
+ ^airflow-core/src/airflow/settings\.py$|
+ ^airflow-core/src/airflow/models/renderedtifields\.py$|
+ ^airflow-core/src/airflow/serialization/helpers\.py$|
+ ^airflow-core/src/airflow/models/expandinput\.py$
+ additional_dependencies: ['rich>=12.4.4']
## ONLY ADD PRE-COMMITS HERE THAT REQUIRE CI IMAGE
diff --git a/.rat-excludes b/.rat-excludes
index 75a85f9873fa1..48939c413c9b3 100644
--- a/.rat-excludes
+++ b/.rat-excludes
@@ -160,10 +160,22 @@ PKG-INFO
# Openapi files
.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
+
+# go setup files
+go.mod
+go.sum
+mocks/*
diff --git a/.readthedocs.yml b/.readthedocs.yml
index c276d282294ca..ddc2ffd3681fe 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -20,7 +20,7 @@ formats: []
sphinx:
configuration: devel-common/src/docs/rtd-deprecation/conf.py
python:
- version: "3.9"
+ version: "3.10"
install:
- method: pip
path: .
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000000000..724896d268710
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,47 @@
+
+
+# AGENTS instructions
+
+The main developer documentation lives in the `contributing-docs` directory. The following points summarise
+how to set up the environment, run checks, build docs and follow the PR workflow.
+
+## Local virtualenv and Breeze
+
+- [`07_local_virtualenv.rst`](contributing-docs/07_local_virtualenv.rst) explains how to prepare a local Python environment using `uv`. The tool creates and syncs a `.venv` and installs dependencies with commands such as `uv venv` and `uv sync`.
+- [`06_development_environments.rst`](contributing-docs/06_development_environments.rst) compares the local virtualenv with the Docker based Breeze environment. Breeze replicates CI and includes services like databases for integration tests.
+
+## Pre-commit hooks
+
+- Installation and usage of `pre-commit` are described in [`03_contributors_quick_start.rst`](contributing-docs/03_contributors_quick_start.rst). Install with `uv tool install pre-commit --with pre-commit-uv` and run checks via `pre-commit run --all-files`.
+- [`08_static_code_checks.rst`](contributing-docs/08_static_code_checks.rst) provides more details on the available hooks and prerequisites. Enable the hooks with `pre-commit install` so they run automatically on each commit.
+
+## Running tests
+
+- [`03_contributors_quick_start.rst`](contributing-docs/03_contributors_quick_start.rst) shows running tests inside Breeze. Use `pytest` inside the container for individual files or invoke `breeze testing` commands to run full suites, e.g. `breeze --backend postgres --python 3.10 testing tests --test-type All`.
+
+## Building documentation
+
+- Documentation can be built locally using `uv run --group docs build-docs` as described in [`11_documentation_building.rst`](contributing-docs/11_documentation_building.rst). Within Breeze the equivalent command is `breeze build-docs`.
+
+## Pull request guidelines
+
+- Follow the PR guidance in [`05_pull_requests.rst`](contributing-docs/05_pull_requests.rst). Always add tests, keep your branch rebased instead of merged, and adhere to the commit message recommendations from [cbea.ms/git-commit](https://cbea.ms/git-commit/).
+
+For advanced topics such as packaging providers and API versioning see [`12_provider_distributions.rst`](contributing-docs/12_provider_distributions.rst) and [`19_execution_api_versioning.rst`](contributing-docs/19_execution_api_versioning.rst).
diff --git a/Dockerfile b/Dockerfile
index 37ac245da5b20..de7624482e862 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -46,18 +46,18 @@ 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.4"
-ARG PYTHON_BASE_IMAGE="python:3.9-slim-bookworm"
+ARG PYTHON_BASE_IMAGE="python:3.10-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.2
# 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.8.9
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,22 @@ function common::get_packaging_tool() {
echo
export PACKAGING_TOOL="uv"
export PACKAGING_TOOL_CMD="uv pip"
- export EXTRA_INSTALL_FLAGS="--group=dev"
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
+ 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 --no-binary lxml --no-binary xmlsec"
+ else
+ export EXTRA_INSTALL_FLAGS="--no-binary lxml --no-binary xmlsec"
+ 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
@@ -470,7 +496,10 @@ function common::get_packaging_tool() {
echo
export PACKAGING_TOOL="pip"
export PACKAGING_TOOL_CMD="pip"
- export EXTRA_INSTALL_FLAGS="--root-user-action ignore"
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
+ export EXTRA_INSTALL_FLAGS="--root-user-action ignore --no-binary lxml,xmlsec"
export EXTRA_UNINSTALL_FLAGS="--yes"
export UPGRADE_TO_HIGHEST_RESOLUTION="--upgrade --upgrade-strategy eager"
export UPGRADE_IF_NEEDED="--upgrade --upgrade-strategy only-if-needed"
@@ -491,7 +520,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 +679,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
@@ -852,8 +881,12 @@ function install_from_sources() {
echo
echo "${COLOR_BLUE}Attempting to upgrade all packages to highest versions.${COLOR_RESET}"
echo
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
set -x
- uv sync --all-packages --resolution highest --group dev --group docs --group docs-gen --group leveldb ${extra_sync_flags}
+ uv sync --all-packages --resolution highest --group dev --group docs --group docs-gen \
+ --group leveldb ${extra_sync_flags} --no-binary-package lxml --no-binary-package xmlsec
else
# We only use uv here but Installing using constraints is not supported with `uv sync`, so we
# do not use ``uv sync`` because we are not committing and using uv.lock yet.
@@ -871,6 +904,7 @@ function install_from_sources() {
installation_command_flags=" --editable .[${AIRFLOW_EXTRAS}] \
--editable ./airflow-core --editable ./task-sdk --editable ./airflow-ctl \
--editable ./kubernetes-tests --editable ./docker-tests --editable ./helm-tests \
+ --editable ./task-sdk-tests \
--editable ./devel-common[all] --editable ./dev \
--group dev --group docs --group docs-gen --group leveldb"
local -a projects_with_devel_dependencies
@@ -910,8 +944,12 @@ function install_from_sources() {
echo
echo "${COLOR_BLUE}Falling back to no-constraints installation.${COLOR_RESET}"
echo
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
set -x
- uv sync --all-packages --group dev --group docs --group docs-gen --group leveldb ${extra_sync_flags}
+ uv sync --all-packages --group dev --group docs --group docs-gen \
+ --group leveldb ${extra_sync_flags} --no-binary-package lxml --no-binary-package xmlsec
set +x
fi
fi
@@ -1290,7 +1328,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 +1342,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 +1637,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..967e2ebfebc96 100644
--- a/Dockerfile.ci
+++ b/Dockerfile.ci
@@ -16,13 +16,13 @@
#
# WARNING: THIS DOCKERFILE IS NOT INTENDED FOR PRODUCTION USE OR DEPLOYMENT.
#
-ARG PYTHON_BASE_IMAGE="python:3.9-slim-bookworm"
+ARG BASE_IMAGE="debian:bookworm-slim"
##############################################################################################
# This is the script image where we keep all inlined bash scripts needed in other segments
-# We use PYTHON_BASE_IMAGE to make sure that the scripts are different for different platforms.
+# We use BASE_IMAGE to make sure that the scripts are different for different platforms.
##############################################################################################
-FROM ${PYTHON_BASE_IMAGE} as scripts
+FROM ${BASE_IMAGE} as scripts
##############################################################################################
# Please DO NOT modify the inlined scripts manually. The content of those files will be
@@ -31,22 +31,27 @@ FROM ${PYTHON_BASE_IMAGE} as scripts
# make the PROD Dockerfile standalone
##############################################################################################
-# The content below is automatically copied from scripts/docker/install_os_dependencies.sh
-COPY <<"EOF" /install_os_dependencies.sh
+# The content below is automatically copied from scripts/docker/install_os_dependencies_ci.sh
+COPY <<"EOF" /install_os_dependencies_ci.sh
#!/usr/bin/env bash
set -euo pipefail
if [[ "$#" != 1 ]]; then
- echo "ERROR! There should be 'runtime' or 'dev' parameter passed as argument.".
+ echo "ERROR! There should be 'runtime', 'ci' or 'dev' parameter passed as argument.".
exit 1
fi
+AIRFLOW_PYTHON_VERSION=${AIRFLOW_PYTHON_VERSION:-v3.10.10}
+GOLANG_MAJOR_MINOR_VERSION=${GOLANG_MAJOR_MINOR_VERSION:-1.24.4}
+
if [[ "${1}" == "runtime" ]]; then
INSTALLATION_TYPE="RUNTIME"
elif [[ "${1}" == "dev" ]]; then
- INSTALLATION_TYPE="dev"
+ INSTALLATION_TYPE="DEV"
+elif [[ "${1}" == "ci" ]]; then
+ INSTALLATION_TYPE="CI"
else
- echo "ERROR! Wrong argument. Passed ${1} and it should be one of 'runtime' or 'dev'.".
+ echo "ERROR! Wrong argument. Passed ${1} and it should be one of 'runtime', 'ci' or 'dev'.".
exit 1
fi
@@ -56,7 +61,10 @@ function get_dev_apt_deps() {
freetds-bin freetds-dev git graphviz graphviz-dev krb5-user ldap-utils libev4 libev-dev libffi-dev libgeos-dev \
libkrb5-dev libldap2-dev libleveldb1d libleveldb-dev libsasl2-2 libsasl2-dev libsasl2-modules \
libssl-dev libxmlsec1 libxmlsec1-dev locales lsb-release openssh-client pkgconf sasl2-bin \
-software-properties-common sqlite3 sudo unixodbc unixodbc-dev zlib1g-dev"
+software-properties-common sqlite3 sudo unixodbc unixodbc-dev zlib1g-dev \
+gdb lcov pkg-config libbz2-dev libgdbm-dev libgdbm-compat-dev liblzma-dev \
+libncurses5-dev libreadline6-dev libsqlite3-dev lzma lzma-dev tk-dev uuid-dev \
+libzstd-dev"
export DEV_APT_DEPS
fi
}
@@ -76,7 +84,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
@@ -143,14 +151,36 @@ function install_debian_runtime_dependencies() {
rm -rf /var/lib/apt/lists/* /var/log/*
}
+function install_python() {
+ git clone --branch "${AIRFLOW_PYTHON_VERSION}" --depth 1 https://github.com/python/cpython.git
+ cd cpython
+ ./configure --enable-optimizations
+ make -s -j "$(nproc)" all
+ make -s -j "$(nproc)" install
+ ln -s /usr/local/bin/python3 /usr/local/bin/python
+ ln -s /usr/local/bin/pip3 /usr/local/bin/pip
+ cd ..
+ rm -rf cpython
+}
+
+function install_golang() {
+ curl "https://dl.google.com/go/go${GOLANG_MAJOR_MINOR_VERSION}.linux-$(dpkg --print-architecture).tar.gz" -o "go${GOLANG_MAJOR_MINOR_VERSION}.linux.tar.gz"
+ rm -rf /usr/local/go && tar -C /usr/local -xzf go"${GOLANG_MAJOR_MINOR_VERSION}".linux.tar.gz
+}
+
if [[ "${INSTALLATION_TYPE}" == "RUNTIME" ]]; then
get_runtime_apt_deps
install_debian_runtime_dependencies
install_docker_cli
else
+
get_dev_apt_deps
install_debian_dev_dependencies
+ install_python
+ if [[ "${INSTALLATION_TYPE}" == "CI" ]]; then
+ install_golang
+ fi
install_docker_cli
fi
EOF
@@ -171,6 +201,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 +244,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 +289,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 +442,22 @@ function common::get_packaging_tool() {
echo
export PACKAGING_TOOL="uv"
export PACKAGING_TOOL_CMD="uv pip"
- export EXTRA_INSTALL_FLAGS="--group=dev"
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
+ 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 --no-binary lxml --no-binary xmlsec"
+ else
+ export EXTRA_INSTALL_FLAGS="--no-binary lxml --no-binary xmlsec"
+ 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
@@ -409,7 +465,10 @@ function common::get_packaging_tool() {
echo
export PACKAGING_TOOL="pip"
export PACKAGING_TOOL_CMD="pip"
- export EXTRA_INSTALL_FLAGS="--root-user-action ignore"
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
+ export EXTRA_INSTALL_FLAGS="--root-user-action ignore --no-binary lxml,xmlsec"
export EXTRA_UNINSTALL_FLAGS="--yes"
export UPGRADE_TO_HIGHEST_RESOLUTION="--upgrade --upgrade-strategy eager"
export UPGRADE_IF_NEEDED="--upgrade --upgrade-strategy only-if-needed"
@@ -430,7 +489,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}
@@ -605,8 +664,12 @@ function install_from_sources() {
echo
echo "${COLOR_BLUE}Attempting to upgrade all packages to highest versions.${COLOR_RESET}"
echo
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
set -x
- uv sync --all-packages --resolution highest --group dev --group docs --group docs-gen --group leveldb ${extra_sync_flags}
+ uv sync --all-packages --resolution highest --group dev --group docs --group docs-gen \
+ --group leveldb ${extra_sync_flags} --no-binary-package lxml --no-binary-package xmlsec
else
# We only use uv here but Installing using constraints is not supported with `uv sync`, so we
# do not use ``uv sync`` because we are not committing and using uv.lock yet.
@@ -624,6 +687,7 @@ function install_from_sources() {
installation_command_flags=" --editable .[${AIRFLOW_EXTRAS}] \
--editable ./airflow-core --editable ./task-sdk --editable ./airflow-ctl \
--editable ./kubernetes-tests --editable ./docker-tests --editable ./helm-tests \
+ --editable ./task-sdk-tests \
--editable ./devel-common[all] --editable ./dev \
--group dev --group docs --group docs-gen --group leveldb"
local -a projects_with_devel_dependencies
@@ -663,8 +727,12 @@ function install_from_sources() {
echo
echo "${COLOR_BLUE}Falling back to no-constraints installation.${COLOR_RESET}"
echo
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
set -x
- uv sync --all-packages --group dev --group docs --group docs-gen --group leveldb ${extra_sync_flags}
+ uv sync --all-packages --group dev --group docs --group docs-gen \
+ --group leveldb ${extra_sync_flags} --no-binary-package lxml --no-binary-package xmlsec
set +x
fi
fi
@@ -804,11 +872,15 @@ EOF
# The content below is automatically copied from scripts/docker/entrypoint_ci.sh
COPY <<"EOF" /entrypoint_ci.sh
#!/usr/bin/env bash
-if [[ ${VERBOSE_COMMANDS:="false"} == "true" ]]; then
- set -x
-fi
-
+function set_verbose() {
+ if [[ ${VERBOSE_COMMANDS:="false"} == "true" ]]; then
+ set -x
+ else
+ set +x
+ fi
+}
+set_verbose
. "${AIRFLOW_SOURCES:-/opt/airflow}"/scripts/in_container/_in_container_script_init.sh
LD_PRELOAD="/usr/lib/$(uname -m)-linux-gnu/libstdc++.so.6"
@@ -818,7 +890,7 @@ chmod 1777 /tmp
AIRFLOW_SOURCES=$(cd "${IN_CONTAINER_DIR}/../.." || exit 1; pwd)
-PYTHON_MAJOR_MINOR_VERSION=${PYTHON_MAJOR_MINOR_VERSION:=3.9}
+PYTHON_MAJOR_MINOR_VERSION=${PYTHON_MAJOR_MINOR_VERSION:=3.10}
export AIRFLOW_HOME=${AIRFLOW_HOME:=${HOME}}
@@ -826,6 +898,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() {
@@ -899,7 +975,7 @@ function environment_initialization() {
CI=${CI:="false"}
# Added to have run-tests on path
- export PATH=${PATH}:${AIRFLOW_SOURCES}
+ export PATH=${PATH}:${AIRFLOW_SOURCES}:/usr/local/go/bin/
mkdir -pv "${AIRFLOW_HOME}/logs/"
@@ -908,6 +984,11 @@ function environment_initialization() {
set +e
+ # shellcheck source=scripts/in_container/configure_environment.sh
+ . "${IN_CONTAINER_DIR}/configure_environment.sh"
+ # shellcheck source=scripts/in_container/run_init_script.sh
+ . "${IN_CONTAINER_DIR}/run_init_script.sh"
+
"${IN_CONTAINER_DIR}/check_environment.sh"
ENVIRONMENT_EXIT_CODE=$?
set -e
@@ -917,6 +998,7 @@ function environment_initialization() {
echo
exit ${ENVIRONMENT_EXIT_CODE}
fi
+
mkdir -p /usr/lib/google-cloud-sdk/bin
touch /usr/lib/google-cloud-sdk/bin/gcloud
ln -s -f /usr/bin/gcloud /usr/lib/google-cloud-sdk/bin/gcloud
@@ -942,14 +1024,14 @@ function environment_initialization() {
ssh-keyscan -H localhost >> ~/.ssh/known_hosts 2>/dev/null
fi
- # shellcheck source=scripts/in_container/configure_environment.sh
- . "${IN_CONTAINER_DIR}/configure_environment.sh"
-
- # shellcheck source=scripts/in_container/run_init_script.sh
- . "${IN_CONTAINER_DIR}/run_init_script.sh"
-
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
@@ -963,13 +1045,13 @@ function handle_mount_sources() {
echo
echo "${COLOR_BLUE}Mounted sources are removed, cleaning up mounted dist-info files${COLOR_RESET}"
echo
- rm -rf /usr/local/lib/python${PYTHON_MAJOR_MINOR_VERSION}/site-packages/apache_airflow*.dist-info/
+ rm -rf /usr/local/lib/python"${PYTHON_MAJOR_MINOR_VERSION}"/site-packages/apache_airflow*.dist-info/
fi
}
function determine_airflow_to_use() {
USE_AIRFLOW_VERSION="${USE_AIRFLOW_VERSION:=""}"
- if [[ ${USE_AIRFLOW_VERSION} == "" && ${USE_DISTRIBUTIONS_FROM_DIST=} != "true" ]]; then
+ if [[ "${USE_AIRFLOW_VERSION}" == "" && "${USE_DISTRIBUTIONS_FROM_DIST}" != "true" ]]; then
export PYTHONPATH=${AIRFLOW_SOURCES}
echo
echo "${COLOR_BLUE}Using airflow version from current sources${COLOR_RESET}"
@@ -985,7 +1067,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,8 +1079,10 @@ 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 \
- --constraint https://raw.githubusercontent.com/apache/airflow/constraints-main/constraints-${PYTHON_MAJOR_MINOR_VERSION}.txt
+ # 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
${PACKAGING_TOOL_CMD} uninstall ${EXTRA_UNINSTALL_FLAGS} typing || true
@@ -1025,12 +1109,22 @@ function check_boto_upgrade() {
echo
echo "${COLOR_BLUE}Upgrading boto3, botocore to latest version to run Amazon tests with them${COLOR_RESET}"
echo
- set -x
# 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
- set +x
+ ${PACKAGING_TOOL_CMD} install ${EXTRA_INSTALL_FLAGS} --upgrade "boto3<1.38.3" "botocore<1.38.3"
+}
+
+function check_upgrade_sqlalchemy() {
+ # The python version constraint is a TEMPORARY WORKAROUND to exclude all FAB tests. Is should be removed once we
+ # upgrade FAB to v5 (PR #50960).
+ if [[ "${UPGRADE_SQLALCHEMY}" != "true" || ${PYTHON_MAJOR_MINOR_VERSION} != "3.13" ]]; then
+ return
+ fi
+ echo
+ echo "${COLOR_BLUE}Upgrading sqlalchemy to the latest version to run tests with it${COLOR_RESET}"
+ echo
+ uv sync --all-packages --no-install-package apache-airflow-providers-fab --resolution highest
}
function check_downgrade_sqlalchemy() {
@@ -1038,12 +1132,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 +1160,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
@@ -1098,13 +1185,19 @@ function check_force_lowest_dependencies() {
exit 0
fi
cd "${AIRFLOW_SOURCES}/providers/${provider_id/.//}" || exit 1
- uv sync --resolution lowest-direct
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
+ uv sync --resolution lowest-direct --no-binary-package lxml --no-binary-package xmlsec --all-extras
else
echo
echo "${COLOR_BLUE}Forcing dependencies to lowest versions for Airflow.${COLOR_RESET}"
echo
cd "${AIRFLOW_SOURCES}/airflow-core"
- uv sync --resolution lowest-direct
+ # --no-binary is needed in order to avoid libxml and xmlsec using different version of libxml2
+ # (binary lxml embeds its own libxml2, while xmlsec uses system one).
+ # See https://bugs.launchpad.net/lxml/+bug/2110068
+ uv sync --resolution lowest-direct --no-binary-package lxml --no-binary-package xmlsec --all-extras
fi
}
@@ -1115,23 +1208,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
@@ -1164,10 +1266,12 @@ handle_mount_sources
determine_airflow_to_use
environment_initialization
check_boto_upgrade
+check_upgrade_sqlalchemy
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 "${@}"
@@ -1186,23 +1290,23 @@ COPY <<"EOF" /entrypoint_exec.sh
exec /bin/bash "${@}"
EOF
-FROM ${PYTHON_BASE_IMAGE} as main
+FROM ${BASE_IMAGE} as main
# Nolog bash flag is currently ignored - but you can replace it with other flags (for example
# xtrace - to show commands executed)
SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-o", "nounset", "-o", "nolog", "-c"]
-ARG PYTHON_BASE_IMAGE
+ARG BASE_IMAGE
ARG AIRFLOW_IMAGE_REPOSITORY="https://github.com/apache/airflow"
# By increasing this number we can do force build of all dependencies.
# 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} \
+ENV BASE_IMAGE=${BASE_IMAGE} \
DEBIAN_FRONTEND=noninteractive LANGUAGE=C.UTF-8 LANG=C.UTF-8 LC_ALL=C.UTF-8 \
LC_CTYPE=C.UTF-8 LC_MESSAGES=C.UTF-8 \
DEPENDENCIES_EPOCH_NUMBER=${DEPENDENCIES_EPOCH_NUMBER} \
@@ -1213,7 +1317,7 @@ ENV PYTHON_BASE_IMAGE=${PYTHON_BASE_IMAGE} \
UV_CACHE_DIR=/root/.cache/uv
-RUN echo "Base image version: ${PYTHON_BASE_IMAGE}"
+RUN echo "Base image version: ${BASE_IMAGE}"
ARG DEV_APT_COMMAND=""
ARG ADDITIONAL_DEV_APT_COMMAND=""
@@ -1228,8 +1332,13 @@ ENV DEV_APT_COMMAND=${DEV_APT_COMMAND} \
ADDITIONAL_DEV_APT_DEPS=${ADDITIONAL_DEV_APT_DEPS} \
ADDITIONAL_DEV_APT_COMMAND=${ADDITIONAL_DEV_APT_COMMAND}
-COPY --from=scripts install_os_dependencies.sh /scripts/docker/
-RUN bash /scripts/docker/install_os_dependencies.sh dev
+ARG AIRFLOW_PYTHON_VERSION=v3.10.18
+ENV AIRFLOW_PYTHON_VERSION=$AIRFLOW_PYTHON_VERSION
+ENV GOLANG_MAJOR_MINOR_VERSION=1.24.6
+
+COPY --from=scripts install_os_dependencies_ci.sh /scripts/docker/
+
+RUN bash /scripts/docker/install_os_dependencies_ci.sh ci
COPY --from=scripts common.sh /scripts/docker/
@@ -1353,12 +1462,12 @@ 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.2
# 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.8.9
# TODO(potiuk): automate with upgrade check (possibly)
-ARG AIRFLOW_PRE_COMMIT_VERSION="4.2.0"
+ARG AIRFLOW_PRE_COMMIT_VERSION="4.3.0"
ARG AIRFLOW_PRE_COMMIT_UV_VERSION="4.1.4"
ENV AIRFLOW_PIP_VERSION=${AIRFLOW_PIP_VERSION} \
@@ -1368,8 +1477,8 @@ ENV AIRFLOW_PIP_VERSION=${AIRFLOW_PIP_VERSION} \
UV_LINK_MODE=copy \
AIRFLOW_PRE_COMMIT_VERSION=${AIRFLOW_PRE_COMMIT_VERSION}
-# The PATH is needed for PIPX to find the tools installed
-ENV PATH="/root/.local/bin:${PATH}"
+# The PATH is needed for PIPX to find the tools installed and cargo to build the wheels
+ENV PATH="/root/.local/bin:/root/.cargo/bin:${PATH}"
# Useful for creating a cache id based on the underlying architecture, preventing the use of cached python packages from
# an incorrect architecture.
@@ -1391,10 +1500,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/INSTALL b/INSTALL
index b7a6a51602623..59e596ca79350 100644
--- a/INSTALL
+++ b/INSTALL
@@ -229,15 +229,15 @@ to avoid "works-for-me" syndrome, where you use different versions of dependenci
that are used in main CI tests and by other contributors.
There are different constraint files for different Python versions. For example, this command will install
-all basic devel requirements and requirements of Google provider as last successfully tested for Python 3.9:
+all basic devel requirements and requirements of Google provider as last successfully tested for Python 3.10:
uv pip install -e ".[devel,google]"" \
- --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-main/constraints-3.9.txt"
+ --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-main/constraints-3.10.txt"
Using the 'constraints-no-providers' constraint files, you can upgrade Airflow without paying attention to the provider's dependencies. This allows you to keep installed provider dependencies and install the latest supported ones using pure Airflow core.
uv pip install -e ".[devel]" \
- --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-main/constraints-no-providers-3.9.txt"
+ --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-main/constraints-no-providers-3.10.txt"
Note that you can also use `pip install` if you do not use `uv`.
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/INTHEWILD.md b/INTHEWILD.md
index 1fcd785c612b7..964dfdcc3cb87 100644
--- a/INTHEWILD.md
+++ b/INTHEWILD.md
@@ -31,6 +31,7 @@ Currently, **officially** using Airflow:
1. [90 Seconds](https://90seconds.tv/) [[@aaronmak](https://github.com/aaronmak)]
1. [99](https://99taxis.com) [[@fbenevides](https://github.com/fbenevides), [@gustavoamigo](https://github.com/gustavoamigo) & [@mmmaia](https://github.com/mmmaia)]
1. [Accenture](https://www.accenture.com/au-en) [[@nijanthanvijayakumar](https://github.com/nijanthanvijayakumar)]
+1. [Acciona Energia France](https://solutions.acciona-energia.fr/) [[@MohamedEqinov](https://github.com/MohamedEqinov)]
1. [AdBOOST](https://www.adboost.sk) [[AdBOOST](https://github.com/AdBOOST)]
1. [Adobe](https://www.adobe.com/) [[@mishikaSingh](https://github.com/mishikaSingh), [@ramandumcs](https://github.com/ramandumcs), [@vardancse](https://github.com/vardancse)]
1. [Adyen](https://www.adyen.com/) [[@jorricks](https://github.com/jorricks), [@MaicoTimmerman](https://github.com/MaicoTimmerman)]
@@ -62,7 +63,7 @@ Currently, **officially** using Airflow:
1. [Asana](https://asana.com/) [[@chang](https://github.com/chang), [@dima-asana](https://github.com/dima-asana), [@jdavidheiser](https://github.com/jdavidheiser), [@ricardoandresrojas](https://github.com/ricardoandresrojas)]
1. [Astronomer](https://www.astronomer.io) [[@schnie](https://github.com/schnie), [@ashb](https://github.com/ashb), [@kaxil](https://github.com/kaxil), [@dimberman](https://github.com/dimberman), [@andriisoldatenko](https://github.com/andriisoldatenko), [@ryw](https://github.com/ryw), [@ryanahamilton](https://github.com/ryanahamilton), [@jhtimmins](https://github.com/jhtimmins), [@vikramkoka](https://github.com/vikramkoka), [@jedcunningham](https://github.com/jedcunningham), [@BasPH](https://github.com/basph), [@ephraimbuddy](https://github.com/ephraimbuddy), [@feluelle](https://github.com/feluelle)]
1. [Audiomack](https://audiomack.com) [[@billcrook](https://github.com/billcrook)]
-1. [Auth0](https://auth0.com) [[@scottypate](https://github.com/scottypate)], [[@dm03514](https://github.com/dm03514)], [[@karangale](https://github.com/karangale)]
+1. [Auth0](https://auth0.com) [[@scottypate](https://github.com/scottypate), [@dm03514](https://github.com/dm03514), [@karangale](https://github.com/karangale)]
1. [Autodesk](https://autodesk.com)
1. [Automattic](https://automattic.com/) [[@anandnalya](https://github.com/anandnalya), [@bperson](https://github.com/bperson), [@khrol](https://github.com/Khrol), [@xyu](https://github.com/xyu)]
1. [Avesta Technologies](https://avestatechnologies.com) [[@TheRum](https://github.com/TheRum)]
@@ -90,10 +91,10 @@ Currently, **officially** using Airflow:
1. [BlaBlaCar](https://www.blablacar.com) [[@puckel](https://github.com/puckel) & [@wmorin](https://github.com/wmorin)]
1. [Blacklane](https://www.blacklane.com) [[@serkef](https://github.com/serkef)]
1. [Bloc](https://www.bloc.io) [[@dpaola2](https://github.com/dpaola2)]
-1. [Bloomberg](https://www.techatbloomberg.com) [[@skandala23] (https://github.com/skandala23) & [@vfeldsher](https://https://github.com/vfeldsher)]
+1. [Bloomberg](https://www.techatbloomberg.com) [[@skandala23](https://github.com/skandala23) & [@vfeldsher](https://https://github.com/vfeldsher)]
1. [Bloomreach](https://www.bloomreach.com/) [[@neelborooah](https://github.com/neelborooah) & [@debodirno](https://github.com/debodirno) & [@ayushmnnit](https://github.com/ayushmnnit)]
1. [Blue Yonder](http://www.blue-yonder.com) [[@blue-yonder](https://github.com/blue-yonder)]
-1. [Blue3 Investimentos](https://blue3investimentos.com.br) [[@ericcoleta] (https://github.com/ericcoleta) & [@plutaniano](https://github.com/plutaniano)]
+1. [Blue3 Investimentos](https://blue3investimentos.com.br) [[@ericcoleta](https://github.com/ericcoleta) & [@plutaniano](https://github.com/plutaniano)]
1. [BlueApron](https://www.blueapron.com) [[@jasonjho](https://github.com/jasonjho) & [@matthewdavidhauser](https://github.com/matthewdavidhauser)]
1. [Bluecore](https://www.bluecore.com) [[@JLDLaughlin](https://github.com/JLDLaughlin)]
1. [Bluekiri](https://bluekiri.com) [[@Bluekiri](https://github.com/bluekiri)]
@@ -118,7 +119,7 @@ Currently, **officially** using Airflow:
1. [Capital One](https://www.capitalone.com) [[@anoopengineer](https://github.com/anoopengineer)]
1. [Carbonite](https://www.carbonite.com) [[@ajbosco](https://github.com/ajbosco)]
1. [CarLabs](https://www.carlabs.ai/) [[@sganz](https://github.com/sganz) & [@odannyc](https://github.com/odannyc)]
-1. [Carpe Data](https://www.carpe.io/) [[@manugarri](https://github.com/manugarri)]]
+1. [Carpe Data](https://www.carpe.io/) [[@manugarri](https://github.com/manugarri)]
1. [CAVA](https://www.cava.com) [[@minh5](https://github.com/minh5) & [@patchus](https://github.com/patchus)]
1. [Celect](http://www.celect.com) [[@superdosh](https://github.com/superdosh) & [@chadcelect](https://github.com/chadcelect)]
1. [Censys](https://censys.io) [[@zakird](https://github.com/zakird), [@dadrian](https://github.com/dadrian), & [@andrewsardone](https://github.com/andrewsardone)]
@@ -127,6 +128,8 @@ Currently, **officially** using Airflow:
1. [Checkr](https://checkr.com) [[@tongboh](https://github.com/tongboh)]
1. [Children's Hospital of Philadelphia Division of Genomic Diagnostics](http://www.chop.edu/centers-programs/division-genomic-diagnostics) [[@genomics-geek](https://github.com/genomics-geek/)]
1. [Cinimex DataLab](http://cinimex.ru) [[@kdubovikov](https://github.com/kdubovikov)]
+1. [City of Ann Arbor](https://www.a2gov.org) [[@a2gov](https://github.com/a2gov), [@sfirke](https://github.com/sfirke)]
+1. [City of Detroit](https://detroitmi.gov) [[@CityOfDetroit](https://github.com/CityOfDetroit), [@jmcbroom](https://github.com/jmcbroom)]
1. [City of San Diego](http://sandiego.gov) [[@MrMaksimize](https://github.com/mrmaksimize), [@andrell81](https://github.com/andrell81) & [@arnaudvedy](https://github.com/arnaudvedy)]
1. [City of Toronto](https://www.toronto.ca/) [[@CityofToronto](https://github.com/CityofToronto), [@radumas](https://github.com/radumas)]
1. [ciValue](https://civalue.com/) [[@chencivalue](https://github.com/chencivalue), [@YoavGaudin](https://github.com/YoavGaudin), [@saleem-boshnak](https://github.com/saleem-boshnak)]
@@ -137,12 +140,13 @@ Currently, **officially** using Airflow:
1. [Classmethod, Inc.](https://classmethod.jp/) [[@shoito](https://github.com/shoito)]
1. [Cleartax](https://cleartax.in/) [[@anks](https://github.com/anks) & [@codebuff](https://github.com/codebuff)]
1. [Clicksign](https://clicksign.com/) [[@mbbernstein](https://github.com/mbbernstein) & [@jorgeac12](https://github.com/jorgeac12) & [@franklin390](https://github.com/franklin390)]
-1. [Cloudera](https://www.cloudera.com/) [[@phraniiac](https://github.com/phraniiac) & [@VivekPemawat](https://github.com/VivekPemawat) & [@amoghrajesh](https://github.com/amoghrajesh) & [@vedantlodha](https://github.com/vedantlodha) & [@shubhamraj-git](https://github.com/shubhamraj-git) & [@Samit-Maharjan](https://github.com/Samit-Maharjan)] & [@anukrati1507](https://github.com/anukrati1507)
+1. [Cloudera](https://www.cloudera.com/) [[@phraniiac](https://github.com/phraniiac) & [@VivekPemawat](https://github.com/VivekPemawat) & [@amoghrajesh](https://github.com/amoghrajesh) & [@vedantlodha](https://github.com/vedantlodha) & [@shubhamraj-git](https://github.com/shubhamraj-git) & [@Samit-Maharjan](https://github.com/Samit-Maharjan) & [@anukrati1507](https://github.com/anukrati1507)]
1. [Clover Health](https://www.cloverhealth.com) [[@ryansiu1995](https://github.com/ryansiu1995)]
1. [Coinbase](https://www.coinbase.com) [[@mingshi-wang](https://github.com/mingshi-wang)]
1. [Coinone](https://www.coinonecorp.com) [[@jx2lee](https://github.com/jx2lee)]
1. [Colgate-Palmolive](https://www.colgatepalmolive.com/) [[@fhoda](https://github.com/fhoda)]
1. [Collectivehealth Inc.](https://www.collectivehealth.com) [[@retornam](https://github.com/retornam)]
+1. [Comcast](https://corporate.comcast.com/) [[@lucid-x](https://github.com/lucid-x)]
1. [Compass](https://www.compass.com) [[@wdhorton](https://github.com/wdhorton)]
1. [ConnectWise](https://www.connectwise.com/) [[@jacobeturpin](https://github.com/jacobeturpin)]
1. [ContaAzul](https://www.contaazul.com) [[@bern4rdelli](https://github.com/bern4rdelli), [@renanleme](https://github.com/renanleme) & [@sabino](https://github.com/sabino)]
@@ -173,26 +177,27 @@ Currently, **officially** using Airflow:
1. [dataroots](https://dataroots.io/) [[@datarootsio]](https://github.com/datarootsio)
1. [DataSprints](https://datasprints.com/) [[@lopesdiego12](https://github.com/lopesdiego12) & [@rafaelsantanaep](https://github.com/rafaelsantanaep)]
1. [Datatonic](https://datatonic.com/) [[@teamdatatonic](https://github.com/teamdatatonic)]
-1. [Datavant](https://datavant.com)/) [@althati(https://github.com/althati)]
+1. [Datavant](https://datavant.com) [[@althati](https://github.com/althati)]
1. [Datumo](https://datumo.io) [[@michalmisiewicz](https://github.com/michalmisiewicz)]
1. [Dcard](https://www.dcard.tw/) [[@damon09273](https://github.com/damon09273) & [@bruce3557](https://github.com/bruce3557) & [@kevin1kevin1k](http://github.com/kevin1kevin1k)]
1. [Delft University of Technology](https://www.tudelft.nl/en/) [[@saveriogzz](https://github.com/saveriogzz)]
1. [Dentsu Inc.](http://www.dentsu.com/) [[@bryan831](https://github.com/bryan831) & [@loozhengyuan](https://github.com/loozhengyuan)]
-1. [Deseret Digital Media](http://deseretdigital.com/) [[@formigone](https://github.com/formigone)
+1. [Deseret Digital Media](http://deseretdigital.com/) [[@formigone](https://github.com/formigone)]
1. [DevITJobs.com](https://devitjobs.com/)
1. [DFDS](https://www.dfds.com/) [[@timonviola](https://github.com/timonviola)]
1. [Digital First Media](http://www.digitalfirstmedia.com/) [[@duffn](https://github.com/duffn) & [@mschmo](https://github.com/mschmo) & [@seanmuth](https://github.com/seanmuth)]
1. [Disney](https://www.disney.com/) [[@coolbeans201](https://github.com/coolbeans201)]
+1. [Docaposte](https://www.docaposte.com) [[@albundy83](https://github.com/albundy83)]
1. [Docsity](https://www.docsity.com/)
1. [Doctrine](https://www.doctrine.fr/)[[@anteverse](https://github.com/anteverse)]
-1. [DoorDash](https://www.doordash.com/)
+1. [DoorDash](https://www.doordash.com/) [[@chiragtodarka](https://github.com/chiragtodarka)]
1. [Dotmodus](http://dotmodus.com) [[@dannylee12](https://github.com/dannylee12)]
1. [Drivy](https://www.drivy.com) [[@AntoineAugusti](https://github.com/AntoineAugusti)]
1. [Dropbox](https://www.dropbox.com) [[@AlexeySanko](https://github.com/AlexeySanko)]
1. [Dunnhumby](https://www.dunnhumby.com)
1. [Dunzo](https://www.dunzo.com)[[@masterlittle](https://github.com/masterlittle)]
1. [Dynata](https://www.dynata.com) [[@neil3handari](https://github.com/neil3handari)]
-1. [e-MPS](https://e-mps.co.uk/)[[@IanDanielM](https://github.com/IanDanielM)
+1. [e-MPS](https://e-mps.co.uk/)[[@IanDanielM](https://github.com/IanDanielM)]
1. [Easy Taxi](http://www.easytaxi.com/) [[@caique-lima](https://github.com/caique-lima) & [@diraol](https://github.com/diraol)]
1. [EBANX](https://www.ebanx.com/) [[@diogodilcl](https://github.com/diogodilcl) & [@estevammr](https://github.com/estevammr) & [@filipe-banzoli](https://github.com/filipe-banzoli) & [@lara-clink](https://github.com/lara-clink) & [@Lucasdsvenancio](https://github.com/Lucasdsvenancio) & [@mariotaddeucci](https://github.com/mariotaddeucci) & [@nadiapetramont](https://github.com/nadiapetramont) & [@nathangngencissk](https://github.com/nathangngencissk) & [@patrickjuan](https://github.com/patrickjuan) & [@raafaadg](https://github.com/raafaadg) & [@samebanx](https://github.com/samebanx) & [@thiagoschonrock](https://github.com/thiagoschonrock) & [@whrocha](https://github.com/whrocha)]
1. [Elai Data](https://www.elaidata.com/) [[@lgov](https://github.com/lgov)]
@@ -208,7 +213,8 @@ Currently, **officially** using Airflow:
1. [Estrategia Educacional](https://github.com/estrategiahq) [[@jonasrla](https://github.com/jonasrla)]
1. [Etsy](https://www.etsy.com) [[@mchalek](https://github.com/mchalek)]
1. [EUIGS - Admiral Group](https://www.linkedin.com/company/euiitglobalservices) [[@emilioego](https://github.com/emilioego)]
-1. [Europcar](https://www.europcar.com/en-us) [[@Conformist101](https://github.com/Conformist101) & [@davidpr91](https://github.com/davidpr91) & [@jcarbonell](https://github.com/jcarbonell)& [@marc-rf](https://github.com/marc-rf)& [@VictorGeaGarcia](https://github.com/VictorGeaGarcia)]
+1. [Europace](https://www.europace.de/)
+1. [Europcar](https://www.europcar.com/en-us) [[@Conformist101](https://github.com/Conformist101) & [@davidpr91](https://github.com/davidpr91) & [@jcarbonell](https://github.com/jcarbonell) & [@marc-rf](https://github.com/marc-rf) & [@VictorGeaGarcia](https://github.com/VictorGeaGarcia)]
1. [Everis](https://www.everis.com) [[@diegobenedicto](https://github.com/diegobenedicto)]
1. [Everlane](https://everlane.com) [[@NickBenthem](https://github.com/NickBenthem)]
1. [evo.company](https://evo.company/) [[@orhideous](https://github.com/orhideous)]
@@ -289,7 +295,7 @@ Currently, **officially** using Airflow:
1. [Inoopa](https://www.inoopa.com/) [[@GraphtyLove](https://github.com/GraphtyLove)]
1. [Instacart 🥕](http://www.instacart.com/) [[@arp1t](https://github.com/arp1t) & [@code-sauce](https://github.com/code-sauce) & [@jasonlew](https://github.com/jasonlew) & [@j4p3](https://github.com/j4p3) & [@lubert](https://github.com/lubert) & [@mmontagna](https://github.com/mmontagna) & [@RyanAD](https://github.com/RyanAD) &[@zzadeh](https://github.com/zzadeh)]
1. [Intellischool 🎓](https://intellischool.co/) [[@intelliscl](https://github.com/intelliscl) & [@dave-philp](https://github.com/dave-philp)]
-1. [Inter Platform Inc.](https://www.bancointer.com.br/) [[@wolvery](https://github.com/wolvery)
+1. [Inter Platform Inc.](https://www.bancointer.com.br/) [[@wolvery](https://github.com/wolvery)]
1. [Intercom](http://www.intercom.com/) [[@fox](https://github.com/fox) & [@paulvic](https://github.com/paulvic)]
1. [Interia](http://www.interia.pl)
1. [Investorise](https://investorise.com/) [[@svenvarkel](https://github.com/svenvarkel)]
@@ -302,6 +308,7 @@ Currently, **officially** using Airflow:
1. [JobTeaser](https://www.jobteaser.com) [[@stefani75](https://github.com/stefani75) & [@knil-sama](https://github.com/knil-sama)]
1. [JULO](https://www.julo.co.id/) [[@sepam](https://github.com/sepam) & [@tenapril](https://github.com/tenapril) & [@verzqy](https://github.com/verzqy)]
1. [Kalibrr](https://www.kalibrr.com/) [[@charlesverdad](https://github.com/charlesverdad)]
+1. [Karana Dynamics](https://www.karanadyn.com) [[@aarongaut](https://github.com/aarongaut), [@leakec](https://github.com/leakec) & [@kajain2](https://github.com/kajain2)]
1. [Kargo](https://kargo.com) [[@chaithra-yenikapati](https://github.com/chaithra-yenikapati), [@akarsh3007](https://github.com/akarsh3007) & [@dineshanchan](https://github.com/dineshanchan)]
1. [Karmic](https://karmiclabs.com) [[@hyw](https://github.com/hyw)]
1. [Kayzen](https://kayzen.io) [[@arvindeybram](https://github.com/arvindeybram)]
@@ -338,6 +345,7 @@ Currently, **officially** using Airflow:
1. [Menhir Financial](https://www.menhir.ai/) [[@pablo-menhir](https://github.com/pablo-menhir), [@dionisio-menhir](https://github.com/dionisio-menhir) & [@luisjvca-menhir](https://github.com/luisjvca-menhir)]
1. [Mercadoni](https://www.mercadoni.com.co) [[@demorenoc](https://github.com/demorenoc)]
1. [Mercari](http://www.mercari.com/) [[@yu-iskw](https://github.com/yu-iskw)]
+1. [Met Office](https://www.metoffice.gov.uk/) [[@MetOffice](https://github.com/MetOffice)]
1. [MeuVendoo](https://www.meuvendoo.com.br) [[@CarlosDutra](https://github.com/CarlosDutra)]
1. [MFG Labs](https://github.com/MfgLabs)
1. [Ministry of Economy of Brazil](https://www.gov.br/economia/) [[@nitaibezerra](https://github.com/nitaibezerra), [@vitorbellini](https://github.com/vitorbellini)]
@@ -354,6 +362,7 @@ Currently, **officially** using Airflow:
1. [NASA Jet Propulsion Laboratory](https://www.jpl.nasa.gov) [[@lewismc](https://github.com/lewismc)]
1. [National Bank of Canada](https://nbc.ca) [[@brilhana](https://github.com/brilhana)]
1. [Nav, Inc.](https://nav.com/) [[@tigerjz32](https://github.com/tigerjz32)]
+1. [Naver](https://naver.com/)
1. [Neoway](https://www.neoway.com.br/) [[@neowaylabs](https://github.com/orgs/NeowayLabs/people)]
1. [Nerdwallet](https://www.nerdwallet.com)
1. [New Relic](https://www.newrelic.com) [[@marcweil](https://github.com/marcweil)]
@@ -388,6 +397,7 @@ Currently, **officially** using Airflow:
1. [Paradigma Digital](https://www.paradigmadigital.com/) [[@paradigmadigital](https://github.com/paradigmadigital)]
1. [Paraná Banco](https://paranabanco.com.br/) [[@lopesdiego12](https://github.com/lopesdiego12/)]
1. [Pathstream](https://pathstream.com) [[@pJackDanger](https://github.com/JackDanger)]
+1. [Pattern](https://pattern.com) [[@patterninc](https://github.com/patterninc)]
1. [Paxful](https://paxful.com) [[@ne1r0n](https://github.com/ne1r0n)]
1. [PayFit](https://payfit.com) [[@pcorbel](https://github.com/pcorbel)]
1. [PAYMILL](https://www.paymill.com/) [[@paymill](https://github.com/paymill) & [@matthiashuschle](https://github.com/matthiashuschle)]
@@ -460,6 +470,7 @@ Currently, **officially** using Airflow:
1. [SnapTravel](https://www.snaptravel.com/)
1. [SocialCops](https://www.socialcops.com/) [[@vinayak-mehta](https://github.com/vinayak-mehta) & [@sharky93](https://github.com/sharky93)]
1. [Société générale](https://www.societegenerale.fr/) [[@medmrgh](https://github.com/medmrgh) & [@s83](https://github.com/s83)]
+1. [Softwrd](https://softwrd.ai/) [[@softwrdai](https://github.com/softwrdai) & [@Mrrobi](https://github.com/Mrrobi)]
1. [Spotahome](https://www.spotahome.com/) [[@spotahome](https://github.com/spotahome)]
1. [SpotHero](https://github.com/spothero) [[@benjigoldberg](https://github.com/benjigoldberg)]
1. [Spotify](https://github.com/spotify) [[@znichols](https://github.com/znichols)]
@@ -478,6 +489,7 @@ Currently, **officially** using Airflow:
1. [T2 Systems](http://t2systems.com) [[@unclaimedpants](https://github.com/unclaimedpants)]
1. [Tails.com](https://tails.com/) [[@alanmcruickshank](https://github.com/alanmcruickshank)]
1. [Talkdesk](https://www.talkdesk.com)
+1. [Tapestry](https://www.tapestry.com) [[@faheem-khau9](https://github.com/faheem-khau9)]
1. [Tapsi](https://tapsi.ir/)
1. [TEK](https://www.tek.fi/en) [[@telac](https://github.com/telac)]
1. [Tekmetric](https://www.tekmetric.com/)
@@ -507,7 +519,7 @@ Currently, **officially** using Airflow:
1. [Topgolf](https://topgolf.com/)[[@BhaveshSK](https://github.com/BhaveshSK)]
1. [Toplyne](https://toplyne.io)[[@Toplyne](https://github.com/Toplyne/)]
1. [Trade Republic](https://traderepublic.com/)
-1. [Trakken](https://www.trkkn.com/) [[@itroulli](https://github.com/itroulli), [@gthar](https://github.com/gthar), [@qulo](https://github.com/qulo), [@Oscar-Rod](https://github.com/Oscar-Rod), [@kondla](https://github.com/kondla), [@semuar](https://github.com/semuar), [@ManuelFreytag](https://github.com/ManuelFreytag)
+1. [Trakken](https://www.trkkn.com/) [[@itroulli](https://github.com/itroulli), [@gthar](https://github.com/gthar), [@qulo](https://github.com/qulo), [@Oscar-Rod](https://github.com/Oscar-Rod), [@kondla](https://github.com/kondla), [@semuar](https://github.com/semuar), [@ManuelFreytag](https://github.com/ManuelFreytag)]
1. [Travix](https://www.travix.com/)
1. [Trocafone](https://www.trocafone.com/) [[@idontdomath](https://github.com/idontdomath) & [@gseva](https://github.com/gseva) & [@ordonezf](https://github.com/ordonezf) & [@PalmaLeandro](https://github.com/PalmaLeandro)]
1. [TruFactor](https://trufactor.io/) [[@gholmes](https://github.com/gholmes) & [@angadsingh](https://github.com/angadsingh/)]
diff --git a/ISSUE_TRIAGE_PROCESS.rst b/ISSUE_TRIAGE_PROCESS.rst
index 42f3f9779677c..676a52f41e505 100644
--- a/ISSUE_TRIAGE_PROCESS.rst
+++ b/ISSUE_TRIAGE_PROCESS.rst
@@ -196,7 +196,7 @@ associated with them such as ``provider:amazon-aws``, ``provider:microsoft-azure
These make it easier for developers working on a single provider to
track issues for that provider.
-Note: each provider has it's own unique label. It is possible for issue to be tagged with more than 1 provider label.
+Note: each provider has its own unique label. It is possible for issue to be tagged with more than 1 provider label.
Most issues need a combination of "kind" and "area" labels to be actionable.
For example:
diff --git a/PROVIDERS.rst b/PROVIDERS.rst
index 1d1386cceb454..ef3239ae6ab35 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,
@@ -145,6 +145,10 @@ classification, whether there are breaking changes, new features or just bugs co
Upgrading Minimum supported version of Airflow
----------------------------------------------
+.. note::
+
+ The following policy applies for Airflow 2. It has not yet been finalized for Airflow 3 and is subject to changes.
+
One of the important limitations of the Providers released by the community is that we introduce the limit
of a minimum supported version of Airflow. The minimum version of Airflow is the ``MINOR`` version (2.4, 2.5 etc.)
indicating that the providers might use features that appeared in this release. The default support timespan
@@ -153,8 +157,8 @@ Airflow version to the next MINOR release, when 12 months passed since the first
MINOR version of Airflow.
For example this means that by default we upgrade the minimum version of Airflow supported by providers
-to 2.9.0 in the first Provider's release after 8th of April 2025. 8th of April 2024 is the date when the
-first ``PATCHLEVEL`` of 2.9 (2.9.0) has been released.
+to 3.0.0 in the first Provider's release after 22nd of April 2026. 22nd of April 2025 is the date when the
+first ``PATCHLEVEL`` version of 3.0 (3.0.0) was released.
When we increase the minimum Airflow version, this is not a reason to bump ``MAJOR`` version of the providers
(unless there are other breaking changes in the provider). The reason for that is that people who use
diff --git a/README.md b/README.md
index 8c93ff8f9260b..eb911e71ecf05 100644
--- a/README.md
+++ b/README.md
@@ -20,20 +20,22 @@
# Apache Airflow
-[](https://badge.fury.io/py/apache-airflow)
-[](https://github.com/apache/airflow/actions)
-[](https://codecov.io/gh/apache/airflow)
-[](https://www.apache.org/licenses/LICENSE-2.0.txt)
-[](https://pypi.org/project/apache-airflow/)
-[](https://hub.docker.com/r/apache/airflow)
-[](https://hub.docker.com/r/apache/airflow)
-[](https://pypi.org/project/apache-airflow/)
-[](https://artifacthub.io/packages/search?repo=apache-airflow)
-[](https://github.com/psf/black)
-[](https://s.apache.org/airflow-slack)
-[](https://github.com/apache/airflow/graphs/contributors)
-
-[](https://ossrank.com/p/6)
+| Badges | |
+|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| License | [](https://www.apache.org/licenses/LICENSE-2.0.txt) |
+| PyPI | [](https://badge.fury.io/py/apache-airflow) [](https://pypi.org/project/apache-airflow/) [](https://pypi.org/project/apache-airflow/) |
+| Containers | [](https://hub.docker.com/r/apache/airflow) [](https://hub.docker.com/r/apache/airflow) [](https://artifacthub.io/packages/search?repo=apache-airflow) |
+| Community | [](https://github.com/apache/airflow/graphs/contributors) [](https://s.apache.org/airflow-slack)  [](https://ossrank.com/p/6) |
+
+
+
+| Version | Build Status |
+|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Main | [](https://github.com/apache/airflow/actions) [](https://github.com/apache/airflow/actions) |
+| 3.x | [](https://github.com/apache/airflow/actions) [](https://github.com/apache/airflow/actions) |
+| 2.x | [](https://github.com/apache/airflow/actions) |
+
+
@@ -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.4) |
+|------------|------------------------|------------------------|
+| Python | 3.10, 3.11, 3.12, 3.13 | 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.4' \
+ --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-3.0.4/constraints-3.10.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.4' \
+ --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-3.0.4/constraints-3.10.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.
- 
+ 
+
+- **Assets**: Overview of Assets with dependencies.
+
+ 
- **Grid**: Grid representation of a DAG that spans across time.
- 
+ 
- **Graph**: Visualization of a DAG's dependencies and their current status for a specific run.
- 
+ 
- **Home**: Summary statistics of your Airflow environment.
- 
+ 
- **Backfill**: Backfilling a DAG for a specific date range.
- 
+ 
- **Code**: Quick way to view source code of a DAG.
- 
+ 
## Semantic versioning
@@ -263,7 +275,7 @@ packages:
Changing limits for versions of Airflow dependencies is not a breaking change on its own.
* **Airflow Providers**: SemVer rules apply to changes in the particular provider's code only.
SemVer MAJOR and MINOR versions for the packages are independent of the Airflow version.
- For example, `google 4.1.0` and `amazon 3.0.3` providers can happily be installed
+ For example, `google 4.1.0` and `amazon 3.0.4` providers can happily be installed
with `Airflow 2.1.2`. If there are limits of cross-dependencies between providers and Airflow packages,
they are present in providers as `install_requires` limitations. We aim to keep backwards
compatibility of providers with all previously released Airflow 2 versions but
@@ -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.4 | 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 |
@@ -310,7 +323,7 @@ They are based on the official release schedule of Python and Kubernetes, nicely
1. We drop support for Python and Kubernetes versions when they reach EOL. Except for Kubernetes, a
version stays supported by Airflow if two major cloud providers still provide support for it. We drop
support for those EOL versions in main right after EOL date, and it is effectively removed when we release
- the first new MINOR (Or MAJOR if there is no new MINOR version) of Airflow. For example, for Python 3.9 it
+ the first new MINOR (Or MAJOR if there is no new MINOR version) of Airflow. For example, for Python 3.10 it
means that we will drop support in main right after 27.06.2023, and the first MAJOR or MINOR version of
Airflow released after will not have it.
@@ -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..c418a65ebc6c0 100644
--- a/RELEASE_NOTES.rst
+++ b/RELEASE_NOTES.rst
@@ -19,206 +19,75 @@
:local:
:depth: 1
+.. note::
+ Release notes for older versions can be found in the versioned documentation.
+
.. towncrier release notes start
-Airflow 3.0.0 (2025-04-22)
+Airflow 3.0.4 (2025-08-08)
--------------------------
-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.
-
-Highlights
-^^^^^^^^^^
-
-Major Architectural Advancements
-""""""""""""""""""""""""""""""""
-
-- **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.
-
-UI Overhaul
-"""""""""""
-
-- **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.
-
-Expanded Scheduling and Execution
-"""""""""""""""""""""""""""""""""
-
-- **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.
-
-ML & AI Use Cases
-"""""""""""""""""
-
-- **Support for Non-Data-Interval DAGs (AIP-83)**: Enables inference DAGs and hyperparameter tuning runs by removing the uniqueness constraint on execution dates.
-
-Breaking Changes
-^^^^^^^^^^^^^^^^
-
-See the :doc:`Upgrade Guide ` for a full list of changes and migration recommendations. Major breaking changes include:
-
-Metadata Database Access
-""""""""""""""""""""""""
-
-- Direct access to the metadata DB from task code is no longer supported. Use the :doc:`REST API ` instead.
-
-Scheduling Changes
-""""""""""""""""""
-
-- New default: ``schedule=None``, ``catchup=False``
-- ``schedule_interval`` and ``timetable`` are removed; use ``schedule`` exclusively.
-- Raw cron strings now use ``CronTriggerTimetable`` instead of ``CronDataIntervalTimetable``.
-
-Context and Parameters
-""""""""""""""""""""""
-
-- 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
-
-Deprecated and Removed Features
-"""""""""""""""""""""""""""""""
-
-+-----------------------------+----------------------------------------------------------+
-| **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 |
-+-----------------------------+----------------------------------------------------------+
-
-Upgrade Process
-^^^^^^^^^^^^^^^
-
-Airflow 3 was designed with migration in mind. Many Airflow 2 DAGs will work without changes. Use these tools:
-
-- ``ruff check --preview --select AIR30 --fix``: Flag and auto-fix DAG-level changes
-- ``airflow config lint``: Identify outdated or removed config options
-
-**Minimum version required to upgrade**: Airflow 2.7
-
-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.
-
-Resources
-^^^^^^^^^
-
-- :doc:`Upgrade Guide `
-- `Airflow AIPs `_
-
-Airflow 2.10.5 (2025-02-10)
----------------------------
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".
-
+No significant changes.
Bug Fixes
"""""""""
-- 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)
-
+- Fix scheduler heartbeat timeout failures with intermittent ``DetachedInstanceError`` crashes (#53838) (#53858)
+- Fix connection editing where sensitive fields like passwords and extras were lost when updating connections (#53943) (#53973)
+- Fix BaseOperator ``on_kill`` functionality not working when tasks are killed externally in TaskSDK (#53718) (#53832)
+- Fix TaskInstance notes not refreshing automatically without manual page refresh (#53307) (#54025)
+- Fix invalid execution API URLs causing failures in task supervisor (#53082) (#53518)
+- Fix task failure callbacks not running on DAG Processor when tasks are externally killed (#53058) (#53143)
+- Fix ``task_success_overtime`` configuration option not being configurable (#53342) (#53351)
+- Fix CSS warning for nth-child selector (#53982) (#54000)
+- Fix DAG filtering where "all" option did not show all DAGs as expected (#53656) (#53672)
+- Fix accordion child contents not being visible when content overflows (#53595) (#53602)
+- Fix navbar positioning for anchor calculations (#52016) (#53581)
+- Fix DagBag safe mode configuration resolution in DAG processor (#52694) (#53507)
+- Fix large log reading causing out-of-memory issues in API server (#49470) (#53167)
+- Fix connection exceptions consistency between Airflow 2.x and 3.x (#52968) (#53093)
+- Remove unnecessary ``group_by`` clause in event logs query for performance (#53733) (#53807)
+- Allow remote logging providers to load connections from API Server (#53719) (#53761)
+- Add certificate support for API server client communication with self-signed certificates (#53574) (#53793)
+- Respect ``apps`` flags for API server command configuration (#52929) (#53775)
+- Skip empty DAG run configuration rows and set statement timeout (#50788) (#53619)
+- Remove incorrect warning for ``BaseOperator.executor`` attribute (#53496) (#53519)
+- Add back DAG parsing pre-import optimization for improved performance (#50371) (#52698)
+- Flexible form use ReactMarkdown instead of default Markdown component (#54032) (#54040)
+- Unconditionally disable ``start_from_trigger`` functionality (#53744) (#53750)
+- Serialize NaN and infinity values to string (#53835) (#53844)
+- Make log redaction safer in edge case when redaction has an error (#54046) (#54048)
+- Flexible form use ReactMarkdown instead of default Markdown component (#54032) (#54040)
+- Fix inconsistent casing in UI of decorated tasks (#54056) (#54092)
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.10.4 (2024-12-16)
----------------------------
-
-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
-^^^^^^^^^
-
-- 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)
+- Fix AIRFLOW_API_APPS constant in API server command (#54007) (#54012)
+- Add deprecation notice for using Connection from models in favor of SDK approach (#53594) (#53621)
+- Remove remnants of ``~=`` used in requires-python configuration (#52985) (#52987)
+- Remove upper-binding for "python-requires" specification (#52980) (#52984)
+- Update GitPython from 3.1.44 to 3.1.45 (#53725) (#53731)(#53724) (#53732)
Doc Only Changes
""""""""""""""""
-- Update XCom docs around containers/helm (#44570) (#44573)
-
-Miscellaneous
-"""""""""""""
-- Raise deprecation warning when accessing inlet or outlet events through str (#43922)
-
-Airflow 2.10.3 (2024-11-05)
----------------------------
+- Update DAG author documentation to use "DAG author" terminology (#53857) (#53950)
+- Update architecture diagrams labels from "Webserver(s)" to "API Server(s)" (#53917) (#54020)
+- Remove bold formatting for Public Interface documentation in Airflow 3.0+ (#53955) (#53964)
+- Add user-facing documentation for running separate Task Execution API server (#53789) (#53794)
+- Add documentation for self-signed certificate configuration (#53788) (#53792)
+- Update systemd unit files and documentation for Airflow 3.0 compatibility (#52294) (#53609)
+- Update public interface documentation to reflect airflow.sdk and AIP-72 changes (#52197) (#53117)
+- Update BaseOperator documentation string for clarity (#53403) (#53404)
+- Remove extra slash from endpoint URL formatting (#53755) (#53764)
+- Clarify our security model for sensitive connection information (#54088) (#54100)
+
+Airflow 3.0.3 (2025-07-14)
+--------------------------
Significant Changes
^^^^^^^^^^^^^^^^^^^
@@ -227,61 +96,82 @@ No significant changes.
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)
+
+- 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
"""""""""""""
-- 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)
+
+- 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
""""""""""""""""
-- 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)
+- 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 2.10.2 (2024-09-18)
----------------------------
+Airflow 3.0.2 (2025-06-10)
+--------------------------
Significant Changes
^^^^^^^^^^^^^^^^^^^
@@ -290,35 +180,112 @@ No significant changes.
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)
+
+- 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
"""""""""""""
-- 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)
+
+- 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
""""""""""""""""
-- 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.10.1 (2024-09-05)
----------------------------
+- 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
^^^^^^^^^^^^^^^^^^^
@@ -327,8324 +294,4253 @@ No significant changes.
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)
+
+- 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
"""""""""""""
-- 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)
+
+- 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 Debian bullseye support (#41569)
-- Add an example for auth with ``keycloak`` (#41791)
+- 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 2.10.0 (2024-08-15)
----------------------------
+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. 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.
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
+Highlights
+^^^^^^^^^^
-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.
+- **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).
-Datasets no longer trigger inactive DAGs (#38891)
-"""""""""""""""""""""""""""""""""""""""""""""""""
+- **Edge Executor**: A new executor that supports distributed, event-driven, and edge-compute workflows (AIP-69), now generally available.
-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.
+- **Stable Authoring Interface**: DAG authors should now use the new ``airflow.sdk`` namespace to import core DAG constructs like ``@dag``, ``@task``, and ``DAG``.
-The behavior of time-based scheduling is unchanged, including the timetable part
-of ``DatasetOrTimeSchedule``.
+- **Scheduler-Managed Backfills**: Backfills are now scheduled and tracked like regular DAG runs, with native UI and API support (AIP-78).
-``try_number`` is no longer incremented during task execution (#39336)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+- **DAG Versioning**: Airflow now tracks structural changes to DAGs over time, enabling inspection of historical DAG definitions via the UI and API (AIP-66).
-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.
-
-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.
-
-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.
-
-``/logout`` endpoint in FAB Auth Manager is now CSRF protected (#40145)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-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.
-
-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.
-
-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
-""""""""""""
-- 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
-""""""""""""
-- 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)
-
-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)
-
-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)
-
-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)
-
-
-
-Airflow 2.9.3 (2024-07-15)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-Time unit for ``scheduled_duration`` and ``queued_duration`` changed (#37936)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-``scheduled_duration`` and ``queued_duration`` metrics are now emitted in milliseconds instead of seconds.
-
-By convention all statsd metrics should be emitted in milliseconds, this is later expected in e.g. ``prometheus`` statsd-exporter.
-
-
-Support for OpenTelemetry Metrics is no longer "Experimental" (#40286)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-
-
-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)
-
-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)
-
-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)
-
-
-
-Airflow 2.9.2 (2024-06-10)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-No significant changes.
-
-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)
-
-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)
-
-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)
-
-
-
-Airflow 2.9.1 (2024-05-03)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-Stackdriver logging bugfix requires Google provider ``10.17.0`` or later (#38071)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-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.
-
-
-
-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)
-
-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)
-
-
-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)
-
-
-
-Airflow 2.9.0 (2024-04-08)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-Following Listener API methods are considered stable and can be used for production system (were experimental feature in older Airflow versions) (#36376):
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Lifecycle events:
-
-- ``on_starting``
-- ``before_stopping``
-
-DagRun State Change Events:
-
-- ``on_dag_run_running``
-- ``on_dag_run_success``
-- ``on_dag_run_failed``
-
-TaskInstance State Change Events:
-
-- ``on_task_instance_running``
-- ``on_task_instance_success``
-- ``on_task_instance_failed``
-
-Support for Microsoft SQL-Server for Airflow Meta Database has been removed (#36514)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-As of Airflow 2.9.0 support of MsSQL has been removed for Airflow Database Backend.
-
-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.
-
-This does not affect the existing provider packages (operators and hooks), DAGs can still access and process data from MsSQL.
-
-Dataset URIs are now validated on input (#37005)
-""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-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 method ``get_permitted_menu_items`` in ``BaseAuthManager`` has been renamed ``filter_permitted_menu_items`` (#37627)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-Add REST API actions to Audit Log events (#37734)
-"""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-Official support for Python 3.12 (#38025)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-There are a few caveats though:
-
-* Pendulum2 does not support Python 3.12. For Python 3.12 you need to use
- `Pendulum 3 `_
-
-* 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.
-
-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:
-
- * ``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 `_
-
-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.
-
-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.
-
-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.
-
-Stronger validation for key parameter defaults in taskflow context variables (#38015)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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``.
-
-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)
-
-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)
-
-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)
-
-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)
-
-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)
-
-
-Airflow 2.8.4 (2024-03-25)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-No significant changes.
-
-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)
-
-Miscellaneous
-"""""""""""""
-- 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)
-
-
-Airflow 2.8.3 (2024-03-11)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-The smtp provider is now pre-installed when you install Airflow. (#37713)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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)
-
-Miscellaneous
-"""""""""""""
-- 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)
-
-
-Airflow 2.8.2 (2024-02-26)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-The ``allowed_deserialization_classes`` flag now follows a glob pattern (#36147).
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.*``).
-
-If you currently use a custom regexp path make sure to rewrite it as a glob pattern.
-
-Alternatively, if you still wish to match it as a regexp pattern, add it under the new
-list ``allowed_deserialization_classes_regexp`` instead.
-
-The audit_logs permissions have been updated for heightened security (#37501).
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-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.
-
-``AirflowTimeoutError`` is no longer ``except`` by default through ``Exception`` (#35653).
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-The ``AirflowTimeoutError`` is now inheriting ``BaseException`` instead of
-``AirflowException``->``Exception``.
-See https://docs.python.org/3/library/exceptions.html#exception-hierarchy
-
-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.
-
-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
-
-
-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)
-
-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)
-
-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)
-
-
-Airflow 2.8.1 (2024-01-19)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-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.
-
-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.
-
-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:
-
-* `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 `__
-
-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 `__
-
-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]"``.
-
-The differences from the user side are:
-
-* 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 ``.``.
-
-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.
-
-* 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.
-
-* 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.
-
-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+.
-
-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.
-
-Graphviz will remain to be installed for most users:
-
-* 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
-
-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.
-
-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)
-
-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)
-
-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)
-
-Airflow 2.8.0 (2023-12-18)
---------------------------
-
-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``.
-
-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.
-
-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)
-
-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)
-
-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)
-
-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)
-
-
-Airflow 2.7.3 (2023-11-06)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-No significant changes.
-
-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)
-
-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)
-
-
-
-Airflow 2.7.2 (2023-10-12)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-No significant changes
-
-
-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)
-
-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)
-
-Misc/Internal
-"""""""""""""
-- 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)
-
-
-Airflow 2.7.1 (2023-09-07)
---------------------------
-
-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.
-
-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.
-
-Note that this is also the behaviour exhibited by various other cron-based
-scheduling tools, such as ``anacron``.
-
-``conf.set()`` becomes case insensitive to match ``conf.get()`` behavior (#33452)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-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.
-
-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.
-
-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")``.
-
-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)
-
-Misc/Internal
-"""""""""""""
-- 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)
-
-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)
-
-
-Airflow 2.7.0 (2023-08-18)
---------------------------
-
-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.
-
-Old Graph View is removed (#32958)
-""""""""""""""""""""""""""""""""""
-The old Graph View is removed. The new Graph View is the default view now.
-
-The trigger UI form is skipped in web UI if no parameters are defined in a DAG (#33351)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-If you are using ``dag_run.conf`` dictionary and web UI JSON entry to run your DAG you should either:
-
-* `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".
-
-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.
-
-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.
-
-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``.
-
-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.
-
-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.
-
-3. ``Hidden``: Disables the test connection functionality and
-hides the Test Connection button in UI.
-
-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.
-
-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``.
-
-Some executors have been moved to corresponding providers (#32767)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-In order to use the executors, you need to install the providers:
-
-* 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
-
-You can achieve it also by installing airflow with ``[celery]``, ``[cncf.kubernetes]``, ``[daskexecutor]`` extras respectively.
-
-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.
-
-Improvement Changes
-^^^^^^^^^^^^^^^^^^^
-
-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.
-
-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)
-
-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 ```` in Mapped Instance table (#23313)
-- Fix duplicated Kubernetes DeprecationWarnings (#23302)
-- Store grid view selection in url params (#23290)
-- Remove custom signal handling in Triggerer (#23274)
-- Override pool for TaskInstance when pool is passed from cli. (#23258)
-- Show warning if '/' is used in a DAG run ID (#23106)
-- Use kubernetes queue in kubernetes hybrid executors (#23048)
-- Add tags inside try block. (#21784)
-
-Doc only changes
-^^^^^^^^^^^^^^^^
-
-- Move ``dag_processing.processor_timeouts`` to counters section (#23393)
-- Clarify that bundle extras should not be used for PyPi installs (#23697)
-- Synchronize support for Postgres and K8S in docs (#23673)
-- Replace DummyOperator references in docs (#23502)
-- Add doc notes for keyword-only args for ``expand()`` and ``partial()`` (#23373)
-- Document fix for broken elasticsearch logs with 2.3.0+ upgrade (#23821)
-
-Misc/Internal
-^^^^^^^^^^^^^
-
-- Add typing for airflow/configuration.py (#23716)
-- Disable Flower by default from docker-compose (#23685)
-- Added postgres 14 to support versions(including breeze) (#23506)
-- add K8S 1.24 support (#23637)
-- Refactor code references from tree to grid (#23254)
-
-
-Airflow 2.3.0 (2022-04-30)
---------------------------
-
-For production docker image related changes, see the `Docker Image Changelog `_.
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-Passing ``execution_date`` to ``XCom.set()``, ``XCom.clear()`` , ``XCom.get_one()`` , and ``XCom.get_many()`` is deprecated (#19825)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-Continuing the effort to bind TaskInstance to a DagRun, XCom entries are now also tied to a DagRun. Use the ``run_id`` argument to specify the DagRun instead.
-
-Task log templates are now read from the metadata database instead of ``airflow.cfg`` (#20165)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-Previously, a task's log is dynamically rendered from the ``[core] log_filename_template`` and ``[elasticsearch] log_id_template`` config values at runtime. This resulted in unfortunate characteristics, e.g. it is impractical to modify the config value after an Airflow instance is running for a while, since all existing task logs have be saved under the previous format and cannot be found with the new config value.
-
-A new ``log_template`` table is introduced to solve this problem. This table is synchronized with the aforementioned config values every time Airflow starts, and a new field ``log_template_id`` is added to every DAG run to point to the format used by tasks (``NULL`` indicates the first ever entry for compatibility).
-
-Minimum kubernetes library version bumped from ``3.0.0`` to ``21.7.0`` (#20759)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-.. note::
-
- This is only about changing the ``kubernetes`` library, not the Kubernetes cluster. Airflow support for
- Kubernetes version is described in `Installation prerequisites `_.
-
-No change in behavior is expected. This was necessary in order to take advantage of a `bugfix `_ concerning refreshing of Kubernetes API tokens with EKS, which enabled the removal of some `workaround code `_.
-
-XCom now defined by ``run_id`` instead of ``execution_date`` (#20975)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-As a continuation to the TaskInstance-DagRun relation change started in Airflow 2.2, the ``execution_date`` columns on XCom has been removed from the database, and replaced by an `association proxy `_ field at the ORM level. If you access Airflow's metadata database directly, you should rewrite the implementation to use the ``run_id`` column instead.
-
-Note that Airflow's metadatabase definition on both the database and ORM levels are considered implementation detail without strict backward compatibility guarantees.
-
-Non-JSON-serializable params deprecated (#21135).
-"""""""""""""""""""""""""""""""""""""""""""""""""
-
-It was previously possible to use dag or task param defaults that were not JSON-serializable.
-
-For example this worked previously:
-
-.. code-block:: python
-
- @dag.task(params={"a": {1, 2, 3}, "b": pendulum.now()})
- def datetime_param(value):
- print(value)
-
-
- datetime_param("{{ params.a }} | {{ params.b }}")
-
-Note the use of ``set`` and ``datetime`` types, which are not JSON-serializable. This behavior is problematic because to override these values in a dag run conf, you must use JSON, which could make these params non-overridable. Another problem is that the support for param validation assumes JSON. Use of non-JSON-serializable params will be removed in Airflow 3.0 and until then, use of them will produce a warning at parse time.
-
-You must use ``postgresql://`` instead of ``postgres://`` in ``sql_alchemy_conn`` for SQLAlchemy 1.4.0+ (#21205)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-When you use SQLAlchemy 1.4.0+, you need to use ``postgresql://`` as the scheme in the ``sql_alchemy_conn``.
-In the previous versions of SQLAlchemy it was possible to use ``postgres://`` , but using it in
-SQLAlchemy 1.4.0+ results in:
-
-.. code-block::
-
- > raise exc.NoSuchModuleError(
- "Can't load plugin: %s:%s" % (self.group, name)
- )
- E sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres
-
-If you cannot change the scheme of your URL immediately, Airflow continues to work with SQLAlchemy
-1.3 and you can downgrade SQLAlchemy, but we recommend updating the scheme.
-Details in the `SQLAlchemy Changelog `_.
-
-``auth_backends`` replaces ``auth_backend`` configuration setting (#21472)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-Previously, only one backend was used to authorize use of the REST API. In 2.3 this was changed to support multiple backends, separated by comma. Each will be tried in turn until a successful response is returned.
-
-``airflow.models.base.Operator`` is removed (#21505)
-""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-Previously, there was an empty class ``airflow.models.base.Operator`` for "type hinting". This class was never really useful for anything (everything it did could be done better with ``airflow.models.baseoperator.BaseOperator``), and has been removed. If you are relying on the class's existence, use ``BaseOperator`` (for concrete operators), ``airflow.models.abstractoperator.AbstractOperator`` (the base class of both ``BaseOperator`` and the AIP-42 ``MappedOperator``), or ``airflow.models.operator.Operator`` (a union type ``BaseOperator | MappedOperator`` for type annotation).
-
-Zip files in the DAGs folder can no longer have a ``.py`` extension (#21538)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-It was previously possible to have any extension for zip files in the DAGs folder. Now ``.py`` files are going to be loaded as modules without checking whether it is a zip file, as it leads to less IO. If a ``.py`` file in the DAGs folder is a zip compressed file, parsing it will fail with an exception.
-
-``auth_backends`` includes session (#21640)
-"""""""""""""""""""""""""""""""""""""""""""
-
-To allow the Airflow UI to use the API, the previous default authorization backend ``airflow.api.auth.backend.deny_all`` is changed to ``airflow.api.auth.backend.session``, and this is automatically added to the list of API authorization backends if a non-default value is set.
-
-Default templates for log filenames and elasticsearch log_id changed (#21734)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-In order to support Dynamic Task Mapping the default templates for per-task instance logging has changed. If your config contains the old default values they will be upgraded-in-place.
-
-If you are happy with the new config values you should *remove* the setting in ``airflow.cfg`` and let the default value be used. Old default values were:
-
-
-* ``[core] log_filename_template``: ``{{ ti.dag_id }}/{{ ti.task_id }}/{{ ts }}/{{ try_number }}.log``
-* ``[elasticsearch] log_id_template``: ``{dag_id}-{task_id}-{execution_date}-{try_number}``
-
-``[core] log_filename_template`` now uses "hive partition style" of ``dag_id=/run_id=`` by default, which may cause problems on some older FAT filesystems. If this affects you then you will have to change the log template.
-
-If you have customized the templates you should ensure that they contain ``{{ ti.map_index }}`` if you want to use dynamically mapped tasks.
-
-If after upgrading you find your task logs are no longer accessible, try adding a row in the ``log_template`` table with ``id=0``
-containing your previous ``log_id_template`` and ``log_filename_template``. For example, if you used the defaults in 2.2.5:
-
-.. code-block:: sql
-
- INSERT INTO log_template (id, filename, elasticsearch_id, created_at) VALUES (0, '{{ ti.dag_id }}/{{ ti.task_id }}/{{ ts }}/{{ try_number }}.log', '{dag_id}-{task_id}-{execution_date}-{try_number}', NOW());
-
-BaseOperatorLink's ``get_link`` method changed to take a ``ti_key`` keyword argument (#21798)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-In v2.2 we "deprecated" passing an execution date to XCom.get methods, but there was no other option for operator links as they were only passed an execution_date.
-
-Now in 2.3 as part of Dynamic Task Mapping (AIP-42) we will need to add map_index to the XCom row to support the "reduce" part of the API.
-
-In order to support that cleanly we have changed the interface for BaseOperatorLink to take an TaskInstanceKey as the ``ti_key`` keyword argument (as execution_date + task is no longer unique for mapped operators).
-
-The existing signature will be detected (by the absence of the ``ti_key`` argument) and continue to work.
-
-``ReadyToRescheduleDep`` now only runs when ``reschedule`` is *True* (#21815)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-When a ``ReadyToRescheduleDep`` is run, it now checks whether the ``reschedule`` attribute on the operator, and always reports itself as *passed* unless it is set to *True*. If you use this dep class on your custom operator, you will need to add this attribute to the operator class. Built-in operator classes that use this dep class (including sensors and all subclasses) already have this attribute and are not affected.
-
-The ``deps`` attribute on an operator class should be a class level attribute (#21815)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-To support operator-mapping (AIP 42), the ``deps`` attribute on operator class must be a set at the class level. This means that if a custom operator implements this as an instance-level variable, it will not be able to be used for operator-mapping. This does not affect existing code, but we highly recommend you to restructure the operator's dep logic in order to support the new feature.
-
-Deprecation: ``Connection.extra`` must be JSON-encoded dict (#21816)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-TLDR
-~~~~
-
-From Airflow 3.0, the ``extra`` field in airflow connections must be a JSON-encoded Python dict.
-
-What, why, and when?
-~~~~~~~~~~~~~~~~~~~~
-
-Airflow's Connection is used for storing credentials. For storage of information that does not
-fit into user / password / host / schema / port, we have the ``extra`` string field. Its intention
-was always to provide for storage of arbitrary key-value pairs, like ``no_host_key_check`` in the SSH
-hook, or ``keyfile_dict`` in GCP.
-
-But since the field is string, it's technically been permissible to store any string value. For example
-one could have stored the string value ``'my-website.com'`` and used this in the hook. But this is a very
-bad practice. One reason is intelligibility: when you look at the value for ``extra`` , you don't have any idea
-what its purpose is. Better would be to store ``{"api_host": "my-website.com"}`` which at least tells you
-*something* about the value. Another reason is extensibility: if you store the API host as a simple string
-value, what happens if you need to add more information, such as the API endpoint, or credentials? Then
-you would need to convert the string to a dict, and this would be a breaking change.
-
-For these reason, starting in Airflow 3.0 we will require that the ``Connection.extra`` field store
-a JSON-encoded Python dict.
-
-How will I be affected?
-~~~~~~~~~~~~~~~~~~~~~~~
-
-For users of providers that are included in the Airflow codebase, you should not have to make any changes
-because in the Airflow codebase we should not allow hooks to misuse the ``Connection.extra`` field in this way.
-
-However, if you have any custom hooks that store something other than JSON dict, you will have to update it.
-If you do, you should see a warning any time that this connection is retrieved or instantiated (e.g. it should show up in
-task logs).
-
-To see if you have any connections that will need to be updated, you can run this command:
-
-.. code-block:: shell
-
- airflow connections export - 2>&1 >/dev/null | grep 'non-JSON'
-
-This will catch any warnings about connections that are storing something other than JSON-encoded Python dict in the ``extra`` field.
-
-The ``tree`` default view setting has been renamed to ``grid`` (#22167)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-If you set the ``dag_default_view`` config option or the ``default_view`` argument to ``DAG()`` to ``tree`` you will need to update your deployment. The old name will continue to work but will issue warnings.
-
-Database configuration moved to new section (#22284)
-""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-The following configurations have been moved from ``[core]`` to the new ``[database]`` section. However when reading the new option, the old option will be checked to see if it exists. If it does a DeprecationWarning will be issued and the old option will be used instead.
-
-* sql_alchemy_conn
-* sql_engine_encoding
-* sql_engine_collation_for_ids
-* sql_alchemy_pool_enabled
-* sql_alchemy_pool_size
-* sql_alchemy_max_overflow
-* sql_alchemy_pool_recycle
-* sql_alchemy_pool_pre_ping
-* sql_alchemy_schema
-* sql_alchemy_connect_args
-* load_default_connections
-* max_db_retries
-
-Remove requirement that custom connection UI fields be prefixed (#22607)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-Hooks can define custom connection fields for their connection type by implementing method ``get_connection_form_widgets``. These custom fields appear in the web UI as additional connection attributes, but internally they are stored in the connection ``extra`` dict field. For technical reasons, previously, when stored in the ``extra`` dict, the custom field's dict key had to take the form ``extra____``. This had the consequence of making it more cumbersome to define connections outside of the UI, since the prefix ``extra____`` makes it tougher to read and work with. With #22607, we make it so that you can now define custom fields such that they can be read from and stored in ``extra`` without the prefix.
-
-To enable this, update the dict returned by the ``get_connection_form_widgets`` method to remove the prefix from the keys. Internally, the providers manager will still use a prefix to ensure each custom field is globally unique, but the absence of a prefix in the returned widget dict will signal to the Web UI to read and store custom fields without the prefix. Note that this is only a change to the Web UI behavior; when updating your hook in this way, you must make sure that when your *hook* reads the ``extra`` field, it will also check for the prefixed value for backward compatibility.
-
-The webserver.X_FRAME_ENABLED configuration works according to description now (#23222).
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-In Airflow 2.0.0 - 2.2.4 the webserver.X_FRAME_ENABLED parameter worked the opposite of its description,
-setting the value to "true" caused "X-Frame-Options" header to "DENY" (not allowing Airflow to be used
-in an iframe). When you set it to "false", the header was not added, so Airflow could be embedded in an
-iframe. By default Airflow could not be embedded in an iframe.
-
-In Airflow 2.2.5 there was a bug introduced that made it impossible to disable Airflow to
-work in iframe. No matter what the configuration was set, it was possible to embed Airflow in an iframe.
-
-Airflow 2.3.0 restores the original meaning to the parameter. If you set it to "true" (default) Airflow
-can be embedded in an iframe (no header is added), but when you set it to "false" the header is added
-and Airflow cannot be embedded in an iframe.
-
-
-New Features
-^^^^^^^^^^^^
-
-- Add dynamic task mapping (`AIP-42 `_)
-- New Grid View replaces Tree View (#18675)
-- Templated ``requirements.txt`` in Python Operators (#17349)
-- Allow reuse of decorated tasks (#22941)
-- Move the database configuration to a new section (#22284)
-- Add ``SmoothOperator`` (#22813)
-- Make operator's ``execution_timeout`` configurable (#22389)
-- Events Timetable (#22332)
-- Support dag serialization with custom ``ti_deps`` rules (#22698)
-- Support log download in task log view (#22804)
-- support for continue backfill on failures (#22697)
-- Add ``dag-processor`` cli command (#22305)
-- Add possibility to create users in LDAP mode (#22619)
-- Add ``ignore_first_depends_on_past`` for scheduled jobs (#22491)
-- Update base sensor operator to support XCOM return value (#20656)
-- Add an option for run id in the ui trigger screen (#21851)
-- Enable JSON serialization for connections (#19857)
-- Add REST API endpoint for bulk update of DAGs (#19758)
-- Add queue button to click-on-DagRun interface. (#21555)
-- Add ``list-import-errors`` to ``airflow dags`` command (#22084)
-- Store callbacks in database if ``standalone_dag_processor`` config is True. (#21731)
-- Add LocalKubernetesExecutor (#19729)
-- Add ``celery.task_timeout_error`` metric (#21602)
-- Airflow ``db downgrade`` cli command (#21596)
-- Add ``ALL_SKIPPED`` trigger rule (#21662)
-- Add ``db clean`` CLI command for purging old data (#20838)
-- Add ``celery_logging_level`` (#21506)
-- Support different timeout value for dag file parsing (#21501)
-- Support generating SQL script for upgrades (#20962)
-- Add option to compress Serialized dag data (#21332)
-- Branch python operator decorator (#20860)
-- Add Audit Log View to Dag View (#20733)
-- Add missing StatsD metric for failing SLA Callback notification (#20924)
-- Add ``ShortCircuitOperator`` configurability for respecting downstream trigger rules (#20044)
-- Allow using Markup in page title in Webserver (#20888)
-- Add Listener Plugin API that tracks TaskInstance state changes (#20443)
-- Add context var hook to inject more env vars (#20361)
-- Add a button to set all tasks to skipped (#20455)
-- Cleanup pending pods (#20438)
-- Add config to warn public deployment exposure in UI (#18557)
-- Log filename template records (#20165)
-- Added windows extensions (#16110)
-- Showing approximate time until next dag_run in Airflow (#20273)
-- Extend config window on UI (#20052)
-- Add show dag dependencies feature to CLI (#19985)
-- Add cli command for 'airflow dags reserialize` (#19471)
-- Add missing description field to Pool schema(REST API) (#19841)
-- Introduce DagRun action to change state to queued. (#19353)
-- Add DAG run details page (#19705)
-- Add role export/import to cli tools (#18916)
-- Adding ``dag_id_pattern`` parameter to the ``/dags`` endpoint (#18924)
-
-
-Improvements
-^^^^^^^^^^^^
-
-- Show schedule_interval/timetable description in UI (#16931)
-- Added column duration to DAG runs view (#19482)
-- Enable use of custom conn extra fields without prefix (#22607)
-- Initialize finished counter at zero (#23080)
-- Improve logging of optional provider features messages (#23037)
-- Meaningful error message in resolve_template_files (#23027)
-- Update ImportError items instead of deleting and recreating them (#22928)
-- Add option ``--skip-init`` to db reset command (#22989)
-- Support importing connections from files with ".yml" extension (#22872)
-- Support glob syntax in ``.airflowignore`` files (#21392) (#22051)
-- Hide pagination when data is a single page (#22963)
-- Support for sorting DAGs in the web UI (#22671)
-- Speed up ``has_access`` decorator by ~200ms (#22858)
-- Add XComArg to lazy-imported list of Airflow module (#22862)
-- Add more fields to REST API dags/dag_id/details endpoint (#22756)
-- Don't show irrelevant/duplicated/"internal" Task attrs in UI (#22812)
-- No need to load whole ti in current_state (#22764)
-- Pickle dag exception string fix (#22760)
-- Better verification of Localexecutor's parallelism option (#22711)
-- log backfill exceptions to sentry (#22704)
-- retry commit on MySQL deadlocks during backfill (#22696)
-- Add more fields to REST API get DAG(dags/dag_id) endpoint (#22637)
-- Use timetable to generate planned days for current year (#22055)
-- Disable connection pool for celery worker (#22493)
-- Make date picker label visible in trigger dag view (#22379)
-- Expose ``try_number`` in airflow vars (#22297)
-- Add generic connection type (#22310)
-- Add a few more fields to the taskinstance finished log message (#22262)
-- Pause auto-refresh if scheduler isn't running (#22151)
-- Show DagModel details. (#21868)
-- Add pip_install_options to PythonVirtualenvOperator (#22158)
-- Show import error for ``airflow dags list`` CLI command (#21991)
-- Pause auto-refresh when page is hidden (#21904)
-- Default args type check (#21809)
-- Enhance magic methods on XComArg for UX (#21882)
-- py files don't have to be checked ``is_zipfiles`` in refresh_dag (#21926)
-- Fix TaskDecorator type hints (#21881)
-- Add 'Show record' option for variables (#21342)
-- Use DB where possible for quicker ``airflow dag`` subcommands (#21793)
-- REST API: add rendered fields in task instance. (#21741)
-- Change the default auth backend to session (#21640)
-- Don't check if ``py`` DAG files are zipped during parsing (#21538)
-- Switch XCom implementation to use ``run_id`` (#20975)
-- Action log on Browse Views (#21569)
-- Implement multiple API auth backends (#21472)
-- Change logging level details of connection info in ``get_connection()`` (#21162)
-- Support mssql in airflow db shell (#21511)
-- Support config ``worker_enable_remote_control`` for celery (#21507)
-- Log memory usage in ``CgroupTaskRunner`` (#21481)
-- Modernize DAG-related URL routes and rename "tree" to "grid" (#20730)
-- Move Zombie detection to ``SchedulerJob`` (#21181)
-- Improve speed to run ``airflow`` by 6x (#21438)
-- Add more SQL template fields renderers (#21237)
-- Simplify fab has access lookup (#19294)
-- Log context only for default method (#21244)
-- Log trigger status only if at least one is running (#21191)
-- Add optional features in providers. (#21074)
-- Better multiple_outputs inferral for @task.python (#20800)
-- Improve handling of string type and non-attribute ``template_fields`` (#21054)
-- Remove un-needed deps/version requirements (#20979)
-- Correctly specify overloads for TaskFlow API for type-hinting (#20933)
-- Introduce notification_sent to SlaMiss view (#20923)
-- Rewrite the task decorator as a composition (#20868)
-- Add "Greater/Smaller than or Equal" to filters in the browse views (#20602) (#20798)
-- Rewrite DAG run retrieval in task command (#20737)
-- Speed up creation of DagRun for large DAGs (5k+ tasks) by 25-130% (#20722)
-- Make native environment Airflow-flavored like sandbox (#20704)
-- Better error when param value has unexpected type (#20648)
-- Add filter by state in DagRun REST API (List Dag Runs) (#20485)
-- Prevent exponential memory growth in Tasks with custom logging handler (#20541)
-- Set default logger in logging Mixin (#20355)
-- Reduce deprecation warnings from www (#20378)
-- Add hour and minute to time format on x-axis of all charts using nvd3.lineChart (#20002)
-- Add specific warning when Task asks for more slots than pool defined with (#20178)
-- UI: Update duration column for better human readability (#20112)
-- Use Viewer role as example public role (#19215)
-- Properly implement DAG param dict copying (#20216)
-- ``ShortCircuitOperator`` push XCom by returning python_callable result (#20071)
-- Add clear logging to tasks killed due to a Dagrun timeout (#19950)
-- Change log level for Zombie detection messages (#20204)
-- Better confirmation prompts (#20183)
-- Only execute TIs of running DagRuns (#20182)
-- Check and run migration in commands if necessary (#18439)
-- Log only when Zombies exists (#20118)
-- Increase length of the email and username (#19932)
-- Add more filtering options for TI's in the UI (#19910)
-- Dynamically enable "Test Connection" button by connection type (#19792)
-- Avoid littering postgres server logs with "could not obtain lock" with HA schedulers (#19842)
-- Renamed ``Connection.get_hook`` parameter to make it the same as in ``SqlSensor`` and ``SqlOperator``. (#19849)
-- Add hook_params in SqlSensor using the latest changes from PR #18718. (#18431)
-- Speed up webserver boot time by delaying provider initialization (#19709)
-- Configurable logging of ``XCOM`` value in PythonOperator (#19378)
-- Minimize production js files (#19658)
-- Add ``hook_params`` in ``BaseSqlOperator`` (#18718)
-- Add missing "end_date" to hash components (#19281)
-- More friendly output of the airflow plugins command + add timetables (#19298)
-- Add sensor default timeout config (#19119)
-- Update ``taskinstance`` REST API schema to include dag_run_id field (#19105)
-- Adding feature in bash operator to append the user defined env variable to system env variable (#18944)
-- Duplicate Connection: Added logic to query if a connection id exists before creating one (#18161)
-
-
-Bug Fixes
-^^^^^^^^^
-
-- Use inherited 'trigger_tasks' method (#23016)
-- In DAG dependency detector, use class type instead of class name (#21706)
-- Fix tasks being wrongly skipped by schedule_after_task_execution (#23181)
-- Fix X-Frame enabled behaviour (#23222)
-- Allow ``extra`` to be nullable in connection payload as per schema(REST API). (#23183)
-- Fix ``dag_id`` extraction for dag level access checks in web ui (#23015)
-- Fix timezone display for logs on UI (#23075)
-- Include message in graph errors (#23021)
-- Change trigger dropdown left position (#23013)
-- Don't add planned tasks for legacy DAG runs (#23007)
-- Add dangling rows check for TaskInstance references (#22924)
-- Validate the input params in connection ``CLI`` command (#22688)
-- Fix trigger event payload is not persisted in db (#22944)
-- Drop "airflow moved" tables in command ``db reset`` (#22990)
-- Add max width to task group tooltips (#22978)
-- Add template support for ``external_task_ids``. (#22809)
-- Allow ``DagParam`` to hold falsy values (#22964)
-- Fix regression in pool metrics (#22939)
-- Priority order tasks even when using pools (#22483)
-- Do not clear XCom when resuming from deferral (#22932)
-- Handle invalid JSON metadata in ``get_logs_with_metadata endpoint``. (#22898)
-- Fix pre-upgrade check for rows dangling w.r.t. dag_run (#22850)
-- Fixed backfill interference with scheduler (#22701)
-- Support conf param override for backfill runs (#22837)
-- Correctly interpolate pool name in ``PoolSlotsAvailableDep`` statues (#22807)
-- Fix ``email_on_failure`` with ``render_template_as_native_obj`` (#22770)
-- Fix processor cleanup on ``DagFileProcessorManager`` (#22685)
-- Prevent meta name clash for task instances (#22783)
-- remove json parse for gantt chart (#22780)
-- Check for missing dagrun should know version (#22752)
-- Fixes ``ScheduleInterval`` spec (#22635)
-- Fixing task status for non-running and non-committed tasks (#22410)
-- Do not log the hook connection details even at DEBUG level (#22627)
-- Stop crashing when empty logs are received from kubernetes client (#22566)
-- Fix bugs about timezone change (#22525)
-- Fix entire DAG stops when one task has end_date (#20920)
-- Use logger to print message during task execution. (#22488)
-- Make sure finalizers are not skipped during exception handling (#22475)
-- update smart sensor docs and minor fix on ``is_smart_sensor_compatible()`` (#22386)
-- Fix ``run_id`` k8s and elasticsearch compatibility with Airflow 2.1 (#22385)
-- Allow to ``except_skip`` None on ``BranchPythonOperator`` (#20411)
-- Fix incorrect datetime details (DagRun views) (#21357)
-- Remove incorrect deprecation warning in secrets backend (#22326)
-- Remove ``RefreshConfiguration`` workaround for K8s token refreshing (#20759)
-- Masking extras in GET ``/connections/`` endpoint (#22227)
-- Set ``queued_dttm`` when submitting task to directly to executor (#22259)
-- Addressed some issues in the tutorial mentioned in discussion #22233 (#22236)
-- Change default python executable to python3 for docker decorator (#21973)
-- Don't validate that Params are JSON when NOTSET (#22000)
-- Add per-DAG delete permissions (#21938)
-- Fix handling some None parameters in kubernetes 23 libs. (#21905)
-- Fix handling of empty (None) tags in ``bulk_write_to_db`` (#21757)
-- Fix DAG date range bug (#20507)
-- Removed ``request.referrer`` from views.py (#21751)
-- Make ``DbApiHook`` use ``get_uri`` from Connection (#21764)
-- Fix some migrations (#21670)
-- [de]serialize resources on task correctly (#21445)
-- Add params ``dag_id``, ``task_id`` etc to ``XCom.serialize_value`` (#19505)
-- Update test connection functionality to use custom form fields (#21330)
-- fix all "high" npm vulnerabilities (#21526)
-- Fix bug incorrectly removing action from role, rather than permission. (#21483)
-- Fix relationship join bug in FAB/SecurityManager with SQLA 1.4 (#21296)
-- Use Identity instead of Sequence in SQLAlchemy 1.4 for MSSQL (#21238)
-- Ensure ``on_task_instance_running`` listener can get at task (#21157)
-- Return to the same place when triggering a DAG (#20955)
-- Fix task ID deduplication in ``@task_group`` (#20870)
-- Add downgrade to some FAB migrations (#20874)
-- Only validate Params when DAG is triggered (#20802)
-- Fix ``airflow trigger`` cli (#20781)
-- Fix task instances iteration in a pool to prevent blocking (#20816)
-- Allow depending to a ``@task_group`` as a whole (#20671)
-- Use original task's ``start_date`` if a task continues after deferral (#20062)
-- Disabled edit button in task instances list view page (#20659)
-- Fix a package name import error (#20519) (#20519)
-- Remove ``execution_date`` label when get cleanup pods list (#20417)
-- Remove unneeded FAB REST API endpoints (#20487)
-- Fix parsing of Cloudwatch log group arn containing slashes (#14667) (#19700)
-- Sanity check for MySQL's TIMESTAMP column (#19821)
-- Allow using default celery command group with executors subclassed from Celery-based executors. (#18189)
-- Move ``class_permission_name`` to mixin so it applies to all classes (#18749)
-- Adjust trimmed_pod_id and replace '.' with '-' (#19036)
-- Pass custom_headers to send_email and send_email_smtp (#19009)
-- Ensure ``catchup=False`` is used in example dags (#19396)
-- Edit permalinks in OpenApi description file (#19244)
-- Navigate directly to DAG when selecting from search typeahead list (#18991)
-- [Minor] Fix padding on home page (#19025)
-
-
-Doc only changes
-^^^^^^^^^^^^^^^^
-
-- Update doc for DAG file processing (#23209)
-- Replace changelog/updating with release notes and ``towncrier`` now (#22003)
-- Fix wrong reference in tracking-user-activity.rst (#22745)
-- Remove references to ``rbac = True`` from docs (#22725)
-- Doc: Update description for executor-bound dependencies (#22601)
-- Update check-health.rst (#22372)
-- Stronger language about Docker Compose customizability (#22304)
-- Update logging-tasks.rst (#22116)
-- Add example config of ``sql_alchemy_connect_args`` (#22045)
-- Update best-practices.rst (#22053)
-- Add information on DAG pausing/deactivation/deletion (#22025)
-- Add brief examples of integration test dags you might want (#22009)
-- Run inclusive language check on CHANGELOG (#21980)
-- Add detailed email docs for Sendgrid (#21958)
-- Add docs for ``db upgrade`` / ``db downgrade`` (#21879)
-- Update modules_management.rst (#21889)
-- Fix UPDATING section on SqlAlchemy 1.4 scheme changes (#21887)
-- Update TaskFlow tutorial doc to show how to pass "operator-level" args. (#21446)
-- Fix doc - replace decreasing by increasing (#21805)
-- Add another way to dynamically generate DAGs to docs (#21297)
-- Add extra information about time synchronization needed (#21685)
-- Update debug.rst docs (#21246)
-- Replaces the usage of ``postgres://`` with ``postgresql://`` (#21205)
-- Fix task execution process in ``CeleryExecutor`` docs (#20783)
-
-
-Misc/Internal
-^^^^^^^^^^^^^
-
-- Bring back deprecated security manager functions (#23243)
-- Replace usage of ``DummyOperator`` with ``EmptyOperator`` (#22974)
-- Deprecate ``DummyOperator`` in favor of ``EmptyOperator`` (#22832)
-- Remove unnecessary python 3.6 conditionals (#20549)
-- Bump ``moment`` from 2.29.1 to 2.29.2 in /airflow/www (#22873)
-- Bump ``prismjs`` from 1.26.0 to 1.27.0 in /airflow/www (#22823)
-- Bump ``nanoid`` from 3.1.23 to 3.3.2 in /airflow/www (#22803)
-- Bump ``minimist`` from 1.2.5 to 1.2.6 in /airflow/www (#22798)
-- Remove dag parsing from db init command (#22531)
-- Update our approach for executor-bound dependencies (#22573)
-- Use ``Airflow.Base.metadata`` in FAB models (#22353)
-- Limit docutils to make our documentation pretty again (#22420)
-- Add Python 3.10 support (#22050)
-- [FEATURE] add 1.22 1.23 K8S support (#21902)
-- Remove pandas upper limit now that SQLA is 1.4+ (#22162)
-- Patch ``sql_alchemy_conn`` if old postgres scheme used (#22333)
-- Protect against accidental misuse of XCom.get_value() (#22244)
-- Order filenames for migrations (#22168)
-- Don't try to auto generate migrations for Celery tables (#22120)
-- Require SQLAlchemy 1.4 (#22114)
-- bump sphinx-jinja (#22101)
-- Add compat shim for SQLAlchemy to avoid warnings (#21959)
-- Rename ``xcom.dagrun_id`` to ``xcom.dag_run_id`` (#21806)
-- Deprecate non-JSON ``conn.extra`` (#21816)
-- Bump upper bound version of ``jsonschema`` to 5.0 (#21712)
-- Deprecate helper utility ``days_ago`` (#21653)
-- Remove ```:type``` lines now ``sphinx-autoapi`` supports type hints (#20951)
-- Silence deprecation warning in tests (#20900)
-- Use ``DagRun.run_id`` instead of ``execution_date`` when updating state of TIs (UI & REST API) (#18724)
-- Add Context stub to Airflow packages (#20817)
-- Update Kubernetes library version (#18797)
-- Rename ``PodLauncher`` to ``PodManager`` (#20576)
-- Removes Python 3.6 support (#20467)
-- Add deprecation warning for non-json-serializable params (#20174)
-- Rename TaskMixin to DependencyMixin (#20297)
-- Deprecate passing execution_date to XCom methods (#19825)
-- Remove ``get_readable_dags`` and ``get_editable_dags``, and ``get_accessible_dags``. (#19961)
-- Remove postgres 9.6 support (#19987)
-- Removed hardcoded connection types. Check if hook is instance of DbApiHook. (#19639)
-- add kubernetes 1.21 support (#19557)
-- Add FAB base class and set import_name explicitly. (#19667)
-- Removes unused state transitions to handle auto-changing view permissions. (#19153)
-- Chore: Use enum for ``__var`` and ``__type`` members (#19303)
-- Use fab models (#19121)
-- Consolidate method names between Airflow Security Manager and FAB default (#18726)
-- Remove distutils usages for Python 3.10 (#19064)
-- Removing redundant ``max_tis_per_query`` initialisation on SchedulerJob (#19020)
-- Remove deprecated usage of ``init_role()`` from API (#18820)
-- Remove duplicate code on dbapi hook (#18821)
-
-
-Airflow 2.2.5, (2022-04-04)
----------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-No significant changes.
-
-Bug Fixes
-"""""""""
-- Check and disallow a relative path for sqlite (#22530)
-- Fixed dask executor and tests (#22027)
-- Fix broken links to celery documentation (#22364)
-- Fix incorrect data provided to tries & landing times charts (#21928)
-- Fix assignment of unassigned triggers (#21770)
-- Fix triggerer ``--capacity`` parameter (#21753)
-- Fix graph auto-refresh on page load (#21736)
-- Fix filesystem sensor for directories (#21729)
-- Fix stray ``order_by(TaskInstance.execution_date)`` (#21705)
-- Correctly handle multiple '=' in LocalFileSystem secrets. (#21694)
-- Log exception in local executor (#21667)
-- Disable ``default_pool`` delete on web ui (#21658)
-- Extends ``typing-extensions`` to be installed with python 3.8+ #21566 (#21567)
-- Dispose unused connection pool (#21565)
-- Fix logging JDBC SQL error when task fails (#21540)
-- Filter out default configs when overrides exist. (#21539)
-- Fix Resources ``__eq__`` check (#21442)
-- Fix ``max_active_runs=1`` not scheduling runs when ``min_file_process_interval`` is high (#21413)
-- Reduce DB load incurred by Stale DAG deactivation (#21399)
-- Fix race condition between triggerer and scheduler (#21316)
-- Fix trigger dag redirect from task instance log view (#21239)
-- Log traceback in trigger exceptions (#21213)
-- A trigger might use a connection; make sure we mask passwords (#21207)
-- Update ``ExternalTaskSensorLink`` to handle templated ``external_dag_id`` (#21192)
-- Ensure ``clear_task_instances`` sets valid run state (#21116)
-- Fix: Update custom connection field processing (#20883)
-- Truncate stack trace to DAG user code for exceptions raised during execution (#20731)
-- Fix duplicate trigger creation race condition (#20699)
-- Fix Tasks getting stuck in scheduled state (#19747)
-- Fix: Do not render undefined graph edges (#19684)
-- Set ``X-Frame-Options`` header to DENY only if ``X_FRAME_ENABLED`` is set to true. (#19491)
-
-Doc only changes
-""""""""""""""""
-- adding ``on_execute_callback`` to callbacks docs (#22362)
-- Add documentation on specifying a DB schema. (#22347)
-- Fix postgres part of pipeline example of tutorial (#21586)
-- Extend documentation for states of DAGs & tasks and update trigger rules docs (#21382)
-- DB upgrade is required when updating Airflow (#22061)
-- Remove misleading MSSQL information from the docs (#21998)
-
-Misc
-""""
-- Add the new Airflow Trove Classifier to setup.cfg (#22241)
-- Rename ``to_delete`` to ``to_cancel`` in TriggerRunner (#20658)
-- Update Flask-AppBuilder to ``3.4.5`` (#22596)
-
-Airflow 2.2.4, (2022-02-22)
----------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-Smart sensors deprecated
-""""""""""""""""""""""""
-
-Smart sensors, an "early access" feature added in Airflow 2, are now deprecated and will be removed in Airflow 2.4.0. They have been superseded by Deferrable Operators, added in Airflow 2.2.0.
-
-See `Migrating to Deferrable Operators `_ for details on how to migrate.
-
-Bug Fixes
-^^^^^^^^^
-
-- Adding missing login provider related methods from Flask-Appbuilder (#21294)
-- Fix slow DAG deletion due to missing ``dag_id`` index for job table (#20282)
-- Add a session backend to store session data in the database (#21478)
-- Show task status only for running dags or only for the last finished dag (#21352)
-- Use compat data interval shim in log handlers (#21289)
-- Fix mismatch in generated run_id and logical date of DAG run (#18707)
-- Fix TriggerDagRunOperator extra link (#19410)
-- Add possibility to create user in the Remote User mode (#19963)
-- Avoid deadlock when rescheduling task (#21362)
-- Fix the incorrect scheduling time for the first run of dag (#21011)
-- Fix Scheduler crash when executing task instances of missing DAG (#20349)
-- Deferred tasks does not cancel when DAG is marked fail (#20649)
-- Removed duplicated dag_run join in ``Dag.get_task_instances()`` (#20591)
-- Avoid unintentional data loss when deleting DAGs (#20758)
-- Fix session usage in ``/rendered-k8s`` view (#21006)
-- Fix ``airflow dags backfill --reset-dagruns`` errors when run twice (#21062)
-- Do not set ``TaskInstance.max_tries`` in ``refresh_from_task`` (#21018)
-- Don't require dag_id in body in dagrun REST API endpoint (#21024)
-- Add Roles from Azure OAUTH Response in internal Security Manager (#20707)
-- Allow Viewing DagRuns and TIs if a user has DAG "read" perms (#20663)
-- Fix running ``airflow dags test `` results in error when run twice (#21031)
-- Switch to non-vendored latest connexion library (#20910)
-- Bump flask-appbuilder to ``>=3.3.4`` (#20628)
-- upgrade celery to ``5.2.3`` (#19703)
-- Bump croniter from ``<1.1`` to ``<1.2`` (#20489)
-- Avoid calling ``DAG.following_schedule()`` for ``TaskInstance.get_template_context()`` (#20486)
-- Fix(standalone): Remove hardcoded Webserver port (#20429)
-- Remove unnecessary logging in experimental API (#20356)
-- Un-ignore DeprecationWarning (#20322)
-- Deepcopying Kubernetes Secrets attributes causing issues (#20318)
-- Fix(dag-dependencies): fix arrow styling (#20303)
-- Adds retry on taskinstance retrieval lock (#20030)
-- Correctly send timing metrics when using dogstatsd (fix schedule_delay metric) (#19973)
-- Enhance ``multiple_outputs`` inference of dict typing (#19608)
-- Fixing Amazon SES email backend (#18042)
-- Pin MarkupSafe until we are able to upgrade Flask/Jinja (#21664)
-
-Doc only changes
-^^^^^^^^^^^^^^^^
-
-- Added explaining concept of logical date in DAG run docs (#21433)
-- Add note about Variable precedence with env vars (#21568)
-- Update error docs to include before_send option (#21275)
-- Augment xcom docs (#20755)
-- Add documentation and release policy on "latest" constraints (#21093)
-- Add a link to the DAG model in the Python API reference (#21060)
-- Added an enum param example (#20841)
-- Compare taskgroup and subdag (#20700)
-- Add note about reserved ``params`` keyword (#20640)
-- Improve documentation on ``Params`` (#20567)
-- Fix typo in MySQL Database creation code (Set up DB docs) (#20102)
-- Add requirements.txt description (#20048)
-- Clean up ``default_args`` usage in docs (#19803)
-- Add docker-compose explanation to conn localhost (#19076)
-- Update CSV ingest code for tutorial (#18960)
-- Adds Pendulum 1.x -> 2.x upgrade documentation (#18955)
-- Clean up dynamic ``start_date`` values from docs (#19607)
-- Docs for multiple pool slots (#20257)
-- Update upgrading.rst with detailed code example of how to resolve post-upgrade warning (#19993)
-
-Misc
-^^^^
-
-- Deprecate some functions in the experimental API (#19931)
-- Deprecate smart sensors (#20151)
-
-Airflow 2.2.3, (2021-12-21)
----------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-No significant changes.
-
-Bug Fixes
-^^^^^^^^^
-
-- Lazy Jinja2 context (#20217)
-- Exclude ``snowflake-sqlalchemy`` v1.2.5 (#20245)
-- Move away from legacy ``importlib.resources`` API (#19091)
-- Move ``setgid`` as the first command executed in forked task runner (#20040)
-- Fix race condition when starting ``DagProcessorAgent`` (#19935)
-- Limit ``httpx`` to <0.20.0 (#20218)
-- Log provider import errors as debug warnings (#20172)
-- Bump minimum required ``alembic`` version (#20153)
-- Fix log link in gantt view (#20121)
-- fixing #19028 by moving chown to use sudo (#20114)
-- Lift off upper bound for ``MarkupSafe`` (#20113)
-- Fix infinite recursion on redact log (#20039)
-- Fix db downgrades (#19994)
-- Context class handles deprecation (#19886)
-- Fix possible reference to undeclared variable (#19933)
-- Validate ``DagRun`` state is valid on assignment (#19898)
-- Workaround occasional deadlocks with MSSQL (#19856)
-- Enable task run setting to be able reinitialize (#19845)
-- Fix log endpoint for same task (#19672)
-- Cast macro datetime string inputs explicitly (#19592)
-- Do not crash with stacktrace when task instance is missing (#19478)
-- Fix log timezone in task log view (#19342) (#19401)
-- Fix: Add taskgroup tooltip to graph view (#19083)
-- Rename execution date in forms and tables (#19063)
-- Simplify "invalid TI state" message (#19029)
-- Handle case of nonexistent file when preparing file path queue (#18998)
-- Do not create dagruns for DAGs with import errors (#19367)
-- Fix field relabeling when switching between conn types (#19411)
-- ``KubernetesExecutor`` should default to template image if used (#19484)
-- Fix task instance api cannot list task instances with ``None`` state (#19487)
-- Fix IntegrityError in ``DagFileProcessor.manage_slas`` (#19553)
-- Declare data interval fields as serializable (#19616)
-- Relax timetable class validation (#19878)
-- Fix labels used to find queued ``KubernetesExecutor`` pods (#19904)
-- Fix moved data migration check for MySQL when replication is used (#19999)
-
-Doc only changes
-^^^^^^^^^^^^^^^^
-
-- Warn without tracebacks when example_dags are missing deps (#20295)
-- Deferrable operators doc clarification (#20150)
-- Ensure the example DAGs are all working (#19355)
-- Updating core example DAGs to use TaskFlow API where applicable (#18562)
-- Add xcom clearing behaviour on task retries (#19968)
-- Add a short chapter focusing on adapting secret format for connections (#19859)
-- Add information about supported OS-es for Apache Airflow (#19855)
-- Update docs to reflect that changes to the ``base_log_folder`` require updating other configs (#19793)
-- Disclaimer in ``KubernetesExecutor`` pod template docs (#19686)
-- Add upgrade note on ``execution_date`` -> ``run_id`` (#19593)
-- Expanding ``.output`` operator property information in TaskFlow tutorial doc (#19214)
-- Add example SLA DAG (#19563)
-- Add a proper example to patch DAG (#19465)
-- Add DAG file processing description to Scheduler Concepts (#18954)
-- Updating explicit arg example in TaskFlow API tutorial doc (#18907)
-- Adds back documentation about context usage in Python/@task (#18868)
-- Add release date for when an endpoint/field is added in the REST API (#19203)
-- Better ``pod_template_file`` examples (#19691)
-- Add description on how you can customize image entrypoint (#18915)
-- Dags-in-image pod template example should not have dag mounts (#19337)
-
-Airflow 2.2.2 (2021-11-15)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-No significant changes.
-
-Bug Fixes
-^^^^^^^^^
-
-- Fix bug when checking for existence of a Variable (#19395)
-- Fix Serialization when ``relativedelta`` is passed as ``schedule_interval`` (#19418)
-- Fix moving of dangling TaskInstance rows for SQL Server (#19425)
-- Fix task instance modal in gantt view (#19258)
-- Fix serialization of ``Params`` with set data type (#19267)
-- Check if job object is ``None`` before calling ``.is_alive()`` (#19380)
-- Task should fail immediately when pod is unprocessable (#19359)
-- Fix downgrade for a DB Migration (#19390)
-- Only mark SchedulerJobs as failed, not any jobs (#19375)
-- Fix message on "Mark as" confirmation page (#19363)
-- Bugfix: Check next run exists before reading data interval (#19307)
-- Fix MySQL db migration with default encoding/collation (#19268)
-- Fix hidden tooltip position (#19261)
-- ``sqlite_default`` Connection has been hard-coded to ``/tmp``, use ``gettempdir`` instead (#19255)
-- Fix Toggle Wrap on DAG code page (#19211)
-- Clarify "dag not found" error message in CLI (#19338)
-- Add Note to SLA regarding ``schedule_interval`` (#19173)
-- Use ``execution_date`` to check for existing ``DagRun`` for ``TriggerDagRunOperator`` (#18968)
-- Add explicit session parameter in ``PoolSlotsAvailableDep`` (#18875)
-- FAB still requires ``WTForms<3.0`` (#19466)
-- Fix missing dagruns when ``catchup=True`` (#19528)
-
-Doc only changes
-^^^^^^^^^^^^^^^^
-
-- Add missing parameter documentation for "timetable" (#19282)
-- Improve Kubernetes Executor docs (#19339)
-- Update image tag used in docker docs
-
-Airflow 2.2.1 (2021-10-29)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-``Param``'s default value for ``default`` removed
-"""""""""""""""""""""""""""""""""""""""""""""""""
-
-``Param``, introduced in Airflow 2.2.0, accidentally set the default value to ``None``. This default has been removed. If you want ``None`` as your default, explicitly set it as such. For example:
-
-.. code-block:: python
-
- Param(None, type=["null", "string"])
-
-Now if you resolve a ``Param`` without a default and don't pass a value, you will get an ``TypeError``. For Example:
-
-.. code-block:: python
-
- Param().resolve() # raises TypeError
-
-``max_queued_runs_per_dag`` configuration has been removed
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-The ``max_queued_runs_per_dag`` configuration option in ``[core]`` section has been removed. Previously, this controlled the number of queued dagrun
-the scheduler can create in a dag. Now, the maximum number is controlled internally by the DAG's ``max_active_runs``
-
-Bug Fixes
-^^^^^^^^^
-
-- Fix Unexpected commit error in SchedulerJob (#19213)
-- Add DagRun.logical_date as a property (#19198)
-- Clear ``ti.next_method`` and ``ti.next_kwargs`` on task finish (#19183)
-- Faster PostgreSQL db migration to Airflow 2.2 (#19166)
-- Remove incorrect type comment in ``Swagger2Specification._set_defaults`` classmethod (#19065)
-- Add TriggererJob to jobs check command (#19179, #19185)
-- Hide tooltip when next run is ``None`` (#19112)
-- Create TI context with data interval compat layer (#19148)
-- Fix queued dag runs changes ``catchup=False`` behaviour (#19130, #19145)
-- add detailed information to logging when a dag or a task finishes. (#19097)
-- Warn about unsupported Python 3.10 (#19060)
-- Fix catchup by limiting queued dagrun creation using ``max_active_runs`` (#18897)
-- Prevent scheduler crash when serialized dag is missing (#19113)
-- Don't install SQLAlchemy/Pendulum adapters for other DBs (#18745)
-- Workaround ``libstdcpp`` TLS error (#19010)
-- Change ``ds``, ``ts``, etc. back to use logical date (#19088)
-- Ensure task state doesn't change when marked as failed/success/skipped (#19095)
-- Relax packaging requirement (#19087)
-- Rename trigger page label to Logical Date (#19061)
-- Allow Param to support a default value of ``None`` (#19034)
-- Upgrade old DAG/task param format when deserializing from the DB (#18986)
-- Don't bake ENV and _cmd into tmp config for non-sudo (#18772)
-- CLI: Fail ``backfill`` command before loading DAGs if missing args (#18994)
-- BugFix: Null execution date on insert to ``task_fail`` violating NOT NULL (#18979)
-- Try to move "dangling" rows in db upgrade (#18953)
-- Row lock TI query in ``SchedulerJob._process_executor_events`` (#18975)
-- Sentry before send fallback (#18980)
-- Fix ``XCom.delete`` error in Airflow 2.2.0 (#18956)
-- Check python version before starting triggerer (#18926)
-
-Doc only changes
-^^^^^^^^^^^^^^^^
-
-- Update access control documentation for TaskInstances and DagRuns (#18644)
-- Add information about keepalives for managed Postgres (#18850)
-- Doc: Add Callbacks Section to Logging & Monitoring (#18842)
-- Group PATCH DAGrun together with other DAGRun endpoints (#18885)
-
-Airflow 2.2.0 (2021-10-11)
---------------------------
-
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
-
-Note: Upgrading the database to ``2.2.0`` or later can take some time to complete, particularly if you have a large ``task_instance`` table.
+- **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).
-``worker_log_server_port`` configuration has been moved to the ``logging`` section.
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+- **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).
-The ``worker_log_server_port`` configuration option has been moved from ``[celery]`` section to ``[logging]`` section to allow for reuse between different executors.
+- **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.
-``pandas`` is now an optional dependency
-""""""""""""""""""""""""""""""""""""""""""""
+- **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.
-Previously ``pandas`` was a core requirement so when you run ``pip install apache-airflow`` it looked for ``pandas``
-library and installed it if it does not exist.
+- **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).
-If you want to install ``pandas`` compatible with Airflow, you can use ``[pandas]`` extra while
-installing Airflow, example for Python 3.8 and Airflow 2.1.2:
+- **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.
-.. code-block:: shell
-
- pip install -U "apache-airflow[pandas]==2.1.2" \
- --constraint https://raw.githubusercontent.com/apache/airflow/constraints-2.1.2/constraints-3.8.txt"
-
-``none_failed_or_skipped`` trigger rule has been deprecated
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``TriggerRule.NONE_FAILED_OR_SKIPPED`` is replaced by ``TriggerRule.NONE_FAILED_MIN_ONE_SUCCESS``.
-This is only name change, no functionality changes made.
-This change is backward compatible however ``TriggerRule.NONE_FAILED_OR_SKIPPED`` will be removed in next major release.
+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.
-Dummy trigger rule has been deprecated
+Task Execution API & Task SDK (AIP-72)
""""""""""""""""""""""""""""""""""""""
-``TriggerRule.DUMMY`` is replaced by ``TriggerRule.ALWAYS``.
-This is only name change, no functionality changes made.
-This change is backward compatible however ``TriggerRule.DUMMY`` will be removed in next major release.
-
-DAG concurrency settings have been renamed
-""""""""""""""""""""""""""""""""""""""""""
-
-``[core] dag_concurrency`` setting in ``airflow.cfg`` has been renamed to ``[core] max_active_tasks_per_dag``
-for better understanding.
-
-It is the maximum number of task instances allowed to run concurrently in each DAG. To calculate
-the number of tasks that is running concurrently for a DAG, add up the number of running
-tasks for all DAG runs of the DAG.
-
-This is configurable at the DAG level with ``max_active_tasks`` and a default can be set in ``airflow.cfg`` as
-``[core] max_active_tasks_per_dag``.
-
-**Before**\ :
-
-.. code-block:: ini
-
- [core]
- dag_concurrency = 16
-
-**Now**\ :
-
-.. code-block:: ini
-
- [core]
- max_active_tasks_per_dag = 16
-
-Similarly, ``DAG.concurrency`` has been renamed to ``DAG.max_active_tasks``.
+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.
-**Before**\ :
+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.
-.. code-block:: python
-
- dag = DAG(
- dag_id="example_dag",
- start_date=datetime(2021, 1, 1),
- catchup=False,
- concurrency=3,
- )
-
-**Now**\ :
-
-.. code-block:: python
-
- dag = DAG(
- dag_id="example_dag",
- start_date=datetime(2021, 1, 1),
- catchup=False,
- max_active_tasks=3,
- )
+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.
-If you are using DAGs Details API endpoint, use ``max_active_tasks`` instead of ``concurrency``.
+Edge Executor (AIP-69)
+""""""""""""""""""""""
-Task concurrency parameter has been renamed
-"""""""""""""""""""""""""""""""""""""""""""
+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.
-``BaseOperator.task_concurrency`` has been deprecated and renamed to ``max_active_tis_per_dag`` for
-better understanding.
+Scheduler-Managed Backfills (AIP-78)
+""""""""""""""""""""""""""""""""""""
-This parameter controls the number of concurrent running task instances across ``dag_runs``
-per task.
+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.
-**Before**\ :
+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.
-.. code-block:: python
+DAG Versioning (AIP-66)
+"""""""""""""""""""""""
- with DAG(dag_id="task_concurrency_example"):
- BashOperator(task_id="t1", task_concurrency=2, bash_command="echo Hi")
+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.
-**After**\ :
+React UI Rewrite (AIP-38, AIP-84)
+"""""""""""""""""""""""""""""""""
-.. code-block:: python
+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.
- with DAG(dag_id="task_concurrency_example"):
- BashOperator(task_id="t1", max_active_tis_per_dag=2, bash_command="echo Hi")
+The new UI replaces the legacy Flask-based frontend and introduces a foundation for future extensibility and community
+contributions.
-``processor_poll_interval`` config have been renamed to ``scheduler_idle_sleep_time``
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Asset-Based Scheduling & Terminology Alignment (AIP-74, AIP-75)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-``[scheduler] processor_poll_interval`` setting in ``airflow.cfg`` has been renamed to ``[scheduler] scheduler_idle_sleep_time``
-for better understanding.
+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.
-It controls the 'time to sleep' at the end of the Scheduler loop if nothing was scheduled inside ``SchedulerJob``.
+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.
-**Before**\ :
+This renaming impacts modules, classes, functions, configuration keys, and internal models. Key changes include:
-.. code-block:: ini
+- ``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``
- [scheduler]
- processor_poll_interval = 16
+Unified Scheduling Field
+""""""""""""""""""""""""
-**Now**\ :
+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.
-.. code-block:: ini
+Updated Scheduling Defaults
+"""""""""""""""""""""""""""
- [scheduler]
- scheduler_idle_sleep_time = 16
+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.
-Marking success/failed automatically clears failed downstream tasks
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+The default DAG schedule has been changed to ``None`` from ``@once``.
-When marking a task success/failed in Graph View, its downstream tasks that are in failed/upstream_failed state are automatically cleared.
+Restricted Metadata Database Access
+"""""""""""""""""""""""""""""""""""
-``[core] store_dag_code`` has been removed
-""""""""""""""""""""""""""""""""""""""""""""""
+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.
-While DAG Serialization is a strict requirements since Airflow 2, we allowed users to control
-where the Webserver looked for when showing the **Code View**.
+Future Logical Dates No Longer Supported
+"""""""""""""""""""""""""""""""""""""""""
-If ``[core] store_dag_code`` was set to ``True``\ , the Scheduler stored the code in the DAG file in the
-DB (in ``dag_code`` table) as a plain string, and the webserver just read it from the same table.
-If the value was set to ``False``\ , the webserver read it from the DAG file.
+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.
-While this setting made sense for Airflow < 2, it caused some confusion to some users where they thought
-this setting controlled DAG Serialization.
+Context Behavior for Asset and Manually Triggered DAGs
+""""""""""""""""""""""""""""""""""""""""""""""""""""""
-From Airflow 2.2, Airflow will only look for DB when a user clicks on **Code View** for a DAG.
+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``.
-Clearing a running task sets its state to ``RESTARTING``
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+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.
-Previously, clearing a running task sets its state to ``SHUTDOWN``. The task gets killed and goes into ``FAILED`` state. After `#16681 `_\ , clearing a running task sets its state to ``RESTARTING``. The task is eligible for retry without going into ``FAILED`` state.
+Improved Callback Behavior
+""""""""""""""""""""""""""
-Remove ``TaskInstance.log_filepath`` attribute
-""""""""""""""""""""""""""""""""""""""""""""""""""
+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.
-This method returned incorrect values for a long time, because it did not take into account the different
-logger configuration and task retries. We have also started supporting more advanced tools that don't use
-files, so it is impossible to determine the correct file path in every case e.g. Stackdriver doesn't use files
-but identifies logs based on labels. For this reason, we decided to delete this attribute.
+Updated Default Configuration
+"""""""""""""""""""""""""""""
-If you need to read logs, you can use ``airflow.utils.log.log_reader.TaskLogReader`` class, which does not have
-the above restrictions.
+Several default configuration values have been updated in Airflow 3.0 to better reflect modern usage patterns and
+simplify onboarding:
-If a sensor times out, it will not retry
-""""""""""""""""""""""""""""""""""""""""
+- ``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``.
-Previously, a sensor is retried when it times out until the number of ``retries`` are exhausted. So the effective timeout of a sensor is ``timeout * (retries + 1)``. This behaviour is now changed. A sensor will immediately fail without retrying if ``timeout`` is reached. If it's desirable to let the sensor continue running for longer time, set a larger ``timeout`` instead.
+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.
-Default Task Pools Slots can be set using ``[core] default_pool_task_slot_count``
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Executor & Scheduler Updates
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-By default tasks are running in ``default_pool``. ``default_pool`` is initialized with ``128`` slots and user can change the
-number of slots through UI/CLI/API for an existing deployment.
+Airflow 3.0 introduces several important improvements and behavior changes in how DAGs and tasks are scheduled,
+prioritized, and executed.
-For new deployments, you can use ``default_pool_task_slot_count`` setting in ``[core]`` section. This setting would
-not have any effect in an existing deployment where the ``default_pool`` already exists.
+Standalone DAG Processor Required
+"""""""""""""""""""""""""""""""""
-Previously this was controlled by ``non_pooled_task_slot_count`` in ``[core]`` section, which was not documented.
+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.
-Webserver DAG refresh buttons removed
+Priority Weight Capped by Pool Slots
"""""""""""""""""""""""""""""""""""""
-Now that the DAG parser syncs DAG permissions there is no longer a need for manually refreshing DAGs. As such, the buttons to refresh a DAG have been removed from the UI.
-
-In addition, the ``/refresh`` and ``/refresh_all`` webserver endpoints have also been removed.
-
-TaskInstances now *require* a DagRun
-""""""""""""""""""""""""""""""""""""""""
+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.
-Under normal operation every TaskInstance row in the database would have DagRun row too, but it was possible to manually delete the DagRun and Airflow would still schedule the TaskInstances.
+Teardown Task Handling During DAG Termination
+"""""""""""""""""""""""""""""""""""""""""""""
-In Airflow 2.2 we have changed this and now there is a database-level foreign key constraint ensuring that every TaskInstance has a DagRun row.
+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.
-Before updating to this 2.2 release you will have to manually resolve any inconsistencies (add back DagRun rows, or delete TaskInstances) if you have any "dangling" TaskInstance" rows.
+Improved Scheduler Fault Tolerance
+""""""""""""""""""""""""""""""""""
-As part of this change the ``clean_tis_without_dagrun_interval`` config option under ``[scheduler]`` section has been removed and has no effect.
+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.
-TaskInstance and TaskReschedule now define ``run_id`` instead of ``execution_date``
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Mapped Task Stats Accuracy
+"""""""""""""""""""""""""""
-As a part of the TaskInstance-DagRun relation change, the ``execution_date`` columns on TaskInstance and TaskReschedule have been removed from the database, and replaced by `association proxy `_ fields at the ORM level. If you access Airflow's metadatabase directly, you should rewrite the implementation to use the ``run_id`` columns instead.
+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.
-Note that Airflow's metadatabase definition on both the database and ORM levels are considered implementation detail without strict backward compatibility guarantees.
+``SequentialExecutor`` has been removed
+"""""""""""""""""""""""""""""""""""""""
-DaskExecutor - Dask Worker Resources and queues
-"""""""""""""""""""""""""""""""""""""""""""""""
+``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.
-If dask workers are not started with complementary resources to match the specified queues, it will now result in an ``AirflowException``\ , whereas before it would have just ignored the ``queue`` argument.
+DAG Authoring Enhancements
+^^^^^^^^^^^^^^^^^^^^^^^^^^
-Logical date of a DAG run triggered from the web UI now have its sub-second component set to zero
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Airflow 3.0 includes several changes that improve consistency, clarity, and long-term stability for DAG authors.
-Due to a change in how the logical date (``execution_date``) is generated for a manual DAG run, a manual DAG run's logical date may not match its time-of-trigger, but have its sub-second part zero-ed out. For example, a DAG run triggered on ``2021-10-11T12:34:56.78901`` would have its logical date set to ``2021-10-11T12:34:56.00000``.
+New Stable DAG Authoring Interface: ``airflow.sdk``
+"""""""""""""""""""""""""""""""""""""""""""""""""""
-This may affect some logic that expects on this quirk to detect whether a run is triggered manually or not. Note that ``dag_run.run_type`` is a more authoritative value for this purpose. Also, if you need this distinction between automated and manually-triggered run for "next execution date" calculation, please also consider using the new data interval variables instead, which provide a more consistent behavior between the two run types.
+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:
-New Features
-^^^^^^^^^^^^
+.. code-block:: python
-- AIP-39: Add (customizable) Timetable class to Airflow for richer scheduling behaviour (#15397, #16030,
- #16352, #17030, #17122, #17414, #17552, #17755, #17989, #18084, #18088, #18244, #18266, #18420, #18434,
- #18421, #18475, #18499, #18573, #18522, #18729, #18706, #18742, #18786, #18804)
-- AIP-40: Add Deferrable "Async" Tasks (#15389, #17564, #17565, #17601, #17745, #17747, #17748, #17875,
- #17876, #18129, #18210, #18214, #18552, #18728, #18414)
-- Add a Docker Taskflow decorator (#15330, #18739)
-- Add Airflow Standalone command (#15826)
-- Display alert messages on dashboard from local settings (#18284)
-- Advanced Params using json-schema (#17100)
-- Ability to test connections from UI or API (#15795, #18750)
-- Add Next Run to UI (#17732)
-- Add default weight rule configuration option (#18627)
-- Add a calendar field to choose the execution date of the DAG when triggering it (#16141)
-- Allow setting specific ``cwd`` for BashOperator (#17751)
-- Show import errors in DAG views (#17818)
-- Add pre/post execution hooks [Experimental] (#17576)
-- Added table to view providers in Airflow ui under admin tab (#15385)
-- Adds secrets backend/logging/auth information to provider yaml (#17625)
-- Add date format filters to Jinja environment (#17451)
-- Introduce ``RESTARTING`` state (#16681)
-- Webserver: Unpause DAG on manual trigger (#16569)
-- API endpoint to create new user (#16609)
-- Add ``insert_args`` for support transfer replace (#15825)
-- Add recursive flag to glob in filesystem sensor (#16894)
-- Add conn to jinja template context (#16686)
-- Add ``default_args`` for ``TaskGroup`` (#16557)
-- Allow adding duplicate connections from UI (#15574)
-- Allow specifying multiple URLs via the CORS config option (#17941)
-- Implement API endpoint for DAG deletion (#17980)
-- Add DAG run endpoint for marking a dagrun success or failed(#17839)
-- Add support for ``kinit`` options ``[-f|-F]`` and ``[-a|-A]`` (#17816)
-- Queue support for ``DaskExecutor`` using Dask Worker Resources (#16829, #18720)
-- Make auto refresh interval configurable (#18107)
+ # Old (Airflow 2.x)
+ from airflow.models import DAG
+ from airflow.decorators import task
-Improvements
-^^^^^^^^^^^^
+ # New (Airflow 3.x)
+ from airflow.sdk import DAG, task
-- Small improvements for Airflow UI (#18715, #18795)
-- Rename ``processor_poll_interval`` to ``scheduler_idle_sleep_time`` (#18704)
-- Check the allowed values for the logging level (#18651)
-- Fix error on triggering a dag that doesn't exist using ``dagrun_conf`` (#18655)
-- Add muldelete action to ``TaskInstanceModelView`` (#18438)
-- Avoid importing DAGs during clean DB installation (#18450)
-- Require can_edit on DAG privileges to modify TaskInstances and DagRuns (#16634)
-- Make Kubernetes job description fit on one log line (#18377)
-- Always draw borders if task instance state is null or undefined (#18033)
-- Inclusive Language (#18349)
-- Improved log handling for zombie tasks (#18277)
-- Adding ``Variable.update`` method and improving detection of variable key collisions (#18159)
-- Add note about params on trigger DAG page (#18166)
-- Change ``TaskInstance`` and ``TaskReschedule`` PK from ``execution_date`` to ``run_id`` (#17719)
-- Adding ``TaskGroup`` support in ``BaseOperator.chain()`` (#17456)
-- Allow filtering DAGS by tags in the REST API (#18090)
-- Optimize imports of Providers Manager (#18052)
-- Adds capability of Warnings for incompatible community providers (#18020)
-- Serialize the ``template_ext`` attribute to show it in UI (#17985)
-- Add ``robots.txt`` and ``X-Robots-Tag`` header (#17946)
-- Refactor ``BranchDayOfWeekOperator``, ``DayOfWeekSensor`` (#17940)
-- Update error message to guide the user into self-help mostly (#17929)
-- Update to Celery 5 (#17397)
-- Add links to provider's documentation (#17736)
-- Remove Marshmallow schema warnings (#17753)
-- Rename ``none_failed_or_skipped`` by ``none_failed_min_one_success`` trigger rule (#17683)
-- Remove ``[core] store_dag_code`` & use DB to get Dag Code (#16342)
-- Rename ``task_concurrency`` to ``max_active_tis_per_dag`` (#17708)
-- Import Hooks lazily individually in providers manager (#17682)
-- Adding support for multiple task-ids in the external task sensor (#17339)
-- Replace ``execution_date`` with ``run_id`` in airflow tasks run command (#16666)
-- Make output from users cli command more consistent (#17642)
-- Open relative extra links in place (#17477)
-- Move ``worker_log_server_port`` option to the logging section (#17621)
-- Use gunicorn to serve logs generated by worker (#17591)
-- Improve validation of Group id (#17578)
-- Simplify 404 page (#17501)
-- Add XCom.clear so it's hookable in custom XCom backend (#17405)
-- Add deprecation notice for ``SubDagOperator`` (#17488)
-- Support DAGS folder being in different location on scheduler and runners (#16860)
-- Remove /dagrun/create and disable edit form generated by F.A.B (#17376)
-- Enable specifying dictionary paths in ``template_fields_renderers`` (#17321)
-- error early if virtualenv is missing (#15788)
-- Handle connection parameters added to Extra and custom fields (#17269)
-- Fix ``airflow celery stop`` to accept the pid file. (#17278)
-- Remove DAG refresh buttons (#17263)
-- Deprecate dummy trigger rule in favor of always (#17144)
-- Be verbose about failure to import ``airflow_local_settings`` (#17195)
-- Include exit code in ``AirflowException`` str when ``BashOperator`` fails. (#17151)
-- Adding EdgeModifier support for chain() (#17099)
-- Only allows supported field types to be used in custom connections (#17194)
-- Secrets backend failover (#16404)
-- Warn on Webserver when using ``SQLite`` or ``SequentialExecutor`` (#17133)
-- Extend ``init_containers`` defined in ``pod_override`` (#17537)
-- Client-side filter dag dependencies (#16253)
-- Improve executor validation in CLI (#17071)
-- Prevent running ``airflow db init/upgrade`` migrations and setup in parallel. (#17078)
-- Update ``chain()`` and ``cross_downstream()`` to support ``XComArgs`` (#16732)
-- Improve graph view refresh (#16696)
-- When a task instance fails with exception, log it (#16805)
-- Set process title for ``serve-logs`` and ``LocalExecutor`` (#16644)
-- Rename ``test_cycle`` to ``check_cycle`` (#16617)
-- Add schema as ``DbApiHook`` instance attribute (#16521, #17423)
-- Improve compatibility with MSSQL (#9973)
-- Add transparency for unsupported connection type (#16220)
-- Call resource based fab methods (#16190)
-- Format more dates with timezone (#16129)
-- Replace deprecated ``dag.sub_dag`` with ``dag.partial_subset`` (#16179)
-- Treat ``AirflowSensorTimeout`` as immediate failure without retrying (#12058)
-- Marking success/failed automatically clears failed downstream tasks (#13037)
-- Add close/open indicator for import dag errors (#16073)
-- Add collapsible import errors (#16072)
-- Always return a response in TI's ``action_clear`` view (#15980)
-- Add cli command to delete user by email (#15873)
-- Use resource and action names for FAB permissions (#16410)
-- Rename DAG concurrency (``[core] dag_concurrency``) settings for easier understanding (#16267, #18730)
-- Calendar UI improvements (#16226)
-- Refactor: ``SKIPPED`` should not be logged again as ``SUCCESS`` (#14822)
-- Remove version limits for ``dnspython`` (#18046, #18162)
-- Accept custom run ID in TriggerDagRunOperator (#18788)
+Renamed Parameter: ``fail_stop`` → ``fail_fast``
+"""""""""""""""""""""""""""""""""""""""""""""""""
-Bug Fixes
-^^^^^^^^^
+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.
-- Make REST API patch user endpoint work the same way as the UI (#18757)
-- Properly set ``start_date`` for cleared tasks (#18708)
-- Ensure task_instance exists before running update on its state(REST API) (#18642)
-- Make ``AirflowDateTimePickerWidget`` a required field (#18602)
-- Retry deadlocked transactions on deleting old rendered task fields (#18616)
-- Fix ``retry_exponential_backoff`` divide by zero error when retry delay is zero (#17003)
-- Improve how UI handles datetimes (#18611, #18700)
-- Bugfix: dag_bag.get_dag should return None, not raise exception (#18554)
-- Only show the task modal if it is a valid instance (#18570)
-- Fix accessing rendered ``{{ task.x }}`` attributes from within templates (#18516)
-- Add missing email type of connection (#18502)
-- Don't use flash for "same-page" UI messages. (#18462)
-- Fix task group tooltip (#18406)
-- Properly fix dagrun update state endpoint (#18370)
-- Properly handle ti state difference between executor and scheduler (#17819)
-- Fix stuck "queued" tasks in KubernetesExecutor (#18152)
-- Don't permanently add zip DAGs to ``sys.path`` (#18384)
-- Fix random deadlocks in MSSQL database (#18362)
-- Deactivating DAGs which have been removed from files (#17121)
-- When syncing dags to db remove ``dag_tag`` rows that are now unused (#8231)
-- Graceful scheduler shutdown on error (#18092)
-- Fix mini scheduler not respecting ``wait_for_downstream`` dep (#18338)
-- Pass exception to ``run_finished_callback`` for Debug Executor (#17983)
-- Make ``XCom.get_one`` return full, not abbreviated values (#18274)
-- Use try/except when closing temporary file in task_runner (#18269)
-- show next run if not none (#18273)
-- Fix DB session handling in ``XCom.set`` (#18240)
-- Fix external_executor_id not being set for manually run jobs (#17207)
-- Fix deleting of zipped Dags in Serialized Dag Table (#18243)
-- Return explicit error on user-add for duplicated email (#18224)
-- Remove loading dots even when last run data is empty (#18230)
-- Swap dag import error dropdown icons (#18207)
-- Automatically create section when migrating config (#16814)
-- Set encoding to utf-8 by default while reading task logs (#17965)
-- Apply parent dag permissions to subdags (#18160)
-- Change id collation for MySQL to case-sensitive (#18072)
-- Logs task launch exception in ``StandardTaskRunner`` (#17967)
-- Applied permissions to ``self._error_file`` (#15947)
-- Fix blank dag dependencies view (#17990)
-- Add missing menu access for dag dependencies and configurations pages (#17450)
-- Fix passing Jinja templates in ``DateTimeSensor`` (#17959)
-- Fixing bug which restricted the visibility of ImportErrors (#17924)
-- Fix grammar in ``traceback.html`` (#17942)
-- Fix ``DagRunState`` enum query for ``MySQLdb`` driver (#17886)
-- Fixed button size in "Actions" group. (#17902)
-- Only show import errors for DAGs a user can access (#17835)
-- Show all import_errors from zip files (#17759)
-- fix EXTRA_LOGGER_NAMES param and related docs (#17808)
-- Use one interpreter for Airflow and gunicorn (#17805)
-- Fix: Mysql 5.7 id utf8mb3 (#14535)
-- Fix dag_processing.last_duration metric random holes (#17769)
-- Automatically use ``utf8mb3_general_ci`` collation for MySQL (#17729)
-- fix: filter condition of ``TaskInstance`` does not work #17535 (#17548)
-- Dont use TaskInstance in CeleryExecutor.trigger_tasks (#16248)
-- Remove locks for upgrades in MSSQL (#17213)
-- Create virtualenv via python call (#17156)
-- Ensure a DAG is acyclic when running ``DAG.cli()`` (#17105)
-- Translate non-ascii characters (#17057)
-- Change the logic of ``None`` comparison in ``model_list`` template (#16893)
-- Have UI and POST /task_instances_state API endpoint have same behaviour (#16539)
-- ensure task is skipped if missing sla (#16719)
-- Fix direct use of ``cached_property`` module (#16710)
-- Fix TI success confirm page (#16650)
-- Modify return value check in python virtualenv jinja template (#16049)
-- Fix dag dependency search (#15924)
-- Make custom JSON encoder support ``Decimal`` (#16383)
-- Bugfix: Allow clearing tasks with just ``dag_id`` and empty ``subdir`` (#16513)
-- Convert port value to a number before calling test connection (#16497)
-- Handle missing/null serialized DAG dependencies (#16393)
-- Correctly set ``dag.fileloc`` when using the ``@dag`` decorator (#16384)
-- Fix TI success/failure links (#16233)
-- Correctly implement autocomplete early return in ``airflow/www/views.py`` (#15940)
-- Backport fix to allow pickling of Loggers to Python 3.6 (#18798)
-- Fix bug that Backfill job fail to run when there are tasks run into ``reschedule`` state (#17305, #18806)
+Context Cleanup and Parameter Removal
+"""""""""""""""""""""""""""""""""""""
-Doc only changes
-^^^^^^^^^^^^^^^^
+Several legacy context variables have been removed or may no longer be available in certain types of DAG runs,
+including:
-- Update ``dagbag_size`` documentation (#18824)
-- Update documentation about bundle extras (#18828)
-- Fix wrong Postgres ``search_path`` set up instructions (#17600)
-- Remove ``AIRFLOW_GID`` from Docker images (#18747)
-- Improve error message for BranchPythonOperator when no task_id to follow (#18471)
-- Improve guidance to users telling them what to do on import timeout (#18478)
-- Explain scheduler fine-tuning better (#18356)
-- Added example JSON for airflow pools import (#18376)
-- Add ``sla_miss_callback`` section to the documentation (#18305)
-- Explain sentry default environment variable for subprocess hook (#18346)
-- Refactor installation pages (#18282)
-- Improves quick-start docker-compose warnings and documentation (#18164)
-- Production-level support for MSSQL (#18382)
-- Update non-working example in documentation (#18067)
-- Remove default_args pattern + added get_current_context() use for Core Airflow example DAGs (#16866)
-- Update max_tis_per_query to better render on the webpage (#17971)
-- Adds Github Oauth example with team based authorization (#17896)
-- Update docker.rst (#17882)
-- Example xcom update (#17749)
-- Add doc warning about connections added via env vars (#17915)
-- fix wrong documents around upgrade-check.rst (#17903)
-- Add Brent to Committers list (#17873)
-- Improves documentation about modules management (#17757)
-- Remove deprecated metrics from metrics.rst (#17772)
-- Make sure "production-readiness" of docker-compose is well explained (#17731)
-- Doc: Update Upgrade to v2 docs with Airflow 1.10.x EOL dates (#17710)
-- Doc: Replace deprecated param from docstrings (#17709)
-- Describe dag owner more carefully (#17699)
-- Update note so avoid misinterpretation (#17701)
-- Docs: Make ``DAG.is_active`` read-only in API (#17667)
-- Update documentation regarding Python 3.9 support (#17611)
-- Fix MySQL database character set instruction (#17603)
-- Document overriding ``XCom.clear`` for data lifecycle management (#17589)
-- Path correction in docs for airflow core (#17567)
-- docs(celery): reworded, add actual multiple queues example (#17541)
-- Doc: Add FAQ to speed up parsing with tons of dag files (#17519)
-- Improve image building documentation for new users (#17409)
-- Doc: Strip unnecessary arguments from MariaDB JIRA URL (#17296)
-- Update warning about MariaDB and multiple schedulers (#17287)
-- Doc: Recommend using same configs on all Airflow components (#17146)
-- Move docs about masking to a new page (#17007)
-- Suggest use of Env vars instead of Airflow Vars in best practices doc (#16926)
-- Docs: Better description for ``pod_template_file`` (#16861)
-- Add Aneesh Joseph as Airflow Committer (#16835)
-- Docs: Added new pipeline example for the tutorial docs (#16548)
-- Remove upstart from docs (#16672)
-- Add new committers: ``Jed`` and ``TP`` (#16671)
-- Docs: Fix ``flask-ouathlib`` to ``flask-oauthlib`` in Upgrading docs (#16320)
-- Docs: Fix creating a connection docs (#16312)
-- Docs: Fix url for ``Elasticsearch`` (#16275)
-- Small improvements for README.md files (#16244)
-- Fix docs for ``dag_concurrency`` (#16177)
-- Check syntactic correctness for code-snippets (#16005)
-- Add proper link for wheel packages in docs. (#15999)
-- Add Docs for ``default_pool`` slots (#15997)
-- Add memory usage warning in quick-start documentation (#15967)
-- Update example ``KubernetesExecutor`` ``git-sync`` pod template file (#15904)
-- Docs: Fix Taskflow API docs (#16574)
-- Added new pipeline example for the tutorial docs (#16084)
-- Updating the DAG docstring to include ``render_template_as_native_obj`` (#16534)
-- Update docs on setting up SMTP (#16523)
-- Docs: Fix API verb from ``POST`` to ``PATCH`` (#16511)
+- ``conf``
+- ``execution_date``
+- ``dag_run.external_trigger``
-Misc/Internal
-^^^^^^^^^^^^^
+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.
-- Renaming variables to be consistent with code logic (#18685)
-- Simplify strings previously split across lines (#18679)
-- fix exception string of ``BranchPythonOperator`` (#18623)
-- Add multiple roles when creating users (#18617)
-- Move FABs base Security Manager into Airflow. (#16647)
-- Remove unnecessary css state colors (#18461)
-- Update ``boto3`` to ``<1.19`` (#18389)
-- Improve coverage for ``airflow.security.kerberos module`` (#18258)
-- Fix Amazon Kinesis test (#18337)
-- Fix provider test accessing ``importlib-resources`` (#18228)
-- Silence warnings in tests from using SubDagOperator (#18275)
-- Fix usage of ``range(len())`` to ``enumerate`` (#18174)
-- Test coverage on the autocomplete view (#15943)
-- Add "packaging" to core requirements (#18122)
-- Adds LoggingMixins to BaseTrigger (#18106)
-- Fix building docs in ``main`` builds (#18035)
-- Remove upper-limit on ``tenacity`` (#17593)
-- Remove redundant ``numpy`` dependency (#17594)
-- Bump ``mysql-connector-python`` to latest version (#17596)
-- Make ``pandas`` an optional core dependency (#17575)
-- Add more typing to airflow.utils.helpers (#15582)
-- Chore: Some code cleanup in ``airflow/utils/db.py`` (#17090)
-- Refactor: Remove processor_factory from DAG processing (#16659)
-- Remove AbstractDagFileProcessorProcess from dag processing (#16816)
-- Update TaskGroup typing (#16811)
-- Update ``click`` to 8.x (#16779)
-- Remove remaining Pylint disables (#16760)
-- Remove duplicated try, there is already a try in create_session (#16701)
-- Removes pylint from our toolchain (#16682)
-- Refactor usage of unneeded function call (#16653)
-- Add type annotations to setup.py (#16658)
-- Remove SQLAlchemy <1.4 constraint (#16630) (Note: our dependencies still have a requirement on <1.4)
-- Refactor ``dag.clear`` method (#16086)
-- Use ``DAG_ACTIONS`` constant (#16232)
-- Use updated ``_get_all_non_dag_permissions`` method (#16317)
-- Add updated-name wrappers for built-in FAB methods (#16077)
-- Remove ``TaskInstance.log_filepath`` attribute (#15217)
-- Removes unnecessary function call in ``airflow/www/app.py`` (#15956)
-- Move ``plyvel`` to google provider extra (#15812)
-- Update permission migrations to use new naming scheme (#16400)
-- Use resource and action names for FAB (#16380)
-- Swap out calls to ``find_permission_view_menu`` for ``get_permission`` wrapper (#16377)
-- Fix deprecated default for ``fab_logging_level`` to ``WARNING`` (#18783)
-- Allow running tasks from UI when using ``CeleryKubernetesExecutor`` (#18441)
-
-Airflow 2.1.4 (2021-09-18)
---------------------------
+Task Context Utilities Moved
+""""""""""""""""""""""""""""
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
+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.
-No significant changes.
+Trigger Rule Restrictions
+"""""""""""""""""""""""""
-Bug Fixes
-^^^^^^^^^
+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.
-- Fix deprecation error message rather than silencing it (#18126)
-- Limit the number of queued dagruns created by the Scheduler (#18065)
-- Fix ``DagRun`` execution order from queued to running not being properly followed (#18061)
-- Fix ``max_active_runs`` not allowing moving of queued dagruns to running (#17945)
-- Avoid redirect loop for users with no permissions (#17838)
-- Avoid endless redirect loop when user has no roles (#17613)
-- Fix log links on graph TI modal (#17862)
-- Hide variable import form if user lacks permission (#18000)
-- Improve dag/task concurrency check (#17786)
-- Fix Clear task instances endpoint resets all DAG runs bug (#17961)
-- Fixes incorrect parameter passed to views (#18083) (#18085)
-- Fix Sentry handler from ``LocalTaskJob`` causing error (#18119)
-- Limit ``colorlog`` version (6.x is incompatible) (#18099)
-- Only show Pause/Unpause tooltip on hover (#17957)
-- Improve graph view load time for dags with open groups (#17821)
-- Increase width for Run column (#17817)
-- Fix wrong query on running tis (#17631)
-- Add root to tree refresh url (#17633)
-- Do not delete running DAG from the UI (#17630)
-- Improve discoverability of Provider packages' functionality
-- Do not let ``create_dagrun`` overwrite explicit ``run_id`` (#17728)
-- Regression on pid reset to allow task start after heartbeat (#17333)
-- Set task state to failed when pod is DELETED while running (#18095)
-- Advises the kernel to not cache log files generated by Airflow (#18054)
-- Sort adopted tasks in ``_check_for_stalled_adopted_tasks`` method (#18208)
+Asset Aliases for Reusability
+"""""""""""""""""""""""""""""
-Doc only changes
-^^^^^^^^^^^^^^^^
+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.
-- Update version added fields in airflow/config_templates/config.yml (#18128)
-- Improve the description of how to handle dynamic task generation (#17963)
-- Improve cross-links to operators and hooks references (#17622)
-- Doc: Fix replacing Airflow version for Docker stack (#17711)
-- Make the providers operators/hooks reference much more usable (#17768)
-- Update description about the new ``connection-types`` provider meta-data
-- Suggest to use secrets backend for variable when it contains sensitive data (#17319)
-- Separate Installing from sources section and add more details (#18171)
-- Doc: Use ``closer.lua`` script for downloading sources (#18179)
-- Doc: Improve installing from sources (#18194)
-- Improves installing from sources pages for all components (#18251)
-
-Airflow 2.1.3 (2021-08-23)
---------------------------
+Operator Links interface changed
+""""""""""""""""""""""""""""""""
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
+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.
-No significant changes.
+Example for users with custom links class:
-Bug Fixes
-^^^^^^^^^
+.. code-block:: python
-- Fix task retries when they receive ``sigkill`` and have retries and properly handle ``sigterm`` (#16301)
-- Fix redacting secrets in context exceptions. (#17618)
-- Fix race condition with dagrun callbacks (#16741)
-- Add 'queued' to DagRunState (#16854)
-- Add 'queued' state to DagRun (#16401)
-- Fix external elasticsearch logs link (#16357)
-- Add proper warning message when recorded PID is different from current PID (#17411)
-- Fix running tasks with ``default_impersonation`` config (#17229)
-- Rescue if a DagRun's DAG was removed from db (#17544)
-- Fixed broken json_client (#17529)
-- Handle and log exceptions raised during task callback (#17347)
-- Fix CLI ``kubernetes cleanup-pods`` which fails on invalid label key (#17298)
-- Show serialization exceptions in DAG parsing log (#17277)
-- Fix: ``TaskInstance`` does not show ``queued_by_job_id`` & ``external_executor_id`` (#17179)
-- Adds more explanatory message when ``SecretsMasker`` is not configured (#17101)
-- Enable the use of ``__init_subclass__`` in subclasses of ``BaseOperator`` (#17027)
-- Fix task instance retrieval in XCom view (#16923)
-- Validate type of ``priority_weight`` during parsing (#16765)
-- Correctly handle custom ``deps`` and ``task_group`` during DAG Serialization (#16734)
-- Fix slow (cleared) tasks being be adopted by Celery worker. (#16718)
-- Fix calculating duration in tree view (#16695)
-- Fix ``AttributeError``: ``datetime.timezone`` object has no attribute ``name`` (#16599)
-- Redact conn secrets in webserver logs (#16579)
-- Change graph focus to top of view instead of center (#16484)
-- Fail tasks in scheduler when executor reports they failed (#15929)
-- fix(smart_sensor): Unbound variable errors (#14774)
-- Add back missing permissions to ``UserModelView`` controls. (#17431)
-- Better diagnostics and self-healing of docker-compose (#17484)
-- Improve diagnostics message when users have ``secret_key`` misconfigured (#17410)
-- Stop checking ``execution_date`` in ``task_instance.refresh_from_db`` (#16809)
+ @attr.s(auto_attribs=True)
+ class CustomBaseIndexOpLink(BaseOperatorLink):
+ """Custom Operator Link for Google BigQuery Console."""
-Improvements
-^^^^^^^^^^^^
+ index: int = attr.ib()
-- Run mini scheduler in ``LocalTaskJob`` during task exit (#16289)
-- Remove ``SQLAlchemy<1.4`` constraint (#16630)
-- Bump Jinja2 upper-bound from 2.12.0 to 4.0.0 (#16595)
-- Bump ``dnspython`` (#16698)
-- Updates to ``FlaskAppBuilder`` 3.3.2+ (#17208)
-- Add State types for tasks and DAGs (#15285)
-- Set Process title for Worker when using ``LocalExecutor`` (#16623)
-- Move ``DagFileProcessor`` and ``DagFileProcessorProcess`` out of ``scheduler_job.py`` (#16581)
+ @property
+ def name(self) -> str:
+ return f"BigQuery Console #{self.index + 1}"
-Doc only changes
-^^^^^^^^^^^^^^^^
+ @property
+ def xcom_key(self) -> str:
+ return f"bigquery_{self.index + 1}"
-- Fix inconsistencies in configuration docs (#17317)
-- Fix docs link for using SQLite as Metadata DB (#17308)
+ 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}"
-Misc
-^^^^
+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``
-- Switch back http provider after requests removes LGPL dependency (#16974)
+Plugins no longer support adding executors, operators & hooks
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Airflow 2.1.2 (2021-07-14)
---------------------------
+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:
-No significant changes.
+.. code-block:: python
-Bug Fixes
-^^^^^^^^^
+ from airflow.hooks.my_plugin import MyHook
-- Only allow webserver to request from the worker log server (#16754)
-- Fix "Invalid JSON configuration, must be a dict" bug (#16648)
-- Fix ``CeleryKubernetesExecutor`` (#16700)
-- Mask value if the key is ``token`` (#16474)
-- Fix impersonation issue with ``LocalTaskJob`` (#16852)
-- Resolve all npm vulnerabilities including bumping ``jQuery`` to ``3.5`` (#16440)
+You should instead import it as:
-Misc
-^^^^
+.. code-block:: python
-- Add Python 3.9 support (#15515)
+ from my_plugin import MyHook
+Support for ML & AI Use Cases (AIP-83)
+"""""""""""""""""""""""""""""""""""""""
-Airflow 2.1.1 (2021-07-02)
---------------------------
+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.
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
+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.
-``activate_dag_runs`` argument of the function ``clear_task_instances`` is replaced with ``dag_run_state``
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Config & Interface Changes
+^^^^^^^^^^^^^^^^^^^^^^^^^^
-To achieve the previous default behaviour of ``clear_task_instances`` with ``activate_dag_runs=True``\ , no change is needed. To achieve the previous behaviour of ``activate_dag_runs=False``\ , pass ``dag_run_state=False`` instead. (The previous parameter is still accepted, but is deprecated)
+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.
-``dag.set_dag_runs_state`` is deprecated
-""""""""""""""""""""""""""""""""""""""""""""
+Default Value Handling
+""""""""""""""""""""""
-The method ``set_dag_runs_state`` is no longer needed after a bug fix in PR: `#15382 `_. This method is now deprecated and will be removed in a future version.
+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.
-Bug Fixes
-^^^^^^^^^
+Refactored Config Defaults
+"""""""""""""""""""""""""""
-- Don't crash attempting to mask secrets in dict with non-string keys (#16601)
-- Always install sphinx_airflow_theme from ``PyPI`` (#16594)
-- Remove limitation for elasticsearch library (#16553)
-- Adding extra requirements for build and runtime of the PROD image. (#16170)
-- Cattrs 1.7.0 released by the end of May 2021 break lineage usage (#16173)
-- Removes unnecessary packages from setup_requires (#16139)
-- Pins docutils to <0.17 until breaking behaviour is fixed (#16133)
-- Improvements for Docker Image docs (#14843)
-- Ensure that ``dag_run.conf`` is a dict (#15057)
-- Fix CLI connections import and migrate logic from secrets to Connection model (#15425)
-- Fix Dag Details start date bug (#16206)
-- Fix DAG run state not updated while DAG is paused (#16343)
-- Allow null value for operator field in task_instance schema(REST API) (#16516)
-- Avoid recursion going too deep when redacting logs (#16491)
-- Backfill: Don't create a DagRun if no tasks match task regex (#16461)
-- Tree View UI for larger DAGs & more consistent spacing in Tree View (#16522)
-- Correctly handle None returns from Query.scalar() (#16345)
-- Adding ``only_active`` parameter to /dags endpoint (#14306)
-- Don't show stale Serialized DAGs if they are deleted in DB (#16368)
-- Make REST API List DAGs endpoint consistent with UI/CLI behaviour (#16318)
-- Support remote logging in elasticsearch with ``filebeat 7`` (#14625)
-- Queue tasks with higher priority and earlier execution_date first. (#15210)
-- Make task ID on legend have enough width and width of line chart to be 100%. (#15915)
-- Fix normalize-url vulnerability (#16375)
-- Validate retries value on init for better errors (#16415)
-- add num_runs query param for tree refresh (#16437)
-- Fix templated default/example values in config ref docs (#16442)
-- Add ``passphrase`` and ``private_key`` to default sensitive field names (#16392)
-- Fix tasks in an infinite slots pool were never scheduled (#15247)
-- Fix Orphaned tasks stuck in CeleryExecutor as running (#16550)
-- Don't fail to log if we can't redact something (#16118)
-- Set max tree width to 1200 pixels (#16067)
-- Fill the "job_id" field for ``airflow task run`` without ``--local``/``--raw`` for KubeExecutor (#16108)
-- Fixes problem where conf variable was used before initialization (#16088)
-- Fix apply defaults for task decorator (#16085)
-- Parse recently modified files even if just parsed (#16075)
-- Ensure that we don't try to mask empty string in logs (#16057)
-- Don't die when masking ``log.exception`` when there is no exception (#16047)
-- Restores apply_defaults import in base_sensor_operator (#16040)
-- Fix auto-refresh in tree view When webserver ui is not in ``/`` (#16018)
-- Fix dag.clear() to set multiple dags to running when necessary (#15382)
-- Fix Celery executor getting stuck randomly because of reset_signals in multiprocessing (#15989)
-
-
-Airflow 2.1.0 (2021-05-21)
---------------------------
+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.
-New "deprecated_api" extra
-""""""""""""""""""""""""""
+Refactored Internal Utilities
+"""""""""""""""""""""""""""""
-We have a new '[deprecated_api]' extra that should be used when installing airflow when the deprecated API
-is going to be used. This is now an optional feature of Airflow now because it pulls in ``requests`` which
-(as of 14 May 2021) pulls LGPL ``chardet`` dependency.
+Several core components have been moved to more intuitive or stable locations:
-The ``http`` provider is not installed by default
-"""""""""""""""""""""""""""""""""""""""""""""""""""""
+- 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``.
-The ``http`` provider is now optional and not installed by default, until ``chardet`` becomes an optional
-dependency of ``requests``.
-See `PR to replace chardet with charset-normalizer `_
+These changes simplify imports and reflect broader efforts to stabilize utility interfaces across the Airflow codebase.
-``@apply_default`` decorator isn't longer necessary
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Improved ``inlet_events``, ``outlet_events``, and ``triggering_asset_events``
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-This decorator is now automatically added to all operators via the metaclass on BaseOperator
+Asset event mappings in the task context are improved to better support asset use cases, including new features introduced in AIP-74.
-Change the configuration options for field masking
-""""""""""""""""""""""""""""""""""""""""""""""""""
+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::
-We've improved masking for sensitive data in Web UI and logs. As part of it, the following configurations have been changed:
+ outlet_events[Asset.ref(name="myasset")] # Get events for asset named "myasset".
+ outlet_events[AssetAlias(name="myalias")] # Get events for asset alias named "myalias".
+Alternatively, two helpers ``for_asset`` and ``for_asset_alias`` are added as shortcuts::
-* ``hide_sensitive_variable_fields`` option in ``admin`` section has been replaced by ``hide_sensitive_var_conn_fields`` section in ``core`` section,
-* ``sensitive_variable_fields`` option in ``admin`` section has been replaced by ``sensitive_var_conn_names`` section in ``core`` section.
+ 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".
-Deprecated PodDefaults and add_xcom_sidecar in airflow.kubernetes.pod_generator
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+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.
-We have moved PodDefaults from ``airflow.kubernetes.pod_generator.PodDefaults`` to
-``airflow.providers.cncf.kubernetes.utils.xcom_sidecar.PodDefaults`` and moved add_xcom_sidecar
-from ``airflow.kubernetes.pod_generator.PodGenerator.add_xcom_sidecar``\ to
-``airflow.providers.cncf.kubernetes.utils.xcom_sidecar.add_xcom_sidecar``.
-This change will allow us to modify the KubernetesPodOperator XCom functionality without requiring airflow upgrades.
+Behaviour change in ``xcom_pull``
+"""""""""""""""""""""""""""""""""
-Removed pod_launcher from core airflow
-""""""""""""""""""""""""""""""""""""""
+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.
-Moved the pod launcher from ``airflow.kubernetes.pod_launcher`` to ``airflow.providers.cncf.kubernetes.utils.pod_launcher``
+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.
-This will allow users to update the pod_launcher for the KubernetesPodOperator without requiring an airflow upgrade
+DAG Authors should update their dags to use ``task_ids`` if their dags used ``xcom_pull`` without ``task_ids`` such as::
-Default ``[webserver] worker_refresh_interval`` is changed to ``6000`` seconds
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+ kwargs["ti"].xcom_pull(key="key")
-The default value for ``[webserver] worker_refresh_interval`` was ``30`` seconds for
-Airflow <=2.0.1. However, since Airflow 2.0 DAG Serialization is a hard requirement
-and the Webserver used the serialized DAGs, there is no need to kill an existing
-worker and create a new one as frequently as ``30`` seconds.
+Should be updated to::
-This setting can be raised to an even higher value, currently it is
-set to ``6000`` seconds (100 minutes) to
-serve as a DagBag cache burst time.
+ kwargs["ti"].xcom_pull(task_ids="task1", key="key")
-``default_queue`` configuration has been moved to the ``operators`` section.
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-The ``default_queue`` configuration option has been moved from ``[celery]`` section to ``[operators]`` section to allow for reuse between different executors.
+Removed Configuration Keys
+"""""""""""""""""""""""""""
-New Features
-^^^^^^^^^^^^
+As part of the deprecation cleanup, several legacy configuration options have been removed. These include:
-- Add ``PythonVirtualenvDecorator`` to Taskflow API (#14761)
-- Add ``Taskgroup`` decorator (#15034)
-- Create a DAG Calendar View (#15423)
-- Create cross-DAG dependencies view (#13199)
-- Add rest API to query for providers (#13394)
-- Mask passwords and sensitive info in task logs and UI (#15599)
-- Add ``SubprocessHook`` for running commands from operators (#13423)
-- Add DAG Timeout in UI page "DAG Details" (#14165)
-- Add ``WeekDayBranchOperator`` (#13997)
-- Add JSON linter to DAG Trigger UI (#13551)
-- Add DAG Description Doc to Trigger UI Page (#13365)
-- Add airflow webserver URL into SLA miss email. (#13249)
-- Add read only REST API endpoints for users (#14735)
-- Add files to generate Airflow's Python SDK (#14739)
-- Add dynamic fields to snowflake connection (#14724)
-- Add read only REST API endpoint for roles and permissions (#14664)
-- Add new datetime branch operator (#11964)
-- Add Google leveldb hook and operator (#13109) (#14105)
-- Add plugins endpoint to the REST API (#14280)
-- Add ``worker_pod_pending_timeout`` support (#15263)
-- Add support for labeling DAG edges (#15142)
-- Add CUD REST API endpoints for Roles (#14840)
-- Import connections from a file (#15177)
-- A bunch of ``template_fields_renderers`` additions (#15130)
-- Add REST API query sort and order to some endpoints (#14895)
-- Add timezone context in new ui (#15096)
-- Add query mutations to new UI (#15068)
-- Add different modes to sort dag files for parsing (#15046)
-- Auto refresh on Tree View (#15474)
-- BashOperator to raise ``AirflowSkipException`` on exit code 99 (by default, configurable) (#13421) (#14963)
-- Clear tasks by task ids in REST API (#14500)
-- Support jinja2 native Python types (#14603)
-- Allow celery workers without gossip or mingle modes (#13880)
-- Add ``airflow jobs check`` CLI command to check health of jobs (Scheduler etc) (#14519)
-- Rename ``DateTimeBranchOperator`` to ``BranchDateTimeOperator`` (#14720)
+- ``[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``
-Improvements
-^^^^^^^^^^^^
+All the webserver configurations have also been removed since API server now replaces webserver, so
+the configurations like below have no effect:
-- Add optional result handler callback to ``DbApiHook`` (#15581)
-- Update Flask App Builder limit to recently released 3.3 (#15792)
-- Prevent creating flask sessions on REST API requests (#15295)
-- Sync DAG specific permissions when parsing (#15311)
-- Increase maximum length of pool name on Tasks to 256 characters (#15203)
-- Enforce READ COMMITTED isolation when using mysql (#15714)
-- Auto-apply ``apply_default`` to subclasses of ``BaseOperator`` (#15667)
-- Emit error on duplicated DAG ID (#15302)
-- Update ``KubernetesExecutor`` pod templates to allow access to IAM permissions (#15669)
-- More verbose logs when running ``airflow db check-migrations`` (#15662)
-- When one_success mark task as failed if no success (#15467)
-- Add an option to trigger a dag w/o changing conf (#15591)
-- Add Airflow UI instance_name configuration option (#10162)
-- Add a decorator to retry functions with DB transactions (#14109)
-- Add return to PythonVirtualenvOperator's execute method (#14061)
-- Add verify_ssl config for kubernetes (#13516)
-- Add description about ``secret_key`` when Webserver > 1 (#15546)
-- Add Traceback in LogRecord in ``JSONFormatter`` (#15414)
-- Add support for arbitrary json in conn uri format (#15100)
-- Adds description field in variable (#12413) (#15194)
-- Add logs to show last modified in SFTP, FTP and Filesystem sensor (#15134)
-- Execute ``on_failure_callback`` when SIGTERM is received (#15172)
-- Allow hiding of all edges when highlighting states (#15281)
-- Display explicit error in case UID has no actual username (#15212)
-- Serve logs with Scheduler when using Local or Sequential Executor (#15557)
-- Deactivate trigger, refresh, and delete controls on dag detail view. (#14144)
-- Turn off autocomplete for connection forms (#15073)
-- Increase default ``worker_refresh_interval`` to ``6000`` seconds (#14970)
-- Only show User's local timezone if it's not UTC (#13904)
-- Suppress LOG/WARNING for a few tasks CLI for better CLI experience (#14567)
-- Configurable API response (CORS) headers (#13620)
-- Allow viewers to see all docs links (#14197)
-- Update Tree View date ticks (#14141)
-- Make the tooltip to Pause / Unpause a DAG clearer (#13642)
-- Warn about precedence of env var when getting variables (#13501)
-- Move ``[celery] default_queue`` config to ``[operators] default_queue`` to reuse between executors (#14699)
+- ``[webserver] allow_raw_html_descriptions``
+- ``[webserver] cookie_samesite``
+- ``[webserver] error_logfile``
+- ``[webserver] access_logformat``
+- ``[webserver] web_server_master_timeout``
+- etc
-Bug Fixes
-^^^^^^^^^
+Several configuration options previously located under the ``[webserver]`` section have
+been **moved to the new ``[api]`` section**. The following configuration keys have been moved:
-- Fix 500 error from ``updateTaskInstancesState`` API endpoint when ``dry_run`` not passed (#15889)
-- Ensure that task preceding a PythonVirtualenvOperator doesn't fail (#15822)
-- Prevent mixed case env vars from crashing processes like worker (#14380)
-- Fixed type annotations in DAG decorator (#15778)
-- Fix on_failure_callback when task receive SIGKILL (#15537)
-- Fix dags table overflow (#15660)
-- Fix changing the parent dag state on subdag clear (#15562)
-- Fix reading from zip package to default to text (#13962)
-- Fix wrong parameter for ``drawDagStatsForDag`` in dags.html (#13884)
-- Fix QueuedLocalWorker crashing with EOFError (#13215)
-- Fix typo in ``NotPreviouslySkippedDep`` (#13933)
-- Fix parallelism after KubeExecutor pod adoption (#15555)
-- Fix kube client on mac with keepalive enabled (#15551)
-- Fixes wrong limit for dask for python>3.7 (should be <3.7) (#15545)
-- Fix Task Adoption in ``KubernetesExecutor`` (#14795)
-- Fix timeout when using XCom with ``KubernetesPodOperator`` (#15388)
-- Fix deprecated provider aliases in "extras" not working (#15465)
-- Fixed default XCom deserialization. (#14827)
-- Fix used_group_ids in ``dag.partial_subset`` (#13700) (#15308)
-- Further fix trimmed ``pod_id`` for ``KubernetesPodOperator`` (#15445)
-- Bugfix: Invalid name when trimmed ``pod_id`` ends with hyphen in ``KubernetesPodOperator`` (#15443)
-- Fix incorrect slots stats when TI ``pool_slots > 1`` (#15426)
-- Fix DAG last run link (#15327)
-- Fix ``sync-perm`` to work correctly when update_fab_perms = False (#14847)
-- Fixes limits on Arrow for plexus test (#14781)
-- Fix UI bugs in tree view (#14566)
-- Fix AzureDataFactoryHook failing to instantiate its connection (#14565)
-- Fix permission error on non-POSIX filesystem (#13121)
-- Fix spelling in "ignorable" (#14348)
-- Fix get_context_data doctest import (#14288)
-- Correct typo in ``GCSObjectsWtihPrefixExistenceSensor`` (#14179)
-- Fix order of failed deps (#14036)
-- Fix critical ``CeleryKubernetesExecutor`` bug (#13247)
-- Fix four bugs in ``StackdriverTaskHandler`` (#13784)
-- ``func.sum`` may return ``Decimal`` that break rest APIs (#15585)
-- Persist tags params in pagination (#15411)
-- API: Raise ``AlreadyExists`` exception when the ``execution_date`` is same (#15174)
-- Remove duplicate call to ``sync_metadata`` inside ``DagFileProcessorManager`` (#15121)
-- Extra ``docker-py`` update to resolve docker op issues (#15731)
-- Ensure executors end method is called (#14085)
-- Remove ``user_id`` from API schema (#15117)
-- Prevent clickable bad links on disabled pagination (#15074)
-- Acquire lock on db for the time of migration (#10151)
-- Skip SLA check only if SLA is None (#14064)
-- Print right version in airflow info command (#14560)
-- Make ``airflow info`` work with pipes (#14528)
-- Rework client-side script for connection form. (#14052)
-- API: Add ``CollectionInfo`` in all Collections that have ``total_entries`` (#14366)
-- Fix ``task_instance_mutation_hook`` when importing airflow.models.dagrun (#15851)
+- ``[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``
-Doc only changes
-^^^^^^^^^^^^^^^^
+Users should review their ``airflow.cfg`` files or use the ``airflow config lint`` command to identify outdated or
+removed options.
-- Fix docstring of SqlSensor (#15466)
-- Small changes on "DAGs and Tasks documentation" (#14853)
-- Add note on changes to configuration options (#15696)
-- Add docs to the ``markdownlint`` and ``yamllint`` config files (#15682)
-- Rename old "Experimental" API to deprecated in the docs. (#15653)
-- Fix documentation error in ``git_sync_template.yaml`` (#13197)
-- Fix doc link permission name (#14972)
-- Fix link to Helm chart docs (#14652)
-- Fix docstrings for Kubernetes code (#14605)
-- docs: Capitalize & minor fixes (#14283) (#14534)
-- Fixed reading from zip package to default to text. (#13984)
-- An initial rework of the "Concepts" docs (#15444)
-- Improve docstrings for various modules (#15047)
-- Add documentation on database connection URI (#14124)
-- Add Helm Chart logo to docs index (#14762)
-- Create a new documentation package for Helm Chart (#14643)
-- Add docs about supported logging levels (#14507)
-- Update docs about tableau and salesforce provider (#14495)
-- Replace deprecated doc links to the correct one (#14429)
-- Refactor redundant doc url logic to use utility (#14080)
-- docs: NOTICE: Updated 2016-2019 to 2016-now (#14248)
-- Skip DAG perm sync during parsing if possible (#15464)
-- Add picture and examples for Edge Labels (#15310)
-- Add example DAG & how-to guide for sqlite (#13196)
-- Add links to new modules for deprecated modules (#15316)
-- Add note in Updating.md about FAB data model change (#14478)
+Upgrade Tooling
+""""""""""""""""
-Misc/Internal
-^^^^^^^^^^^^^
+Airflow 3.0 includes improved support for upgrade validation. Use the following tools to proactively catch incompatible
+configs or deprecated usage patterns:
-- Fix ``logging.exception`` redundancy (#14823)
-- Bump ``stylelint`` to remove vulnerable sub-dependency (#15784)
-- Add resolution to force dependencies to use patched version of lodash (#15777)
-- Update croniter to 1.0.x series (#15769)
-- Get rid of Airflow 1.10 in Breeze (#15712)
-- Run helm chart tests in parallel (#15706)
-- Bump ``ssri`` from 6.0.1 to 6.0.2 in /airflow/www (#15437)
-- Remove the limit on Gunicorn dependency (#15611)
-- Better "dependency already registered" warning message for tasks #14613 (#14860)
-- Pin pandas-gbq to <0.15.0 (#15114)
-- Use Pip 21.* to install airflow officially (#15513)
-- Bump mysqlclient to support the 1.4.x and 2.x series (#14978)
-- Finish refactor of DAG resource name helper (#15511)
-- Refactor/Cleanup Presentation of Graph Task and Path Highlighting (#15257)
-- Standardize default fab perms (#14946)
-- Remove ``datepicker`` for task instance detail view (#15284)
-- Turn provider's import warnings into debug logs (#14903)
-- Remove left-over fields from required in provider_info schema. (#14119)
-- Deprecate ``tableau`` extra (#13595)
-- Use built-in ``cached_property`` on Python 3.8 where possible (#14606)
-- Clean-up JS code in UI templates (#14019)
-- Bump elliptic from 6.5.3 to 6.5.4 in /airflow/www (#14668)
-- Switch to f-strings using ``flynt``. (#13732)
-- use ``jquery`` ready instead of vanilla js (#15258)
-- Migrate task instance log (ti_log) js (#15309)
-- Migrate graph js (#15307)
-- Migrate dags.html javascript (#14692)
-- Removes unnecessary AzureContainerInstance connection type (#15514)
-- Separate Kubernetes pod_launcher from core airflow (#15165)
-- update remaining old import paths of operators (#15127)
-- Remove broken and undocumented "demo mode" feature (#14601)
-- Simplify configuration/legibility of ``Webpack`` entries (#14551)
-- remove inline tree js (#14552)
-- Js linting and inline migration for simple scripts (#14215)
-- Remove use of repeated constant in AirflowConfigParser (#14023)
-- Deprecate email credentials from environment variables. (#13601)
-- Remove unused 'context' variable in task_instance.py (#14049)
-- Disable suppress_logs_and_warning in cli when debugging (#13180)
-
-
-Airflow 2.0.2 (2021-04-19)
---------------------------
+- ``airflow config lint``: Identifies removed or invalid config keys
+- ``ruff check --select AIR30 --preview``: Flags removed interfaces and common migration issues
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
+CLI & API Changes
+^^^^^^^^^^^^^^^^^
-Default ``[kubernetes] enable_tcp_keepalive`` is changed to ``True``
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Airflow 3.0 introduces changes to both the CLI and REST API interfaces to better align with service-oriented deployments
+and event-driven workflows.
-This allows Airflow to work more reliably with some environments (like Azure) by default.
+Split CLI Architecture (AIP-81)
+"""""""""""""""""""""""""""""""
-``sync-perm`` CLI no longer syncs DAG specific permissions by default
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+The Airflow CLI has been split into two distinct interfaces:
-The ``sync-perm`` CLI command will no longer sync DAG specific permissions by default as they are now being handled during
-DAG parsing. If you need or want the old behavior, you can pass ``--include-dags`` to have ``sync-perm`` also sync DAG
-specific permissions.
+- 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.
-Bug Fixes
-^^^^^^^^^
+This change improves security and modularity for deployments that use Airflow in a distributed or API-first context.
-* Bugfix: ``TypeError`` when Serializing & sorting iterable properties of DAGs (#15395)
-* Fix missing ``on_load`` trigger for folder-based plugins (#15208)
-* ``kubernetes cleanup-pods`` subcommand will only clean up Airflow-created Pods (#15204)
-* Fix password masking in CLI action_logging (#15143)
-* Fix url generation for TriggerDagRunOperatorLink (#14990)
-* Restore base lineage backend (#14146)
-* Unable to trigger backfill or manual jobs with Kubernetes executor. (#14160)
-* Bugfix: Task docs are not shown in the Task Instance Detail View (#15191)
-* Bugfix: Fix overriding ``pod_template_file`` in KubernetesExecutor (#15197)
-* Bugfix: resources in ``executor_config`` breaks Graph View in UI (#15199)
-* Fix celery executor bug trying to call len on map (#14883)
-* Fix bug in airflow.stats timing that broke dogstatsd mode (#15132)
-* Avoid scheduler/parser manager deadlock by using non-blocking IO (#15112)
-* Re-introduce ``dagrun.schedule_delay`` metric (#15105)
-* Compare string values, not if strings are the same object in Kube executor(#14942)
-* Pass queue to BaseExecutor.execute_async like in airflow 1.10 (#14861)
-* Scheduler: Remove TIs from starved pools from the critical path. (#14476)
-* Remove extra/needless deprecation warnings from airflow.contrib module (#15065)
-* Fix support for long dag_id and task_id in KubernetesExecutor (#14703)
-* Sort lists, sets and tuples in Serialized DAGs (#14909)
-* Simplify cleaning string passed to origin param (#14738) (#14905)
-* Fix error when running tasks with Sentry integration enabled. (#13929)
-* Webserver: Sanitize string passed to origin param (#14738)
-* Fix losing duration < 1 secs in tree (#13537)
-* Pin SQLAlchemy to <1.4 due to breakage of sqlalchemy-utils (#14812)
-* Fix KubernetesExecutor issue with deleted pending pods (#14810)
-* Default to Celery Task model when backend model does not exist (#14612)
-* Bugfix: Plugins endpoint was unauthenticated (#14570)
-* BugFix: fix DAG doc display (especially for TaskFlow DAGs) (#14564)
-* BugFix: TypeError in airflow.kubernetes.pod_launcher's monitor_pod (#14513)
-* Bugfix: Fix wrong output of tags and owners in dag detail API endpoint (#14490)
-* Fix logging error with task error when JSON logging is enabled (#14456)
-* Fix StatsD metrics not sending when using daemon mode (#14454)
-* Gracefully handle missing start_date and end_date for DagRun (#14452)
-* BugFix: Serialize max_retry_delay as a timedelta (#14436)
-* Fix crash when user clicks on "Task Instance Details" caused by start_date being None (#14416)
-* BugFix: Fix TaskInstance API call fails if a task is removed from running DAG (#14381)
-* Scheduler should not fail when invalid ``executor_config`` is passed (#14323)
-* Fix bug allowing task instances to survive when dagrun_timeout is exceeded (#14321)
-* Fix bug where DAG timezone was not always shown correctly in UI tooltips (#14204)
-* Use ``Lax`` for ``cookie_samesite`` when empty string is passed (#14183)
-* [AIRFLOW-6076] fix ``dag.cli()`` KeyError (#13647)
-* Fix running child tasks in a subdag after clearing a successful subdag (#14776)
+REST API v2 replaces v1
+"""""""""""""""""""""""
-Improvements
-^^^^^^^^^^^^
+The legacy REST API v1, previously built with Connexion and Marshmallow, has been replaced by a modern FastAPI-based REST API v2.
-* Remove unused JS packages causing false security alerts (#15383)
-* Change default of ``[kubernetes] enable_tcp_keepalive`` for new installs to ``True`` (#15338)
-* Fixed #14270: Add error message in OOM situations (#15207)
-* Better compatibility/diagnostics for arbitrary UID in docker image (#15162)
-* Updates 3.6 limits for latest versions of a few libraries (#15209)
-* Adds Blinker dependency which is missing after recent changes (#15182)
-* Remove 'conf' from search_columns in DagRun View (#15099)
-* More proper default value for namespace in K8S cleanup-pods CLI (#15060)
-* Faster default role syncing during webserver start (#15017)
-* Speed up webserver start when there are many DAGs (#14993)
-* Much easier to use and better documented Docker image (#14911)
-* Use ``libyaml`` C library when available. (#14577)
-* Don't create unittest.cfg when not running in unit test mode (#14420)
-* Webserver: Allow Filtering TaskInstances by queued_dttm (#14708)
-* Update Flask-AppBuilder dependency to allow 3.2 (and all 3.x series) (#14665)
-* Remember expanded task groups in browser local storage (#14661)
-* Add plain format output to cli tables (#14546)
-* Make ``airflow dags show`` command display TaskGroups (#14269)
-* Increase maximum size of ``extra`` connection field. (#12944)
-* Speed up clear_task_instances by doing a single sql delete for TaskReschedule (#14048)
-* Add more flexibility with FAB menu links (#13903)
-* Add better description and guidance in case of sqlite version mismatch (#14209)
+This new implementation improves performance, aligns more closely with web standards, and provides a consistent developer experience across the API and UI.
-Doc only changes
-^^^^^^^^^^^^^^^^
+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.
-* Add documentation create/update community providers (#15061)
-* Fix mistake and typos in airflow.utils.timezone docstrings (#15180)
-* Replace new url for Stable Airflow Docs (#15169)
-* Docs: Clarify behavior of delete_worker_pods_on_failure (#14958)
-* Create a documentation package for Docker image (#14846)
-* Multiple minor doc (OpenAPI) fixes (#14917)
-* Replace Graph View Screenshot to show Auto-refresh (#14571)
+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.
-Misc/Internal
-^^^^^^^^^^^^^
+For details, see the :doc:`Airflow REST API v2 ` documentation.
-* Import Connection lazily in hooks to avoid cycles (#15361)
-* Rename last_scheduler_run into last_parsed_time, and ensure it's updated in DB (#14581)
-* Make TaskInstance.pool_slots not nullable with a default of 1 (#14406)
-* Log migrations info in consistent way (#14158)
+REST API: DAG Trigger Behavior Updated
+""""""""""""""""""""""""""""""""""""""
-Airflow 2.0.1 (2021-02-08)
---------------------------
+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``.
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
+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``.
-Permission to view Airflow Configurations has been removed from ``User`` and ``Viewer`` role
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Removed CLI Flags and Commands
+""""""""""""""""""""""""""""""
-Previously, Users with ``User`` or ``Viewer`` role were able to get/view configurations using
-the REST API or in the Webserver. From Airflow 2.0.1, only users with ``Admin`` or ``Op`` role would be able
-to get/view Configurations.
+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.
-To allow users with other roles to view configuration, add ``can read on Configurations`` permissions to that role.
+- Deprecated ``--ignore-depends-on-past`` cli option is replaced by ``--depends-on-past ignore``.
-Note that if ``[webserver] expose_config`` is set to ``False``\ , the API will throw a ``403`` response even if
-the user has role with ``can read on Configurations`` permission.
+- ``--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.
-Default ``[celery] worker_concurrency`` is changed to ``16``
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+- Changing ``dag_id`` from flag (``-d``, ``--dag-id``) to a positional argument in the ``dags list-runs`` CLI command.
-The default value for ``[celery] worker_concurrency`` was ``16`` for Airflow <2.0.0.
-However, it was unintentionally changed to ``8`` in 2.0.0.
+- 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``.
-From Airflow 2.0.1, we revert to the old default of ``16``.
+- ``airflow api-server`` has replaced ``airflow webserver`` cli command.
-Default ``[scheduler] min_file_process_interval`` is changed to ``30``
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-The default value for ``[scheduler] min_file_process_interval`` was ``0``\ ,
-due to which the CPU Usage mostly stayed around 100% as the DAG files are parsed
-constantly.
+Provider Refactor & Standardization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-From Airflow 2.0.0, the scheduling decisions have been moved from
-DagFileProcessor to Scheduler, so we can keep the default a bit higher: ``30``.
+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:
-Bug Fixes
-^^^^^^^^^
+- ``PythonOperator``
+- ``BashOperator``
+- ``EmailOperator``
+- ``ShortCircuitOperator``
-- Bugfix: Return XCom Value in the XCom Endpoint API (#13684)
-- Bugfix: Import error when using custom backend and ``sql_alchemy_conn_secret`` (#13260)
-- Allow PID file path to be relative when daemonize a process (scheduler, kerberos, etc) (#13232)
-- Bugfix: no generic ``DROP CONSTRAINT`` in MySQL during ``airflow db upgrade`` (#13239)
-- Bugfix: Sync Access Control defined in DAGs when running ``sync-perm`` (#13377)
-- Stop sending Callback Requests if no callbacks are defined on DAG (#13163)
-- BugFix: Dag-level Callback Requests were not run (#13651)
-- Stop creating duplicate Dag File Processors (#13662)
-- Filter DagRuns with Task Instances in removed State while Scheduling (#13165)
-- Bump ``datatables.net`` from 1.10.21 to 1.10.22 in /airflow/www (#13143)
-- Bump ``datatables.net`` JS to 1.10.23 (#13253)
-- Bump ``dompurify`` from 2.0.12 to 2.2.6 in /airflow/www (#13164)
-- Update minimum ``cattrs`` version (#13223)
-- Remove inapplicable arg 'output' for CLI pools import/export (#13071)
-- Webserver: Fix the behavior to deactivate the authentication option and add docs (#13191)
-- Fix: add support for no-menu plugin views (#11742)
-- Add ``python-daemon`` limit for Python 3.8+ to fix daemon crash (#13540)
-- Change the default celery ``worker_concurrency`` to 16 (#13612)
-- Audit Log records View should not contain link if ``dag_id`` is None (#13619)
-- Fix invalid ``continue_token`` for cleanup list pods (#13563)
-- Switches to latest version of snowflake connector (#13654)
-- Fix backfill crash on task retry or reschedule (#13712)
-- Setting ``max_tis_per_query`` to ``0`` now correctly removes the limit (#13512)
-- Fix race conditions in task callback invocations (#10917)
-- Fix webserver exiting when gunicorn master crashes (#13518)(#13780)
-- Fix SQL syntax to check duplicate connections (#13783)
-- ``BaseBranchOperator`` will push to xcom by default (#13704) (#13763)
-- Fix Deprecation for ``configuration.getsection`` (#13804)
-- Fix TaskNotFound in log endpoint (#13872)
-- Fix race condition when using Dynamic DAGs (#13893)
-- Fix: Linux/Chrome window bouncing in Webserver
-- Fix db shell for sqlite (#13907)
-- Only compare updated time when Serialized DAG exists (#13899)
-- Fix dag run type enum query for mysqldb driver (#13278)
-- Add authentication to lineage endpoint for experimental API (#13870)
-- Do not add User role perms to custom roles. (#13856)
-- Do not add ``Website.can_read`` access to default roles. (#13923)
-- Fix invalid value error caused by long Kubernetes pod name (#13299)
-- Fix DB Migration for SQLite to upgrade to 2.0 (#13921)
-- Bugfix: Manual DagRun trigger should not skip scheduled runs (#13963)
-- Stop loading Extra Operator links in Scheduler (#13932)
-- Added missing return parameter in read function of ``FileTaskHandler`` (#14001)
-- Bugfix: Do not try to create a duplicate Dag Run in Scheduler (#13920)
-- Make ``v1/config`` endpoint respect webserver ``expose_config`` setting (#14020)
-- Disable row level locking for Mariadb and MySQL <8 (#14031)
-- Bugfix: Fix permissions to triggering only specific DAGs (#13922)
-- Fix broken SLA Mechanism (#14056)
-- Bugfix: Scheduler fails if task is removed at runtime (#14057)
-- Remove permissions to read Configurations for User and Viewer roles (#14067)
-- Fix DB Migration from 2.0.1rc1
+These operators were previously bundled inside ``airflow-core`` but are now treated as provider-managed components to
+improve modularity, testability, and lifecycle independence.
-Improvements
-^^^^^^^^^^^^
+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.
-- Increase the default ``min_file_process_interval`` to decrease CPU Usage (#13664)
-- Dispose connections when running tasks with ``os.fork`` & ``CeleryExecutor`` (#13265)
-- Make function purpose clearer in ``example_kubernetes_executor`` example dag (#13216)
-- Remove unused libraries - ``flask-swagger``, ``funcsigs`` (#13178)
-- Display alternative tooltip when a Task has yet to run (no TI) (#13162)
-- User werkzeug's own type conversion for request args (#13184)
-- UI: Add ``queued_by_job_id`` & ``external_executor_id`` Columns to TI View (#13266)
-- Make ``json-merge-patch`` an optional library and unpin it (#13175)
-- Adds missing LDAP "extra" dependencies to ldap provider. (#13308)
-- Refactor ``setup.py`` to better reflect changes in providers (#13314)
-- Pin ``pyjwt`` and Add integration tests for Apache Pinot (#13195)
-- Removes provider-imposed requirements from ``setup.cfg`` (#13409)
-- Replace deprecated decorator (#13443)
-- Streamline & simplify ``__eq__`` methods in models Dag and BaseOperator (#13449)
-- Additional properties should be allowed in provider schema (#13440)
-- Remove unused dependency - ``contextdecorator`` (#13455)
-- Remove 'typing' dependency (#13472)
-- Log migrations info in consistent way (#13458)
-- Unpin ``mysql-connector-python`` to allow ``8.0.22`` (#13370)
-- Remove thrift as a core dependency (#13471)
-- Add ``NotFound`` response for DELETE methods in OpenAPI YAML (#13550)
-- Stop Log Spamming when ``[core] lazy_load_plugins`` is ``False`` (#13578)
-- Display message and docs link when no plugins are loaded (#13599)
-- Unpin restriction for ``colorlog`` dependency (#13176)
-- Add missing Dag Tag for Example DAGs (#13665)
-- Support tables in DAG docs (#13533)
-- Add ``python3-openid`` dependency (#13714)
-- Add ``__repr__`` for Executors (#13753)
-- Add description to hint if ``conn_type`` is missing (#13778)
-- Upgrade Azure blob to v12 (#12188)
-- Add extra field to ``get_connnection`` REST endpoint (#13885)
-- Make Smart Sensors DB Migration idempotent (#13892)
-- Improve the error when DAG does not exist when running dag pause command (#13900)
-- Update ``airflow_local_settings.py`` to fix an error message (#13927)
-- Only allow passing JSON Serializable conf to ``TriggerDagRunOperator`` (#13964)
-- Bugfix: Allow getting details of a DAG with null ``start_date`` (REST API) (#13959)
-- Add params to the DAG details endpoint (#13790)
-- Make the role assigned to anonymous users customizable (#14042)
-- Retry critical methods in Scheduler loop in case of ``OperationalError`` (#14032)
+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.
-Doc only changes
-^^^^^^^^^^^^^^^^
+Legacy imports such as ``airflow.operators.python.PythonOperator`` are deprecated and will be removed soon. They should be
+replaced with:
-- Add Missing StatsD Metrics in Docs (#13708)
-- Add Missing Email configs in Configuration doc (#13709)
-- Add quick start for Airflow on Docker (#13660)
-- Describe which Python versions are supported (#13259)
-- Add note block to 2.x migration docs (#13094)
-- Add documentation about webserver_config.py (#13155)
-- Add missing version information to recently added configs (#13161)
-- API: Use generic information in UpdateMask component (#13146)
-- Add Airflow 2.0.0 to requirements table (#13140)
-- Avoid confusion in doc for CeleryKubernetesExecutor (#13116)
-- Update docs link in REST API spec (#13107)
-- Add link to PyPI Repository to provider docs (#13064)
-- Fix link to Airflow master branch documentation (#13179)
-- Minor enhancements to Sensors docs (#13381)
-- Use 2.0.0 in Airflow docs & Breeze (#13379)
-- Improves documentation regarding providers and custom connections (#13375)(#13410)
-- Fix malformed table in production-deployment.rst (#13395)
-- Update celery.rst to fix broken links (#13400)
-- Remove reference to scheduler run_duration param in docs (#13346)
-- Set minimum SQLite version supported (#13412)
-- Fix installation doc (#13462)
-- Add docs about mocking variables and connections (#13502)
-- Add docs about Flask CLI (#13500)
-- Fix Upgrading to 2 guide to use ``rbac`` UI (#13569)
-- Make docs clear that Auth can not be disabled for Stable API (#13568)
-- Remove archived links from docs & add link for AIPs (#13580)
-- Minor fixes in upgrading-to-2.rst (#13583)
-- Fix Link in Upgrading to 2.0 guide (#13584)
-- Fix heading for Mocking section in best-practices.rst (#13658)
-- Add docs on how to use custom operators within plugins folder (#13186)
-- Update docs to register Operator Extra Links (#13683)
-- Improvements for database setup docs (#13696)
-- Replace module path to Class with just Class Name (#13719)
-- Update DAG Serialization docs (#13722)
-- Fix link to Apache Airflow docs in webserver (#13250)
-- Clarifies differences between extras and provider packages (#13810)
-- Add information about all access methods to the environment (#13940)
-- Docs: Fix FAQ on scheduler latency (#13969)
-- Updated taskflow api doc to show dependency with sensor (#13968)
-- Add deprecated config options to docs (#13883)
-- Added a FAQ section to the Upgrading to 2 doc (#13979)
-
-Airflow 2.0.0 (2020-12-18)
---------------------------
+.. code-block:: python
-The full changelog is about 3,000 lines long (already excluding everything backported to 1.10)
-so please check `Airflow 2.0.0 Highlights Blog Post `_
-instead.
+ from airflow.providers.standard.operators.python import PythonOperator
-Significant Changes
-^^^^^^^^^^^^^^^^^^^
+The SimpleHttpOperator has been migrated to apache-airflow-providers-http and renamed to HttpOperator
-The 2.0 release of the Airflow is a significant upgrade, and includes substantial major changes,
-and some of them may be breaking. Existing code written for earlier versions of this project will may require updates
-to use this version. Sometimes necessary configuration changes are also required.
-This document describes the changes that have been made, and what you need to do to update your usage.
+UI & Usability Improvements
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
-If you experience issues or have questions, please file `an issue `_.
+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.
-Major changes
+New Home Page
"""""""""""""
-This section describes the major changes that have been made in this release.
-
-The experimental REST API is disabled by default
-""""""""""""""""""""""""""""""""""""""""""""""""
-
-The experimental REST API is disabled by default. To restore these APIs while migrating to
-the stable REST API, set ``enable_experimental_api`` option in ``[api]`` section to ``True``.
-
-Please note that the experimental REST API do not have access control.
-The authenticated user has full access.
-
-SparkJDBCHook default connection
-""""""""""""""""""""""""""""""""
-
-For SparkJDBCHook default connection was ``spark-default``\ , and for SparkSubmitHook it was
-``spark_default``. Both hooks now use the ``spark_default`` which is a common pattern for the connection
-names used across all providers.
+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.
-Changes to output argument in commands
-""""""""""""""""""""""""""""""""""""""
+Unified DAG List View
+""""""""""""""""""""""
-From Airflow 2.0, We are replacing `tabulate `_ with `rich `_ to render commands output. Due to this change, the ``--output`` argument
-will no longer accept formats of tabulate tables. Instead, it now accepts:
-
-
-* ``table`` - will render the output in predefined table
-* ``json`` - will render the output as a json
-* ``yaml`` - will render the output as yaml
-
-By doing this we increased consistency and gave users possibility to manipulate the
-output programmatically (when using json or yaml).
-
-Affected commands:
-
-
-* ``airflow dags list``
-* ``airflow dags report``
-* ``airflow dags list-runs``
-* ``airflow dags list-jobs``
-* ``airflow connections list``
-* ``airflow connections get``
-* ``airflow pools list``
-* ``airflow pools get``
-* ``airflow pools set``
-* ``airflow pools delete``
-* ``airflow pools import``
-* ``airflow pools export``
-* ``airflow role list``
-* ``airflow providers list``
-* ``airflow providers get``
-* ``airflow providers hooks``
-* ``airflow tasks states-for-dag-run``
-* ``airflow users list``
-* ``airflow variables list``
-
-Azure Wasb Hook does not work together with Snowflake hook
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-
-The WasbHook in Apache Airflow use a legacy version of Azure library. While the conflict is not
-significant for most of the Azure hooks, it is a problem for Wasb Hook because the ``blob`` folders
-for both libraries overlap. Installing both Snowflake and Azure extra will result in non-importable
-WasbHook.
-
-Rename ``all`` to ``devel_all`` extra
-"""""""""""""""""""""""""""""""""""""""""""""
+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.
-The ``all`` extras were reduced to include only user-facing dependencies. This means
-that this extra does not contain development dependencies. If you were relying on
-``all`` extra then you should use now ``devel_all`` or figure out if you need development
-extras at all.
+Version-Aware Graph and Grid Views
+"""""""""""""""""""""""""""""""""""
-Context variables ``prev_execution_date_success`` and ``prev_execution_date_success`` are now ``pendulum.DateTime``
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+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.
-Rename policy to task_policy
-""""""""""""""""""""""""""""
+Expanded DAG Graph Visualization
+""""""""""""""""""""""""""""""""
-Because Airflow introduced DAG level policy (\ ``dag_policy``\ ) we decided to rename existing ``policy``
-function to ``task_policy`` to make the distinction more profound and avoid any confusion.
+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.
-Users using cluster policy need to rename their ``policy`` functions in ``airflow_local_settings.py``
-to ``task_policy``.
+DAG Code View
+"""""""""""""
-Default value for ``[celery] operation_timeout`` has changed to ``1.0``
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+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.
-From Airflow 2, by default Airflow will retry 3 times to publish task to Celery broker. This is controlled by
-``[celery] task_publish_max_retries``. Because of this we can now have a lower Operation timeout that raises
-``AirflowTaskTimeout``. This generally occurs during network blips or intermittent DNS issues.
+Improved Task Log Access
+"""""""""""""""""""""""""
-Adding Operators and Sensors via plugins is no longer supported
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+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.
-Operators and Sensors should 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.
+Enhanced Asset and Backfill Views
+""""""""""""""""""""""""""""""""""
-If you previously had a ``plugins/my_plugin.py`` and you used it like this in a DAG:
+New UI components support asset-centric DAGs and backfill workflows:
-.. code-block::
+- 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.
- from airflow.operators.my_plugin import MyOperator
+These improvements make Airflow more accessible to operators, data engineers, and stakeholders working across both
+time-based and event-driven workflows.
-You should instead import it as:
+Deprecations & Removals
+^^^^^^^^^^^^^^^^^^^^^^^^
-.. code-block::
+A number of deprecated features, modules, and interfaces have been removed in Airflow 3.0, completing long-standing
+migrations and cleanups.
- from my_plugin import MyOperator
+Users are encouraged to review the following removals to ensure compatibility:
-The name under ``airflow.operators.`` was the plugin name, where as in the second example it is the python module name where the operator is defined.
+- **SubDag support has been removed** entirely, including the ``SubDagOperator``, related CLI and API interfaces. TaskGroups are now the recommended alternative for nested DAG structures.
-See https://airflow.apache.org/docs/apache-airflow/stable/howto/custom-operator.html for more info.
+- **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.
-Importing Hooks via plugins is no longer supported
-""""""""""""""""""""""""""""""""""""""""""""""""""
+- **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.
-Importing hooks added in plugins via ``airflow.hooks.`` is no longer supported, and hooks should just be imported as regular python modules.
+- **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.
-.. code-block::
+- **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.
- from airflow.hooks.my_plugin import MyHook
+- **Configuration cleanup**: Several legacy config options have been removed, including:
-You should instead import it as:
+ - ``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.
-.. code-block::
+- **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.
- from my_plugin import MyHook
+- **Removal of deprecated CLI flags and behavior**: Several CLI entrypoints and arguments that were marked for removal in earlier versions have been cleaned up.
-It is still possible (but not required) to "register" hooks in plugins. This is to allow future support for dynamically populating the Connections form in the UI.
+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.
-See https://airflow.apache.org/docs/apache-airflow/stable/howto/custom-operator.html for more info.
+Summary of Removed Features
+"""""""""""""""""""""""""""
-The default value for ``[core] enable_xcom_pickling`` has been changed to ``False``
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+The following table summarizes user-facing features removed in 3.0 and their recommended replacements. Not all of these
+are called out individually above.
-The pickle type for XCom messages has been replaced to JSON by default to prevent RCE attacks.
-Note that JSON serialization is stricter than pickling, so for example if you want to pass
-raw bytes through XCom you must encode them using an encoding like ``base64``.
-If you understand the risk and still want to use `pickling `_\ ,
-set ``enable_xcom_pickling = True`` in your Airflow config's ``core`` section.
++-------------------------------------------+----------------------------------------------------------+
+| **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 |
++-------------------------------------------+----------------------------------------------------------+
-Airflowignore of base path
-""""""""""""""""""""""""""
+Migration Tooling & Upgrade Process
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-There was a bug fixed in https://github.com/apache/airflow/pull/11993 that the "airflowignore" checked
-the base path of the dag folder for forbidden dags, not only the relative part. This had the effect
-that if the base path contained the excluded word the whole dag folder could have been excluded. For
-example if the airflowignore file contained x, and the dags folder was '/var/x/dags', then all dags in
-the folder would be excluded. The fix only matches the relative path only now which means that if you
-previously used full path as ignored, you should change it to relative one. For example if your dag
-folder was '/var/dags/' and your airflowignore contained '/var/dag/excluded/', you should change it
-to 'excluded/'.
+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.
-``ExternalTaskSensor`` provides all task context variables to ``execution_date_fn`` as keyword arguments
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+For a step-by-step upgrade process, see the :doc:`Upgrade Guide `.
-The old syntax of passing ``context`` as a dictionary will continue to work with the caveat that the argument must be named ``context``. The following will break. To fix it, change ``ctx`` to ``context``.
+Minimum Supported Versions
+"""""""""""""""""""""""""""
-.. code-block:: python
+To upgrade to Airflow 3.0, you must be running **Airflow 2.7 or later**.
- def execution_date_fn(execution_date, ctx): ...
+Airflow 3.0 supports the following Python versions:
-``execution_date_fn`` can take in any number of keyword arguments available in the task context dictionary. The following forms of ``execution_date_fn`` are all supported:
+- Python 3.9
+- Python 3.10
+- Python 3.11
+- Python 3.12
-.. code-block:: python
+Earlier versions of Airflow or Python are not supported due to architectural changes and updated dependency requirements.
- def execution_date_fn(dt): ...
+DAG Compatibility Checks
+"""""""""""""""""""""""""
+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:
- def execution_date_fn(execution_date): ...
+.. code-block:: bash
+ ruff check dags/ --select AIR301 --preview
+ ruff check dags/ --select AIR301 --fix --preview
- def execution_date_fn(execution_date, ds_nodash): ...
+These checks can automatically fix many common issues such as renamed arguments, removed imports, or legacy context
+variable usage.
+Configuration Migration
+"""""""""""""""""""""""
- def execution_date_fn(execution_date, ds_nodash, dag): ...
+Airflow 3.0 introduces a new utility to validate and upgrade your Airflow configuration file:
-The default value for ``[webserver] cookie_samesite`` has been changed to ``Lax``
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.. code-block:: bash
-As `recommended `_ by Flask, the
-``[webserver] cookie_samesite`` has been changed to ``Lax`` from ``''`` (empty string) .
-
-Changes to import paths
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Formerly the core code was maintained by the original creators - Airbnb. The code that was in the contrib
-package was supported by the community. The project was passed to the Apache community and currently the
-entire code is maintained by the community, so now the division has no justification, and it is only due
-to historical reasons. In Airflow 2.0, we want to organize packages and move integrations
-with third party services to the ``airflow.providers`` package.
-
-All changes made are backward compatible, but if you use the old import paths you will
-see a deprecation warning. The old import paths can be abandoned in the future.
-
-According to `AIP-21 `_
-``_operator`` suffix has been removed from operators. A deprecation warning has also been raised for paths
-importing with the suffix.
-
-The following table shows changes in import paths.
-
-.. list-table::
- :header-rows: 1
-
- * - Old path
- - New path
- * - ``airflow.hooks.base_hook.BaseHook``
- - ``airflow.hooks.base.BaseHook``
- * - ``airflow.hooks.dbapi_hook.DbApiHook``
- - ``airflow.hooks.dbapi.DbApiHook``
- * - ``airflow.operators.dummy_operator.DummyOperator``
- - ``airflow.operators.dummy.DummyOperator``
- * - ``airflow.operators.dagrun_operator.TriggerDagRunOperator``
- - ``airflow.operators.trigger_dagrun.TriggerDagRunOperator``
- * - ``airflow.operators.branch_operator.BaseBranchOperator``
- - ``airflow.operators.branch.BaseBranchOperator``
- * - ``airflow.operators.subdag_operator.SubDagOperator``
- - ``airflow.operators.subdag.SubDagOperator``
- * - ``airflow.sensors.base_sensor_operator.BaseSensorOperator``
- - ``airflow.sensors.base.BaseSensorOperator``
- * - ``airflow.sensors.date_time_sensor.DateTimeSensor``
- - ``airflow.sensors.date_time.DateTimeSensor``
- * - ``airflow.sensors.external_task_sensor.ExternalTaskMarker``
- - ``airflow.sensors.external_task.ExternalTaskMarker``
- * - ``airflow.sensors.external_task_sensor.ExternalTaskSensor``
- - ``airflow.sensors.external_task.ExternalTaskSensor``
- * - ``airflow.sensors.sql_sensor.SqlSensor``
- - ``airflow.sensors.sql.SqlSensor``
- * - ``airflow.sensors.time_delta_sensor.TimeDeltaSensor``
- - ``airflow.sensors.time_delta.TimeDeltaSensor``
- * - ``airflow.contrib.sensors.weekday_sensor.DayOfWeekSensor``
- - ``airflow.sensors.weekday.DayOfWeekSensor``
-
-
-Database schema changes
-"""""""""""""""""""""""
+ airflow config update
+ airflow config update --fix
-In order to migrate the database, you should use the command ``airflow db upgrade``\ , but in
-some cases manual steps are required.
+This utility detects removed or deprecated configuration options and, if desired, updates them in-place.
-Unique conn_id in connection table
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Additional validation is available via:
-Previously, Airflow allowed users to add more than one connection with the same ``conn_id`` and on access it would choose one connection randomly. This acted as a basic load balancing and fault tolerance technique, when used in conjunction with retries.
+.. code-block:: bash
-This behavior caused some confusion for users, and there was no clear evidence if it actually worked well or not.
+ airflow config lint
-Now the ``conn_id`` will be unique. If you already have duplicates in your metadata database, you will have to manage those duplicate connections before upgrading the database.
+This command surfaces obsolete configuration keys and helps align your environment with Airflow 3.0 requirements.
-Not-nullable conn_type column in connection table
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Metadata Database Upgrade
+"""""""""""""""""""""""""
-The ``conn_type`` column in the ``connection`` table must contain content. Previously, this rule was enforced
-by application logic, but was not enforced by the database schema.
+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:
-If you made any modifications to the table directly, make sure you don't have
-null in the ``conn_type`` column.
+.. code-block:: bash
-Configuration changes
-"""""""""""""""""""""
+ airflow db clean
-This release contains many changes that require a change in the configuration of this application or
-other application that integrate with it.
+to remove old task instance, log, or XCom data. To apply the new schema:
-This section describes the changes that have been made, and what you need to do to.
+.. code-block:: bash
-airflow.contrib.utils.log has been moved
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ airflow db migrate
-Formerly the core code was maintained by the original creators - Airbnb. The code that was in the contrib
-package was supported by the community. The project was passed to the Apache community and currently the
-entire code is maintained by the community, so now the division has no justification, and it is only due
-to historical reasons. In Airflow 2.0, we want to organize packages and move integrations
-with third party services to the ``airflow.providers`` package.
+Startup Behavior Changes
+"""""""""""""""""""""""""
-To clean up, the following packages were moved:
+Airflow components are now started explicitly. For example:
-.. list-table::
- :header-rows: 1
+.. code-block:: bash
- * - Old package
- - New package
- * - ``airflow.contrib.utils.log``
- - ``airflow.utils.log``
- * - ``airflow.utils.log.gcs_task_handler``
- - ``airflow.providers.google.cloud.log.gcs_task_handler``
- * - ``airflow.utils.log.wasb_task_handler``
- - ``airflow.providers.microsoft.azure.log.wasb_task_handler``
- * - ``airflow.utils.log.stackdriver_task_handler``
- - ``airflow.providers.google.cloud.log.stackdriver_task_handler``
- * - ``airflow.utils.log.s3_task_handler``
- - ``airflow.providers.amazon.aws.log.s3_task_handler``
- * - ``airflow.utils.log.es_task_handler``
- - ``airflow.providers.elasticsearch.log.es_task_handler``
- * - ``airflow.utils.log.cloudwatch_task_handler``
- - ``airflow.providers.amazon.aws.log.cloudwatch_task_handler``
+ airflow api-server # Replaces airflow webserver
+ airflow dag-processor # Required in all environments
-You should update the import paths if you are setting log configurations with the ``logging_config_class`` option.
-The old import paths still works but can be abandoned.
+These changes reflect Airflow's new service-oriented architecture.
-SendGrid emailer has been moved
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Resources
+^^^^^^^^^
-Formerly the core code was maintained by the original creators - Airbnb. The code that was in the contrib
-package was supported by the community. The project was passed to the Apache community and currently the
-entire code is maintained by the community, so now the division has no justification, and it is only due
-to historical reasons.
+- :doc:`Upgrade Guide `
+- `Airflow AIPs `_
-To clean up, the ``send_mail`` function from the ``airflow.contrib.utils.sendgrid`` module has been moved.
+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.
-If your configuration file looks like this:
+Airflow 2.11.0 (2025-05-20)
+---------------------------
-.. code-block:: ini
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
- [email]
- email_backend = airflow.contrib.utils.sendgrid.send_email
+``DeltaTriggerTimetable`` for trigger-based scheduling (#47074)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-It should look like this now:
+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.
-.. code-block:: ini
+Airflow currently has two major types of timetables:
+ - Data interval-based (e.g., ``CronDataIntervalTimetable``, ``DeltaDataIntervalTimetable``)
+ - Trigger-based (e.g., ``CronTriggerTimetable``)
- [email]
- email_backend = airflow.providers.sendgrid.utils.emailer.send_email
+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.
-The old configuration still works but can be abandoned.
+This feature is backported to Airflow 2.11.0 to help users begin transitioning before upgrading to Airflow 3.0.
-Unify ``hostname_callable`` option in ``core`` section
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ - 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.
-The previous option used a colon(\ ``:``\ ) to split the module from function. Now the dot(\ ``.``\ ) is used.
+By flipping this config in 2.11, users can preview and adopt the new scheduling behavior in advance — minimizing surprises during upgrade.
-The change aims to unify the format of all options that refer to objects in the ``airflow.cfg`` file.
-Custom executors is loaded using full import path
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consistent timing metrics across all backends (#39908, #43966)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-In previous versions of Airflow it was possible to use plugins to load custom executors. It is still
-possible, but the configuration has changed. Now you don't have to create a plugin to configure a
-custom executor, but you need to provide the full path to the module in the ``executor`` option
-in the ``core`` section. The purpose of this change is to simplify the plugin mechanism and make
-it easier to configure executor.
+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.
-If your module was in the path ``my_acme_company.executors.MyCustomExecutor`` and the plugin was
-called ``my_plugin`` then your configuration looks like this
+Airflow 2.11 introduces a new config option:
-.. code-block:: ini
+ - ``[metrics] timer_unit_consistency`` (default: ``False`` in 2.11, ``True`` and dropped in Airflow 3.0).
- [core]
- executor = my_plugin.MyCustomExecutor
+When enabled, all timing metrics are consistently reported in milliseconds, regardless of the backend.
-And now it should look like this:
+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.
-.. code-block:: ini
+Ease migration to Airflow 3
+"""""""""""""""""""""""""""
+This release introduces several changes to help users prepare for upgrading to Airflow 3:
- [core]
- executor = my_acme_company.executors.MyCustomExecutor
+ - 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)
-The old configuration is still works but can be abandoned at any time.
+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.
-Use ``CustomSQLAInterface`` instead of ``SQLAInterface`` for custom data models.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+New Features
+""""""""""""
-From Airflow 2.0, if you want to define your own Flask App Builder data models you need to use CustomSQLAInterface
-instead of SQLAInterface.
+- 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)
-For Non-RBAC replace:
+Bug Fixes
+"""""""""
-.. code-block:: python
+- 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)
- from flask_appbuilder.models.sqla.interface import SQLAInterface
+Miscellaneous
+"""""""""""""
- datamodel = SQLAInterface(your_data_model)
+- 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)
-with RBAC (in 1.10):
+Doc Only Changes
+""""""""""""""""
+- Unquote executor ``airflow.cfg`` variable (#48084)
+- Update ``XCom`` docs to show examples of pushing multiple ``XComs`` (#46284, #47068)
-.. code-block:: python
+Airflow 2.10.5 (2025-02-10)
+---------------------------
- from airflow.www_rbac.utils import CustomSQLAInterface
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
- datamodel = CustomSQLAInterface(your_data_model)
+Ensure teardown tasks are executed when DAG run is set to failed (#45530)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-and in 2.0:
+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.
-.. code-block:: python
+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.
- from airflow.www.utils import CustomSQLAInterface
+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".
- datamodel = CustomSQLAInterface(your_data_model)
-Drop plugin support for stat_name_handler
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Bug Fixes
+"""""""""
-In previous version, you could use plugins mechanism to configure ``stat_name_handler``. You should now use the ``stat_name_handler``
-option in ``[scheduler]`` section to achieve the same effect.
+- 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)
-If your plugin looked like this and was available through the ``test_plugin`` path:
-.. code-block:: python
+Miscellaneous
+"""""""""""""
- def my_stat_name_handler(stat):
- return stat
+- 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)
- class AirflowTestPlugin(AirflowPlugin):
- name = "test_plugin"
- stat_name_handler = my_stat_name_handler
+Airflow 2.10.4 (2024-12-16)
+---------------------------
-then your ``airflow.cfg`` file should look like this:
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-.. code-block:: ini
+TaskInstance ``priority_weight`` is capped in 32-bit signed integer ranges (#43611)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- [scheduler]
- stat_name_handler=test_plugin.my_stat_name_handler
+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.
-This change is intended to simplify the statsd configuration.
+Bug Fixes
+^^^^^^^^^
-Logging configuration has been moved to new section
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- 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)
-The following configurations have been moved from ``[core]`` to the new ``[logging]`` section.
+Doc Only Changes
+""""""""""""""""
+- Update XCom docs around containers/helm (#44570) (#44573)
+Miscellaneous
+"""""""""""""
+- Raise deprecation warning when accessing inlet or outlet events through str (#43922)
-* ``base_log_folder``
-* ``remote_logging``
-* ``remote_log_conn_id``
-* ``remote_base_log_folder``
-* ``encrypt_s3_logs``
-* ``logging_level``
-* ``fab_logging_level``
-* ``logging_config_class``
-* ``colored_console_log``
-* ``colored_log_format``
-* ``colored_formatter_class``
-* ``log_format``
-* ``simple_log_format``
-* ``task_log_prefix_template``
-* ``log_filename_template``
-* ``log_processor_filename_template``
-* ``dag_processor_manager_log_location``
-* ``task_log_reader``
-Metrics configuration has been moved to new section
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Airflow 2.10.3 (2024-11-05)
+---------------------------
-The following configurations have been moved from ``[scheduler]`` to the new ``[metrics]`` section.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
+No significant changes.
-* ``statsd_on``
-* ``statsd_host``
-* ``statsd_port``
-* ``statsd_prefix``
-* ``statsd_allow_list``
-* ``stat_name_handler``
-* ``statsd_datadog_enabled``
-* ``statsd_datadog_tags``
-* ``statsd_custom_client_path``
+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)
-Changes to Elasticsearch logging provider
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-When JSON output to stdout is enabled, log lines will now contain the ``log_id`` & ``offset`` fields, this should make reading task logs from elasticsearch on the webserver work out of the box. Example configuration:
+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)
-.. code-block:: ini
- [logging]
- remote_logging = True
- [elasticsearch]
- host = http://es-host:9200
- write_stdout = True
- json_format = True
+Airflow 2.10.2 (2024-09-18)
+---------------------------
-Note that the webserver expects the log line data itself to be present in the ``message`` field of the document.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Remove gcp_service_account_keys option in airflow.cfg file
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+No significant changes.
-This option has been removed because it is no longer supported by the Google Kubernetes Engine. The new
-recommended service account keys for the Google Cloud management method is
-`Workload Identity `_.
+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)
-Fernet is enabled by default
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-The fernet mechanism is enabled by default to increase the security of the default installation. In order to
-restore the previous behavior, the user must consciously set an empty key in the ``fernet_key`` option of
-section ``[core]`` in the ``airflow.cfg`` file.
+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)
-At the same time, this means that the ``apache-airflow[crypto]`` extra-packages are always installed.
-However, this requires that your operating system has ``libffi-dev`` installed.
-Changes to propagating Kubernetes worker annotations
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Airflow 2.10.1 (2024-09-05)
+---------------------------
-``kubernetes_annotations`` configuration section has been removed.
-A new key ``worker_annotations`` has been added to existing ``kubernetes`` section instead.
-That is to remove restriction on the character set for k8s annotation keys.
-All key/value pairs from ``kubernetes_annotations`` should now go to ``worker_annotations`` as a json. I.e. instead of e.g.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-.. code-block::
+No significant changes.
- [kubernetes_annotations]
- annotation_key = annotation_value
- annotation_key2 = annotation_value2
+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)
-it should be rewritten to
+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::
+Doc Only Changes
+""""""""""""""""
+- Remove Debian bullseye support (#41569)
+- Add an example for auth with ``keycloak`` (#41791)
- [kubernetes]
- worker_annotations = { "annotation_key" : "annotation_value", "annotation_key2" : "annotation_value2" }
-Remove run_duration
-~~~~~~~~~~~~~~~~~~~
+Airflow 2.10.0 (2024-08-15)
+---------------------------
-We should not use the ``run_duration`` option anymore. This used to be for restarting the scheduler from time to time, but right now the scheduler is getting more stable and therefore using this setting is considered bad and might cause an inconsistent state.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Rename pool statsd metrics
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-Used slot has been renamed to running slot to make the name self-explanatory
-and the code more maintainable.
+Datasets no longer trigger inactive DAGs (#38891)
+"""""""""""""""""""""""""""""""""""""""""""""""""
-This means ``pool.used_slots.`` metric has been renamed to
-``pool.running_slots.``. The ``Used Slots`` column in Pools Web UI view
-has also been changed to ``Running Slots``.
+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.
-Removal of Mesos Executor
-~~~~~~~~~~~~~~~~~~~~~~~~~
+The behavior of time-based scheduling is unchanged, including the timetable part
+of ``DatasetOrTimeSchedule``.
-The Mesos Executor is removed from the code base as it was not widely used and not maintained. `Mailing List Discussion on deleting it `_.
+``try_number`` is no longer incremented during task execution (#39336)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Change dag loading duration metric name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-Change DAG file loading duration metric from
-``dag.loading-duration.`` to ``dag.loading-duration.``. This is to
-better handle the case when a DAG file has multiple DAGs.
+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.
-Sentry is disabled by default
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-Sentry is disabled by default. To enable these integrations, you need set ``sentry_on`` option
-in ``[sentry]`` section to ``"True"``.
+``/logout`` endpoint in FAB Auth Manager is now CSRF protected (#40145)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Simplified GCSTaskHandler configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-In previous versions, in order to configure the service account key file, you had to create a connection entry.
-In the current version, you can configure ``google_key_path`` option in ``[logging]`` section to set
-the key file path.
+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.
-Users using Application Default Credentials (ADC) need not take any action.
+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 change aims to simplify the configuration of logging, to prevent corruption of
-the instance configuration by changing the value controlled by the user - connection entry. If you
-configure a backend secret, it also means the webserver doesn't need to connect to it. This
-simplifies setups with multiple GCP projects, because only one project will require the Secret Manager API
-to be enabled.
+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.
-Changes to the core operators/hooks
-"""""""""""""""""""""""""""""""""""
+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)
-We strive to ensure that there are no changes that may affect the end user and your files, but this
-release may contain changes that will require changes to your DAG files.
-This section describes the changes that have been made, and what you need to do to update your DAG File,
-if you use core operators or any other.
+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)
-BaseSensorOperator now respects the trigger_rule of downstream tasks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-Previously, BaseSensorOperator with setting ``soft_fail=True`` skips itself
-and skips all its downstream tasks unconditionally, when it fails i.e the trigger_rule of downstream tasks is not
-respected.
+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)
-In the new behavior, the trigger_rule of downstream tasks is respected.
-User can preserve/achieve the original behaviour by setting the trigger_rule of each downstream task to ``all_success``.
+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)
-BaseOperator uses metaclass
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-``BaseOperator`` class uses a ``BaseOperatorMeta`` as a metaclass. This meta class is based on
-``abc.ABCMeta``. If your custom operator uses different metaclass then you will have to adjust it.
-Remove SQL support in BaseHook
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Airflow 2.9.3 (2024-07-15)
+--------------------------
-Remove ``get_records`` and ``get_pandas_df`` and ``run`` from BaseHook, which only apply for SQL-like hook,
-If want to use them, or your custom hook inherit them, please use ``airflow.hooks.dbapi.DbApiHook``
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Assigning task to a DAG using bitwise shift (bit-shift) operators are no longer supported
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Time unit for ``scheduled_duration`` and ``queued_duration`` changed (#37936)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Previously, you could assign a task to a DAG as follows:
+``scheduled_duration`` and ``queued_duration`` metrics are now emitted in milliseconds instead of seconds.
-.. code-block:: python
+By convention all statsd metrics should be emitted in milliseconds, this is later expected in e.g. ``prometheus`` statsd-exporter.
- dag = DAG("my_dag")
- dummy = DummyOperator(task_id="dummy")
- dag >> dummy
+Support for OpenTelemetry Metrics is no longer "Experimental" (#40286)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-This is no longer supported. Instead, we recommend using the DAG as context manager:
+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.
-.. code-block:: python
- with DAG("my_dag") as dag:
- dummy = DummyOperator(task_id="dummy")
-Removed deprecated import mechanism
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-The deprecated import mechanism has been removed so the import of modules becomes more consistent and explicit.
+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)
-For example: ``from airflow.operators import BashOperator``
-becomes ``from airflow.operators.bash_operator import BashOperator``
+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)
-Changes to sensor imports
-~~~~~~~~~~~~~~~~~~~~~~~~~
-Sensors are now accessible via ``airflow.sensors`` and no longer via ``airflow.operators.sensors``.
-For example: ``from airflow.operators.sensors import BaseSensorOperator``
-becomes ``from airflow.sensors.base import BaseSensorOperator``
+Airflow 2.9.2 (2024-06-10)
+--------------------------
-Skipped tasks can satisfy wait_for_downstream
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Previously, a task instance with ``wait_for_downstream=True`` will only run if the downstream task of
-the previous task instance is successful. Meanwhile, a task instance with ``depends_on_past=True``
-will run if the previous task instance is either successful or skipped. These two flags are close siblings
-yet they have different behavior. This inconsistency in behavior made the API less intuitive to users.
-To maintain consistent behavior, both successful or skipped downstream task can now satisfy the
-``wait_for_downstream=True`` flag.
+No significant changes.
-``airflow.utils.helpers.cross_downstream``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``airflow.utils.helpers.chain``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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 ``chain`` and ``cross_downstream`` methods are now moved to airflow.models.baseoperator module from
-``airflow.utils.helpers`` module.
+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)
-The ``baseoperator`` module seems to be a better choice to keep
-closely coupled methods together. Helpers module is supposed to contain standalone helper methods
-that can be imported by all classes.
-The ``chain`` method and ``cross_downstream`` method both use BaseOperator. If any other package imports
-any classes or functions from helpers module, then it automatically has an
-implicit dependency to BaseOperator. That can often lead to cyclic dependencies.
-More information in `AIRFLOW-6392 `_
+Airflow 2.9.1 (2024-05-03)
+--------------------------
-In Airflow < 2.0 you imported those two methods like this:
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-.. code-block:: python
+Stackdriver logging bugfix requires Google provider ``10.17.0`` or later (#38071)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- from airflow.utils.helpers import chain
- from airflow.utils.helpers import cross_downstream
+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.
-In Airflow 2.0 it should be changed to:
+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.
-.. code-block:: python
- from airflow.models.baseoperator import chain
- from airflow.models.baseoperator import cross_downstream
-``airflow.operators.python.BranchPythonOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``BranchPythonOperator`` will now return a value equal to the ``task_id`` of the chosen branch,
-where previously it returned None. Since it inherits from BaseOperator it will do an
-``xcom_push`` of this value if ``do_xcom_push=True``. This is useful for downstream decision-making.
+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)
-``airflow.sensors.sql_sensor.SqlSensor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-SQLSensor now consistent with python ``bool()`` function and the ``allow_null`` parameter has been removed.
+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)
-It will resolve after receiving any value that is casted to ``True`` with python ``bool(value)``. That
-changes the previous response receiving ``NULL`` or ``'0'``. Earlier ``'0'`` has been treated as success
-criteria. ``NULL`` has been treated depending on value of ``allow_null``\ parameter. But all the previous
-behaviour is still achievable setting param ``success`` to ``lambda x: x is None or str(x) not in ('0', '')``.
-``airflow.operators.trigger_dagrun.TriggerDagRunOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The TriggerDagRunOperator now takes a ``conf`` argument to which a dict can be provided as conf for the DagRun.
-As a result, the ``python_callable`` argument was removed. PR: https://github.com/apache/airflow/pull/6317.
+Airflow 2.9.0 (2024-04-08)
+--------------------------
-``airflow.operators.python.PythonOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``provide_context`` argument on the PythonOperator was removed. The signature of the callable passed to the PythonOperator is now inferred and argument values are always automatically provided. There is no need to explicitly provide or not provide the context anymore. For example:
+Following Listener API methods are considered stable and can be used for production system (were experimental feature in older Airflow versions) (#36376):
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Lifecycle events:
-.. code-block:: python
+- ``on_starting``
+- ``before_stopping``
- def myfunc(execution_date):
- print(execution_date)
+DagRun State Change Events:
+- ``on_dag_run_running``
+- ``on_dag_run_success``
+- ``on_dag_run_failed``
- python_operator = PythonOperator(task_id="mytask", python_callable=myfunc, dag=dag)
+TaskInstance State Change Events:
-Notice you don't have to set provide_context=True, variables from the task context are now automatically detected and provided.
+- ``on_task_instance_running``
+- ``on_task_instance_success``
+- ``on_task_instance_failed``
-All context variables can still be provided with a double-asterisk argument:
+Support for Microsoft SQL-Server for Airflow Meta Database has been removed (#36514)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.. code-block:: python
+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.
- def myfunc(**context):
- print(context) # all variables will be provided to context
+As of Airflow 2.9.0 support of MsSQL has been removed for Airflow Database Backend.
+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.
- python_operator = PythonOperator(task_id="mytask", python_callable=myfunc)
+This does not affect the existing provider packages (operators and hooks), DAGs can still access and process data from MsSQL.
-The task context variable names are reserved names in the callable function, hence a clash with ``op_args`` and ``op_kwargs`` results in an exception:
+Dataset URIs are now validated on input (#37005)
+""""""""""""""""""""""""""""""""""""""""""""""""
-.. code-block:: python
+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.
- def myfunc(dag):
- # raises a ValueError because "dag" is a reserved name
- # valid signature example: myfunc(mydag)
- print("output")
+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 method ``get_permitted_menu_items`` in ``BaseAuthManager`` has been renamed ``filter_permitted_menu_items`` (#37627)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- python_operator = PythonOperator(
- task_id="mytask",
- op_args=[1],
- python_callable=myfunc,
- )
+Add REST API actions to Audit Log events (#37734)
+"""""""""""""""""""""""""""""""""""""""""""""""""
-The change is backwards compatible, setting ``provide_context`` will add the ``provide_context`` variable to the ``kwargs`` (but won't do anything).
+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.
-PR: `#5990 `_
+Official support for Python 3.12 (#38025)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+There are a few caveats though:
-``airflow.providers.standard.sensors.filesystem.FileSensor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Pendulum2 does not support Python 3.12. For Python 3.12 you need to use
+ `Pendulum 3 `_
-FileSensor is now takes a glob pattern, not just a filename. If the filename you are looking for has ``*``\ , ``?``\ , or ``[`` in it then you should replace these with ``[*]``\ , ``[?]``\ , and ``[[]``.
+* 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.
-``airflow.operators.subdag_operator.SubDagOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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:
-``SubDagOperator`` is changed to use Airflow scheduler instead of backfill
-to schedule tasks in the subdag. User no longer need to specify the executor
-in ``SubDagOperator``.
+ * ``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 `_
-``airflow.providers.google.cloud.operators.datastore.CloudDatastoreExportEntitiesOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.google.cloud.operators.datastore.CloudDatastoreImportEntitiesOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.cncf.kubernetes.operators.kubernetes_pod.KubernetesPodOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.ssh.operators.ssh.SSHOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Stronger validation for key parameter defaults in taskflow context variables (#38015)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-``airflow.providers.microsoft.winrm.operators.winrm.WinRMOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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``.
-``airflow.operators.bash.BashOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``airflow.providers.docker.operators.docker.DockerOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``airflow.providers.http.operators.http.SimpleHttpOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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 ``do_xcom_push`` flag (a switch to push the result of an operator to xcom or not) was appearing in different incarnations in different operators. It's function has been unified under a common name (\ ``do_xcom_push``\ ) on ``BaseOperator``. This way it is also easy to globally disable pushing results to xcom.
+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)
-The following operators were affected:
+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)
-* DatastoreExportOperator (Backwards compatible)
-* DatastoreImportOperator (Backwards compatible)
-* KubernetesPodOperator (Not backwards compatible)
-* SSHOperator (Not backwards compatible)
-* WinRMOperator (Not backwards compatible)
-* BashOperator (Not backwards compatible)
-* DockerOperator (Not backwards compatible)
-* SimpleHttpOperator (Not backwards compatible)
+Airflow 2.8.4 (2024-03-25)
+--------------------------
-See `AIRFLOW-3249 `_ for details
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``airflow.operators.latest_only_operator.LatestOnlyOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+No significant changes.
-In previous versions, the ``LatestOnlyOperator`` forcefully skipped all (direct and indirect) downstream tasks on its own. From this version on the operator will **only skip direct downstream** tasks and the scheduler will handle skipping any further downstream dependencies.
+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)
-No change is needed if only the default trigger rule ``all_success`` is being used.
+Miscellaneous
+"""""""""""""
+- 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)
-If the DAG relies on tasks with other trigger rules (i.e. ``all_done``\ ) being skipped by the ``LatestOnlyOperator``\ , adjustments to the DAG need to be made to accommodate the change in behaviour, i.e. with additional edges from the ``LatestOnlyOperator``.
+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 goal of this change is to achieve a more consistent and configurable cascading behaviour based on the ``BaseBranchOperator`` (see `AIRFLOW-2923 `_ and `AIRFLOW-1784 `_\ ).
-Changes to the core Python API
-""""""""""""""""""""""""""""""
+Airflow 2.8.3 (2024-03-11)
+--------------------------
-We strive to ensure that there are no changes that may affect the end user, and your Python files, but this
-release may contain changes that will require changes to your plugins, DAG File or other integration.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Only changes unique to this provider are described here. You should still pay attention to the changes that
-have been made to the core (including core operators) as they can affect the integration behavior
-of this provider.
+The smtp provider is now pre-installed when you install Airflow. (#37713)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-This section describes the changes that have been made, and what you need to do to update your Python files.
+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)
-Removed sub-package imports from ``airflow/__init__.py``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Miscellaneous
+"""""""""""""
+- 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)
-The imports ``LoggingMixin``\ , ``conf``\ , and ``AirflowException`` have been removed from ``airflow/__init__.py``.
-All implicit references of these objects will no longer be valid. To migrate, all usages of each old path must be
-replaced with its corresponding new path.
+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)
-.. list-table::
- :header-rows: 1
- * - Old Path (Implicit Import)
- - New Path (Explicit Import)
- * - ``airflow.LoggingMixin``
- - ``airflow.utils.log.logging_mixin.LoggingMixin``
- * - ``airflow.conf``
- - ``airflow.configuration.conf``
- * - ``airflow.AirflowException``
- - ``airflow.exceptions.AirflowException``
+Airflow 2.8.2 (2024-02-26)
+--------------------------
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Variables removed from the task instance context
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The ``allowed_deserialization_classes`` flag now follows a glob pattern (#36147).
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-The following variables were removed from the task instance context:
+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.*``).
+If you currently use a custom regexp path make sure to rewrite it as a glob pattern.
-* end_date
-* latest_date
-* tables
+Alternatively, if you still wish to match it as a regexp pattern, add it under the new
+list ``allowed_deserialization_classes_regexp`` instead.
-``airflow.contrib.utils.Weekday``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The audit_logs permissions have been updated for heightened security (#37501).
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Formerly the core code was maintained by the original creators - Airbnb. The code that was in the contrib
-package was supported by the community. The project was passed to the Apache community and currently the
-entire code is maintained by the community, so now the division has no justification, and it is only due
-to historical reasons.
+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.
-To clean up, ``Weekday`` enum has been moved from ``airflow.contrib.utils`` into ``airflow.utils`` module.
+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.
-``airflow.models.connection.Connection``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+``AirflowTimeoutError`` is no longer ``except`` by default through ``Exception`` (#35653).
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-The connection module has new deprecated methods:
+The ``AirflowTimeoutError`` is now inheriting ``BaseException`` instead of
+``AirflowException``->``Exception``.
+See https://docs.python.org/3/library/exceptions.html#exception-hierarchy
+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.
-* ``Connection.parse_from_uri``
-* ``Connection.log_info``
-* ``Connection.debug_info``
+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
-and one deprecated function:
+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)
-* ``parse_netloc_to_hostname``
+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)
-Previously, users could create a connection object in two ways
+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)
-.. code-block::
- conn_1 = Connection(conn_id="conn_a", uri="mysql://AAA/")
- # or
- conn_2 = Connection(conn_id="conn_a")
- conn_2.parse_uri(uri="mysql://AAA/")
+Airflow 2.8.1 (2024-01-19)
+--------------------------
-Now the second way is not supported.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``Connection.log_info`` and ``Connection.debug_info`` method have been deprecated. Read each Connection field individually or use the
-default representation (\ ``__repr__``\ ).
+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.
-The old method is still works but can be abandoned at any time. The changes are intended to delete method
-that are rarely used.
+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.
-``airflow.models.dag.DAG.create_dagrun``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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:
-DAG.create_dagrun accepts run_type and does not require run_id
-This change is caused by adding ``run_type`` column to ``DagRun``.
+* `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 `__
-Previous signature:
+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 `__
-.. code-block:: python
+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]"``.
- def create_dagrun(
- self,
- run_id,
- state,
- execution_date=None,
- start_date=None,
- external_trigger=False,
- conf=None,
- session=None,
- ): ...
+The differences from the user side are:
-current:
+* 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 ``.``.
-.. code-block:: python
+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.
- def create_dagrun(
- self,
- state,
- execution_date=None,
- run_id=None,
- start_date=None,
- external_trigger=False,
- conf=None,
- run_type=None,
- session=None,
- ): ...
+* 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.
-If user provides ``run_id`` then the ``run_type`` will be derived from it by checking prefix, allowed types
-: ``manual``\ , ``scheduled``\ , ``backfill`` (defined by ``airflow.utils.types.DagRunType``\ ).
+* 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.
-If user provides ``run_type`` and ``execution_date`` then ``run_id`` is constructed as
-``{run_type}__{execution_data.isoformat()}``.
+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+.
-Airflow should construct dagruns using ``run_type`` and ``execution_date``\ , creation using
-``run_id`` is preserved for user actions.
+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.
-``airflow.models.dagrun.DagRun``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Graphviz will remain to be installed for most users:
-Use DagRunType.SCHEDULED.value instead of DagRun.ID_PREFIX
+* 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
-All the run_id prefixes for different kind of DagRuns have been grouped into a single
-enum in ``airflow.utils.types.DagRunType``.
+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.
-Previously, there were defined in various places, example as ``ID_PREFIX`` class variables for
-``DagRun``\ , ``BackfillJob`` and in ``_trigger_dag`` function.
+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)
-Was:
+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)
-.. code-block:: pycon
+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)
- >> from airflow.models.dagrun import DagRun
- >> DagRun.ID_PREFIX
- scheduled__
+Airflow 2.8.0 (2023-12-18)
+--------------------------
-Replaced by:
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-.. code-block:: pycon
+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``.
- >> from airflow.utils.types import DagRunType
- >> DagRunType.SCHEDULED.value
- scheduled
+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.
-``airflow.utils.file.TemporaryDirectory``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-We remove ``airflow.utils.file.TemporaryDirectory``
-Since Airflow dropped support for Python < 3.5 there's no need to have this custom
-implementation of ``TemporaryDirectory`` because the same functionality is provided by
-``tempfile.TemporaryDirectory``.
+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)
-Now users instead of ``import from airflow.utils.files import TemporaryDirectory`` should
-do ``from tempfile import TemporaryDirectory``. Both context managers provide the same
-interface, thus no additional changes should be required.
+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)
-``airflow.AirflowMacroPlugin``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-We removed ``airflow.AirflowMacroPlugin`` class. The class was there in airflow package but it has not been used (apparently since 2015).
-It has been removed.
+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)
-``airflow.settings.CONTEXT_MANAGER_DAG``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-CONTEXT_MANAGER_DAG was removed from settings. Its role has been taken by ``DagContext`` in
-'airflow.models.dag'. One of the reasons was that settings should be rather static than store
-dynamic context from the DAG, but the main one is that moving the context out of settings allowed to
-untangle cyclic imports between DAG, BaseOperator, SerializedDAG, SerializedBaseOperator which was
-part of AIRFLOW-6010.
+Airflow 2.7.3 (2023-11-06)
+--------------------------
-``airflow.utils.log.logging_mixin.redirect_stderr``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``airflow.utils.log.logging_mixin.redirect_stdout``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+No significant changes.
-Function ``redirect_stderr`` and ``redirect_stdout`` from ``airflow.utils.log.logging_mixin`` module has
-been deleted because it can be easily replaced by the standard library.
-The functions of the standard library are more flexible and can be used in larger cases.
+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)
-The code below
+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)
-.. code-block:: python
+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)
- import logging
- from airflow.utils.log.logging_mixin import redirect_stderr, redirect_stdout
- logger = logging.getLogger("custom-logger")
- with redirect_stdout(logger, logging.INFO), redirect_stderr(logger, logging.WARN):
- print("I love Airflow")
+Airflow 2.7.2 (2023-10-12)
+--------------------------
-can be replaced by the following code:
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-.. code-block:: python
+No significant changes
- from contextlib import redirect_stdout, redirect_stderr
- import logging
- from airflow.utils.log.logging_mixin import StreamLogWriter
+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)
- logger = logging.getLogger("custom-logger")
+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)
- with (
- redirect_stdout(StreamLogWriter(logger, logging.INFO)),
- redirect_stderr(StreamLogWriter(logger, logging.WARN)),
- ):
- print("I Love Airflow")
+Misc/Internal
+"""""""""""""
+- 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)
-``airflow.models.baseoperator.BaseOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Now, additional arguments passed to BaseOperator cause an exception. Previous versions of Airflow took additional arguments and displayed a message on the console. When the
-message was not noticed by users, it caused very difficult to detect errors.
+Airflow 2.7.1 (2023-09-07)
+--------------------------
-In order to restore the previous behavior, you must set an ``True`` in the ``allow_illegal_arguments``
-option of section ``[operators]`` in the ``airflow.cfg`` file. In the future it is possible to completely
-delete this option.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``airflow.models.dagbag.DagBag``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+CronTriggerTimetable is now less aggressive when trying to skip a run (#33404)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Passing ``store_serialized_dags`` argument to DagBag.\ **init** and accessing ``DagBag.store_serialized_dags`` property
-are deprecated and will be removed in future versions.
+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.
-**Previous signature**\ :
+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.
-.. code-block:: python
+Note that this is also the behaviour exhibited by various other cron-based
+scheduling tools, such as ``anacron``.
- def __init__(
- dag_folder=None,
- include_examples=conf.getboolean("core", "LOAD_EXAMPLES"),
- safe_mode=conf.getboolean("core", "DAG_DISCOVERY_SAFE_MODE"),
- store_serialized_dags=False,
- ): ...
+``conf.set()`` becomes case insensitive to match ``conf.get()`` behavior (#33452)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-**current**\ :
+Also, ``conf.get()`` will now break if used with non-string parameters.
-.. code-block:: python
+``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.
- def __init__(
- dag_folder=None,
- include_examples=conf.getboolean("core", "LOAD_EXAMPLES"),
- safe_mode=conf.getboolean("core", "DAG_DISCOVERY_SAFE_MODE"),
- read_dags_from_db=False,
- ): ...
-
-If you were using positional arguments, it requires no change but if you were using keyword
-arguments, please change ``store_serialized_dags`` to ``read_dags_from_db``.
-
-Similarly, if you were using ``DagBag().store_serialized_dags`` property, change it to
-``DagBag().read_dags_from_db``.
-
-Changes in ``google`` provider package
-""""""""""""""""""""""""""""""""""""""""""
-
-We strive to ensure that there are no changes that may affect the end user and your Python files, but this
-release may contain changes that will require changes to your configuration, DAG Files or other integration
-e.g. custom operators.
-
-Only changes unique to this provider are described here. You should still pay attention to the changes that
-have been made to the core (including core operators) as they can affect the integration behavior
-of this provider.
-
-This section describes the changes that have been made, and what you need to do to update your if
-you use operators or hooks which integrate with Google services (including Google Cloud - GCP).
-
-Direct impersonation added to operators communicating with Google services
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`Directly impersonating a service account `_
-has been made possible for operators communicating with Google services via new argument called ``impersonation_chain``
-(\ ``google_impersonation_chain`` in case of operators that also communicate with services of other cloud providers).
-As a result, GCSToS3Operator no longer derivatives from GCSListObjectsOperator.
-
-Normalize gcp_conn_id for Google Cloud
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Previously not all hooks and operators related to Google Cloud use
-``gcp_conn_id`` as parameter for GCP connection. There is currently one parameter
-which apply to most services. Parameters like ``datastore_conn_id``\ , ``bigquery_conn_id``\ ,
-``google_cloud_storage_conn_id`` and similar have been deprecated. Operators that require two connections are not changed.
-
-Following components were affected by normalization:
-
-
-* ``airflow.providers.google.cloud.hooks.datastore.DatastoreHook``
-* ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook``
-* ``airflow.providers.google.cloud.hooks.gcs.GoogleCloudStorageHook``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryCheckOperator``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryValueCheckOperator``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryIntervalCheckOperator``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryGetDataOperator``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryOperator``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryDeleteDatasetOperator``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryCreateEmptyDatasetOperator``
-* ``airflow.providers.google.cloud.operators.bigquery.BigQueryTableDeleteOperator``
-* ``airflow.providers.google.cloud.operators.gcs.GoogleCloudStorageCreateBucketOperator``
-* ``airflow.providers.google.cloud.operators.gcs.GoogleCloudStorageListOperator``
-* ``airflow.providers.google.cloud.operators.gcs.GoogleCloudStorageDownloadOperator``
-* ``airflow.providers.google.cloud.operators.gcs.GoogleCloudStorageDeleteOperator``
-* ``airflow.providers.google.cloud.operators.gcs.GoogleCloudStorageBucketCreateAclEntryOperator``
-* ``airflow.providers.google.cloud.operators.gcs.GoogleCloudStorageObjectCreateAclEntryOperator``
-* ``airflow.operators.sql_to_gcs.BaseSQLToGoogleCloudStorageOperator``
-* ``airflow.operators.adls_to_gcs.AdlsToGoogleCloudStorageOperator``
-* ``airflow.operators.gcs_to_s3.GoogleCloudStorageToS3Operator``
-* ``airflow.operators.gcs_to_gcs.GoogleCloudStorageToGoogleCloudStorageOperator``
-* ``airflow.operators.bigquery_to_gcs.BigQueryToCloudStorageOperator``
-* ``airflow.operators.local_to_gcs.FileToGoogleCloudStorageOperator``
-* ``airflow.operators.cassandra_to_gcs.CassandraToGoogleCloudStorageOperator``
-* ``airflow.operators.bigquery_to_bigquery.BigQueryToBigQueryOperator``
-
-Changes to import paths and names of GCP operators and hooks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-According to `AIP-21 `_
-operators related to Google Cloud has been moved from contrib to core.
-The following table shows changes in import paths.
-
-.. list-table::
- :header-rows: 1
-
- * - Old path
- - New path
- * - ``airflow.contrib.hooks.bigquery_hook.BigQueryHook``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook``
- * - ``airflow.contrib.hooks.datastore_hook.DatastoreHook``
- - ``airflow.providers.google.cloud.hooks.datastore.DatastoreHook``
- * - ``airflow.contrib.hooks.gcp_bigtable_hook.BigtableHook``
- - ``airflow.providers.google.cloud.hooks.bigtable.BigtableHook``
- * - ``airflow.contrib.hooks.gcp_cloud_build_hook.CloudBuildHook``
- - ``airflow.providers.google.cloud.hooks.cloud_build.CloudBuildHook``
- * - ``airflow.contrib.hooks.gcp_container_hook.GKEClusterHook``
- - ``airflow.providers.google.cloud.hooks.kubernetes_engine.GKEHook``
- * - ``airflow.contrib.hooks.gcp_compute_hook.GceHook``
- - ``airflow.providers.google.cloud.hooks.compute.ComputeEngineHook``
- * - ``airflow.contrib.hooks.gcp_dataflow_hook.DataFlowHook``
- - ``airflow.providers.google.cloud.hooks.dataflow.DataflowHook``
- * - ``airflow.contrib.hooks.gcp_dataproc_hook.DataProcHook``
- - ``airflow.providers.google.cloud.hooks.dataproc.DataprocHook``
- * - ``airflow.contrib.hooks.gcp_dlp_hook.CloudDLPHook``
- - ``airflow.providers.google.cloud.hooks.dlp.CloudDLPHook``
- * - ``airflow.contrib.hooks.gcp_function_hook.GcfHook``
- - ``airflow.providers.google.cloud.hooks.functions.CloudFunctionsHook``
- * - ``airflow.contrib.hooks.gcp_kms_hook.GoogleCloudKMSHook``
- - ``airflow.providers.google.cloud.hooks.kms.CloudKMSHook``
- * - ``airflow.contrib.hooks.gcp_mlengine_hook.MLEngineHook``
- - ``airflow.providers.google.cloud.hooks.mlengine.MLEngineHook``
- * - ``airflow.contrib.hooks.gcp_natural_language_hook.CloudNaturalLanguageHook``
- - ``airflow.providers.google.cloud.hooks.natural_language.CloudNaturalLanguageHook``
- * - ``airflow.contrib.hooks.gcp_pubsub_hook.PubSubHook``
- - ``airflow.providers.google.cloud.hooks.pubsub.PubSubHook``
- * - ``airflow.contrib.hooks.gcp_speech_to_text_hook.GCPSpeechToTextHook``
- - ``airflow.providers.google.cloud.hooks.speech_to_text.CloudSpeechToTextHook``
- * - ``airflow.contrib.hooks.gcp_spanner_hook.CloudSpannerHook``
- - ``airflow.providers.google.cloud.hooks.spanner.SpannerHook``
- * - ``airflow.contrib.hooks.gcp_sql_hook.CloudSqlDatabaseHook``
- - ``airflow.providers.google.cloud.hooks.cloud_sql.CloudSQLDatabaseHook``
- * - ``airflow.contrib.hooks.gcp_sql_hook.CloudSqlHook``
- - ``airflow.providers.google.cloud.hooks.cloud_sql.CloudSQLHook``
- * - ``airflow.contrib.hooks.gcp_tasks_hook.CloudTasksHook``
- - ``airflow.providers.google.cloud.hooks.tasks.CloudTasksHook``
- * - ``airflow.contrib.hooks.gcp_text_to_speech_hook.GCPTextToSpeechHook``
- - ``airflow.providers.google.cloud.hooks.text_to_speech.CloudTextToSpeechHook``
- * - ``airflow.contrib.hooks.gcp_transfer_hook.GCPTransferServiceHook``
- - ``airflow.providers.google.cloud.hooks.cloud_storage_transfer_service.CloudDataTransferServiceHook``
- * - ``airflow.contrib.hooks.gcp_translate_hook.CloudTranslateHook``
- - ``airflow.providers.google.cloud.hooks.translate.CloudTranslateHook``
- * - ``airflow.contrib.hooks.gcp_video_intelligence_hook.CloudVideoIntelligenceHook``
- - ``airflow.providers.google.cloud.hooks.video_intelligence.CloudVideoIntelligenceHook``
- * - ``airflow.contrib.hooks.gcp_vision_hook.CloudVisionHook``
- - ``airflow.providers.google.cloud.hooks.vision.CloudVisionHook``
- * - ``airflow.contrib.hooks.gcs_hook.GoogleCloudStorageHook``
- - ``airflow.providers.google.cloud.hooks.gcs.GCSHook``
- * - ``airflow.contrib.operators.adls_to_gcs.AdlsToGoogleCloudStorageOperator``
- - ``airflow.operators.adls_to_gcs.AdlsToGoogleCloudStorageOperator``
- * - ``airflow.contrib.operators.bigquery_check_operator.BigQueryCheckOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryCheckOperator``
- * - ``airflow.contrib.operators.bigquery_check_operator.BigQueryIntervalCheckOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryIntervalCheckOperator``
- * - ``airflow.contrib.operators.bigquery_check_operator.BigQueryValueCheckOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryValueCheckOperator``
- * - ``airflow.contrib.operators.bigquery_get_data.BigQueryGetDataOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryGetDataOperator``
- * - ``airflow.contrib.operators.bigquery_operator.BigQueryCreateEmptyDatasetOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryCreateEmptyDatasetOperator``
- * - ``airflow.contrib.operators.bigquery_operator.BigQueryCreateEmptyTableOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryCreateEmptyTableOperator``
- * - ``airflow.contrib.operators.bigquery_operator.BigQueryCreateExternalTableOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryCreateExternalTableOperator``
- * - ``airflow.contrib.operators.bigquery_operator.BigQueryDeleteDatasetOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryDeleteDatasetOperator``
- * - ``airflow.contrib.operators.bigquery_operator.BigQueryOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryExecuteQueryOperator``
- * - ``airflow.contrib.operators.bigquery_table_delete_operator.BigQueryTableDeleteOperator``
- - ``airflow.providers.google.cloud.operators.bigquery.BigQueryDeleteTableOperator``
- * - ``airflow.contrib.operators.bigquery_to_bigquery.BigQueryToBigQueryOperator``
- - ``airflow.operators.bigquery_to_bigquery.BigQueryToBigQueryOperator``
- * - ``airflow.contrib.operators.bigquery_to_gcs.BigQueryToCloudStorageOperator``
- - ``airflow.operators.bigquery_to_gcs.BigQueryToCloudStorageOperator``
- * - ``airflow.contrib.operators.bigquery_to_mysql_operator.BigQueryToMySqlOperator``
- - ``airflow.operators.bigquery_to_mysql.BigQueryToMySqlOperator``
- * - ``airflow.contrib.operators.dataflow_operator.DataFlowJavaOperator``
- - ``airflow.providers.google.cloud.operators.dataflow.DataFlowJavaOperator``
- * - ``airflow.contrib.operators.dataflow_operator.DataFlowPythonOperator``
- - ``airflow.providers.google.cloud.operators.dataflow.DataFlowPythonOperator``
- * - ``airflow.contrib.operators.dataflow_operator.DataflowTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dataflow.DataflowTemplateOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataProcHadoopOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitHadoopJobOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataProcHiveOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitHiveJobOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataProcJobBaseOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocJobBaseOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataProcPigOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitPigJobOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataProcPySparkOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitPySparkJobOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataProcSparkOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitSparkJobOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataProcSparkSqlOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitSparkSqlJobOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataprocClusterCreateOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocCreateClusterOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataprocClusterDeleteOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocDeleteClusterOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataprocClusterScaleOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocScaleClusterOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataprocOperationBaseOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocOperationBaseOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataprocWorkflowTemplateInstantiateInlineOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocInstantiateInlineWorkflowTemplateOperator``
- * - ``airflow.contrib.operators.dataproc_operator.DataprocWorkflowTemplateInstantiateOperator``
- - ``airflow.providers.google.cloud.operators.dataproc.DataprocInstantiateWorkflowTemplateOperator``
- * - ``airflow.contrib.operators.datastore_export_operator.DatastoreExportOperator``
- - ``airflow.providers.google.cloud.operators.datastore.DatastoreExportOperator``
- * - ``airflow.contrib.operators.datastore_import_operator.DatastoreImportOperator``
- - ``airflow.providers.google.cloud.operators.datastore.DatastoreImportOperator``
- * - ``airflow.contrib.operators.file_to_gcs.FileToGoogleCloudStorageOperator``
- - ``airflow.providers.google.cloud.transfers.local_to_gcs.FileToGoogleCloudStorageOperator``
- * - ``airflow.contrib.operators.gcp_bigtable_operator.BigtableClusterUpdateOperator``
- - ``airflow.providers.google.cloud.operators.bigtable.BigtableUpdateClusterOperator``
- * - ``airflow.contrib.operators.gcp_bigtable_operator.BigtableInstanceCreateOperator``
- - ``airflow.providers.google.cloud.operators.bigtable.BigtableCreateInstanceOperator``
- * - ``airflow.contrib.operators.gcp_bigtable_operator.BigtableInstanceDeleteOperator``
- - ``airflow.providers.google.cloud.operators.bigtable.BigtableDeleteInstanceOperator``
- * - ``airflow.contrib.operators.gcp_bigtable_operator.BigtableTableCreateOperator``
- - ``airflow.providers.google.cloud.operators.bigtable.BigtableCreateTableOperator``
- * - ``airflow.contrib.operators.gcp_bigtable_operator.BigtableTableDeleteOperator``
- - ``airflow.providers.google.cloud.operators.bigtable.BigtableDeleteTableOperator``
- * - ``airflow.contrib.operators.gcp_bigtable_operator.BigtableTableWaitForReplicationSensor``
- - ``airflow.providers.google.cloud.sensors.bigtable.BigtableTableReplicationCompletedSensor``
- * - ``airflow.contrib.operators.gcp_cloud_build_operator.CloudBuildCreateBuildOperator``
- - ``airflow.providers.google.cloud.operators.cloud_build.CloudBuildCreateBuildOperator``
- * - ``airflow.contrib.operators.gcp_compute_operator.GceBaseOperator``
- - ``airflow.providers.google.cloud.operators.compute.GceBaseOperator``
- * - ``airflow.contrib.operators.gcp_compute_operator.GceInstanceGroupManagerUpdateTemplateOperator``
- - ``airflow.providers.google.cloud.operators.compute.GceInstanceGroupManagerUpdateTemplateOperator``
- * - ``airflow.contrib.operators.gcp_compute_operator.GceInstanceStartOperator``
- - ``airflow.providers.google.cloud.operators.compute.GceInstanceStartOperator``
- * - ``airflow.contrib.operators.gcp_compute_operator.GceInstanceStopOperator``
- - ``airflow.providers.google.cloud.operators.compute.GceInstanceStopOperator``
- * - ``airflow.contrib.operators.gcp_compute_operator.GceInstanceTemplateCopyOperator``
- - ``airflow.providers.google.cloud.operators.compute.GceInstanceTemplateCopyOperator``
- * - ``airflow.contrib.operators.gcp_compute_operator.GceSetMachineTypeOperator``
- - ``airflow.providers.google.cloud.operators.compute.GceSetMachineTypeOperator``
- * - ``airflow.contrib.operators.gcp_container_operator.GKEClusterCreateOperator``
- - ``airflow.providers.google.cloud.operators.kubernetes_engine.GKECreateClusterOperator``
- * - ``airflow.contrib.operators.gcp_container_operator.GKEClusterDeleteOperator``
- - ``airflow.providers.google.cloud.operators.kubernetes_engine.GKEDeleteClusterOperator``
- * - ``airflow.contrib.operators.gcp_container_operator.GKEPodOperator``
- - ``airflow.providers.google.cloud.operators.kubernetes_engine.GKEStartPodOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPCancelDLPJobOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPCancelDLPJobOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPCreateDLPJobOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPCreateDLPJobOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPCreateDeidentifyTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPCreateDeidentifyTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPCreateInspectTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPCreateInspectTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPCreateJobTriggerOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPCreateJobTriggerOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPCreateStoredInfoTypeOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPCreateStoredInfoTypeOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPDeidentifyContentOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPDeidentifyContentOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPDeleteDeidentifyTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPDeleteDeidentifyTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPDeleteDlpJobOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPDeleteDLPJobOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPDeleteInspectTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPDeleteInspectTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPDeleteJobTriggerOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPDeleteJobTriggerOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPDeleteStoredInfoTypeOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPDeleteStoredInfoTypeOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPGetDeidentifyTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPGetDeidentifyTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPGetDlpJobOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPGetDLPJobOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPGetInspectTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPGetInspectTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPGetJobTripperOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPGetJobTriggerOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPGetStoredInfoTypeOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPGetStoredInfoTypeOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPInspectContentOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPInspectContentOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPListDeidentifyTemplatesOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPListDeidentifyTemplatesOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPListDlpJobsOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPListDLPJobsOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPListInfoTypesOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPListInfoTypesOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPListInspectTemplatesOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPListInspectTemplatesOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPListJobTriggersOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPListJobTriggersOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPListStoredInfoTypesOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPListStoredInfoTypesOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPRedactImageOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPRedactImageOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPReidentifyContentOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPReidentifyContentOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPUpdateDeidentifyTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPUpdateDeidentifyTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPUpdateInspectTemplateOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPUpdateInspectTemplateOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPUpdateJobTriggerOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPUpdateJobTriggerOperator``
- * - ``airflow.contrib.operators.gcp_dlp_operator.CloudDLPUpdateStoredInfoTypeOperator``
- - ``airflow.providers.google.cloud.operators.dlp.CloudDLPUpdateStoredInfoTypeOperator``
- * - ``airflow.contrib.operators.gcp_function_operator.GcfFunctionDeleteOperator``
- - ``airflow.providers.google.cloud.operators.functions.GcfFunctionDeleteOperator``
- * - ``airflow.contrib.operators.gcp_function_operator.GcfFunctionDeployOperator``
- - ``airflow.providers.google.cloud.operators.functions.GcfFunctionDeployOperator``
- * - ``airflow.contrib.operators.gcp_natural_language_operator.CloudNaturalLanguageAnalyzeEntitiesOperator``
- - ``airflow.providers.google.cloud.operators.natural_language.CloudNaturalLanguageAnalyzeEntitiesOperator``
- * - ``airflow.contrib.operators.gcp_natural_language_operator.CloudNaturalLanguageAnalyzeEntitySentimentOperator``
- - ``airflow.providers.google.cloud.operators.natural_language.CloudNaturalLanguageAnalyzeEntitySentimentOperator``
- * - ``airflow.contrib.operators.gcp_natural_language_operator.CloudNaturalLanguageAnalyzeSentimentOperator``
- - ``airflow.providers.google.cloud.operators.natural_language.CloudNaturalLanguageAnalyzeSentimentOperator``
- * - ``airflow.contrib.operators.gcp_natural_language_operator.CloudNaturalLanguageClassifyTextOperator``
- - ``airflow.providers.google.cloud.operators.natural_language.CloudNaturalLanguageClassifyTextOperator``
- * - ``airflow.contrib.operators.gcp_spanner_operator.CloudSpannerInstanceDatabaseDeleteOperator``
- - ``airflow.providers.google.cloud.operators.spanner.SpannerDeleteDatabaseInstanceOperator``
- * - ``airflow.contrib.operators.gcp_spanner_operator.CloudSpannerInstanceDatabaseDeployOperator``
- - ``airflow.providers.google.cloud.operators.spanner.SpannerDeployDatabaseInstanceOperator``
- * - ``airflow.contrib.operators.gcp_spanner_operator.CloudSpannerInstanceDatabaseQueryOperator``
- - ``airflow.providers.google.cloud.operators.spanner.SpannerQueryDatabaseInstanceOperator``
- * - ``airflow.contrib.operators.gcp_spanner_operator.CloudSpannerInstanceDatabaseUpdateOperator``
- - ``airflow.providers.google.cloud.operators.spanner.SpannerUpdateDatabaseInstanceOperator``
- * - ``airflow.contrib.operators.gcp_spanner_operator.CloudSpannerInstanceDeleteOperator``
- - ``airflow.providers.google.cloud.operators.spanner.SpannerDeleteInstanceOperator``
- * - ``airflow.contrib.operators.gcp_spanner_operator.CloudSpannerInstanceDeployOperator``
- - ``airflow.providers.google.cloud.operators.spanner.SpannerDeployInstanceOperator``
- * - ``airflow.contrib.operators.gcp_speech_to_text_operator.GcpSpeechToTextRecognizeSpeechOperator``
- - ``airflow.providers.google.cloud.operators.speech_to_text.CloudSpeechToTextRecognizeSpeechOperator``
- * - ``airflow.contrib.operators.gcp_text_to_speech_operator.GcpTextToSpeechSynthesizeOperator``
- - ``airflow.providers.google.cloud.operators.text_to_speech.CloudTextToSpeechSynthesizeOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceJobCreateOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceCreateJobOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceJobDeleteOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceDeleteJobOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceJobUpdateOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceUpdateJobOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceOperationCancelOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceCancelOperationOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceOperationGetOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceGetOperationOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceOperationPauseOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServicePauseOperationOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceOperationResumeOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceResumeOperationOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GcpTransferServiceOperationsListOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceListOperationsOperator``
- * - ``airflow.contrib.operators.gcp_transfer_operator.GoogleCloudStorageToGoogleCloudStorageTransferOperator``
- - ``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceGCSToGCSOperator``
- * - ``airflow.contrib.operators.gcp_translate_operator.CloudTranslateTextOperator``
- - ``airflow.providers.google.cloud.operators.translate.CloudTranslateTextOperator``
- * - ``airflow.contrib.operators.gcp_translate_speech_operator.GcpTranslateSpeechOperator``
- - ``airflow.providers.google.cloud.operators.translate_speech.GcpTranslateSpeechOperator``
- * - ``airflow.contrib.operators.gcp_video_intelligence_operator.CloudVideoIntelligenceDetectVideoExplicitContentOperator``
- - ``airflow.providers.google.cloud.operators.video_intelligence.CloudVideoIntelligenceDetectVideoExplicitContentOperator``
- * - ``airflow.contrib.operators.gcp_video_intelligence_operator.CloudVideoIntelligenceDetectVideoLabelsOperator``
- - ``airflow.providers.google.cloud.operators.video_intelligence.CloudVideoIntelligenceDetectVideoLabelsOperator``
- * - ``airflow.contrib.operators.gcp_video_intelligence_operator.CloudVideoIntelligenceDetectVideoShotsOperator``
- - ``airflow.providers.google.cloud.operators.video_intelligence.CloudVideoIntelligenceDetectVideoShotsOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionAddProductToProductSetOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionAddProductToProductSetOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionAnnotateImageOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionImageAnnotateOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionDetectDocumentTextOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionTextDetectOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionDetectImageLabelsOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionDetectImageLabelsOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionDetectImageSafeSearchOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionDetectImageSafeSearchOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionDetectTextOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionDetectTextOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductCreateOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionCreateProductOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductDeleteOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionDeleteProductOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductGetOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionGetProductOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductSetCreateOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionCreateProductSetOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductSetDeleteOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionDeleteProductSetOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductSetGetOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionGetProductSetOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductSetUpdateOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionUpdateProductSetOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionProductUpdateOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionUpdateProductOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionReferenceImageCreateOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionCreateReferenceImageOperator``
- * - ``airflow.contrib.operators.gcp_vision_operator.CloudVisionRemoveProductFromProductSetOperator``
- - ``airflow.providers.google.cloud.operators.vision.CloudVisionRemoveProductFromProductSetOperator``
- * - ``airflow.contrib.operators.gcs_acl_operator.GoogleCloudStorageBucketCreateAclEntryOperator``
- - ``airflow.providers.google.cloud.operators.gcs.GCSBucketCreateAclEntryOperator``
- * - ``airflow.contrib.operators.gcs_acl_operator.GoogleCloudStorageObjectCreateAclEntryOperator``
- - ``airflow.providers.google.cloud.operators.gcs.GCSObjectCreateAclEntryOperator``
- * - ``airflow.contrib.operators.gcs_delete_operator.GoogleCloudStorageDeleteOperator``
- - ``airflow.providers.google.cloud.operators.gcs.GCSDeleteObjectsOperator``
- * - ``airflow.contrib.operators.gcs_download_operator.GoogleCloudStorageDownloadOperator``
- - ``airflow.providers.google.cloud.operators.gcs.GCSToLocalFilesystemOperator``
- * - ``airflow.contrib.operators.gcs_list_operator.GoogleCloudStorageListOperator``
- - ``airflow.providers.google.cloud.operators.gcs.GCSListObjectsOperator``
- * - ``airflow.contrib.operators.gcs_operator.GoogleCloudStorageCreateBucketOperator``
- - ``airflow.providers.google.cloud.operators.gcs.GCSCreateBucketOperator``
- * - ``airflow.contrib.operators.gcs_to_bq.GoogleCloudStorageToBigQueryOperator``
- - ``airflow.operators.gcs_to_bq.GoogleCloudStorageToBigQueryOperator``
- * - ``airflow.contrib.operators.gcs_to_gcs.GoogleCloudStorageToGoogleCloudStorageOperator``
- - ``airflow.operators.gcs_to_gcs.GoogleCloudStorageToGoogleCloudStorageOperator``
- * - ``airflow.contrib.operators.gcs_to_s3.GoogleCloudStorageToS3Operator``
- - ``airflow.operators.gcs_to_s3.GCSToS3Operator``
- * - ``airflow.contrib.operators.mlengine_operator.MLEngineBatchPredictionOperator``
- - ``airflow.providers.google.cloud.operators.mlengine.MLEngineStartBatchPredictionJobOperator``
- * - ``airflow.contrib.operators.mlengine_operator.MLEngineModelOperator``
- - ``airflow.providers.google.cloud.operators.mlengine.MLEngineManageModelOperator``
- * - ``airflow.contrib.operators.mlengine_operator.MLEngineTrainingOperator``
- - ``airflow.providers.google.cloud.operators.mlengine.MLEngineStartTrainingJobOperator``
- * - ``airflow.contrib.operators.mlengine_operator.MLEngineVersionOperator``
- - ``airflow.providers.google.cloud.operators.mlengine.MLEngineManageVersionOperator``
- * - ``airflow.contrib.operators.mssql_to_gcs.MsSqlToGoogleCloudStorageOperator``
- - ``airflow.operators.mssql_to_gcs.MsSqlToGoogleCloudStorageOperator``
- * - ``airflow.contrib.operators.mysql_to_gcs.MySqlToGoogleCloudStorageOperator``
- - ``airflow.operators.mysql_to_gcs.MySqlToGoogleCloudStorageOperator``
- * - ``airflow.contrib.operators.postgres_to_gcs_operator.PostgresToGoogleCloudStorageOperator``
- - ``airflow.operators.postgres_to_gcs.PostgresToGoogleCloudStorageOperator``
- * - ``airflow.contrib.operators.pubsub_operator.PubSubPublishOperator``
- - ``airflow.providers.google.cloud.operators.pubsub.PubSubPublishMessageOperator``
- * - ``airflow.contrib.operators.pubsub_operator.PubSubSubscriptionCreateOperator``
- - ``airflow.providers.google.cloud.operators.pubsub.PubSubCreateSubscriptionOperator``
- * - ``airflow.contrib.operators.pubsub_operator.PubSubSubscriptionDeleteOperator``
- - ``airflow.providers.google.cloud.operators.pubsub.PubSubDeleteSubscriptionOperator``
- * - ``airflow.contrib.operators.pubsub_operator.PubSubTopicCreateOperator``
- - ``airflow.providers.google.cloud.operators.pubsub.PubSubCreateTopicOperator``
- * - ``airflow.contrib.operators.pubsub_operator.PubSubTopicDeleteOperator``
- - ``airflow.providers.google.cloud.operators.pubsub.PubSubDeleteTopicOperator``
- * - ``airflow.contrib.operators.sql_to_gcs.BaseSQLToGoogleCloudStorageOperator``
- - ``airflow.operators.sql_to_gcs.BaseSQLToGoogleCloudStorageOperator``
- * - ``airflow.contrib.sensors.bigquery_sensor.BigQueryTableSensor``
- - ``airflow.providers.google.cloud.sensors.bigquery.BigQueryTableExistenceSensor``
- * - ``airflow.contrib.sensors.gcp_transfer_sensor.GCPTransferServiceWaitForJobStatusSensor``
- - ``airflow.providers.google.cloud.sensors.cloud_storage_transfer_service.DataTransferServiceJobStatusSensor``
- * - ``airflow.contrib.sensors.gcs_sensor.GoogleCloudStorageObjectSensor``
- - ``airflow.providers.google.cloud.sensors.gcs.GCSObjectExistenceSensor``
- * - ``airflow.contrib.sensors.gcs_sensor.GoogleCloudStorageObjectUpdatedSensor``
- - ``airflow.providers.google.cloud.sensors.gcs.GCSObjectUpdateSensor``
- * - ``airflow.contrib.sensors.gcs_sensor.GoogleCloudStoragePrefixSensor``
- - ``airflow.providers.google.cloud.sensors.gcs.GCSObjectsWithPrefixExistenceSensor``
- * - ``airflow.contrib.sensors.gcs_sensor.GoogleCloudStorageUploadSessionCompleteSensor``
- - ``airflow.providers.google.cloud.sensors.gcs.GCSUploadSessionCompleteSensor``
- * - ``airflow.contrib.sensors.pubsub_sensor.PubSubPullSensor``
- - ``airflow.providers.google.cloud.sensors.pubsub.PubSubPullSensor``
-
-
-Unify default conn_id for Google Cloud
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Previously not all hooks and operators related to Google Cloud use
-``google_cloud_default`` as a default conn_id. There is currently one default
-variant. Values like ``google_cloud_storage_default``\ , ``bigquery_default``\ ,
-``google_cloud_datastore_default`` have been deprecated. The configuration of
-existing relevant connections in the database have been preserved. To use those
-deprecated GCP conn_id, you need to explicitly pass their conn_id into
-operators/hooks. Otherwise, ``google_cloud_default`` will be used as GCP's conn_id
-by default.
-
-``airflow.providers.google.cloud.hooks.dataflow.DataflowHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.google.cloud.operators.dataflow.DataflowCreateJavaJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.google.cloud.operators.dataflow.DataflowTemplatedJobStartOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.google.cloud.operators.dataflow.DataflowCreatePythonJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To use project_id argument consistently across GCP hooks and operators, we did the following changes:
-
-
-* Changed order of arguments in DataflowHook.start_python_dataflow. Uses
- with positional arguments may break.
-* Changed order of arguments in DataflowHook.is_job_dataflow_running. Uses
- with positional arguments may break.
-* Changed order of arguments in DataflowHook.cancel_job. Uses
- with positional arguments may break.
-* Added optional project_id argument to DataflowCreateJavaJobOperator
- constructor.
-* Added optional project_id argument to DataflowTemplatedJobStartOperator
- constructor.
-* Added optional project_id argument to DataflowCreatePythonJobOperator
- constructor.
-
-``airflow.providers.google.cloud.sensors.gcs.GCSUploadSessionCompleteSensor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To provide more precise control in handling of changes to objects in
-underlying GCS Bucket the constructor of this sensor now has changed.
-
-
-* Old Behavior: This constructor used to optionally take ``previous_num_objects: int``.
-* New replacement constructor kwarg: ``previous_objects: Optional[Set[str]]``.
-
-Most users would not specify this argument because the bucket begins empty
-and the user wants to treat any files as new.
-
-Example of Updating usage of this sensor:
-Users who used to call:
-
-``GCSUploadSessionCompleteSensor(bucket='my_bucket', prefix='my_prefix', previous_num_objects=1)``
-
-Will now call:
-
-``GCSUploadSessionCompleteSensor(bucket='my_bucket', prefix='my_prefix', previous_num_objects={'.keep'})``
-
-Where '.keep' is a single file at your prefix that the sensor should not consider new.
-
-``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To simplify BigQuery operators (no need of ``Cursor``\ ) and standardize usage of hooks within all GCP integration methods from ``BiqQueryBaseCursor``
-were moved to ``BigQueryHook``. Using them by from ``Cursor`` object is still possible due to preserved backward compatibility but they will raise ``DeprecationWarning``.
-The following methods were moved:
-
-.. list-table::
- :header-rows: 1
-
- * - Old path
- - New path
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.cancel_query``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.cancel_query``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.create_empty_dataset``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.create_empty_dataset``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.create_empty_table``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.create_empty_table``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.create_external_table``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.create_external_table``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.delete_dataset``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.delete_dataset``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.get_dataset``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.get_dataset``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.get_dataset_tables``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.get_dataset_tables``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.get_dataset_tables_list``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.get_dataset_tables_list``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.get_datasets_list``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.get_datasets_list``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.get_schema``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.get_schema``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.get_tabledata``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.get_tabledata``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.insert_all``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.insert_all``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.patch_dataset``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.patch_dataset``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.patch_table``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.patch_table``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.poll_job_complete``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.poll_job_complete``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_copy``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_copy``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_extract``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_extract``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_grant_dataset_view_access``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_grant_dataset_view_access``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_load``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_load``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_query``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_query``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_table_delete``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_table_delete``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_table_upsert``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_table_upsert``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_with_configuration``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.run_with_configuration``
- * - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.update_dataset``
- - ``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook.update_dataset``
+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.
+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")``.
-``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-Since BigQuery is the part of the GCP it was possible to simplify the code by handling the exceptions
-by usage of the ``airflow.providers.google.common.hooks.base.GoogleBaseHook.catch_http_exception`` decorator however it changes
-exceptions raised by the following methods:
+Misc/Internal
+"""""""""""""
+- 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)
+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)
-* ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.run_table_delete`` raises ``AirflowException`` instead of ``Exception``.
-* ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.create_empty_dataset`` raises ``AirflowException`` instead of ``ValueError``.
-* ``airflow.providers.google.cloud.hooks.bigquery.BigQueryBaseCursor.get_dataset`` raises ``AirflowException`` instead of ``ValueError``.
-``airflow.providers.google.cloud.operators.bigquery.BigQueryCreateEmptyTableOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Airflow 2.7.0 (2023-08-18)
+--------------------------
-``airflow.providers.google.cloud.operators.bigquery.BigQueryCreateEmptyDatasetOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Idempotency was added to ``BigQueryCreateEmptyTableOperator`` and ``BigQueryCreateEmptyDatasetOperator``.
-But to achieve that try / except clause was removed from ``create_empty_dataset`` and ``create_empty_table``
-methods of ``BigQueryHook``.
+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.
-``airflow.providers.google.cloud.hooks.dataflow.DataflowHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Old Graph View is removed (#32958)
+""""""""""""""""""""""""""""""""""
+The old Graph View is removed. The new Graph View is the default view now.
-``airflow.providers.google.cloud.hooks.mlengine.MLEngineHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The trigger UI form is skipped in web UI if no parameters are defined in a DAG (#33351)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-``airflow.providers.google.cloud.hooks.pubsub.PubSubHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you are using ``dag_run.conf`` dictionary and web UI JSON entry to run your DAG you should either:
-The change in GCP operators implies that GCP Hooks for those operators require now keyword parameters rather
-than positional ones in all methods where ``project_id`` is used. The methods throw an explanatory exception
-in case they are called using positional parameters.
+* `Add params to your DAG `_
+* Enable the new configuration ``show_trigger_form_if_no_params`` to bring back old behaviour
-Other GCP hooks are unaffected.
+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.providers.google.cloud.hooks.pubsub.PubSubHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.google.cloud.operators.pubsub.PubSubTopicCreateOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.google.cloud.operators.pubsub.PubSubSubscriptionCreateOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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``.
-``airflow.providers.google.cloud.operators.pubsub.PubSubTopicDeleteOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.google.cloud.operators.pubsub.PubSubSubscriptionDeleteOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.google.cloud.operators.pubsub.PubSubPublishOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.google.cloud.sensors.pubsub.PubSubPullSensor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3. ``Hidden``: Disables the test connection functionality and
+hides the Test Connection button in UI.
-In the ``PubSubPublishOperator`` and ``PubSubHook.publish`` method the data field in a message should be bytestring (utf-8 encoded) rather than base64 encoded string.
+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.
-Due to the normalization of the parameters within GCP operators and hooks a parameters like ``project`` or ``topic_project``
-are deprecated and will be substituted by parameter ``project_id``.
-In ``PubSubHook.create_subscription`` hook method in the parameter ``subscription_project`` is replaced by ``subscription_project_id``.
-Template fields are updated accordingly and old ones may not work.
+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.
-It is required now to pass key-word only arguments to ``PubSub`` hook.
+However, it is strongly advised to **not** enable the feature, and perform
+deserialization at the client side instead.
-These changes are not backward compatible.
+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``.
-``airflow.providers.google.cloud.operators.kubernetes_engine.GKEStartPodOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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 gcp_conn_id parameter in GKEPodOperator is required. In previous versions, it was possible to pass
-the ``None`` value to the ``gcp_conn_id`` in the GKEStartPodOperator
-operator, which resulted in credentials being determined according to the
-`Application Default Credentials `_ strategy.
-Now this parameter requires a value. To restore the previous behavior, configure the connection without
-specifying the service account.
+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.
-Detailed information about connection management is available:
-`Google Cloud Connection `_.
+``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``).
-``airflow.providers.google.cloud.hooks.gcs.GCSHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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``.
+Some executors have been moved to corresponding providers (#32767)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+In order to use the executors, you need to install the providers:
-*
- The following parameters have been replaced in all the methods in GCSHook:
+* 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
+You can achieve it also by installing airflow with ``[celery]``, ``[cncf.kubernetes]``, ``[daskexecutor]`` extras respectively.
- * ``bucket`` is changed to ``bucket_name``
- * ``object`` is changed to ``object_name``
+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.
-*
- The ``maxResults`` parameter in ``GoogleCloudStorageHook.list`` has been renamed to ``max_results`` for consistency.
+Improvement Changes
+^^^^^^^^^^^^^^^^^^^
-``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitPigJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitHiveJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitSparkSqlJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitSparkJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitHadoopJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-``airflow.providers.google.cloud.operators.dataproc.DataprocSubmitPySparkJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-The 'properties' and 'jars' properties for the Dataproc related operators (\ ``DataprocXXXOperator``\ ) have been renamed from
-``dataproc_xxxx_properties`` and ``dataproc_xxx_jars`` to ``dataproc_properties``
-and ``dataproc_jars``\ respectively.
-Arguments for dataproc_properties dataproc_jars
-``airflow.providers.google.cloud.operators.cloud_storage_transfer_service.CloudDataTransferServiceCreateJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Airflow 2.6.3 (2023-07-10)
+--------------------------
-To obtain pylint compatibility the ``filter`` argument in ``CloudDataTransferServiceCreateJobOperator``
-has been renamed to ``request_filter``.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``airflow.providers.google.cloud.hooks.cloud_storage_transfer_service.CloudDataTransferServiceHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
- To obtain pylint compatibility the ``filter`` argument in ``CloudDataTransferServiceHook.list_transfer_job`` and
- ``CloudDataTransferServiceHook.list_transfer_operations`` has been renamed to ``request_filter``.
+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)
-``airflow.providers.google.cloud.hooks.bigquery.BigQueryHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-In general all hook methods are decorated with ``@GoogleBaseHook.fallback_to_default_project_id`` thus
-parameters to hook can only be passed via keyword arguments.
+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)
-* ``create_empty_table`` method accepts now ``table_resource`` parameter. If provided all
- other parameters are ignored.
-* ``create_empty_dataset`` will now use values from ``dataset_reference`` instead of raising error
- if parameters were passed in ``dataset_reference`` and as arguments to method. Additionally validation
- of ``dataset_reference`` is done using ``Dataset.from_api_repr``. Exception and log messages has been
- changed.
-* ``update_dataset`` requires now new ``fields`` argument (breaking change)
-* ``delete_dataset`` has new signature (dataset_id, project_id, ...)
- previous one was (project_id, dataset_id, ...) (breaking change)
-* ``get_tabledata`` returns list of rows instead of API response in dict format. This method is deprecated in
- favor of ``list_rows``. (breaking change)
+Airflow 2.6.2 (2023-06-17)
+--------------------------
-``airflow.providers.google.cloud.hooks.cloud_build.CloudBuildHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``airflow.providers.google.cloud.operators.cloud_build.CloudBuildCreateBuildOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+No significant changes.
-The ``api_version`` has been removed and will not be used since we migrate ``CloudBuildHook`` from using
- Discovery API to native google-cloud-build python library.
+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)
-The ``body`` parameter in ``CloudBuildCreateBuildOperator`` has been deprecated.
- Instead, you should pass body using the ``build`` parameter.
+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)
-``airflow.providers.google.cloud.hooks.dataflow.DataflowHook.start_python_dataflow``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.providers.google.cloud.hooks.dataflow.DataflowHook.start_python_dataflow``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Airflow 2.6.1 (2023-05-16)
+--------------------------
-``airflow.providers.google.cloud.operators.dataflow.DataflowCreatePythonJobOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Change python3 as Dataflow Hooks/Operators default interpreter
+Clarifications of the external Health Check mechanism and using ``Job`` classes (#31277).
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Now the ``py_interpreter`` argument for DataFlow Hooks/Operators has been changed from python2 to python3.
+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.
-``airflow.providers.google.common.hooks.base_google.GoogleBaseHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-To simplify the code, the decorator provide_gcp_credential_file has been moved from the inner-class.
+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)
-Instead of ``@GoogleBaseHook._Decorators.provide_gcp_credential_file``\ ,
-you should write ``@GoogleBaseHook.provide_gcp_credential_file``
+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.providers.google.cloud.operators.dataproc.DataprocCreateClusterOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-It is highly recommended to have 1TB+ disk size for Dataproc to have sufficient throughput:
-https://cloud.google.com/compute/docs/disks/performance
+Airflow 2.6.0 (2023-04-30)
+--------------------------
-Hence, the default value for ``master_disk_size`` in ``DataprocCreateClusterOperator`` has been changed from 500GB to 1TB.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Generating Cluster Config
-"""""""""""""""""""""""""
+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.
-If you are upgrading from Airflow 1.10.x and are not using **CLUSTER_CONFIG**\ ,
-You can easily generate config using **make()** of ``airflow.providers.google.cloud.operators.dataproc.ClusterGenerator``
+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.
-This has been proved specially useful if you are using **metadata** argument from older API, refer `AIRFLOW-16911 `_ for details.
+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.
-eg. your cluster creation may look like this in **v1.10.x**
+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.
-.. code-block:: python
+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.
- path = f"gs://goog-dataproc-initialization-actions-us-central1/python/pip-install.sh"
+Improvement Changes
+^^^^^^^^^^^^^^^^^^^
- create_cluster = DataprocClusterCreateOperator(
- task_id="create_dataproc_cluster",
- cluster_name="test",
- project_id="test",
- zone="us-central1-a",
- region="us-central1",
- master_machine_type="n1-standard-4",
- worker_machine_type="n1-standard-4",
- num_workers=2,
- storage_bucket="test_bucket",
- init_actions_uris=[path],
- metadata={"PIP_PACKAGES": "pyyaml requests pandas openpyxl"},
- )
+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.
-After upgrading to **v2.x.x** and using **CLUSTER_CONFIG**\ , it will look like followed:
+Explicit skipped states list for ExternalTaskSensor (#29933)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+ExternalTaskSensor now has an explicit ``skipped_states`` list
-.. code-block:: python
+Miscellaneous Changes
+^^^^^^^^^^^^^^^^^^^^^
- path = f"gs://goog-dataproc-initialization-actions-us-central1/python/pip-install.sh"
+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.
- CLUSTER_CONFIG = ClusterGenerator(
- project_id="test",
- zone="us-central1-a",
- master_machine_type="n1-standard-4",
- worker_machine_type="n1-standard-4",
- num_workers=2,
- storage_bucket="test",
- init_actions_uris=[path],
- metadata={"PIP_PACKAGES": "pyyaml requests pandas openpyxl"},
- ).make()
+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.
- create_cluster_operator = DataprocClusterCreateOperator(
- task_id="create_dataproc_cluster",
- cluster_name="test",
- project_id="test",
- region="us-central1",
- cluster_config=CLUSTER_CONFIG,
- )
+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.
-``airflow.providers.google.cloud.operators.bigquery.BigQueryGetDatasetTablesOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-We changed signature of ``BigQueryGetDatasetTablesOperator``.
+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)
-Before:
-.. code-block:: python
+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)
- def __init__(
- dataset_id: str,
- dataset_resource: dict,
- # ...
- ): ...
+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)
-After:
-.. code-block:: python
+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)
- def __init__(
- dataset_resource: dict,
- dataset_id: Optional[str] = None,
- # ...
- ): ...
-
-Changes in ``amazon`` provider package
-""""""""""""""""""""""""""""""""""""""""""
-
-We strive to ensure that there are no changes that may affect the end user, and your Python files, but this
-release may contain changes that will require changes to your configuration, DAG Files or other integration
-e.g. custom operators.
-
-Only changes unique to this provider are described here. You should still pay attention to the changes that
-have been made to the core (including core operators) as they can affect the integration behavior
-of this provider.
-
-This section describes the changes that have been made, and what you need to do to update your if
-you use operators or hooks which integrate with Amazon services (including Amazon Web Service - AWS).
-
-Migration of AWS components
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-All AWS components (hooks, operators, sensors, example DAGs) will be grouped together as decided in
-`AIP-21 `_. Migrated
-components remain backwards compatible but raise a ``DeprecationWarning`` when imported from the old module.
-Migrated are:
-
-.. list-table::
- :header-rows: 1
-
- * - Old path
- - New path
- * - ``airflow.hooks.S3_hook.S3Hook``
- - ``airflow.providers.amazon.aws.hooks.s3.S3Hook``
- * - ``airflow.contrib.hooks.aws_athena_hook.AWSAthenaHook``
- - ``airflow.providers.amazon.aws.hooks.athena.AWSAthenaHook``
- * - ``airflow.contrib.hooks.aws_lambda_hook.AwsLambdaHook``
- - ``airflow.providers.amazon.aws.hooks.lambda_function.AwsLambdaHook``
- * - ``airflow.contrib.hooks.aws_sqs_hook.SQSHook``
- - ``airflow.providers.amazon.aws.hooks.sqs.SQSHook``
- * - ``airflow.contrib.hooks.aws_sns_hook.AwsSnsHook``
- - ``airflow.providers.amazon.aws.hooks.sns.AwsSnsHook``
- * - ``airflow.contrib.operators.aws_athena_operator.AWSAthenaOperator``
- - ``airflow.providers.amazon.aws.operators.athena.AWSAthenaOperator``
- * - ``airflow.contrib.operators.awsbatch.AWSBatchOperator``
- - ``airflow.providers.amazon.aws.operators.batch.AwsBatchOperator``
- * - ``airflow.contrib.operators.awsbatch.BatchProtocol``
- - ``airflow.providers.amazon.aws.hooks.batch_client.AwsBatchProtocol``
- * - private attrs and methods on ``AWSBatchOperator``
- - ``airflow.providers.amazon.aws.hooks.batch_client.AwsBatchClient``
- * - n/a
- - ``airflow.providers.amazon.aws.hooks.batch_waiters.AwsBatchWaiters``
- * - ``airflow.contrib.operators.aws_sqs_publish_operator.SQSPublishOperator``
- - ``airflow.providers.amazon.aws.operators.sqs.SQSPublishOperator``
- * - ``airflow.contrib.operators.aws_sns_publish_operator.SnsPublishOperator``
- - ``airflow.providers.amazon.aws.operators.sns.SnsPublishOperator``
- * - ``airflow.contrib.sensors.aws_athena_sensor.AthenaSensor``
- - ``airflow.providers.amazon.aws.sensors.athena.AthenaSensor``
- * - ``airflow.contrib.sensors.aws_sqs_sensor.SQSSensor``
- - ``airflow.providers.amazon.aws.sensors.sqs.SQSSensor``
-
-
-``airflow.providers.amazon.aws.hooks.emr.EmrHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.amazon.aws.operators.emr_add_steps.EmrAddStepsOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.amazon.aws.operators.emr_create_job_flow.EmrCreateJobFlowOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``airflow.providers.amazon.aws.operators.emr_terminate_job_flow.EmrTerminateJobFlowOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The default value for the `aws_conn_id `_ was accidentally set to 's3_default' instead of 'aws_default' in some of the emr operators in previous
-versions. This was leading to EmrStepSensor not being able to find their corresponding emr cluster. With the new
-changes in the EmrAddStepsOperator, EmrTerminateJobFlowOperator and EmrCreateJobFlowOperator this issue is
-solved.
-
-``airflow.providers.amazon.aws.operators.batch.AwsBatchOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``AwsBatchOperator`` was refactored to extract an ``AwsBatchClient`` (and inherit from it). The
-changes are mostly backwards compatible and clarify the public API for these classes; some
-private methods on ``AwsBatchOperator`` for polling a job status were relocated and renamed
-to surface new public methods on ``AwsBatchClient`` (and via inheritance on ``AwsBatchOperator``\ ). A
-couple of job attributes are renamed on an instance of ``AwsBatchOperator``\ ; these were mostly
-used like private attributes but they were surfaced in the public API, so any use of them needs
-to be updated as follows:
-
-
-* ``AwsBatchOperator().jobId`` -> ``AwsBatchOperator().job_id``
-* ``AwsBatchOperator().jobName`` -> ``AwsBatchOperator().job_name``
-
-The ``AwsBatchOperator`` gets a new option to define a custom model for waiting on job status changes.
-The ``AwsBatchOperator`` can use a new ``waiters`` parameter, an instance of ``AwsBatchWaiters``\ , to
-specify that custom job waiters will be used to monitor a batch job. See the latest API
-documentation for details.
-
-``airflow.providers.amazon.aws.sensors.athena.AthenaSensor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Replace parameter ``max_retires`` with ``max_retries`` to fix typo.
-
-``airflow.providers.amazon.aws.hooks.s3.S3Hook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Note: The order of arguments has changed for ``check_for_prefix``.
-The ``bucket_name`` is now optional. It falls back to the ``connection schema`` attribute.
-The ``delete_objects`` now returns ``None`` instead of a response, since the method now makes multiple api requests when the keys list length is > 1000.
-
-Changes in other provider packages
-""""""""""""""""""""""""""""""""""
-We strive to ensure that there are no changes that may affect the end user and your Python files, but this
-release may contain changes that will require changes to your configuration, DAG Files or other integration
-e.g. custom operators.
+Airflow 2.5.3 (2023-04-01)
+--------------------------
-Only changes unique to providers are described here. You should still pay attention to the changes that
-have been made to the core (including core operators) as they can affect the integration behavior
-of this provider.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-This section describes the changes that have been made, and what you need to do to update your if
-you use any code located in ``airflow.providers`` package.
+No significant changes.
-Changed return type of ``list_prefixes`` and ``list_keys`` methods in ``S3Hook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-Previously, the ``list_prefixes`` and ``list_keys`` methods returned ``None`` when there were no
-results. The behavior has been changed to return an empty list instead of ``None`` in this
-case.
+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)
-Removed HipChat integration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-HipChat has reached end of life and is no longer available.
-For more information please see
-https://community.atlassian.com/t5/Stride-articles/Stride-and-Hipchat-Cloud-have-reached-End-of-Life-updated/ba-p/940248
+Airflow 2.5.2 (2023-03-15)
+--------------------------
-``airflow.providers.salesforce.hooks.salesforce.SalesforceHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Replace parameter ``sandbox`` with ``domain``. According to change in simple-salesforce package.
+The date-time fields passed as API parameters or Params should be RFC3339-compliant (#29395)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-Rename ``sign_in`` function to ``get_conn``.
+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``).
-``airflow.providers.apache.pinot.hooks.pinot.PinotAdminHook.create_segment``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-Rename parameter name from ``format`` to ``segment_format`` in PinotAdminHook function create_segment for pylint compatible
+Default for ``[webserver] expose_hostname`` changed to ``False`` (#29547)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-``airflow.providers.apache.hive.hooks.hive.HiveMetastoreHook.get_partitions``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-Rename parameter name from ``filter`` to ``partition_filter`` in HiveMetastoreHook function get_partitions for pylint compatible
+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)
-``airflow.providers.ftp.hooks.ftp.FTPHook.list_directory``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-Remove unnecessary parameter ``nlst`` in FTPHook function ``list_directory`` for pylint compatible
+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.providers.postgres.hooks.postgres.PostgresHook.copy_expert``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Remove unnecessary parameter ``open`` in PostgresHook function ``copy_expert`` for pylint compatible
+Airflow 2.5.1 (2023-01-20)
+--------------------------
-``airflow.providers.opsgenie.operators.opsgenie_alert.OpsgenieAlertOperator``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-Change parameter name from ``visibleTo`` to ``visible_to`` in OpsgenieAlertOperator for pylint compatible
+Trigger gevent ``monkeypatching`` via environment variable (#28283)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-``airflow.providers.imap.hooks.imap.ImapHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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.
-``airflow.providers.imap.sensors.imap_attachment.ImapAttachmentSensor``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-ImapHook:
+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)
-* The order of arguments has changed for ``has_mail_attachment``\ ,
- ``retrieve_mail_attachments`` and ``download_mail_attachments``.
-* A new ``mail_filter`` argument has been added to each of those.
-``airflow.providers.http.hooks.http.HttpHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Airflow 2.5.0 (2022-12-02)
+--------------------------
-The HTTPHook is now secured by default: ``verify=True`` (before: ``verify=False``\ )
-This can be overwritten by using the extra_options param as ``{'verify': False}``.
+Significant Changes
+^^^^^^^^^^^^^^^^^^^
-``airflow.providers.cloudant.hooks.cloudant.CloudantHook``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+``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.
-* upgraded cloudant version from ``>=0.5.9,<2.0`` to ``>=2.0``
-* removed the use of the ``schema`` attribute in the connection
-* removed ``db`` function since the database object can also be retrieved by calling ``cloudant_session['database_name']``
+Airflow config section ``kubernetes`` renamed to ``kubernetes_executor`` (#26873)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-For example:
+KubernetesPodOperator no longer considers any core kubernetes config params, so this section now only applies to kubernetes executor. Renaming it reduces potential for confusion.
-.. code-block:: python
+``AirflowException`` is now thrown as soon as any dependent tasks of ExternalTaskSensor fails (#27190)
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- from airflow.providers.cloudant.hooks.cloudant import CloudantHook
+``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.
- with CloudantHook().get_conn() as cloudant_session:
- database = cloudant_session["database_name"]
+The Airflow config option ``scheduler.deactivate_stale_dags_interval`` has been renamed to ``scheduler.parsing_cleanup_interval`` (#27828).
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-See the `docs `_ for more information on how to use the new cloudant version.
+The old option will continue to work but will issue deprecation warnings, and will be removed entirely in Airflow 3.
-``airflow.providers.snowflake``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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)
-When initializing a Snowflake hook or operator, the value used for ``snowflake_conn_id`` was always ``snowflake_conn_id``\ , regardless of whether or not you specified a value for it. The default ``snowflake_conn_id`` value is now switched to ``snowflake_default`` for consistency and will be properly overridden when specified.
+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)
-Other changes
-"""""""""""""
+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)
-This release also includes changes that fall outside any of the sections above.
-
-Standardized "extra" requirements
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We standardized the Extras names and synchronized providers package names with the main airflow extras.
-
-We deprecated a number of extras in 2.0.
-
-.. list-table::
- :header-rows: 1
-
- * - Deprecated extras
- - New extras
- * - atlas
- - apache.atlas
- * - aws
- - amazon
- * - azure
- - microsoft.azure
- * - azure_blob_storage
- - microsoft.azure
- * - azure_data_lake
- - microsoft.azure
- * - azure_cosmos
- - microsoft.azure
- * - azure_container_instances
- - microsoft.azure
- * - cassandra
- - apache.cassandra
- * - druid
- - apache.druid
- * - gcp
- - google
- * - gcp_api
- - google
- * - hdfs
- - apache.hdfs
- * - hive
- - apache.hive
- * - kubernetes
- - cncf.kubernetes
- * - mssql
- - microsoft.mssql
- * - pinot
- - apache.pinot
- * - webhdfs
- - apache.webhdfs
- * - winrm
- - apache.winrm
-
-
-For example:
-
-If you want to install integration for Apache Atlas, then instead of ``pip install apache-airflow[atlas]``
-you should use ``pip install apache-airflow[apache.atlas]``.
-
-NOTE!
-
-If you want to install integration for Microsoft Azure, then instead of
-
-.. code-block::
-
- pip install 'apache-airflow[azure_blob_storage,azure_data_lake,azure_cosmos,azure_container_instances]'
-
-you should run ``pip install 'apache-airflow[microsoft.azure]'``
-
-If you want to install integration for Amazon Web Services, then instead of
-``pip install 'apache-airflow[s3,emr]'``\ , you should execute ``pip install 'apache-airflow[aws]'``
-
-The deprecated extras will be removed in 3.0.
-
-Simplify the response payload of endpoints /dag_stats and /task_stats
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The response of endpoints ``/dag_stats`` and ``/task_stats`` help UI fetch brief statistics about DAGs and Tasks. The format was like
-
-.. code-block:: json
-
- {
- "example_http_operator": [
- {
- "state": "success",
- "count": 0,
- "dag_id": "example_http_operator",
- "color": "green"
- },
- {
- "state": "running",
- "count": 0,
- "dag_id": "example_http_operator",
- "color": "lime"
- }
- ]
- }
-
-The ``dag_id`` was repeated in the payload, which makes the response payload unnecessarily bigger.
-
-Now the ``dag_id`` will not appear repeated in the payload, and the response format is like
-
-.. code-block:: json
-
- {
- "example_http_operator": [
- {
- "state": "success",
- "count": 0,
- "color": "green"
- },
- {
- "state": "running",
- "count": 0,
- "color": "lime"
- }
- ]
- }
+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)
.. spelling::
diff --git a/airflow-core/docs/administration-and-deployment/cluster-policies.rst b/airflow-core/docs/administration-and-deployment/cluster-policies.rst
index e0b71eef7a353..b67234c61b58f 100644
--- a/airflow-core/docs/administration-and-deployment/cluster-policies.rst
+++ b/airflow-core/docs/administration-and-deployment/cluster-policies.rst
@@ -104,7 +104,7 @@ configure local settings.
[project.entry-points.'airflow.policy']
_ = 'my_airflow_plugin.policies'
- The entrypoint group must be ``airflow.policy``, and the name is ignored. The value should be your module (or class) decorated with the ``@hookimpl`` marker.
+ The entrypoint group must be ``airflow.policy``, and the name must be unique per entry, otherwise duplicate entries will be ignored by pluggy. The value should be your module (or class) decorated with the ``@hookimpl`` marker.
Once you have done that, and you have installed your distribution into your Airflow env, the policy functions will get called by the various Airflow components. (The exact call order is undefined, so don't rely on any particular calling order if you have multiple plugins).
@@ -152,7 +152,7 @@ Here's an example of enforcing a maximum timeout policy on every task:
:start-after: [START example_task_cluster_policy]
:end-before: [END example_task_cluster_policy]
-You could also implement to protect against common errors, rather than as technical security controls. For example, don't run tasks without airflow owners:
+You could also implement to protect against common errors, rather than as technical security controls. For example, don't run tasks without Airflow owners:
.. literalinclude:: /../tests/unit/cluster_policies/__init__.py
:language: python
diff --git a/airflow-core/docs/administration-and-deployment/dag-bundles.rst b/airflow-core/docs/administration-and-deployment/dag-bundles.rst
index 7dc03ebab1451..53bd5e16afbdf 100644
--- a/airflow-core/docs/administration-and-deployment/dag-bundles.rst
+++ b/airflow-core/docs/administration-and-deployment/dag-bundles.rst
@@ -50,6 +50,9 @@ Airflow supports multiple types of dag Bundles, each catering to specific use ca
**airflow.providers.git.bundles.git.GitDagBundle**
These bundles integrate with Git repositories, allowing Airflow to fetch dags directly from a repository.
+**airflow.providers.amazon.aws.bundles.s3.S3DagBundle**
+ These bundles reference an S3 bucket containing DAG files. They do not support versioning of the bundle, meaning tasks always run using the latest code.
+
Configuring dag bundles
-----------------------
@@ -65,7 +68,7 @@ For example, adding multiple dag bundles to your ``airflow.cfg`` file:
dag_bundle_config_list = [
{
"name": "my_git_repo",
- "classpath": "airflow.dag_processing.bundles.git.GitDagBundle",
+ "classpath": "airflow.providers.git.bundles.git.GitDagBundle",
"kwargs": {"tracking_ref": "main", "git_conn_id": "my_git_conn"}
},
{
@@ -80,9 +83,42 @@ For example, adding multiple dag bundles to your ``airflow.cfg`` file:
The whitespace, particularly on the last line, is important so a multi-line value works properly. More details can be found in the
the `configparser docs `_.
+If you want a view url different from the default provided by the dag bundle, you can change the url in the kwargs of the dag bundle configuration.
+For example, if you want to use a custom URL for the git dag bundle:
+
+.. code-block:: ini
+
+ [dag_processor]
+ dag_bundle_config_list = [
+ {
+ "name": "my_git_repo",
+ "classpath": "airflow.dag_processing.bundles.git.GitDagBundle",
+ "kwargs": {
+ "tracking_ref": "main",
+ "git_conn_id": "my_git_conn",
+ "view_url_template": "https://my.custom.git.repo/view/{subdir}",
+ }
+ }
+ ]
+
+Above, the ``view_url_template`` is set to a custom URL that will be used to view the Dags in the ``my_git_repo`` bundle. The ``{subdir}`` placeholder will be replaced
+with the ``subdir`` attribute of the bundle. The placeholders are attributes of the bundle. You cannot use any placeholder outside of the bundle's attributes.
+When you specify a custom URL, it overrides the default URL provided by the dag bundle.
+
+The url is verified for safety, and if it is not safe, the view url for the bundle will be set to ``None``. This is to prevent any potential security issues with unsafe URLs.
+
You can also override the :ref:`config:dag_processor__refresh_interval` per dag bundle by passing it in kwargs.
This controls how often the dag processor refreshes, or looks for new files, in the dag bundles.
+Starting Airflow 3.0.2 git is pre installed in the base image. However, if you are using versions prior 3.0.2, you would need to install git in your docker image.
+
+.. code-block:: Dockerfile
+
+ RUN apt-get update && apt-get install -y git
+ ENV GIT_PYTHON_GIT_EXECUTABLE=/usr/bin/git
+ ENV GIT_PYTHON_REFRESH=quiet
+
+
Writing custom dag bundles
--------------------------
diff --git a/airflow-core/docs/administration-and-deployment/dagfile-processing.rst b/airflow-core/docs/administration-and-deployment/dagfile-processing.rst
index 353f12a72a246..d2050e1df6af3 100644
--- a/airflow-core/docs/administration-and-deployment/dagfile-processing.rst
+++ b/airflow-core/docs/administration-and-deployment/dagfile-processing.rst
@@ -16,13 +16,13 @@
specific language governing permissions and limitations
under the License.
-DAG File Processing
+Dag File Processing
-------------------
-DAG File Processing refers to the process of reading the python files that define your dags and storing them such that the scheduler can schedule them.
+Dag File Processing refers to the process of reading the python files that define your Dags and storing them such that the scheduler can schedule them.
-There are two primary components involved in DAG file processing. The ``DagFileProcessorManager`` is a process executing an infinite loop that determines which files need
-to be processed, and the ``DagFileProcessorProcess`` is a separate process that is started to convert an individual file into one or more DAG objects.
+There are two primary components involved in Dag file processing. The ``DagFileProcessorManager`` is a process executing an infinite loop that determines which files need
+to be processed, and the ``DagFileProcessorProcess`` is a separate process that is started to convert an individual file into one or more Dag objects.
The ``DagFileProcessorManager`` runs user codes. As a result, it runs as a standalone process by running the ``airflow dag-processor`` CLI command.
@@ -30,61 +30,61 @@ The ``DagFileProcessorManager`` runs user codes. As a result, it runs as a stand
``DagFileProcessorManager`` has the following steps:
-1. Check for new files: If the elapsed time since the DAG was last refreshed is > :ref:`config:scheduler__dag_dir_list_interval` then update the file paths list
+1. Check for new files: If the elapsed time since the Dag was last refreshed is > :ref:`config:dag_processor__refresh_interval` then update the file paths list
2. Exclude recently processed files: Exclude files that have been processed more recently than :ref:`min_file_process_interval` and have not been modified
3. Queue file paths: Add files discovered to the file path queue
4. Process files: Start a new ``DagFileProcessorProcess`` for each file, up to a maximum of :ref:`config:dag_processor__parsing_processes`
-5. Collect results: Collect the result from any finished DAG processors
+5. Collect results: Collect the result from any finished Dag processors
6. Log statistics: Print statistics and emit ``dag_processing.total_parse_time``
``DagFileProcessorProcess`` has the following steps:
1. Process file: The entire process must complete within :ref:`dag_file_processor_timeout`
-2. The DAG files are loaded as Python module: Must complete within :ref:`dagbag_import_timeout`
-3. Process modules: Find DAG objects within Python module
-4. Return DagBag: Provide the ``DagFileProcessorManager`` a list of the discovered DAG objects
+2. The Dag files are loaded as Python module: Must complete within :ref:`dagbag_import_timeout`
+3. Process modules: Find Dag objects within Python module
+4. Return DagBag: Provide the ``DagFileProcessorManager`` a list of the discovered Dag objects
-Fine-tuning your DAG processor performance
+Fine-tuning your Dag processor performance
------------------------------------------
-What impacts DAG processor's performance
+What impacts Dag processor's performance
""""""""""""""""""""""""""""""""""""""""
-The DAG processor is responsible for continuously parsing DAG files and synchronizing with the DAG in the database
-In order to fine-tune your DAG processor, you need to include a number of factors:
+The Dag processor is responsible for continuously parsing Dag files and synchronizing with the Dag in the database
+In order to fine-tune your Dag processor, you need to include a number of factors:
* The kind of deployment you have
- * what kind of filesystem you have to share the dags (impacts performance of continuously reading dags)
+ * what kind of filesystem you have to share the Dags (impacts performance of continuously reading Dags)
* how fast the filesystem is (in many cases of distributed cloud filesystem you can pay extra to get
more throughput/faster filesystem)
* how much memory you have for your processing
* how much CPU you have available
* how much networking throughput you have available
-* The logic and definition of your DAG structure:
- * how many DAG files you have
- * how many dags you have in your files
- * how large the DAG files are (remember DAG parser needs to read and parse the file every n seconds)
+* The logic and definition of your Dag structure:
+ * how many Dag files you have
+ * how many Dags you have in your files
+ * how large the Dag files are (remember Dag parser needs to read and parse the file every n seconds)
* how complex they are (i.e. how fast they can be parsed, how many tasks and dependencies they have)
- * whether parsing your DAG file involves importing a lot of libraries or heavy processing at the top level
+ * whether parsing your Dag file involves importing a lot of libraries or heavy processing at the top level
(Hint! It should not. See :ref:`best_practices/top_level_code`)
-* The DAG processor configuration
- * How many DAG processors you have
- * How many parsing processes you have in your DAG processor
- * How much time DAG processor waits between re-parsing of the same DAG (it happens continuously)
- * How many callbacks you run per DAG processor loop
+* The Dag processor configuration
+ * How many Dag processors you have
+ * How many parsing processes you have in your Dag processor
+ * How much time Dag processor waits between re-parsing of the same Dag (it happens continuously)
+ * How many callbacks you run per Dag processor loop
-How to approach DAG processor's fine-tuning
+How to approach Dag processor's fine-tuning
"""""""""""""""""""""""""""""""""""""""""""
Airflow gives you a lot of "knobs" to turn to fine tune the performance but it's a separate task,
-depending on your particular deployment, your DAG structure, hardware availability and expectations,
+depending on your particular deployment, your Dag structure, hardware availability and expectations,
to decide which knobs to turn to get best effect for you. Part of the job when managing the
deployment is to decide what you are going to optimize for. Some users are ok with
-30 seconds delays of new DAG parsing, at the expense of lower CPU usage, whereas some other users
-expect the dags to be parsed almost instantly when they appear in the dags folder at the
+30 seconds delays of new Dag parsing, at the expense of lower CPU usage, whereas some other users
+expect the Dags to be parsed almost instantly when they appear in the Dags folder at the
expense of higher CPU usage for example.
Airflow gives you the flexibility to decide, but you should find out what aspect of performance is
@@ -103,30 +103,30 @@ to observe and monitor your systems):
* based on your expectations and observations - decide what is your next improvement and go back to
the observation of your performance, bottlenecks. Performance improvement is an iterative process.
-What resources might limit DAG processors's performance
+What resources might limit Dag processors's performance
"""""""""""""""""""""""""""""""""""""""""""""""""""""""
There are several areas of resource usage that you should pay attention to:
-* FileSystem performance. The Airflow DAG processor relies heavily on parsing (sometimes a lot) of Python
- files, which are often located on a shared filesystem. The DAG processor continuously reads and
+* FileSystem performance. The Airflow Dag processor relies heavily on parsing (sometimes a lot) of Python
+ files, which are often located on a shared filesystem. The Dag processor continuously reads and
re-parses those files. The same files have to be made available to workers, so often they are
stored in a distributed filesystem. You can use various filesystems for that purpose (NFS, CIFS, EFS,
GCS fuse, Azure File System are good examples). There are various parameters you can control for those
filesystems and fine-tune their performance, but this is beyond the scope of this document. You should
observe statistics and usage of your filesystem to determine if problems come from the filesystem
performance. For example there are anecdotal evidences that increasing IOPS (and paying more) for the
- EFS performance, dramatically improves stability and speed of parsing Airflow dags when EFS is used.
+ EFS performance, dramatically improves stability and speed of parsing Airflow Dags when EFS is used.
* Another solution to FileSystem performance, if it becomes your bottleneck, is to turn to alternative
- mechanisms of distributing your dags. Embedding dags in your image and GitSync distribution have both
- the property that the files are available locally for the DAG processor and it does not have to use a
- distributed filesystem to read the files, the files are available locally for the the DAG processor and it is
+ mechanisms of distributing your Dags. Embedding Dags in your image and GitSync distribution have both
+ the property that the files are available locally for the Dag processor and it does not have to use a
+ distributed filesystem to read the files, the files are available locally for the the Dag processor and it is
usually as fast as it can be, especially if your machines use fast SSD disks for local storage. Those
distribution mechanisms have other characteristics that might make them not the best choice for you,
but if your problems with performance come from distributed filesystem performance, they might be the
best approach to follow.
* Database connections and Database usage might become a problem as you want to increase performance and
- process more things in parallel. Airflow is known for being "database-connection hungry" - the more dags
+ process more things in parallel. Airflow is known for being "database-connection hungry" - the more Dags
you have and the more you want to process in parallel, the more database connections will be opened.
This is generally not a problem for MySQL as its model of handling connections is thread-based, but this
might be a problem for Postgres, where connection handling is process-based. It is a general consensus
@@ -134,12 +134,12 @@ There are several areas of resource usage that you should pay attention to:
`PGBouncer `_ as a proxy to your database. The :doc:`helm-chart:index`
supports PGBouncer out-of-the-box.
* CPU usage is most important for FileProcessors - those are the processes that parse and execute
- Python DAG files. Since DAG processors typically triggers such parsing continuously, when you have a lot of dags,
+ Python Dag files. Since Dag processors typically triggers such parsing continuously, when you have a lot of Dags,
the processing might take a lot of CPU. You can mitigate it by increasing the
:ref:`config:dag_processor__min_file_process_interval`, but this is one of the mentioned trade-offs,
result of this is that changes to such files will be picked up slower and you will see delays between
submitting the files and getting them available in Airflow UI and executed by Scheduler. Optimizing
- the way how your dags are built, avoiding external data sources is your best approach to improve CPU
+ the way how your Dags are built, avoiding external data sources is your best approach to improve CPU
usage. If you have more CPUs available, you can increase number of processing threads
:ref:`config:dag_processor__parsing_processes`.
* Airflow might use quite a significant amount of memory when you try to get more performance out of it.
@@ -152,14 +152,14 @@ There are several areas of resource usage that you should pay attention to:
kind of memory you are observing. Usually you should look at ``working memory`` (names might vary depending
on your deployment) rather than ``total memory used``.
-What can you do, to improve DAG processor's performance
+What can you do, to improve Dag processor's performance
"""""""""""""""""""""""""""""""""""""""""""""""""""""""
When you know what your resource usage is, the improvements that you can consider might be:
-* improve the logic, efficiency of parsing and reduce complexity of your top-level DAG Python code. It is
+* improve the logic, efficiency of parsing and reduce complexity of your top-level Dag Python code. It is
parsed continuously so optimizing that code might bring tremendous improvements, especially if you try
- to reach out to some external databases etc. while parsing dags (this should be avoided at all cost).
+ to reach out to some external databases etc. while parsing Dags (this should be avoided at all cost).
The :ref:`best_practices/top_level_code` explains what are the best practices for writing your top-level
Python code. The :ref:`best_practices/reducing_dag_complexity` document provides some areas that you might
look at when you want to reduce complexity of your code.
@@ -168,31 +168,31 @@ When you know what your resource usage is, the improvements that you can conside
actions like increasing number of parsing processes might bring improvements in performance at the
expense of higher utilization of those.
* increase hardware capacity (for example if you see that CPU is limiting you or that I/O you use for
- DAG filesystem is at its limits). Often the problem with DAG processor performance is
+ Dag filesystem is at its limits). Often the problem with Dag processor performance is
simply because your system is not "capable" enough and this might be the only way, unless a shared database
or filesystem is a bottleneck.
-* experiment with different values for the "DAG processor tunables". Often you might get better effects by
+* experiment with different values for the "Dag processor tunables". Often you might get better effects by
simply exchanging one performance aspect for another. For example if you want to decrease the
- CPU usage, you might increase file processing interval (but the result will be that new dags will
+ CPU usage, you might increase file processing interval (but the result will be that new Dags will
appear with bigger delay). Usually performance tuning is the art of balancing different aspects.
-* sometimes you change DAG processor behavior slightly (for example change parsing sort order)
+* sometimes you change Dag processor behavior slightly (for example change parsing sort order)
in order to get better fine-tuned results for your particular deployment.
-DAG processor Configuration options
+Dag processor Configuration options
"""""""""""""""""""""""""""""""""""
-The following config settings can be used to control aspects of the Scheduler.
-However, you can also look at other non-performance-related scheduler configuration parameters available at
-:doc:`../configurations-ref` in the ``[scheduler]`` section.
+The following config settings can be used to control aspects of the Dag processor.
+However, you can also look at other non-performance-related Dag processor configuration parameters available at
+:doc:`../configurations-ref` in the ``[dag_processor]`` section.
- :ref:`config:dag_processor__file_parsing_sort_mode`
- The scheduler will list and sort the DAG files to decide the parsing order.
+ The Dag processor will list and sort the Dag files to decide the parsing order.
- :ref:`config:dag_processor__min_file_process_interval`
- Number of seconds after which a DAG file is re-parsed. The DAG file is parsed every
- min_file_process_interval number of seconds. Updates to dags are reflected after
+ Number of seconds after which a Dag file is re-parsed. The Dag file is parsed every
+ ``min_file_process_interval`` number of seconds. Updates to Dags are reflected after
this interval. Keeping this number low will increase CPU usage.
- :ref:`config:dag_processor__parsing_processes`
- The scheduler can run multiple processes in parallel to parse DAG files. This defines
+ The Dag processor can run multiple processes in parallel to parse Dag files. This defines
how many processes will run.
diff --git a/airflow-core/docs/administration-and-deployment/index.rst b/airflow-core/docs/administration-and-deployment/index.rst
index ec39a526a7717..720f5f695eb2c 100644
--- a/airflow-core/docs/administration-and-deployment/index.rst
+++ b/airflow-core/docs/administration-and-deployment/index.rst
@@ -18,7 +18,7 @@
Administration and Deployment
=====================================
-This section contains information about deploying dags into production and the administration of airflow deployments.
+This section contains information about deploying dags into production and the administration of Airflow deployments.
.. toctree::
:maxdepth: 2
diff --git a/airflow-core/docs/administration-and-deployment/listeners.rst b/airflow-core/docs/administration-and-deployment/listeners.rst
index 2ae7899e26199..b1ccf181d0c91 100644
--- a/airflow-core/docs/administration-and-deployment/listeners.rst
+++ b/airflow-core/docs/administration-and-deployment/listeners.rst
@@ -101,7 +101,7 @@ Asset Events
--------------
- ``on_asset_created``
-- ``on_dataset_alias_created``
+- ``on_asset_alias_created``
- ``on_asset_changed``
Asset events occur when Asset management operations are run.
@@ -131,7 +131,7 @@ Airflow defines the specification as `hookspec `.
-Listener API is meant to be called across all dags and all operators. You can't listen to events generated by specific dags. For that behavior, try methods like ``on_success_callback`` and ``pre_execute``. These provide callbacks for particular DAG authors or operator creators. The logs and ``print()`` calls will be handled as part of the listeners.
+Listener API is meant to be called across all dags and all operators. You can't listen to events generated by specific dags. For that behavior, try methods like ``on_success_callback`` and ``pre_execute``. These provide callbacks for particular Dag authors or operator creators. The logs and ``print()`` calls will be handled as part of the listeners.
Compatibility note
diff --git a/airflow-core/docs/administration-and-deployment/logging-monitoring/advanced-logging-configuration.rst b/airflow-core/docs/administration-and-deployment/logging-monitoring/advanced-logging-configuration.rst
index 2cfc44e725515..fa34e74f3140b 100644
--- a/airflow-core/docs/administration-and-deployment/logging-monitoring/advanced-logging-configuration.rst
+++ b/airflow-core/docs/administration-and-deployment/logging-monitoring/advanced-logging-configuration.rst
@@ -25,7 +25,7 @@ Not all configuration options are available from the ``airflow.cfg`` file. The c
how to configure logging for tasks, because the logs generated by tasks are not only logged in separate
files by default but has to be also accessible via the webserver.
-By default standard airflow component logs are written to the ``$AIRFLOW_HOME/logs`` directory, but you
+By default standard Airflow component logs are written to the ``$AIRFLOW_HOME/logs`` directory, but you
can also customize it and configure it as you want by overriding Python logger configuration that can
be configured by providing custom logging configuration object. You can also create and use logging configuration
for specific operators and tasks.
@@ -34,7 +34,7 @@ Some configuration options require that the logging config class be overwritten.
configuration of Airflow and modifying it to suit your needs.
The default configuration can be seen in the
-`airflow_local_settings.py template `_
+`airflow_local_settings.py template `_
and you can see the loggers and handlers used there.
See :ref:`Configuring local settings ` for details on how to
diff --git a/airflow-core/docs/administration-and-deployment/logging-monitoring/callbacks.rst b/airflow-core/docs/administration-and-deployment/logging-monitoring/callbacks.rst
index 377d06579cf54..c2201921cd135 100644
--- a/airflow-core/docs/administration-and-deployment/logging-monitoring/callbacks.rst
+++ b/airflow-core/docs/administration-and-deployment/logging-monitoring/callbacks.rst
@@ -20,13 +20,19 @@
Callbacks
=========
-A valuable component of logging and monitoring is the use of task callbacks to act upon changes in state of a given task, or across all tasks in a given DAG.
-For example, you may wish to alert when certain tasks have failed, or have the last task in your DAG invoke a callback when it succeeds.
+A valuable component of logging and monitoring is the use of task callbacks to act upon changes in state of a given DAG or task, or across all tasks in a given DAG.
+For example, you may wish to alert when certain tasks have failed, or invoke a callback when your DAG succeeds.
+
+There are three different places where callbacks can be defined.
+
+- Callbacks set in the DAG definition will be applied at the DAG level.
+- Using ``default_args``, callbacks can be set for each task in a DAG.
+- Individual callbacks can be set for a task by setting that callback within the task definition itself.
.. note::
- Callback functions are only invoked when the task state changes due to execution by a worker.
- As such, task changes set by the command line interface (:doc:`CLI <../../howto/usage-cli>`) or user interface (:doc:`UI <../../ui>`) do not
+ Callback functions are only invoked when the DAG or task state changes due to execution by a worker.
+ As such, DAG and task changes set by the command line interface (:doc:`CLI <../../howto/usage-cli>`) or user interface (:doc:`UI <../../ui>`) do not
execute callback functions.
.. warning::
@@ -39,26 +45,32 @@ For example, you may wish to alert when certain tasks have failed, or have the l
Callback Types
--------------
-There are five types of task events that can trigger a callback:
+There are six types of events that can trigger a callback:
=========================================== ================================================================
Name Description
=========================================== ================================================================
-``on_success_callback`` Invoked when the task :ref:`succeeds `
-``on_failure_callback`` Invoked when the task :ref:`fails `
-``on_retry_callback`` Invoked when the task is :ref:`up for retry `
+``on_success_callback`` Invoked when the :ref:`DAG succeeds ` or :ref:`task succeeds `.
+ Available at the DAG or task level.
+``on_failure_callback`` Invoked when the task :ref:`fails `.
+ Available at the DAG or task level.
+``on_retry_callback`` Invoked when the task is :ref:`up for retry `.
+ Available only at the task level.
``on_execute_callback`` Invoked right before the task begins executing.
+ Available only at the task level.
``on_skipped_callback`` Invoked when the task is :ref:`running ` and AirflowSkipException raised.
Explicitly it is NOT called if a task is not started to be executed because of a preceding branching
decision in the DAG or a trigger rule which causes execution to skip so that the task execution
is never scheduled.
+ Available only at the task level.
=========================================== ================================================================
Example
-------
-In the following example, failures in any task call the ``task_failure_alert`` function, and success in the last task calls the ``dag_success_alert`` function:
+In the following example, failures in ``task1`` call the ``task_failure_alert`` function, and success at DAG level calls the ``dag_success_alert`` function.
+Before each task begins to execute, the ``task_execute_callback`` function will be called:
.. code-block:: python
@@ -69,6 +81,10 @@ In the following example, failures in any task call the ``task_failure_alert`` f
from airflow.providers.standard.operators.empty import EmptyOperator
+ def task_execute_callback(context):
+ print(f"Task has begun execution, task_instance_key_str: {context['task_instance_key_str']}")
+
+
def task_failure_alert(context):
print(f"Task has failed, task_instance_key_str: {context['task_instance_key_str']}")
@@ -83,13 +99,13 @@ In the following example, failures in any task call the ``task_failure_alert`` f
start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
dagrun_timeout=datetime.timedelta(minutes=60),
catchup=False,
- on_success_callback=None,
- on_failure_callback=task_failure_alert,
+ on_success_callback=dag_success_alert,
+ default_args={"on_execute_callback": task_execute_callback},
tags=["example"],
):
- task1 = EmptyOperator(task_id="task1")
+ task1 = EmptyOperator(task_id="task1", on_failure_callback=[task_failure_alert])
task2 = EmptyOperator(task_id="task2")
- task3 = EmptyOperator(task_id="task3", on_success_callback=[dag_success_alert])
+ task3 = EmptyOperator(task_id="task3")
task1 >> task2 >> task3
.. note::
diff --git a/airflow-core/docs/administration-and-deployment/logging-monitoring/check-health.rst b/airflow-core/docs/administration-and-deployment/logging-monitoring/check-health.rst
index daca7dc8738c9..c803791762ef0 100644
--- a/airflow-core/docs/administration-and-deployment/logging-monitoring/check-health.rst
+++ b/airflow-core/docs/administration-and-deployment/logging-monitoring/check-health.rst
@@ -36,7 +36,7 @@ Webserver Health Check Endpoint
-------------------------------
To check the health status of your Airflow instance, you can simply access the endpoint
-``/health``. It will return a JSON object in which a high-level glance is provided.
+``/api/v2/monitor/health``. It will return a JSON object in which a high-level glance is provided.
.. code-block:: JSON
@@ -79,7 +79,7 @@ To check the health status of your Airflow instance, you can simply access the e
Note that the ``status`` and ``latest_dag_processor_heartbeat`` fields in the health check response will be null for
deployments that do not include a ``dag_processor`` component.
-Please keep in mind that the HTTP response code of ``/health`` endpoint **should not** be used to determine the health
+Please keep in mind that the HTTP response code of ``/api/v2/monitor/health`` endpoint **should not** be used to determine the health
status of the application. The return code is only indicative of the state of the rest call (200 for success).
Served by the web server, this health check endpoint is independent of the newer :ref:`Scheduler Health Check Server `, which optionally runs on each scheduler.
@@ -96,7 +96,7 @@ Scheduler Health Check Server
-----------------------------
In order to check scheduler health independent of the web server, Airflow optionally starts a small HTTP server
-in each scheduler to serve a scheduler ``\health`` endpoint. It returns status code ``200`` when the scheduler
+in each scheduler to serve a scheduler ``/health`` endpoint. It returns status code ``200`` when the scheduler
is healthy and status code ``503`` when the scheduler is unhealthy. To run this server in each scheduler, set
``[scheduler]enable_health_check`` to ``True``. By default, it is ``False``. The server is running on the port
specified by the ``[scheduler]scheduler_health_check_server_port`` option. By default, it is ``8974``. We are
diff --git a/airflow-core/docs/administration-and-deployment/logging-monitoring/logging-tasks.rst b/airflow-core/docs/administration-and-deployment/logging-monitoring/logging-tasks.rst
index 81def9b50cdd9..5ab451f29b66d 100644
--- a/airflow-core/docs/administration-and-deployment/logging-monitoring/logging-tasks.rst
+++ b/airflow-core/docs/administration-and-deployment/logging-monitoring/logging-tasks.rst
@@ -57,7 +57,7 @@ In addition, you can supply a remote location to store current logs and backups.
Writing to task logs from your code
-----------------------------------
-Airflow uses standard the Python `logging `_ framework to
+Airflow uses the standard Python `logging `_ framework to
write logs, and for the duration of a task, the root logger is configured to write to the task's log.
Most operators will write logs to the task log automatically. This is because they
@@ -89,7 +89,7 @@ Grouping of log lines
Like CI pipelines also Airflow logs can be quite large and become hard to read. Sometimes therefore it is useful to group sections of log areas
and provide folding of text areas to hide non relevant content. Airflow therefore implements a compatible log message grouping like
-`Github `_ and
+`GitHub `_ and
`Azure DevOps `_
such that areas of text can be folded. The implemented scheme is compatible such that tools making output in CI can leverage the same experience
in Airflow directly.
@@ -113,7 +113,7 @@ When displaying the logs in web UI, the display of logs will be condensed:
[2024-03-08, 23:30:18 CET] {logging_mixin.py:188} ⯈ Non important details
[2024-03-08, 23:30:18 CET] {logging_mixin.py:188} INFO - Here is again some standard text.
-If you click on the log text label, the detailed log lies will be displayed.
+If you click on the log text label, the detailed log lines will be displayed.
.. code-block:: text
@@ -178,7 +178,7 @@ Most task handlers send logs upon completion of a task. In order to view logs in
In triggerer, logs are served unless the service is started with option ``--skip-serve-logs``.
The server is running on the port specified by ``worker_log_server_port`` option in ``[logging]`` section, and option ``triggerer_log_server_port`` for triggerer. Defaults are 8793 and 8794, respectively.
-Communication between the webserver and the worker is signed with the key specified by ``secret_key`` option in ``[webserver]`` section. You must ensure that the key matches so that communication can take place without problems.
+Communication between the webserver and the worker is signed with the key specified by ``secret_key`` option in ``[api]`` section. You must ensure that the key matches so that communication can take place without problems.
We are using `Gunicorn `__ as a WSGI server. Its configuration options can be overridden with the ``GUNICORN_CMD_ARGS`` env variable. For details, see `Gunicorn settings `__.
diff --git a/airflow-core/docs/administration-and-deployment/logging-monitoring/metrics.rst b/airflow-core/docs/administration-and-deployment/logging-monitoring/metrics.rst
index 34296c2ed7b0d..56170c4c41fee 100644
--- a/airflow-core/docs/administration-and-deployment/logging-monitoring/metrics.rst
+++ b/airflow-core/docs/administration-and-deployment/logging-monitoring/metrics.rst
@@ -243,8 +243,6 @@ Name Description
``pool.scheduled_slots`` Number of scheduled slots in the pool. Metric with pool_name tagging.
``pool.starving_tasks.`` Number of starving tasks in the pool
``pool.starving_tasks`` Number of starving tasks in the pool. Metric with pool_name tagging.
-``task.cpu_usage..`` Percentage of CPU used by a task
-``task.mem_usage..`` Percentage of memory used by a task
``triggers.running.`` Number of triggers currently running for a triggerer (described by hostname)
``triggers.running`` Number of triggers currently running for a triggerer (described by hostname).
Metric with hostname tagging.
diff --git a/airflow-core/docs/administration-and-deployment/modules_management.rst b/airflow-core/docs/administration-and-deployment/modules_management.rst
index 865dab06867cb..e6b8b7d14fc7b 100644
--- a/airflow-core/docs/administration-and-deployment/modules_management.rst
+++ b/airflow-core/docs/administration-and-deployment/modules_management.rst
@@ -318,7 +318,7 @@ try to import the package now:
>>>
We can also use :envvar:`PYTHONPATH` variable with the airflow commands.
-For example, if we run the following airflow command:
+For example, if we run the following Airflow command:
.. code-block:: bash
diff --git a/airflow-core/docs/administration-and-deployment/plugins.rst b/airflow-core/docs/administration-and-deployment/plugins.rst
index 47c0f2fecdf84..2a74ca54d2020 100644
--- a/airflow-core/docs/administration-and-deployment/plugins.rst
+++ b/airflow-core/docs/administration-and-deployment/plugins.rst
@@ -104,18 +104,16 @@ looks like:
name = None
# A list of references to inject into the macros namespace
macros = []
- # A list of Blueprint object created from flask.Blueprint. For use with the flask_appbuilder based GUI
- flask_blueprints = []
# A list of dictionaries containing FastAPI app objects and some metadata. See the example below.
fastapi_apps = []
# A list of dictionaries containing FastAPI middleware factory objects and some metadata. See the example below.
fastapi_root_middlewares = []
- # A list of dictionaries containing FlaskAppBuilder BaseView object and some metadata. See example below
- appbuilder_views = []
- # A list of dictionaries containing kwargs for FlaskAppBuilder add_link. See example below
- appbuilder_menu_items = []
+ # A list of dictionaries containing external views and some metadata. See the example below.
+ external_views = []
+ # A list of dictionaries containing react apps and some metadata. See the example below.
+ react_apps = []
- # A callback to perform actions when airflow starts and the plugin is loaded.
+ # A callback to perform actions when Airflow starts and the plugin is loaded.
# NOTE: Ensure your plugin has *args, and **kwargs in the method definition
# to protect against extra parameters injected into the on_load(...)
# function in future changes
@@ -164,35 +162,21 @@ definitions in Airflow.
# This is the class you derive to create a plugin
from airflow.plugins_manager import AirflowPlugin
- from airflow.security import permissions
- from airflow.providers.fab.www.auth import has_access
from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware
- from flask import Blueprint
- from flask_appbuilder import expose, BaseView as AppBuilderBaseView
# Importing base classes that we need to derive
from airflow.hooks.base import BaseHook
from airflow.providers.amazon.aws.transfers.gcs_to_s3 import GCSToS3Operator
- # Will show up under airflow.macros.test_plugin.plugin_macro
- # and in templates through {{ macros.test_plugin.plugin_macro }}
+ # Will show up in templates through {{ macros.test_plugin.plugin_macro }}
def plugin_macro():
pass
- # Creating a flask blueprint to integrate the templates and static folder
- bp = Blueprint(
- "test_plugin",
- __name__,
- template_folder="templates", # registers airflow/plugins/templates as a Jinja template folder
- static_folder="static",
- static_url_path="/static/test_plugin",
- )
-
- # Creating a FastAPI application to integrate in airflow Rest API.
+ # Creating a FastAPI application to integrate in Airflow Rest API.
app = FastAPI()
@@ -212,54 +196,49 @@ definitions in Airflow.
"name": "Name of the Middleware",
}
-
- # Creating a flask appbuilder BaseView
- class TestAppBuilderBaseView(AppBuilderBaseView):
- default_view = "test"
-
- @expose("/")
- @has_access(
- [
- (permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
- ]
- )
- def test(self):
- return self.render_template("test_plugin/test.html", content="Hello galaxy!")
-
-
- # Creating a flask appbuilder BaseView
- class TestAppBuilderBaseNoMenuView(AppBuilderBaseView):
- default_view = "test"
-
- @expose("/")
- @has_access(
- [
- (permissions.ACTION_CAN_READ, permissions.RESOURCE_WEBSITE),
- ]
- )
- def test(self):
- return self.render_template("test_plugin/test.html", content="Hello galaxy!")
-
-
- v_appbuilder_view = TestAppBuilderBaseView()
- v_appbuilder_package = {
- "name": "Test View",
- "category": "Test Plugin",
- "view": v_appbuilder_view,
+ # Creating an external view that will be rendered in the Airflow UI.
+ external_view_with_metadata = {
+ # Name of the external view, this will be displayed in the UI.
+ "name": "Name of the External View",
+ # Source URL of the external view. This URL can be templated using context variables, depending on the location where the external view is rendered
+ # the context variables available will be different, i.e a subset of (DAG_ID, RUN_ID, TASK_ID, MAP_INDEX).
+ "href": "https://example.com/{DAG_ID}/{RUN_ID}/{TASK_ID}/{MAP_INDEX}",
+ # Destination of the external view. This is used to determine where the view will be loaded in the UI.
+ # Supported locations are Literal["nav", "dag", "dag_run", "task", "task_instance"], default to "nav".
+ "destination": "dag_run",
+ # Optional icon, url to an svg file.
+ "icon": "https://example.com/icon.svg",
+ # Optional dark icon for the dark theme, url to an svg file. If not provided, "icon" will be used for both light and dark themes.
+ "icon_dark_mode": "https://example.com/dark_icon.svg",
+ # Optional parameters, relative URL location for the External View rendering. If not provided, external view will be rendeded as an external link. If provided
+ # will be rendered inside an Iframe in the UI. Should not contain a leading slash.
+ "url_route": "my_external_view",
+ # Optional category, only relevant for destination "nav". This is used to group the external links in the navigation bar. We will match the existing
+ # menus of ["browse", "docs", "admin", "user"] and if there's no match then create a new menu.
+ "category": "browse",
}
- v_appbuilder_nomenu_view = TestAppBuilderBaseNoMenuView()
- v_appbuilder_nomenu_package = {"view": v_appbuilder_nomenu_view}
-
- # Creating flask appbuilder Menu Items
- appbuilder_mitem = {
- "name": "Google",
- "href": "https://www.google.com",
- "category": "Search",
- }
- appbuilder_mitem_toplevel = {
- "name": "Apache",
- "href": "https://www.apache.org/",
+ react_app_with_metadata = {
+ # Name of the React app, this will be displayed in the UI.
+ "name": "Name of the React App",
+ # Bundle URL of the React app. This is the URL where the React app is served from. It can be a static file or a CDN.
+ # This URL can be templated using context variables, depending on the location where the external view is rendered
+ # the context variables available will be different, i.e a subset of (DAG_ID, RUN_ID, TASK_ID, MAP_INDEX).
+ "bundle_url": "https://example.com/static/js/my_react_app.js",
+ # Destination of the react app. This is used to determine where the app will be loaded in the UI.
+ # Supported locations are Literal["nav", "dag", "dag_run", "task", "task_instance"], default to "nav".
+ # It can also be put inside of an existing page, the supported views are ["dashboard", "dag_overview", "task_overview"]. You can position
+ # element in the existing page via the css `order` rule which will determine the flex order.
+ "destination": "dag_run",
+ # Optional icon, url to an svg file.
+ "icon": "https://example.com/icon.svg",
+ # Optional dark icon for the dark theme, url to an svg file. If not provided, "icon" will be used for both light and dark themes.
+ "icon_dark_mode": "https://example.com/dark_icon.svg",
+ # URL route for the React app, relative to the Airflow UI base URL. Should not contain a leading slash.
+ "url_route": "my_react_app",
+ # Optional category, only relevant for destination "nav". This is used to group the react apps in the navigation bar. We will match the existing
+ # menus of ["browse", "docs", "admin", "user"] and if there's no match then create a new menu.
+ "category": "browse",
}
@@ -267,11 +246,10 @@ definitions in Airflow.
class AirflowTestPlugin(AirflowPlugin):
name = "test_plugin"
macros = [plugin_macro]
- flask_blueprints = [bp]
fastapi_apps = [app_with_metadata]
fastapi_root_middlewares = [middleware_with_metadata]
- appbuilder_views = [v_appbuilder_package, v_appbuilder_nomenu_package]
- appbuilder_menu_items = [appbuilder_mitem, appbuilder_mitem_toplevel]
+ external_views = [external_view_with_metadata]
+ react_apps = [react_app_with_metadata]
.. seealso:: :doc:`/howto/define-extra-link`
@@ -307,21 +285,10 @@ will automatically load the registered plugins from the entrypoint list.
# my_package/my_plugin.py
from airflow.plugins_manager import AirflowPlugin
- from flask import Blueprint
-
- # Creating a flask blueprint to integrate the templates and static folder
- bp = Blueprint(
- "test_plugin",
- __name__,
- template_folder="templates", # registers airflow/plugins/templates as a Jinja template folder
- static_folder="static",
- static_url_path="/static/test_plugin",
- )
class MyAirflowPlugin(AirflowPlugin):
name = "my_namespace"
- flask_blueprints = [bp]
Then inside pyproject.toml:
@@ -330,6 +297,18 @@ Then inside pyproject.toml:
[project.entry-points."airflow.plugins"]
my_plugin = "my_package.my_plugin:MyAirflowPlugin"
+Flask Appbuilder and Flask Blueprints in Airflow 3
+--------------------------------------------------
+
+Airflow 2 supported Flask Appbuilder views (``appbuilder_views``), Flask AppBuilder menu items (``appbuilder_menu_items``),
+and Flask Blueprints (``flask_blueprints``) in plugins. These have been superseded in Airflow 3 by External Views (``external_views``), Fast API apps (``fastapi_apps``),
+FastAPI middlewares (``fastapi_root_middlewares``) and React apps (``react_apps``) that allow extended functionality and better integration with the Airflow UI.
+
+All new plugins should use the new interfaces.
+
+However, a compatibility layer is provided for Flask and FAB plugins to ease the transition to Airflow 3 - simply install the FAB provider and tweak the code
+following Airflow 3 migration guide. This compatibility layer allows you to continue using your existing Flask Appbuilder views, Flask Blueprints and Flask Appbuilder menu items.
+
Troubleshooting
---------------
diff --git a/airflow-core/docs/administration-and-deployment/priority-weight.rst b/airflow-core/docs/administration-and-deployment/priority-weight.rst
index fd83c6806df13..e0a2d43baec67 100644
--- a/airflow-core/docs/administration-and-deployment/priority-weight.rst
+++ b/airflow-core/docs/administration-and-deployment/priority-weight.rst
@@ -21,7 +21,8 @@ Priority Weights
================
``priority_weight`` defines priorities in the executor queue. The default ``priority_weight`` is ``1``, and can be
-bumped to any integer. Moreover, each task has a true ``priority_weight`` that is calculated based on its
+bumped to any integer; larger numbers mean higher priority.
+Moreover, each task has a true ``priority_weight`` that is calculated based on its
``weight_rule`` which defines the weighting method used for the effective total priority weight of the task.
Below are the weighting methods. By default, Airflow's weighting method is ``downstream``.
diff --git a/airflow-core/docs/administration-and-deployment/web-stack.rst b/airflow-core/docs/administration-and-deployment/web-stack.rst
index 9a16906ab6acf..5f2159649b3b0 100644
--- a/airflow-core/docs/administration-and-deployment/web-stack.rst
+++ b/airflow-core/docs/administration-and-deployment/web-stack.rst
@@ -20,6 +20,10 @@
Web Stack
=========
+
+Configuration
+-------------
+
Sometimes you want to deploy the backend and frontend behind a
variable url path prefix. To do so, you can configure the url :ref:`config:api__base_url`
for instance, set it to ``http://localhost:28080/d12345``. All the APIs routes will
@@ -30,3 +34,26 @@ and served successfully.
You will also need to update the execution API server url
:ref:`config:core__execution_api_server_url` for tasks to be able to reach the API
with the new prefix.
+
+Separating API Servers
+-----------------------
+
+By default, both the Core API Server and the Execution API Server are served together:
+
+.. code-block:: bash
+
+ airflow api-server
+ # same as
+ airflow api-server --apps all
+ # or
+ airflow api-server --apps core,execution
+
+If you want to separate the Core API Server and the Execution API Server, you can run them
+separately. This might be useful for scaling them independently or for deploying them on different machines.
+
+.. code-block:: bash
+
+ # serve only the Core API Server
+ airflow api-server --apps core
+ # serve only the Execution API Server
+ airflow api-server --apps execution
diff --git a/airflow-core/docs/authoring-and-scheduling/asset-scheduling.rst b/airflow-core/docs/authoring-and-scheduling/asset-scheduling.rst
new file mode 100644
index 0000000000000..fc9086cb0783e
--- /dev/null
+++ b/airflow-core/docs/authoring-and-scheduling/asset-scheduling.rst
@@ -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.
+
+Asset-Aware Scheduling
+======================
+
+.. versionadded:: 2.4
+
+Quickstart
+----------
+
+In addition to scheduling dags based on time, you can also schedule dags to run based on when a task updates an asset.
+
+.. code-block:: python
+
+ from airflow.sdk import DAG, Asset
+
+ with DAG(...):
+ MyOperator(
+ # this task updates example.csv
+ outlets=[Asset("s3://asset-bucket/example.csv")],
+ ...,
+ )
+
+
+ with DAG(
+ # this DAG should be run when example.csv is updated (by dag1)
+ schedule=[Asset("s3://asset-bucket/example.csv")],
+ ...,
+ ):
+ ...
+
+
+.. image:: /img/ui-dark/asset_scheduled_dags.png
+
+.. seealso::
+
+ :ref:`asset_definitions` for how to declare assets.
+
+Schedule dags with assets
+-------------------------
+
+You can use assets to specify data dependencies in your dags. The following example shows how after the ``producer`` task in the ``producer`` DAG successfully completes, Airflow schedules the ``consumer`` DAG. Airflow marks an asset as ``updated`` only if the task completes successfully. If the task fails or if it is skipped, no update occurs, and Airflow doesn't schedule the ``consumer`` DAG.
+
+.. code-block:: python
+
+ example_asset = Asset("s3://asset/example.csv")
+
+ with DAG(dag_id="producer", ...):
+ BashOperator(task_id="producer", outlets=[example_asset], ...)
+
+ with DAG(dag_id="consumer", schedule=[example_asset], ...):
+ ...
+
+
+You can find a listing of the relationships between assets and dags in the :ref:`Asset Views `.
+
+Multiple assets
+-----------------
+
+Because the ``schedule`` parameter is a list, dags can require multiple assets. Airflow schedules a DAG after **all** assets the DAG consumes have been updated at least once since the last time the DAG ran:
+
+.. code-block:: python
+
+ with DAG(
+ dag_id="multiple_assets_example",
+ schedule=[
+ example_asset_1,
+ example_asset_2,
+ example_asset_3,
+ ],
+ ...,
+ ):
+ ...
+
+
+If one asset is updated multiple times before all consumed assets update, the downstream DAG still only runs once, as shown in this illustration:
+
+.. ::
+ ASCII art representation of this diagram
+
+ example_asset_1 x----x---x---x----------------------x-
+ example_asset_2 -------x---x-------x------x----x------
+ example_asset_3 ---------------x-----x------x---------
+ DAG runs created * *
+
+.. graphviz::
+
+ graph asset_event_timeline {
+ graph [layout=neato]
+ {
+ node [margin=0 fontcolor=blue width=0.1 shape=point label=""]
+ e1 [pos="1,2.5!"]
+ e2 [pos="2,2.5!"]
+ e3 [pos="2.5,2!"]
+ e4 [pos="4,2.5!"]
+ e5 [pos="5,2!"]
+ e6 [pos="6,2.5!"]
+ e7 [pos="7,1.5!"]
+ r7 [pos="7,1!" shape=star width=0.25 height=0.25 fixedsize=shape]
+ e8 [pos="8,2!"]
+ e9 [pos="9,1.5!"]
+ e10 [pos="10,2!"]
+ e11 [pos="11,1.5!"]
+ e12 [pos="12,2!"]
+ e13 [pos="13,2.5!"]
+ r13 [pos="13,1!" shape=star width=0.25 height=0.25 fixedsize=shape]
+ }
+ {
+ node [shape=none label="" width=0]
+ end_ds1 [pos="14,2.5!"]
+ end_ds2 [pos="14,2!"]
+ end_ds3 [pos="14,1.5!"]
+ }
+
+ {
+ node [shape=none margin=0.25 fontname="roboto,sans-serif"]
+ example_asset_1 [ pos="-0.5,2.5!"]
+ example_asset_2 [ pos="-0.5,2!"]
+ example_asset_3 [ pos="-0.5,1.5!"]
+ dag_runs [label="DagRuns created" pos="-0.5,1!"]
+ }
+
+ edge [color=lightgrey]
+
+ example_asset_1 -- e1 -- e2 -- e4 -- e6 -- e13 -- end_ds1
+ example_asset_2 -- e3 -- e5 -- e8 -- e10 -- e12 -- end_ds2
+ example_asset_3 -- e7 -- e9 -- e11 -- end_ds3
+
+ }
+
+Fetching information from a triggering asset event
+----------------------------------------------------
+
+A triggered DAG can fetch information from the asset that triggered it using the ``triggering_asset_events`` template or parameter. See more at :ref:`templates-ref`.
+
+Example:
+
+.. code-block:: python
+
+ example_snowflake_asset = Asset("snowflake://my_db/my_schema/my_table")
+
+ with DAG(dag_id="load_snowflake_data", schedule="@hourly", ...):
+ SQLExecuteQueryOperator(
+ task_id="load", conn_id="snowflake_default", outlets=[example_snowflake_asset], ...
+ )
+
+ with DAG(dag_id="query_snowflake_data", schedule=[example_snowflake_asset], ...):
+ SQLExecuteQueryOperator(
+ task_id="query",
+ conn_id="snowflake_default",
+ sql="""
+ SELECT *
+ FROM my_db.my_schema.my_table
+ WHERE "updated_at" >= '{{ (triggering_asset_events.values() | first | first).source_dag_run.data_interval_start }}'
+ AND "updated_at" < '{{ (triggering_asset_events.values() | first | first).source_dag_run.data_interval_end }}';
+ """,
+ )
+
+ @task
+ def print_triggering_asset_events(triggering_asset_events=None):
+ for asset, asset_list in triggering_asset_events.items():
+ print(asset, asset_list)
+ print(asset_list[0].source_dag_run.dag_id)
+
+ print_triggering_asset_events()
+
+Note that this example is using `(.values() | first | first) `_ to fetch the first of one asset given to the DAG, and the first of one AssetEvent for that asset. An implementation can be quite complex if you have multiple assets, potentially with multiple AssetEvents.
+
+
+Manipulating queued asset events through REST API
+---------------------------------------------------
+
+.. versionadded:: 2.9
+
+In this example, the DAG ``waiting_for_asset_1_and_2`` will be triggered when tasks update both assets "asset-1" and "asset-2". Once "asset-1" is updated, Airflow creates a record. This ensures that Airflow knows to trigger the DAG when "asset-2" is updated. We call such records queued asset events.
+
+.. code-block:: python
+
+ with DAG(
+ dag_id="waiting_for_asset_1_and_2",
+ schedule=[Asset("asset-1"), Asset("asset-2")],
+ ...,
+ ):
+ ...
+
+
+``queuedEvent`` API endpoints are introduced to manipulate such records.
+
+* Get a queued asset event for a DAG: ``/assets/queuedEvent/{uri}``
+* Get queued asset events for a DAG: ``/dags/{dag_id}/assets/queuedEvent``
+* Delete a queued asset event for a DAG: ``/assets/queuedEvent/{uri}``
+* Delete queued asset events for a DAG: ``/dags/{dag_id}/assets/queuedEvent``
+* Get queued asset events for an asset: ``/dags/{dag_id}/assets/queuedEvent/{uri}``
+* Delete queued asset events for an asset: ``DELETE /dags/{dag_id}/assets/queuedEvent/{uri}``
+
+ For how to use REST API and the parameters needed for these endpoints, please refer to :doc:`Airflow API `.
+
+Advanced asset scheduling with conditional expressions
+--------------------------------------------------------
+
+Apache Airflow includes advanced scheduling capabilities that use conditional expressions with assets. This feature allows you to define complex dependencies for DAG executions based on asset updates, using logical operators for more control on workflow triggers.
+
+Logical operators for assets
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Airflow supports two logical operators for combining asset conditions:
+
+- **AND (``&``)**: Specifies that the DAG should be triggered only after all of the specified assets have been updated.
+- **OR (``|``)**: Specifies that the DAG should be triggered when any of the specified assets is updated.
+
+These operators enable you to configure your Airflow workflows to use more complex asset update conditions, making them more dynamic and flexible.
+
+Example Use
+-------------
+
+**Scheduling based on multiple asset updates**
+
+To schedule a DAG to run only when two specific assets have both been updated, use the AND operator (``&``):
+
+.. code-block:: python
+
+ dag1_asset = Asset("s3://dag1/output_1.txt")
+ dag2_asset = Asset("s3://dag2/output_1.txt")
+
+ with DAG(
+ # Consume asset 1 and 2 with asset expressions
+ schedule=(dag1_asset & dag2_asset),
+ ...,
+ ):
+ ...
+
+**Scheduling based on any asset update**
+
+To trigger a DAG execution when either one of two assets is updated, apply the OR operator (``|``):
+
+.. code-block:: python
+
+ with DAG(
+ # Consume asset 1 or 2 with asset expressions
+ schedule=(dag1_asset | dag2_asset),
+ ...,
+ ):
+ ...
+
+**Complex Conditional Logic**
+
+For scenarios requiring more intricate conditions, such as triggering a DAG when one asset is updated or when both of two other assets are updated, combine the OR and AND operators:
+
+.. code-block:: python
+
+ dag3_asset = Asset("s3://dag3/output_3.txt")
+
+ with DAG(
+ # Consume asset 1 or both 2 and 3 with asset expressions
+ schedule=(dag1_asset | (dag2_asset & dag3_asset)),
+ ...,
+ ):
+ ...
+
+
+Scheduling based on asset aliases
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Since asset events added to an alias are just simple asset events, a downstream DAG depending on the actual asset can read asset events of it normally, without considering the associated aliases. A downstream DAG can also depend on an asset alias. The authoring syntax is referencing the ``AssetAlias`` by name, and the associated asset events are picked up for scheduling. Note that a DAG can be triggered by a task with ``outlets=AssetAlias("xxx")`` if and only if the alias is resolved into ``Asset("s3://bucket/my-task")``. The DAG runs whenever a task with outlet ``AssetAlias("out")`` gets associated with at least one asset at runtime, regardless of the asset's identity. The downstream DAG is not triggered if no assets are associated to the alias for a particular given task run. This also means we can do conditional asset-triggering.
+
+The asset alias is resolved to the assets during DAG parsing. Thus, if the "min_file_process_interval" configuration is set to a high value, there is a possibility that the asset alias may not be resolved. To resolve this issue, you can trigger DAG parsing.
+
+.. code-block:: python
+
+ with DAG(dag_id="asset-producer"):
+
+ @task(outlets=[Asset("example-alias")])
+ def produce_asset_events():
+ pass
+
+
+ with DAG(dag_id="asset-alias-producer"):
+
+ @task(outlets=[AssetAlias("example-alias")])
+ def produce_asset_events(*, outlet_events):
+ outlet_events[AssetAlias("example-alias")].add(Asset("s3://bucket/my-task"))
+
+
+ with DAG(dag_id="asset-consumer", schedule=Asset("s3://bucket/my-task")):
+ ...
+
+ with DAG(dag_id="asset-alias-consumer", schedule=AssetAlias("example-alias")):
+ ...
+
+
+In the example provided, once the DAG ``asset-alias-producer`` is executed, the asset alias ``AssetAlias("example-alias")`` will be resolved to ``Asset("s3://bucket/my-task")``. However, the DAG ``asset-alias-consumer`` will have to wait for the next DAG re-parsing to update its schedule. To address this, Airflow will re-parse the dags relying on the asset alias ``AssetAlias("example-alias")`` when it's resolved into assets that these dags did not previously depend on. As a result, both the "asset-consumer" and "asset-alias-consumer" dags will be triggered after the execution of DAG ``asset-alias-producer``.
+
+
+Combining asset and time-based schedules
+------------------------------------------
+
+AssetTimetable Integration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can schedule dags based on both asset events and time-based schedules using ``AssetOrTimeSchedule``. This allows you to create workflows when a DAG needs both to be triggered by data updates and run periodically according to a fixed timetable.
+
+For more detailed information on ``AssetOrTimeSchedule``, refer to the corresponding section in :ref:`AssetOrTimeSchedule `.
diff --git a/airflow-core/docs/authoring-and-scheduling/assets.rst b/airflow-core/docs/authoring-and-scheduling/assets.rst
index f7f018c6d97db..366a4069ca52b 100644
--- a/airflow-core/docs/authoring-and-scheduling/assets.rst
+++ b/airflow-core/docs/authoring-and-scheduling/assets.rst
@@ -229,6 +229,18 @@ The other way around also applies:
def process_example_asset(example_asset):
"""Process inlet example_asset..."""
+In addition, ``@asset`` can be used with ``@task`` to customize the task that generates the asset,
+utilizing the modern TaskFlow approach described in :doc:`/tutorial/taskflow`.
+
+This combination allows you to set initial arguments for the task and to use various operators, such as the ``BashOperator``:
+
+.. code-block:: python
+
+ @asset(schedule=None)
+ @task.bash(retries=3)
+ def example_asset():
+ """Write to example_asset, from a Bash task with 3 retries..."""
+ return "echo 'run'"
Output to multiple assets in one task
-------------------------------------
@@ -280,7 +292,7 @@ The following example creates an asset event against the S3 URI ``f"s3://bucket/
.. code-block:: python
- from airflow.sdk.definitions.asset import AssetAlias
+ from airflow.sdk import AssetAlias
@task(outlets=[AssetAlias("my-task-outputs")])
@@ -292,19 +304,19 @@ The following example creates an asset event against the S3 URI ``f"s3://bucket/
.. code-block:: python
- from airflow.sdk.definitions.asset.metadata import Metadata
+ from airflow.sdk import Metadata
@task(outlets=[AssetAlias("my-task-outputs")])
def my_task_with_metadata():
s3_asset = Asset(uri="s3://bucket/my-task", name="example_s3")
- yield Metadata(s3_asset, extra={"k": "v"}, alias="my-task-outputs")
+ yield Metadata(s3_asset, extra={"k": "v"}, alias=AssetAlias("my-task-outputs"))
Only one asset event is emitted for an added asset, even if it is added to the alias multiple times, or added to multiple aliases. However, if different ``extra`` values are passed, it can emit multiple asset events. In the following example, two asset events will be emitted.
.. code-block:: python
- from airflow.sdk.definitions.asset import AssetAlias
+ from airflow.sdk import AssetAlias
@task(
diff --git a/airflow-core/docs/authoring-and-scheduling/connections.rst b/airflow-core/docs/authoring-and-scheduling/connections.rst
index 2f24e3cc83b5a..7f9cbaa443ecc 100644
--- a/airflow-core/docs/authoring-and-scheduling/connections.rst
+++ b/airflow-core/docs/authoring-and-scheduling/connections.rst
@@ -38,7 +38,7 @@ A Hook is a high-level interface to an external platform that lets you quickly a
They integrate with Connections to gather credentials, and many have a default ``conn_id``; for example, the :class:`~airflow.providers.postgres.hooks.postgres.PostgresHook` automatically looks for the Connection with a ``conn_id`` of ``postgres_default`` if you don't pass one in.
-You can view a :ref:`full list of airflow hooks ` in our API documentation.
+You can view a :ref:`full list of Airflow hooks ` in our API documentation.
Custom connections
------------------
@@ -47,5 +47,5 @@ Airflow allows to define custom connection types. This is what is described in d
:doc:`apache-airflow-providers:index` - providers give you the capability of defining your own connections.
The connection customization can be done by any provider, but also
many of the providers managed by the community define custom connection types.
-The full list of all providers delivered by ``Apache Airflow community managed providers`` can be found in
+The full list of all connections delivered by ``Apache Airflow community managed providers`` can be found in
:doc:`apache-airflow-providers:core-extensions/connections`.
diff --git a/airflow-core/docs/authoring-and-scheduling/datasets.rst b/airflow-core/docs/authoring-and-scheduling/datasets.rst
deleted file mode 100644
index 1c8387600c411..0000000000000
--- a/airflow-core/docs/authoring-and-scheduling/datasets.rst
+++ /dev/null
@@ -1,316 +0,0 @@
- .. 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.
-
-Asset-Aware Scheduling
-======================
-
-.. versionadded:: 2.4
-
-Quickstart
-----------
-
-In addition to scheduling dags based on time, you can also schedule dags to run based on when a task updates an asset.
-
-.. code-block:: python
-
- from airflow.sdk import DAG, Asset
-
- with DAG(...):
- MyOperator(
- # this task updates example.csv
- outlets=[Asset("s3://asset-bucket/example.csv")],
- ...,
- )
-
-
- with DAG(
- # this DAG should be run when example.csv is updated (by dag1)
- schedule=[Asset("s3://asset-bucket/example.csv")],
- ...,
- ):
- ...
-
-
-.. image:: /img/asset-scheduled-dags.png
-
-.. seealso::
-
- :ref:`asset_definitions` for how to declare assets.
-
-Schedule dags with assets
--------------------------
-
-You can use assets to specify data dependencies in your dags. The following example shows how after the ``producer`` task in the ``producer`` DAG successfully completes, Airflow schedules the ``consumer`` DAG. Airflow marks an asset as ``updated`` only if the task completes successfully. If the task fails or if it is skipped, no update occurs, and Airflow doesn't schedule the ``consumer`` DAG.
-
-.. code-block:: python
-
- example_asset = Asset("s3://asset/example.csv")
-
- with DAG(dag_id="producer", ...):
- BashOperator(task_id="producer", outlets=[example_asset], ...)
-
- with DAG(dag_id="consumer", schedule=[example_asset], ...):
- ...
-
-
-You can find a listing of the relationships between assets and dags in the
-:ref:`Assets View`
-
-Multiple assets
------------------
-
-Because the ``schedule`` parameter is a list, dags can require multiple assets. Airflow schedules a DAG after **all** assets the DAG consumes have been updated at least once since the last time the DAG ran:
-
-.. code-block:: python
-
- with DAG(
- dag_id="multiple_assets_example",
- schedule=[
- example_asset_1,
- example_asset_2,
- example_asset_3,
- ],
- ...,
- ):
- ...
-
-
-If one asset is updated multiple times before all consumed assets update, the downstream DAG still only runs once, as shown in this illustration:
-
-.. ::
- ASCII art representation of this diagram
-
- example_asset_1 x----x---x---x----------------------x-
- example_asset_2 -------x---x-------x------x----x------
- example_asset_3 ---------------x-----x------x---------
- DAG runs created * *
-
-.. graphviz::
-
- graph asset_event_timeline {
- graph [layout=neato]
- {
- node [margin=0 fontcolor=blue width=0.1 shape=point label=""]
- e1 [pos="1,2.5!"]
- e2 [pos="2,2.5!"]
- e3 [pos="2.5,2!"]
- e4 [pos="4,2.5!"]
- e5 [pos="5,2!"]
- e6 [pos="6,2.5!"]
- e7 [pos="7,1.5!"]
- r7 [pos="7,1!" shape=star width=0.25 height=0.25 fixedsize=shape]
- e8 [pos="8,2!"]
- e9 [pos="9,1.5!"]
- e10 [pos="10,2!"]
- e11 [pos="11,1.5!"]
- e12 [pos="12,2!"]
- e13 [pos="13,2.5!"]
- r13 [pos="13,1!" shape=star width=0.25 height=0.25 fixedsize=shape]
- }
- {
- node [shape=none label="" width=0]
- end_ds1 [pos="14,2.5!"]
- end_ds2 [pos="14,2!"]
- end_ds3 [pos="14,1.5!"]
- }
-
- {
- node [shape=none margin=0.25 fontname="roboto,sans-serif"]
- example_asset_1 [ pos="-0.5,2.5!"]
- example_asset_2 [ pos="-0.5,2!"]
- example_asset_3 [ pos="-0.5,1.5!"]
- dag_runs [label="DagRuns created" pos="-0.5,1!"]
- }
-
- edge [color=lightgrey]
-
- example_asset_1 -- e1 -- e2 -- e4 -- e6 -- e13 -- end_ds1
- example_asset_2 -- e3 -- e5 -- e8 -- e10 -- e12 -- end_ds2
- example_asset_3 -- e7 -- e9 -- e11 -- end_ds3
-
- }
-
-Fetching information from a triggering asset event
-----------------------------------------------------
-
-A triggered DAG can fetch information from the asset that triggered it using the ``triggering_asset_events`` template or parameter. See more at :ref:`templates-ref`.
-
-Example:
-
-.. code-block:: python
-
- example_snowflake_asset = Asset("snowflake://my_db/my_schema/my_table")
-
- with DAG(dag_id="load_snowflake_data", schedule="@hourly", ...):
- SQLExecuteQueryOperator(
- task_id="load", conn_id="snowflake_default", outlets=[example_snowflake_asset], ...
- )
-
- with DAG(dag_id="query_snowflake_data", schedule=[example_snowflake_asset], ...):
- SQLExecuteQueryOperator(
- task_id="query",
- conn_id="snowflake_default",
- sql="""
- SELECT *
- FROM my_db.my_schema.my_table
- WHERE "updated_at" >= '{{ (triggering_asset_events.values() | first | first).source_dag_run.data_interval_start }}'
- AND "updated_at" < '{{ (triggering_asset_events.values() | first | first).source_dag_run.data_interval_end }}';
- """,
- )
-
- @task
- def print_triggering_asset_events(triggering_asset_events=None):
- for asset, asset_list in triggering_asset_events.items():
- print(asset, asset_list)
- print(asset_list[0].source_dag_run.dag_id)
-
- print_triggering_asset_events()
-
-Note that this example is using `(.values() | first | first) `_ to fetch the first of one asset given to the DAG, and the first of one AssetEvent for that asset. An implementation can be quite complex if you have multiple assets, potentially with multiple AssetEvents.
-
-
-Manipulating queued asset events through REST API
----------------------------------------------------
-
-.. versionadded:: 2.9
-
-In this example, the DAG ``waiting_for_asset_1_and_2`` will be triggered when tasks update both assets "asset-1" and "asset-2". Once "asset-1" is updated, Airflow creates a record. This ensures that Airflow knows to trigger the DAG when "asset-2" is updated. We call such records queued asset events.
-
-.. code-block:: python
-
- with DAG(
- dag_id="waiting_for_asset_1_and_2",
- schedule=[Asset("asset-1"), Asset("asset-2")],
- ...,
- ):
- ...
-
-
-``queuedEvent`` API endpoints are introduced to manipulate such records.
-
-* Get a queued asset event for a DAG: ``/assets/queuedEvent/{uri}``
-* Get queued asset events for a DAG: ``/dags/{dag_id}/assets/queuedEvent``
-* Delete a queued asset event for a DAG: ``/assets/queuedEvent/{uri}``
-* Delete queued asset events for a DAG: ``/dags/{dag_id}/assets/queuedEvent``
-* Get queued asset events for an asset: ``/dags/{dag_id}/assets/queuedEvent/{uri}``
-* Delete queued asset events for an asset: ``DELETE /dags/{dag_id}/assets/queuedEvent/{uri}``
-
- For how to use REST API and the parameters needed for these endpoints, please refer to :doc:`Airflow API `.
-
-Advanced asset scheduling with conditional expressions
---------------------------------------------------------
-
-Apache Airflow includes advanced scheduling capabilities that use conditional expressions with assets. This feature allows you to define complex dependencies for DAG executions based on asset updates, using logical operators for more control on workflow triggers.
-
-Logical operators for assets
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Airflow supports two logical operators for combining asset conditions:
-
-- **AND (``&``)**: Specifies that the DAG should be triggered only after all of the specified assets have been updated.
-- **OR (``|``)**: Specifies that the DAG should be triggered when any of the specified assets is updated.
-
-These operators enable you to configure your Airflow workflows to use more complex asset update conditions, making them more dynamic and flexible.
-
-Example Use
--------------
-
-**Scheduling based on multiple asset updates**
-
-To schedule a DAG to run only when two specific assets have both been updated, use the AND operator (``&``):
-
-.. code-block:: python
-
- dag1_asset = Asset("s3://dag1/output_1.txt")
- dag2_asset = Asset("s3://dag2/output_1.txt")
-
- with DAG(
- # Consume asset 1 and 2 with asset expressions
- schedule=(dag1_asset & dag2_asset),
- ...,
- ):
- ...
-
-**Scheduling based on any asset update**
-
-To trigger a DAG execution when either one of two assets is updated, apply the OR operator (``|``):
-
-.. code-block:: python
-
- with DAG(
- # Consume asset 1 or 2 with asset expressions
- schedule=(dag1_asset | dag2_asset),
- ...,
- ):
- ...
-
-**Complex Conditional Logic**
-
-For scenarios requiring more intricate conditions, such as triggering a DAG when one asset is updated or when both of two other assets are updated, combine the OR and AND operators:
-
-.. code-block:: python
-
- dag3_asset = Asset("s3://dag3/output_3.txt")
-
- with DAG(
- # Consume asset 1 or both 2 and 3 with asset expressions
- schedule=(dag1_asset | (dag2_asset & dag3_asset)),
- ...,
- ):
- ...
-
-
-Scheduling based on asset aliases
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Since asset events added to an alias are just simple asset events, a downstream DAG depending on the actual asset can read asset events of it normally, without considering the associated aliases. A downstream DAG can also depend on an asset alias. The authoring syntax is referencing the ``AssetAlias`` by name, and the associated asset events are picked up for scheduling. Note that a DAG can be triggered by a task with ``outlets=AssetAlias("xxx")`` if and only if the alias is resolved into ``Asset("s3://bucket/my-task")``. The DAG runs whenever a task with outlet ``AssetAlias("out")`` gets associated with at least one asset at runtime, regardless of the asset's identity. The downstream DAG is not triggered if no assets are associated to the alias for a particular given task run. This also means we can do conditional asset-triggering.
-
-The asset alias is resolved to the assets during DAG parsing. Thus, if the "min_file_process_interval" configuration is set to a high value, there is a possibility that the asset alias may not be resolved. To resolve this issue, you can trigger DAG parsing.
-
-.. code-block:: python
-
- with DAG(dag_id="asset-producer"):
-
- @task(outlets=[Asset("example-alias")])
- def produce_asset_events():
- pass
-
-
- with DAG(dag_id="asset-alias-producer"):
-
- @task(outlets=[AssetAlias("example-alias")])
- def produce_asset_events(*, outlet_events):
- outlet_events[AssetAlias("example-alias")].add(Asset("s3://bucket/my-task"))
-
-
- with DAG(dag_id="asset-consumer", schedule=Asset("s3://bucket/my-task")):
- ...
-
- with DAG(dag_id="asset-alias-consumer", schedule=AssetAlias("example-alias")):
- ...
-
-
-In the example provided, once the DAG ``asset-alias-producer`` is executed, the asset alias ``AssetAlias("example-alias")`` will be resolved to ``Asset("s3://bucket/my-task")``. However, the DAG ``asset-alias-consumer`` will have to wait for the next DAG re-parsing to update its schedule. To address this, Airflow will re-parse the dags relying on the asset alias ``AssetAlias("example-alias")`` when it's resolved into assets that these dags did not previously depend on. As a result, both the "asset-consumer" and "asset-alias-consumer" dags will be triggered after the execution of DAG ``asset-alias-producer``.
-
-
-Combining asset and time-based schedules
-------------------------------------------
-
-AssetTimetable Integration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You can schedule dags based on both asset events and time-based schedules using ``AssetOrTimeSchedule``. This allows you to create workflows when a DAG needs both to be triggered by data updates and run periodically according to a fixed timetable.
-
-For more detailed information on ``AssetOrTimeSchedule``, refer to the corresponding section in :ref:`AssetOrTimeSchedule `.
diff --git a/airflow-core/docs/authoring-and-scheduling/deferring.rst b/airflow-core/docs/authoring-and-scheduling/deferring.rst
index 68933af157d74..b34b33295ea62 100644
--- a/airflow-core/docs/authoring-and-scheduling/deferring.rst
+++ b/airflow-core/docs/authoring-and-scheduling/deferring.rst
@@ -31,19 +31,19 @@ An overview of how this process works:
* The trigger runs until it fires, at which point its source task is re-scheduled by the scheduler.
* The scheduler queues the task to resume on a worker node.
-You can either use pre-written deferrable operators as a DAG author or write your own. Writing them, however, requires that they meet certain design criteria.
+You can either use pre-written deferrable operators as a Dag author or write your own. Writing them, however, requires that they meet certain design criteria.
Using Deferrable Operators
--------------------------
-If you want to use pre-written deferrable operators that come with Airflow, such as ``TimeSensorAsync``, then you only need to complete two steps:
+If you want to use pre-written deferrable operators that come with Airflow, such as ``TimeSensor``, then you only need to complete two steps:
* Ensure your Airflow installation runs at least one ``triggerer`` process, as well as the normal ``scheduler``
* Use deferrable operators/sensors in your dags
Airflow automatically handles and implements the deferral processes for you.
-If you're upgrading existing dags to use deferrable operators, Airflow contains API-compatible sensor variants, like ``TimeSensorAsync`` for ``TimeSensor``. Add these variants into your DAG to use deferrable operators with no other changes required.
+If you're upgrading existing dags to use deferrable operators, Airflow contains API-compatible sensor variants. Add these variants into your dag to use deferrable operators with no other changes required.
Note that you can't use the deferral ability from inside custom PythonOperator or TaskFlow Python functions. Deferral is only available to traditional, class-based operators.
@@ -113,7 +113,7 @@ This example shows the structure of a basic trigger, a very simplified version o
import asyncio
from airflow.triggers.base import BaseTrigger, TriggerEvent
- from airflow.utils import timezone
+ from airflow.sdk.timezone import utcnow
class DateTimeTrigger(BaseTrigger):
@@ -125,7 +125,7 @@ This example shows the structure of a basic trigger, a very simplified version o
return ("airflow.providers.standard.triggers.temporal.DateTimeTrigger", {"moment": self.moment})
async def run(self):
- while self.moment > timezone.utcnow():
+ while self.moment > utcnow():
await asyncio.sleep(1)
yield TriggerEvent(self.moment)
diff --git a/airflow-core/docs/authoring-and-scheduling/dynamic-task-mapping.rst b/airflow-core/docs/authoring-and-scheduling/dynamic-task-mapping.rst
index d25f1204bd95b..e254bf52071f3 100644
--- a/airflow-core/docs/authoring-and-scheduling/dynamic-task-mapping.rst
+++ b/airflow-core/docs/authoring-and-scheduling/dynamic-task-mapping.rst
@@ -21,7 +21,7 @@
Dynamic Task Mapping
====================
-Dynamic Task Mapping allows a way for a workflow to create a number of tasks at runtime based upon current data, rather than the DAG author having to know in advance how many tasks would be needed.
+Dynamic Task Mapping allows a way for a workflow to create a number of tasks at runtime based upon current data, rather than the Dag author having to know in advance how many tasks would be needed.
This is similar to defining your tasks in a for loop, but instead of having the DAG file fetch the data and do that itself, the scheduler can do this based on the output of a previous task. Right before a mapped task is executed the scheduler will create *n* copies of the task, one for each input.
@@ -41,11 +41,11 @@ This will show ``Total was 9`` in the task logs when executed.
This is the resulting DAG structure:
-.. image:: /img/mapping-simple-graph.png
+.. image:: /img/ui-light/mapping_simple_graph.png
The grid view also provides visibility into your mapped tasks in the details panel:
-.. image:: /img/mapping-simple-grid.png
+.. image:: /img/ui-dark/grid_mapped_task.png
.. note:: Only keyword arguments are allowed to be passed to ``expand()``.
@@ -203,7 +203,7 @@ Since the template is rendered after the main execution block, it is possible to
.. code-block:: python
- from airflow.providers.standard.operators.python import get_current_context
+ from airflow.sdk import get_current_context
@task(map_index_template="{{ my_variable }}")
diff --git a/airflow-core/docs/authoring-and-scheduling/event-scheduling.rst b/airflow-core/docs/authoring-and-scheduling/event-scheduling.rst
index e6bcbe4ae869d..8a81f01461c07 100644
--- a/airflow-core/docs/authoring-and-scheduling/event-scheduling.rst
+++ b/airflow-core/docs/authoring-and-scheduling/event-scheduling.rst
@@ -25,7 +25,7 @@ predefined time-based schedules.
This is particularly useful in modern data architectures where workflows need to react to real-time data changes,
messages, or system signals.
-By using assets, as described in :doc:`datasets`, you can configure dags to start execution when specific external events
+By using assets, as described in :doc:`asset-scheduling`, you can configure dags to start execution when specific external events
occur. Assets provide a mechanism to establish dependencies between external events and DAG execution, ensuring that
workflows react dynamically to changes in the external environment.
@@ -55,7 +55,7 @@ main scenarios for working with triggers in this context:
1. **Creating a new event-driven trigger**: If you need a new trigger for an unsupported event source, you should create
a new class inheriting from ``BaseEventTrigger`` and implement its logic.
-2. **Adapting an existing compatible trigger**: If an existing trigger (inheriting from ``BaseEvent``) is proven to be
+2. **Adapting an existing compatible trigger**: If an existing trigger (inheriting from ``BaseTrigger``) is proven to be
already compatible with event-driven scheduling, then you just need to change the base class from ``BaseTrigger`` to
``BaseEventTrigger``.
diff --git a/airflow-core/docs/authoring-and-scheduling/index.rst b/airflow-core/docs/authoring-and-scheduling/index.rst
index fab495298c45c..beefa12e5cc9c 100644
--- a/airflow-core/docs/authoring-and-scheduling/index.rst
+++ b/airflow-core/docs/authoring-and-scheduling/index.rst
@@ -18,7 +18,7 @@
Authoring and Scheduling
=========================
-Here you can find detailed documentation about advanced authoring and scheduling airflow dags.
+Here you can find detailed documentation about advanced authoring and scheduling Airflow dags.
It's recommended that you first review the pages in :doc:`core concepts `
.. _authoring-section:
@@ -43,6 +43,6 @@ It's recommended that you first review the pages in :doc:`core concepts
+ Asset-Aware Scheduling
timetable
Event-Driven Scheduling
diff --git a/airflow-core/docs/authoring-and-scheduling/timetable.rst b/airflow-core/docs/authoring-and-scheduling/timetable.rst
index e43f99e2c6211..163366b3bab0d 100644
--- a/airflow-core/docs/authoring-and-scheduling/timetable.rst
+++ b/airflow-core/docs/authoring-and-scheduling/timetable.rst
@@ -312,17 +312,16 @@ Whether taking care of *Data Interval*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A trigger timetable *does not* include *data interval*. This means that the value of ``data_interval_start``
-and ``data_interval_end`` (and the legacy ``execution_date``) are the same; the time when a DAG run is
-triggered.
+and ``data_interval_end`` are the same; the time when a DAG run is triggered.
-For a data interval timetable, the value of ``data_interval_start`` and ``data_interval_end`` (and legacy
-``execution_date``) are different. ``data_interval_start`` is the time when a DAG run is triggered and
-``data_interval_end`` is the end of the interval.
+For a data interval timetable, the value of ``data_interval_start`` and ``data_interval_end`` are different.
+``data_interval_end`` is the time when a DAG run is triggered, while ``data_interval_start`` is the start of the interval.
*Catchup* behavior
^^^^^^^^^^^^^^^^^^
By default, ``catchup`` is set to ``False``. This prevents running unnecessary dags in the following scenarios:
+
- If you create a new DAG with a start date in the past, and don't want to run dags for the past. If ``catchup`` is ``True``, Airflow runs all dags that would have run in that time interval.
- If you pause an existing DAG, and then restart it at a later date, ``catchup`` being ``False`` means that Airflow does not run the dags that would have run during the paused period.
@@ -343,12 +342,14 @@ Both trigger and data interval timetables trigger DAG runs at the same time. How
For example, suppose there is a cron expression ``@daily`` or ``0 0 * * *``, which is scheduled to run at 12AM every day. If you enable dags using the two timetables at 3PM on January
31st,
+
- `CronTriggerTimetable`_ creates a new DAG run at 12AM on February 1st. The ``run_id`` timestamp is midnight, on February 1st.
- `CronDataIntervalTimetable`_ immediately creates a new DAG run, because a DAG run for the daily time interval beginning at 12AM on January 31st did not occur yet. The ``run_id`` timestamp is midnight, on January 31st, since that is the beginning of the data interval.
The following is another example showing the difference in the case of skipping DAG runs:
Suppose there are two running dags with a cron expression ``@daily`` or ``0 0 * * *`` that use the two different timetables. If you pause the dags at 3PM on January 31st and re-enable them at 3PM on February 2nd,
+
- `CronTriggerTimetable`_ skips the DAG runs that were supposed to trigger on February 1st and 2nd. The next DAG run will be triggered at 12AM on February 3rd.
- `CronDataIntervalTimetable`_ skips the DAG runs that were supposed to trigger on February 1st only. A DAG run for February 2nd is immediately triggered after you re-enable the DAG.
diff --git a/airflow-core/docs/authoring-and-scheduling/timezone.rst b/airflow-core/docs/authoring-and-scheduling/timezone.rst
index e192bd2371cf1..20b3219472e2b 100644
--- a/airflow-core/docs/authoring-and-scheduling/timezone.rst
+++ b/airflow-core/docs/authoring-and-scheduling/timezone.rst
@@ -75,7 +75,7 @@ Because Airflow uses time zone aware datetime objects. If your code creates date
.. code-block:: python
- from airflow.utils import timezone
+ from airflow.sdk import timezone
now = timezone.utcnow()
a_date = timezone.datetime(2017, 1, 1)
diff --git a/airflow-core/docs/best-practices.rst b/airflow-core/docs/best-practices.rst
index 9f596a9d257bc..839c95dbfe94f 100644
--- a/airflow-core/docs/best-practices.rst
+++ b/airflow-core/docs/best-practices.rst
@@ -296,18 +296,12 @@ When you execute that code you will see:
This means that the ``get_array`` is not executed as top-level code, but ``get_task_id`` is.
-.. _best_practices/dynamic_dag_generation:
-
Code Quality and Linting
------------------------
Maintaining high code quality is essential for the reliability and maintainability of your Airflow workflows. Utilizing linting tools can help identify potential issues and enforce coding standards. One such tool is ``ruff``, a fast Python linter that now includes specific rules for Airflow.
-ruff assists in detecting deprecated features and patterns that may affect your migration to Airflow 3.0. For instance, it includes rules prefixed with ``AIR`` to flag potential issues:
-
-- **AIR301**: Flags DAGs without an explicit ``schedule`` argument.
-- **AIR302**: Identifies usage of deprecated ``schedule_interval`` parameter.
-- **AIR303**: Detects imports from modules that have been relocated or removed in Airflow 3.0.
+ruff assists in detecting deprecated features and patterns that may affect your migration to Airflow 3.0. For instance, it includes rules prefixed with ``AIR`` to flag potential issues. The full list is detailed in `Airflow (AIR) `_.
Installing and Using ruff
-------------------------
@@ -316,13 +310,13 @@ Installing and Using ruff
.. code-block:: bash
- pip install "ruff>=0.9.5"
+ pip install "ruff>=0.11.6"
2. **Running ruff**: Execute ``ruff`` to check your dags for potential issues:
.. code-block:: bash
- ruff check dags/ --select AIR301,AIR302,AIR303
+ ruff check dags/ --select AIR3 --preview
This command will analyze your dags located in the ``dags/`` directory and report any issues related to the specified rules.
@@ -355,6 +349,7 @@ By integrating ``ruff`` into your development workflow, you can proactively addr
For more information on ``ruff`` and its integration with Airflow, refer to the `official Airflow documentation `_.
+.. _best_practices/dynamic_dag_generation:
Dynamic DAG Generation
----------------------
@@ -451,7 +446,7 @@ for any variable that contains sensitive data.
Timetables
----------
-Avoid using Airflow Variables/Connections or accessing airflow database at the top level of your timetable code.
+Avoid using Airflow Variables/Connections or accessing Airflow database at the top level of your timetable code.
Database access should be delayed until the execution time of the DAG. This means that you should not have variables/connections retrieval
as argument to your timetable class initialization or have Variable/connection at the top level of your custom timetable module.
@@ -776,52 +771,28 @@ This is an example test want to verify the structure of a code-generated DAG aga
.. code-block:: python
- import datetime
-
import pendulum
- import pytest
from airflow.sdk import DAG
- from airflow.utils.state import DagRunState, TaskInstanceState
- from airflow.utils.types import DagRunTriggeredByType, DagRunType
-
- DATA_INTERVAL_START = pendulum.datetime(2021, 9, 13, tz="UTC")
- DATA_INTERVAL_END = DATA_INTERVAL_START + datetime.timedelta(days=1)
+ from airflow.utils.state import TaskInstanceState
- TEST_DAG_ID = "my_custom_operator_dag"
- TEST_TASK_ID = "my_custom_operator_task"
- TEST_RUN_ID = "my_custom_operator_dag_run"
-
- @pytest.fixture()
- def dag():
+ def test_my_custom_operator_execute_no_trigger(dag):
+ TEST_TASK_ID = "my_custom_operator_task"
with DAG(
- dag_id=TEST_DAG_ID,
+ dag_id="my_custom_operator_dag",
schedule="@daily",
- start_date=DATA_INTERVAL_START,
+ start_date=pendulum.datetime(2021, 9, 13, tz="UTC"),
) as dag:
MyCustomOperator(
task_id=TEST_TASK_ID,
prefix="s3://bucket/some/prefix",
)
- return dag
-
- def test_my_custom_operator_execute_no_trigger(dag):
- dagrun = dag.create_dagrun(
- run_id=TEST_RUN_ID,
- logical_date=DATA_INTERVAL_START,
- data_interval=(DATA_INTERVAL_START, DATA_INTERVAL_END),
- run_type=DagRunType.MANUAL,
- triggered_by=DagRunTriggeredByType.TIMETABLE,
- state=DagRunState.RUNNING,
- start_date=DATA_INTERVAL_END,
- )
+ dagrun = dag.test()
ti = dagrun.get_task_instance(task_id=TEST_TASK_ID)
- ti.task = dag.get_task(task_id=TEST_TASK_ID)
- ti.run(ignore_ti_state=True)
assert ti.state == TaskInstanceState.SUCCESS
- # Assert something related to tasks results.
+ # Assert something related to tasks results: ti.xcom_pull()
Self-Checks
@@ -980,15 +951,15 @@ The benefits of the operator are:
* There is no need to prepare the venv upfront. It will be dynamically created before task is run, and
removed after it is finished, so there is nothing special (except having virtualenv package in your
- airflow dependencies) to make use of multiple virtual environments
+ Airflow dependencies) to make use of multiple virtual environments
* You can run tasks with different sets of dependencies on the same workers - thus Memory resources are
reused (though see below about the CPU overhead involved in creating the venvs).
-* In bigger installations, DAG Authors do not need to ask anyone to create the venvs for you.
- As a DAG Author, you only have to have virtualenv dependency installed and you can specify and modify the
+* In bigger installations, Dag authors do not need to ask anyone to create the venvs for you.
+ As a Dag author, you only have to have virtualenv dependency installed and you can specify and modify the
environments as you see fit.
* No changes in deployment requirements - whether you use Local virtualenv, or Docker, or Kubernetes,
the tasks will work without adding anything to your deployment.
-* No need to learn more about containers, Kubernetes as a DAG Author. Only knowledge of Python requirements
+* No need to learn more about containers, Kubernetes as a Dag author. Only knowledge of Python requirements
is required to author dags this way.
There are certain limitations and overhead introduced by this operator:
@@ -1015,7 +986,7 @@ There are certain limitations and overhead introduced by this operator:
same worker might be affected by previous tasks creating/modifying files etc.
You can see detailed examples of using :class:`airflow.providers.standard.operators.python.PythonVirtualenvOperator` in
-:ref:`this section in the Taskflow API tutorial `.
+:ref:`this section in the TaskFlow API tutorial `.
Using ExternalPythonOperator
@@ -1034,7 +1005,7 @@ and available in all the workers in case your Airflow runs in a distributed envi
This way you avoid the overhead and problems of re-creating the virtual environment but they have to be
prepared and deployed together with Airflow installation. Usually people who manage Airflow installation
-need to be involved, and in bigger installations those are usually different people than DAG Authors
+need to be involved, and in bigger installations those are usually different people than Dag authors
(DevOps/System Admins).
Those virtual environments can be prepared in various ways - if you use LocalExecutor they just need to be installed
@@ -1053,7 +1024,7 @@ The benefits of the operator are:
be added dynamically. This is good for both, security and stability.
* Limited impact on your deployment - you do not need to switch to Docker containers or Kubernetes to
make a good use of the operator.
-* No need to learn more about containers, Kubernetes as a DAG Author. Only knowledge of Python, requirements
+* No need to learn more about containers, Kubernetes as a Dag author. Only knowledge of Python, requirements
is required to author dags this way.
The drawbacks:
@@ -1074,7 +1045,7 @@ The drawbacks:
same worker might be affected by previous tasks creating/modifying files etc.
You can think about the ``PythonVirtualenvOperator`` and ``ExternalPythonOperator`` as counterparts -
-that make it smoother to move from development phase to production phase. As a DAG author you'd normally
+that make it smoother to move from development phase to production phase. As a Dag author you'd normally
iterate with dependencies and develop your DAG using ``PythonVirtualenvOperator`` (thus decorating
your tasks with ``@task.virtualenv`` decorators) while after the iteration and changes you would likely
want to change it for production to switch to the ``ExternalPythonOperator`` (and ``@task.external_python``)
@@ -1083,7 +1054,7 @@ The nice thing about this is that you can switch the decorator back at any time
developing it "dynamically" with ``PythonVirtualenvOperator``.
You can see detailed examples of using :class:`airflow.providers.standard.operators.python.ExternalPythonOperator` in
-:ref:`Taskflow External Python example `
+:ref:`TaskFlow External Python example `
Using DockerOperator or Kubernetes Pod Operator
-----------------------------------------------
@@ -1147,9 +1118,9 @@ The drawbacks:
containers etc. in order to author a DAG that uses those operators.
You can see detailed examples of using :class:`airflow.operators.providers.Docker` in
-:ref:`Taskflow Docker example `
+:ref:`TaskFlow Docker example `
and :class:`airflow.providers.cncf.kubernetes.operators.pod.KubernetesPodOperator`
-:ref:`Taskflow Kubernetes example `
+:ref:`TaskFlow Kubernetes example `
Using multiple Docker Images and Celery Queues
----------------------------------------------
diff --git a/airflow-core/docs/cli-and-env-variables-ref.rst b/airflow-core/docs/cli-and-env-variables-ref.rst
index b679bc7b7986c..6336396911baf 100644
--- a/airflow-core/docs/cli-and-env-variables-ref.rst
+++ b/airflow-core/docs/cli-and-env-variables-ref.rst
@@ -77,7 +77,7 @@ Environment Variables
* ``result_backend`` in ``[celery]`` section
* ``password`` in ``[atlas]`` section
* ``smtp_password`` in ``[smtp]`` section
-* ``secret_key`` in ``[webserver]`` section
+* ``secret_key`` in ``[api]`` section
.. envvar:: AIRFLOW__{SECTION}__{KEY}_SECRET
diff --git a/airflow-core/docs/conf.py b/airflow-core/docs/conf.py
index 43026bb39f258..c9886a172b328 100644
--- a/airflow-core/docs/conf.py
+++ b/airflow-core/docs/conf.py
@@ -67,8 +67,6 @@
SYSTEM_TESTS_DIR: pathlib.Path | None
SYSTEM_TESTS_DIR = AIRFLOW_REPO_ROOT_PATH / "airflow-core" / "tests" / "system" / "core"
-conf_py_path = f"/docs/{PACKAGE_NAME}/"
-
os.environ["AIRFLOW_PACKAGE_NAME"] = PACKAGE_NAME
# Hack to allow changing for piece of the code to behave differently while
@@ -122,7 +120,6 @@
PACKAGES_THAT_WE_SHOULD_ADD_TO_API_DOCS = {
"hooks",
- "decorators",
"example_dags",
"executors",
"operators",
@@ -142,15 +139,7 @@
MODELS_THAT_SHOULD_BE_INCLUDED_IN_API_DOCS: set[str] = {
"baseoperator.py",
- "connection.py",
- "dag.py",
- "dagrun.py",
- "dagbag.py",
"param.py",
- "taskinstance.py",
- "taskinstancekey.py",
- "variable.py",
- "xcom.py",
}
@@ -200,7 +189,7 @@ def add_airflow_core_exclude_patterns_to_sphinx(exclude_patterns: list[str]):
# a list of builtin themes.
html_theme = "sphinx_airflow_theme"
-html_title = "Airflow Documentation"
+html_title = f"Airflow {PACKAGE_VERSION} Documentation"
# A shorter title for the navigation bar. Default is the same as html_title.
html_short_title = ""
@@ -223,6 +212,7 @@ def add_airflow_core_exclude_patterns_to_sphinx(exclude_patterns: list[str]):
"installation/installing-from-sources.html",
"administration-and-deployment/logging-monitoring/advanced-logging-configuration.html",
"howto/docker-compose/index.html",
+ "security/sbom.html",
]
html_css_files = ["custom.css"]
@@ -238,6 +228,7 @@ def add_airflow_core_exclude_patterns_to_sphinx(exclude_patterns: list[str]):
# html theme options
html_theme_options: dict[str, Any] = get_html_theme_options()
+conf_py_path = "/airflow-core/docs/"
# A dictionary of values to pass into the template engine's context for all pages.
html_context = get_html_context(conf_py_path)
@@ -263,6 +254,13 @@ def add_airflow_core_exclude_patterns_to_sphinx(exclude_patterns: list[str]):
},
}
+# Use for generate rst_epilog and other post-generation substitutions
+global_substitutions = {
+ "version": PACKAGE_VERSION,
+ "airflow-version": airflow.__version__,
+ "experimental": "This is an :ref:`experimental feature `.",
+}
+
# -- Options for sphinx.ext.autodoc --------------------------------------------
# See: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html
@@ -343,8 +341,8 @@ def add_airflow_core_exclude_patterns_to_sphinx(exclude_patterns: list[str]):
graphviz_output_format = "svg"
-main_openapi_path = Path(main_openapi_file).parent.joinpath("v1-rest-api-generated.yaml")
-sam_openapi_path = Path(sam_openapi_file).parent.joinpath("v1-simple-auth-manager-generated.yaml")
+main_openapi_path = Path(main_openapi_file).parent.joinpath("v2-rest-api-generated.yaml")
+sam_openapi_path = Path(sam_openapi_file).parent.joinpath("v2-simple-auth-manager-generated.yaml")
redoc = [
{
"name": "Simple auth manager token API",
@@ -360,7 +358,6 @@ def add_airflow_core_exclude_patterns_to_sphinx(exclude_patterns: list[str]):
"spec": main_openapi_path.as_posix(),
"opts": {
"hide-hostname": True,
- "no-auto-auth": True,
},
},
]
diff --git a/airflow-core/docs/configurations-ref.rst b/airflow-core/docs/configurations-ref.rst
index 2d6b9cc3cc8ea..83c5d8a8ed51a 100644
--- a/airflow-core/docs/configurations-ref.rst
+++ b/airflow-core/docs/configurations-ref.rst
@@ -24,12 +24,12 @@ can set in ``airflow.cfg`` file or using environment variables.
Use the same configuration across all the Airflow components. While each component
does not require all, some configurations need to be same otherwise they would not
-work as expected. A good example for that is :ref:`secret_key` which
+work as expected. A good example for that is :ref:`secret_key` which
should be same on the Webserver and Worker to allow Webserver to fetch logs from Worker.
The webserver key is also used to authorize requests to Celery workers when logs are retrieved. The token
generated using the secret key has a short expiry time though - make sure that time on ALL the machines
-that you run airflow components on is synchronized (for example using ntpd) otherwise you might get
+that you run Airflow components on is synchronized (for example using ntpd) otherwise you might get
"forbidden" errors when the logs are accessed.
.. note::
diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst b/airflow-core/docs/core-concepts/auth-manager/index.rst
index 417bad407db1f..845d03b03d010 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -51,10 +51,7 @@ Provided by Airflow:
* :doc:`simple/index`
-Provided by providers:
-
-* :doc:`apache-airflow-providers-fab:auth-manager/index`
-* :doc:`apache-airflow-providers-amazon:auth-manager/index`
+Provided by providers. The list of supported auth managers is available in :doc:`apache-airflow-providers:core-extensions/auth-managers`.
Why pluggable auth managers?
----------------------------
@@ -66,7 +63,7 @@ users does not need the same user management as an environment used by thousand
This is why the whole user management (user authentication and user authorization) is packaged in one component
called auth manager. So that it is easy to plug-and-play an auth manager that suits your specific needs.
-By default, Airflow comes with the :doc:`apache-airflow-providers-fab:auth-manager/index`.
+By default, Airflow comes with the :doc:`simple/index`.
.. note::
Switching to a different auth manager is a heavy operation and should be considered as such. It will
@@ -94,14 +91,28 @@ Some reasons you may want to write a custom auth manager include:
* You'd like to use an auth manager that leverages an identity provider from your preferred cloud provider.
* You have a private user management tool that is only available to you or your organization.
-Authentication related BaseAuthManager methods
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+User representation
+^^^^^^^^^^^^^^^^^^^
+
+:class:`~airflow.api_fastapi.auth.managers.base_auth_manager.BaseAuthManager` defines an authentication manager,
+parameterized by a user class T representing the authenticated user type.
+Auth manager implementations (subclasses of :class:`~airflow.api_fastapi.auth.managers.base_auth_manager.BaseAuthManager`)
+should specify the associated concrete user type. Each auth manager has its own user type definition.
+Concrete user types should be subclass of :class:`~airflow.api_fastapi.auth.managers.models.base_user.BaseUser`.
+
+Authentication related methods
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-* ``get_user``: Return the signed-in user.
* ``get_url_login``: Return the URL the user is redirected to for signing in.
+* ``get_url_logout``: Return the URL the user is redirected to when logging out. This is an optional method,
+ this redirection is usually needed to invalidate resources when logging out, such as a session.
+* ``serialize_user``: Serialize a user instance to a dict. This dict is the actual content of the JWT token.
+ It should contain all the information needed to identify the user and make an authorization request.
+* ``deserialize_user``: Create a user instance from a dict. The dict is the payload of the JWT token.
+ This is the same dict returned by ``serialize_user``.
-Authorization related BaseAuthManager methods
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Authorization related methods
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Most of authorization methods in :class:`~airflow.api_fastapi.auth.managers.base_auth_manager.BaseAuthManager` look the same.
Let's go over the different parameters used by most of these methods.
@@ -112,11 +123,11 @@ Let's go over the different parameters used by most of these methods.
* ``POST``: Can the user create a resource?
* ``PUT``: Can the user modify the resource?
* ``DELETE``: Can the user delete the resource?
- * ``MENU``: Can the user see the resource in the menu?
* ``details``: Optional details about the resource being accessed.
* ``user``: The user trying to access the resource.
+
These authorization methods are:
* ``is_authorized_configuration``: Return whether the user is authorized to access Airflow configuration. Some details about the configuration can be provided (e.g. the config section).
@@ -125,22 +136,28 @@ These authorization methods are:
Also, ``is_authorized_dag`` is called for any entity related to dags (e.g. task instances, dag runs, ...). This information is passed in ``access_entity``.
Example: ``auth_manager.is_authorized_dag(method="GET", access_entity=DagAccessEntity.Run, details=DagDetails(id="dag-1"))`` asks
whether the user has permission to read the Dag runs of the dag "dag-1".
-* ``is_authorized_dataset``: Return whether the user is authorized to access Airflow datasets. Some details about the dataset can be provided (e.g. the dataset uri).
+* ``is_authorized_backfill``: Return whether the user is authorized to access Airflow backfills. Some details about the backfill can be provided (e.g. the backfill ID).
+* ``is_authorized_asset``: Return whether the user is authorized to access Airflow assets. Some details about the asset can be provided (e.g. the asset ID).
+* ``is_authorized_asset_alias``: Return whether the user is authorized to access Airflow asset aliases. Some details about the asset alias can be provided (e.g. the asset alias ID).
* ``is_authorized_pool``: Return whether the user is authorized to access Airflow pools. Some details about the pool can be provided (e.g. the pool name).
* ``is_authorized_variable``: Return whether the user is authorized to access Airflow variables. Some details about the variable can be provided (e.g. the variable key).
* ``is_authorized_view``: Return whether the user is authorized to access a specific view in Airflow. The view is specified through ``access_view`` (e.g. ``AccessView.CLUSTER_ACTIVITY``).
* ``is_authorized_custom_view``: Return whether the user is authorized to access a specific view not defined in Airflow. This view can be provided by the auth manager itself or a plugin defined by the user.
+* ``filter_authorized_menu_items``: Given the list of menu items in the UI, return the list of menu items the user has access to.
+
+It should be noted that the ``method`` parameter listed above may only have relevance for a specific subset of the auth manager's authorization methods.
+For example, the ``configuration`` resource is by definition read-only, so only the ``GET`` parameter is relevant in the context of ``is_authorized_configuration``.
JWT token management by auth managers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The auth manager is responsible for creating the JWT token needed to interact with Airflow public API.
-To achieve this, the auth manager **must** provide an endpoint to create this JWT token. This endpoint must be
-available at ``POST /auth/token``
+To achieve this, the auth manager **must** provide an endpoint to create this JWT token. This endpoint is usually
+available at ``POST /auth/token``.
+Please double check the auth manager documentation to find the accurate token generation endpoint.
-The auth manager is also responsible of passing the JWT token to Airflow UI. The protocol to exchange the JWT
+The auth manager is also responsible for passing the JWT token to the Airflow UI. The protocol to exchange the JWT
token between the auth manager and Airflow UI is using cookies. The auth manager needs to save the JWT token in a
-cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI will then read the cookie, save it and
-delete the cookie.
+cookie named ``_token`` before redirecting to the Airflow UI. The Airflow UI will then read the cookie, save it, and delete it.
.. code-block:: python
@@ -148,7 +165,7 @@ delete the cookie.
response = RedirectResponse(url="/")
- secure = conf.has_option("api", "ssl_cert")
+ secure = request.base_url.scheme == "https" or bool(conf.get("api", "ssl_cert", fallback=""))
response.set_cookie(COOKIE_NAME_JWT_TOKEN, token, secure=secure)
return response
@@ -162,11 +179,11 @@ Optional methods recommended to override for optimization
The following methods aren't required to override to have a functional Airflow auth manager. However, it is recommended to override these to make your auth manager faster (and potentially less costly):
* ``batch_is_authorized_dag``: Batch version of ``is_authorized_dag``. If not overridden, it will call ``is_authorized_dag`` for every single item.
-* ``batch_is_authorized_connection``: Batch version of ``is_authorized_connection``. If not overridden, it will call ``is_authorized_connection`` for every single item.
-* ``batch_is_authorized_pool``: Batch version of ``is_authorized_pool``. If not overridden, it will call ``is_authorized_pool`` for every single item.
-* ``batch_is_authorized_variable``: Batch version of ``is_authorized_variable``. If not overridden, it will call ``is_authorized_variable`` for every single item.
* ``get_authorized_dag_ids``: Return the list of DAG IDs the user has access to. If not overridden, it will call ``is_authorized_dag`` for every single DAG available in the environment.
+ * Note: To filter the results of ``get_authorized_dag_ids``, it is recommended that you define the filtering logic in your ``filter_authorized_dag_ids`` method. For example, this may be useful if you rely on per-DAG access controls derived from one or more fields on a given DAG (e.g. DAG tags).
+ * This method requires an active session with the Airflow metadata database. As such, overriding the ``get_authorized_dag_ids`` method is an advanced use case, which should be considered carefully -- it is recommended you refer to the :doc:`../../database-erd-ref`.
+
CLI
^^^
@@ -207,6 +224,41 @@ To extend the API server application, you need to implement the ``get_fastapi_ap
Such additional endpoints can be used to manage resources such as users, groups, roles (if any) handled by your auth manager.
Endpoints defined by ``get_fastapi_app`` are mounted in ``/auth``.
+Other optional methods
+^^^^^^^^^^^^^^^^^^^^^^
+
+* ``init``: This method is executed when Airflow is initializing.
+ Override this method if you need to make any action (e.g. create resources, API call) that the auth manager needs.
+* ``get_extra_menu_items``: Provide additional links to be added to the menu in the UI.
+* ``get_db_manager``: If your auth manager requires one or several database managers (see :class:`~airflow.utils.db_manager.BaseDBManager`),
+ their class paths need to be returned as part of this method. By doing so, they will be automatically added to the
+ config ``[database] external_db_managers``.
+
+
+Additional Caveats
+^^^^^^^^^^^^^^^^^^
+
+* Your auth manager should not reference anything from the ``airflow.security.permissions`` module, as that module is in the process of being deprecated.
+ Instead, your code should use the definitions in ``airflow.api_fastapi.auth.managers.models.resource_details``. For more details on the ``airflow.security.permissions`` deprecation, see :doc:`/security/deprecated_permissions`
+* The ``access_control`` attribute of a DAG instance is only compatible with the FAB auth manager. Custom auth manager implementations should leverage ``get_authorized_dag_ids`` for DAG instance attribute-based access controls in more customizable ways (e.g. authorization based on DAG tags, DAG bundles, etc.).
+* You may find it useful to define a private, generalized ``_is_authorized`` method which acts as the standardized authorization mechanism, and which each
+ public ``is_authorized_*`` method calls with the appropriate parameters.
+ For concrete examples of this, refer to the ``SimpleAuthManager._is_authorized_method``. Further, it may be useful to optionally use the ``airflow.api_fastapi.auth.managers.base_auth_manager.ExtendedResourceMethod`` reference within your private method.
+
+DAG and DAG Sub-Component Authorization
+---------------------------------------
+
+Given the hierarchical structure of DAGs and their composite resources, the auth manager's ``is_authorized_dag`` method should also handle the authorization logic for DAG runs, tasks, and task instances.
+The ``access_entity`` parameter passed to ``is_authorized_dag`` indicates which (if any) DAG sub-component the user is attempting to access. This leads to a few important points:
+
+* If the ``access_entity`` parameter is ``None``, then the user is attempting to interact directly with the DAG, not any of its sub-components.
+* When the ``access_entity`` parameter is not ``None``, it means the user is attempting to access some sub-component of the DAG. This is noteworthy, as in some cases the ``method`` parameter may be valid
+ for the DAG's sub-entity, but not a valid action directly on the DAG itself. For example, the ``POST`` method is valid for DAG runs, but **not** for DAGs.
+* One potential way to model the example request mentioned above -- where the ``method`` only has meaning for the DAG sub-component -- is to authorize the user if **both** statements are true:
+
+ * The user has ``PUT`` ("edit") permissions for the given DAG.
+ * The user has ``POST`` ("create") permissions for DAG runs.
+
Next Steps
----------
diff --git a/airflow-core/docs/core-concepts/auth-manager/simple/token.rst b/airflow-core/docs/core-concepts/auth-manager/simple/token.rst
index 4e9e5cadf3200..0fdaee5dd78f5 100644
--- a/airflow-core/docs/core-concepts/auth-manager/simple/token.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/simple/token.rst
@@ -30,7 +30,7 @@ Example
.. code-block:: bash
- ENDPOINT_URL="http://localhost:8080/"
+ ENDPOINT_URL="http://localhost:8080"
curl -X 'POST' \
"${ENDPOINT_URL}/auth/token" \
-H 'Content-Type: application/json' \
@@ -45,5 +45,5 @@ If ``[core] simple_auth_manager_all_admins`` is set to True, you can also genera
.. code-block:: bash
- ENDPOINT_URL="http://localhost:8080/"
+ ENDPOINT_URL="http://localhost:8080"
curl -X 'GET' "${ENDPOINT_URL}/auth/token"
diff --git a/airflow-core/docs/core-concepts/backfill.rst b/airflow-core/docs/core-concepts/backfill.rst
index ac6729b23d0d7..955a3661557fb 100644
--- a/airflow-core/docs/core-concepts/backfill.rst
+++ b/airflow-core/docs/core-concepts/backfill.rst
@@ -20,7 +20,7 @@ Backfill
Backfill is when you create runs for past dates of a dag. Airflow provides a mechanism
to do this through the CLI and REST API. You provide a dag, a start date, and an end date,
-and airflow will create runs in the range according to the dag's schedule.
+and Airflow will create runs in the range according to the dag's schedule.
Backfill does not make sense for dags that don't have a time-based schedule.
diff --git a/airflow-core/docs/core-concepts/dag-run.rst b/airflow-core/docs/core-concepts/dag-run.rst
index 1befa0b7c13e1..1cb121c9b721b 100644
--- a/airflow-core/docs/core-concepts/dag-run.rst
+++ b/airflow-core/docs/core-concepts/dag-run.rst
@@ -167,6 +167,8 @@ the errors after going through the logs, you can re-run the tasks by clearing th
scheduled date. Clearing a task instance creates a record of the task instance.
The ``try_number`` of the current task instance is incremented, the ``max_tries`` set to ``0`` and the state set to ``None``, which causes the task to re-run.
+An experimental feature in Airflow 3.1.0 allows you to clear the task instances and re-run with the latest bundle version.
+
Click on the failed task in the Tree or Graph views and then click on **Clear**.
The executor will re-run it.
@@ -199,7 +201,7 @@ Task Instance History
---------------------
When a task instance retries or is cleared, the task instance history is preserved. You can see this history by clicking on the task instance in the Grid view.
-.. image:: ../img/task_instance_history.png
+.. image:: ../img/ui-dark/task_instance_history.png
.. note::
The try selector shown above is only available for tasks that have been retried or cleared.
@@ -207,7 +209,7 @@ When a task instance retries or is cleared, the task instance history is preserv
The history shows the value of the task instance attributes at the end of the particular run. On the log page, you can also see the logs for each of the task instance tries.
This can be useful for debugging.
-.. image:: ../img/task_instance_history_log.png
+.. image:: ../img/ui-dark/task_instance_history_log.png
.. note::
Related task instance objects like the XComs, rendered template fields, etc., are not preserved in the history. Only the task instance attributes, including the logs, are preserved.
diff --git a/airflow-core/docs/core-concepts/dags.rst b/airflow-core/docs/core-concepts/dags.rst
index 5537ea12d9488..bca75697f76c3 100644
--- a/airflow-core/docs/core-concepts/dags.rst
+++ b/airflow-core/docs/core-concepts/dags.rst
@@ -26,7 +26,7 @@ Dags
Here's a basic example DAG:
-.. image:: /img/basic-dag.png
+.. image:: /img/ui-light/basic_dag.png
It defines four Tasks - A, B, C, and D - and dictates the order in which they have to run, and which tasks depend on what others. It will also say how often to run the DAG - maybe "every 5 minutes starting tomorrow", or "every day since January 1st, 2020".
@@ -331,7 +331,7 @@ The task_id returned by the Python function has to reference a task directly dow
.. note::
When a Task is downstream of both the branching operator *and* downstream of one or more of the selected tasks, it will not be skipped:
- .. image:: /img/branch_note.png
+ .. image:: /img/ui-light/branch_note.png
The paths of the branching task are ``branch_a``, ``join`` and ``branch_b``. Since ``join`` is a downstream task of ``branch_a``, it will still be run, even though it was not returned as part of the branch decision.
@@ -435,6 +435,7 @@ However, this is just the default behaviour, and you can control it using the ``
* ``all_success`` (default): All upstream tasks have succeeded
* ``all_failed``: All upstream tasks are in a ``failed`` or ``upstream_failed`` state
* ``all_done``: All upstream tasks are done with their execution
+* ``all_done_min_one_success``: All non-skipped upstream tasks are done with their execution and at least one upstream task has succeeded
* ``all_skipped``: All upstream tasks are in a ``skipped`` state
* ``one_failed``: At least one upstream task has failed (does not wait for all upstream tasks to be done)
* ``one_success``: At least one upstream task has succeeded (does not wait for all upstream tasks to be done)
@@ -491,11 +492,11 @@ You can also combine this with the :ref:`concepts:depends-on-past` functionality
``join`` is downstream of ``follow_branch_a`` and ``branch_false``. The ``join`` task will show up as skipped because its ``trigger_rule`` is set to ``all_success`` by default, and the skip caused by the branching operation cascades down to skip a task marked as ``all_success``.
- .. image:: /img/branch_without_trigger.png
+ .. image:: /img/ui-light/branch_without_trigger.png
By setting ``trigger_rule`` to ``none_failed_min_one_success`` in the ``join`` task, we can instead get the intended behaviour:
- .. image:: /img/branch_with_trigger.png
+ .. image:: /img/ui-light/branch_with_trigger.png
Setup and teardown
@@ -550,7 +551,7 @@ A TaskGroup can be used to organize tasks into hierarchical groups in Graph view
Tasks in TaskGroups live on the same original DAG, and honor all the DAG settings and pool configurations.
-.. image:: /img/task_group.gif
+.. image:: /img/ui-light/task_group.gif
Dependency relationships can be applied across all tasks in a TaskGroup with the ``>>`` and ``<<`` operators. For example, the following code puts ``task1`` and ``task2`` in TaskGroup ``group1`` and then puts both tasks upstream of ``task3``:
@@ -634,7 +635,7 @@ Or, you can pass a Label object to ``set_upstream``/``set_downstream``:
Here's an example DAG which illustrates labeling different branches:
-.. image:: /img/edge_label_example.png
+.. image:: /img/ui-light/edge_label_example.png
.. exampleinclude:: /../src/airflow/example_dags/example_branch_labels.py
:language: python
diff --git a/airflow-core/docs/core-concepts/debug.rst b/airflow-core/docs/core-concepts/debug.rst
index 1e713229f214b..097754b6fd1da 100644
--- a/airflow-core/docs/core-concepts/debug.rst
+++ b/airflow-core/docs/core-concepts/debug.rst
@@ -78,14 +78,14 @@ Run ``python -m pdb .py`` for an interactive debugging experie
.. code-block:: bash
- root@ef2c84ad4856:/opt/airflow# python -m pdb airflow/example_dags/example_bash_operator.py
- > /opt/airflow/airflow/example_dags/example_bash_operator.py(18)()
+ root@ef2c84ad4856:/opt/airflow# python -m pdb providers/standard/src/airflow/providers/standard/example_dags/example_bash_operator.py
+ > /opt/airflow/providers/standard/src/airflow/providers/standard/example_dags/example_bash_operator.py(18)()
-> """Example DAG demonstrating the usage of the BashOperator."""
(Pdb) b 45
- Breakpoint 1 at /opt/airflow/airflow/example_dags/example_bash_operator.py:45
+ Breakpoint 1 at /opt/airflow/providers/standard/src/airflow/providers/standard/example_dags/example_bash_operator.py:45
(Pdb) c
- > /opt/airflow/airflow/example_dags/example_bash_operator.py(45)()
- -> bash_command='echo 1',
+ > /opt/airflow/providers/standard/src/airflow/providers/standard/example_dags/example_bash_operator.py(45)()
+ -> task_id="run_after_loop",
(Pdb) run_this_last
diff --git a/airflow-core/docs/core-concepts/executor/index.rst b/airflow-core/docs/core-concepts/executor/index.rst
index c83f10cb050bc..ef488f4d9f8e2 100644
--- a/airflow-core/docs/core-concepts/executor/index.rst
+++ b/airflow-core/docs/core-concepts/executor/index.rst
@@ -48,8 +48,6 @@ If you want to check which executor is currently set, you can use the ``airflow
$ airflow config get-value core executor
LocalExecutor
-
-
Executor Types
--------------
@@ -114,6 +112,8 @@ Airflow tasks are executed ad hoc inside containers/pods. Each task is isolated
New Airflow users may assume they need to run a separate executor process using one of the Local or Remote Executors. This is not correct. The executor logic runs *inside* the scheduler process, and will run the tasks locally or not depending on the executor selected.
+.. _using-multiple-executors-concurrently:
+
Using Multiple Executors Concurrently
-------------------------------------
@@ -210,11 +210,13 @@ Logging works the same as the single executor use case.
Statically-coded Hybrid Executors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-There are currently two "statically coded" executors, these executors are hybrids of two different executors: the :doc:`LocalKubernetesExecutor ` and the :doc:`CeleryKubernetesExecutor `. Their implementation is not native or intrinsic to core Airflow. These hybrid executors instead make use of the ``queue`` field on Task Instances to indicate and persist which sub-executor to run on. This is a misuse of the ``queue`` field and makes it impossible to use it for its intended purpose when using these hybrid executors.
+There were two "statically coded" executors, but they are no longer supported starting from Airflow 3.0.0.
+
+These executors are hybrids of two different executors: the :doc:`LocalKubernetesExecutor ` and the :doc:`CeleryKubernetesExecutor `. Their implementation is not native or intrinsic to core Airflow. These hybrid executors instead make use of the ``queue`` field on Task Instances to indicate and persist which sub-executor to run on. This is a misuse of the ``queue`` field and makes it impossible to use it for its intended purpose when using these hybrid executors.
Executors such as these also require hand crafting new "concrete" classes to create each permutation of possible combinations of executors. This is untenable as more executors are created and leads to more maintenance overhead. Bespoke coding effort should not be required to use any combination of executors.
-Therefore using these types of executors is no longer recommended.
+Therefore using these types of executors is no longer supported starting from Airflow 3.0.0. It's recommended to use the :ref:`Using Multiple Executors Concurrently ` feature instead.
Writing Your Own Executor
@@ -232,6 +234,40 @@ Some reasons you may want to write a custom executor include:
* You'd like to use an executor that leverages a compute service from your preferred cloud provider.
* You have a private tool/service for task execution that is only available to you or your organization.
+Workloads
+^^^^^^^^^
+
+A workload in context of an Executor is the fundamental unit of execution for an executor. It represents a discrete
+operation or job that the executor runs on a worker. For example, it can run user code encapsulated in an Airflow task
+on a worker.
+
+Example:
+
+.. code-block:: python
+
+ ExecuteTask(
+ token="mock",
+ ti=TaskInstance(
+ id=UUID("4d828a62-a417-4936-a7a6-2b3fabacecab"),
+ task_id="mock",
+ dag_id="mock",
+ run_id="mock",
+ try_number=1,
+ map_index=-1,
+ pool_slots=1,
+ queue="default",
+ priority_weight=1,
+ executor_config=None,
+ parent_context_carrier=None,
+ context_carrier=None,
+ queued_dttm=None,
+ ),
+ dag_rel_path=PurePosixPath("mock.py"),
+ bundle_info=BundleInfo(name="n/a", version="no matter"),
+ log_path="mock.log",
+ type="ExecuteTask",
+ )
+
Important BaseExecutor Methods
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -239,7 +275,7 @@ Important BaseExecutor Methods
These methods don't require overriding to implement your own executor, but are useful to be aware of:
* ``heartbeat``: The Airflow scheduler Job loop will periodically call heartbeat on the executor. This is one of the main points of interaction between the Airflow scheduler and the executor. This method updates some metrics, triggers newly queued tasks to execute and updates state of running/completed tasks.
-* ``queue_command``: The Airflow Executor will call this method of the BaseExecutor to provide tasks to be run by the executor. The BaseExecutor simply adds the TaskInstances to an internal list of queued tasks within the executor.
+* ``queue_workload``: The Airflow Executor will call this method of the BaseExecutor to provide tasks to be run by the executor. The BaseExecutor simply adds the *workloads* (check section above to understand) to an internal list of queued workloads to run within the executor. All executors present in the repository use this method.
* ``get_event_buffer``: The Airflow scheduler calls this method to retrieve the current state of the TaskInstances the executor is executing.
* ``has_task``: The scheduler uses this BaseExecutor method to determine if an executor already has a specific task instance queued or running.
* ``send_callback``: Sends any callbacks to the sink configured on the executor.
@@ -251,7 +287,7 @@ Mandatory Methods to Implement
The following methods must be overridden at minimum to have your executor supported by Airflow:
* ``sync``: Sync will get called periodically during executor heartbeats. Implement this method to update the state of the tasks which the executor knows about. Optionally, attempting to execute queued tasks that have been received from the scheduler.
-* ``execute_async``: Executes a command asynchronously. A command in this context is an Airflow CLI command to run an Airflow task. This method is called (after a few layers) during executor heartbeat which is run periodically by the scheduler. In practice, this method often just enqueues tasks into an internal or external queue of tasks to be run (e.g. ``KubernetesExecutor``). But can also execute the tasks directly as well (e.g. ``LocalExecutor``). This will depend on the executor.
+* ``execute_async``: Executes a *workload* asynchronously. This method is called (after a few layers) during executor heartbeat which is run periodically by the scheduler. In practice, this method often just enqueues tasks into an internal or external queue of tasks to be run (e.g. ``KubernetesExecutor``). But can also execute the tasks directly as well (e.g. ``LocalExecutor``). This will depend on the executor.
Optional Interface Methods to Implement
diff --git a/airflow-core/docs/core-concepts/index.rst b/airflow-core/docs/core-concepts/index.rst
index fdb9c2d146aaa..8ba314cd36778 100644
--- a/airflow-core/docs/core-concepts/index.rst
+++ b/airflow-core/docs/core-concepts/index.rst
@@ -43,6 +43,7 @@ Here you can find detailed documentation about each one of the core concepts of
auth-manager/index
objectstorage
backfill
+ message-queues
**Communication**
diff --git a/airflow-core/docs/core-concepts/message-queues.rst b/airflow-core/docs/core-concepts/message-queues.rst
new file mode 100644
index 0000000000000..573189a24f891
--- /dev/null
+++ b/airflow-core/docs/core-concepts/message-queues.rst
@@ -0,0 +1,41 @@
+ .. 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.
+
+.. _concepts:message-queues:
+
+Message Queues
+==============
+
+The Message Queues are a way to expose capability of external event-driven scheduling of Dags.
+
+Apache Airflow is primarily designed for time-based and dependency-based scheduling of workflows. However,
+modern data architectures often require near real-time processing and the ability to react to
+events from various sources, such as message queues.
+
+Airflow has native event-driven capability, allowing users to create workflows that can be
+triggered by external events, thus enabling more responsive data pipelines.
+
+Airflow supports poll-based event-driven scheduling, where the Triggerer can poll
+external message queues using built-in :class:`airflow.triggers.base.BaseTrigger` classes. This allows users
+to create workflows that can be triggered by external events, such as messages arriving
+in a queue or changes in a database efficiently.
+
+Airflow constantly monitors the state of an external resource and updates the asset whenever the external
+resource reaches a given state (if it does reach it). To achieve this, we leverage Airflow Triggers.
+Triggers are small, asynchronous pieces of Python code whose job is to poll an external resource state.
+
+The list of supported message queues is available in :doc:`apache-airflow-providers:core-extensions/message-queues`.
diff --git a/airflow-core/docs/core-concepts/operators.rst b/airflow-core/docs/core-concepts/operators.rst
index 0d66ba3f61d21..596b10ae16954 100644
--- a/airflow-core/docs/core-concepts/operators.rst
+++ b/airflow-core/docs/core-concepts/operators.rst
@@ -199,7 +199,7 @@ In some cases, you may want to exclude a string from templating and use it direc
)
This will fail with ``TemplateNotFound: cat script.sh`` since Airflow would treat the string as a path to a file, not a command.
-We can prevent airflow from treating this value as a reference to a file by wrapping it in :func:`~airflow.util.template.literal`.
+We can prevent Airflow from treating this value as a reference to a file by wrapping it in :func:`~airflow.util.template.literal`.
This approach disables the rendering of both macros and files and can be applied to selected nested fields while retaining the default templating rules for the remainder of the content.
.. code-block:: python
diff --git a/airflow-core/docs/core-concepts/overview.rst b/airflow-core/docs/core-concepts/overview.rst
index 027d14da12ea8..96eda6bdff1e4 100644
--- a/airflow-core/docs/core-concepts/overview.rst
+++ b/airflow-core/docs/core-concepts/overview.rst
@@ -22,7 +22,7 @@ Airflow is a platform that lets you build and run *workflows*. A workflow is rep
:doc:`DAG ` (a Directed Acyclic Graph), and contains individual pieces of work called
:doc:`tasks`, arranged with dependencies and data flows taken into account.
-.. image:: ../img/edge_label_example.png
+.. image:: ../img/ui-light/edge_label_example.png
:alt: An example Airflow DAG, rendered in Graph
A DAG specifies the dependencies between tasks, which defines the order in which to execute the tasks.
@@ -59,7 +59,7 @@ A minimal Airflow installation consists of the following components:
* A folder of *DAG files*, which is read by the *scheduler* to figure out what tasks to run and when to
run them.
-* A *metadata database*, which airflow components use to store state of workflows and tasks.
+* A *metadata database*, which Airflow components use to store state of workflows and tasks.
Setting up a metadata database is described in :doc:`/howto/set-up-database` and is required for
Airflow to work.
@@ -98,7 +98,7 @@ and can be scaled by running multiple instances of the components above.
The separation of components also allow for increased security, by isolating the components from each other
and by allowing to perform different tasks. For example separating *dag processor* from *scheduler*
allows to make sure that the *scheduler* does not have access to the *DAG files* and cannot execute
-code provided by *DAG author*.
+code provided by *Dag author*.
Also while single person can run and manage Airflow installation, Airflow Deployment in more complex
setup can involve various roles of users that can interact with different parts of the system, which is
@@ -106,7 +106,7 @@ an important aspect of secure Airflow deployment. The roles are described in det
:doc:`/security/security_model` and generally speaking include:
* Deployment Manager - a person that installs and configures Airflow and manages the deployment
-* DAG author - a person that writes dags and submits them to Airflow
+* Dag author - a person that writes dags and submits them to Airflow
* Operations User - a person that triggers dags and tasks and monitors their execution
Architecture Diagrams
@@ -153,13 +153,13 @@ Distributed Airflow architecture
................................
This is the architecture of Airflow where components of Airflow are distributed among multiple machines
-and where various roles of users are introduced - *Deployment Manager*, **DAG author**,
+and where various roles of users are introduced - *Deployment Manager*, **Dag author**,
**Operations User**. You can read more about those various roles in the :doc:`/security/security_model`.
In the case of a distributed deployment, it is important to consider the security aspects of the components.
The *webserver* does not have access to the *DAG files* directly. The code in the ``Code`` tab of the
UI is read from the *metadata database*. The *webserver* cannot execute any code submitted by the
-**DAG author**. It can only execute code that is installed as an *installed package* or *plugin* by
+**Dag author**. It can only execute code that is installed as an *installed package* or *plugin* by
the **Deployment Manager**. The **Operations User** only has access to the UI and can only trigger
dags and tasks, but cannot author dags.
@@ -178,7 +178,7 @@ Separate DAG processing architecture
In a more complex installation where security and isolation are important, you'll also see the
standalone *dag processor* component that allows to separate *scheduler* from accessing *DAG files*.
This is suitable if the deployment focus is on isolation between parsed tasks. While Airflow does not yet
-support full multi-tenant features, it can be used to make sure that **DAG author** provided code is never
+support full multi-tenant features, it can be used to make sure that **Dag author** provided code is never
executed in the context of the scheduler.
.. image:: ../img/diagram_dag_processor_airflow_architecture.png
@@ -243,6 +243,6 @@ User interface
Airflow comes with a user interface that lets you see what dags and their tasks are doing, trigger runs of dags, view logs, and do some limited debugging and resolution of problems with your dags.
-.. image:: ../img/dags.png
+.. image:: ../img/ui-dark/dags.png
It's generally the best way to see the status of your Airflow installation as a whole, as well as diving into individual dags to see their layout, the status of each task, and the logs from each task.
diff --git a/airflow-core/docs/core-concepts/params.rst b/airflow-core/docs/core-concepts/params.rst
index dd655cae2a324..f313f0bd1591d 100644
--- a/airflow-core/docs/core-concepts/params.rst
+++ b/airflow-core/docs/core-concepts/params.rst
@@ -32,15 +32,14 @@ If the user-supplied values don't pass validation, Airflow shows a warning inste
DAG-level Params
----------------
-To add Params to a :class:`~airflow.models.dag.DAG`, initialize it with the ``params`` kwarg.
+To add Params to a :class:`~airflow.sdk.DAG`, initialize it with the ``params`` kwarg.
Use a dictionary that maps Param names to either a :class:`~airflow.sdk.definitions.param.Param` or an object indicating the parameter's default value.
.. code-block::
:emphasize-lines: 7-10
- from airflow.sdk import DAG
- from airflow.sdk import task
- from airflow.sdk import Param
+ from airflow.sdk import DAG, task, Param, get_current_context
+ import logging
with DAG(
"the_dag",
@@ -51,15 +50,18 @@ Use a dictionary that maps Param names to either a :class:`~airflow.sdk.definiti
) as dag:
@task.python
- def example_task(params: dict):
+ def example_task():
+ ctx = get_current_context()
+ logger = logging.getLogger("airflow.task")
+
# This will print the default value, 6:
- dag.log.info(dag.params['my_int_param'])
+ logger.info(ctx["dag"].params["my_int_param"])
# This will print the manually-provided value, 42:
- dag.log.info(params['my_int_param'])
+ logger.info(ctx["params"]["my_int_param"])
# This will print the default value, 5, since it wasn't provided manually:
- dag.log.info(params['x'])
+ logger.info(ctx["params"]["x"])
example_task()
@@ -191,7 +193,7 @@ JSON Schema Validation
.. note::
If ``schedule`` is defined for a DAG, params with defaults must be valid. This is validated during DAG parsing.
If ``schedule=None`` then params are not validated during DAG parsing but before triggering a DAG.
- This is useful in cases where the DAG author does not want to provide defaults but wants to force users provide valid parameters
+ This is useful in cases where the Dag author does not want to provide defaults but wants to force users provide valid parameters
at time of trigger.
.. note::
@@ -386,19 +388,19 @@ For examples, please take a look at the two example dags provided: :ref:`Params
The Params UI Tutorial is rendered in 4 sections with the most common examples. The first section shows the basic usage without
``Param`` class.
-.. image:: ../img/trigger-dag-tutorial-form-1.png
+.. image:: ../img/ui-dark/trigger-dag-tutorial-form-1.png
The second section shows how to use the ``Param`` class to define more attributes.
-.. image:: ../img/trigger-dag-tutorial-form-2.png
+.. image:: ../img/ui-dark/trigger-dag-tutorial-form-2.png
The third section shows how to model selection lists and drop-downs.
-.. image:: ../img/trigger-dag-tutorial-form-3.png
+.. image:: ../img/ui-dark/trigger-dag-tutorial-form-3.png
Finally the fourth section shows advanced form elements.
-.. image:: ../img/trigger-dag-tutorial-form-4.png
+.. image:: ../img/ui-dark/trigger-dag-tutorial-form-4.png
.. versionchanged:: 3.0.0
By default custom HTML is not allowed to prevent injection of scripts or other malicious HTML code. The previous field named
diff --git a/airflow-core/docs/core-concepts/variables.rst b/airflow-core/docs/core-concepts/variables.rst
index db0ffacb0884f..6487fd0c131a3 100644
--- a/airflow-core/docs/core-concepts/variables.rst
+++ b/airflow-core/docs/core-concepts/variables.rst
@@ -33,6 +33,20 @@ To use them, just import and call ``get`` on the Variable model::
# Returns the value of default (None) if the variable is not set
baz = Variable.get("baz", default=None)
+You can also access variables through the Task Context using
+:func:`~airflow.sdk.get_current_context`:
+
+.. code-block:: python
+
+ from airflow.sdk import get_current_context
+
+
+ def my_task():
+ context = get_current_context()
+ var = context["var"]
+ my_variable = var.get("my_variable_name")
+ return my_variable
+
You can also use them from :ref:`templates `::
# Raw value
diff --git a/airflow-core/docs/core-concepts/xcoms.rst b/airflow-core/docs/core-concepts/xcoms.rst
index 2be9b75bbf849..93463a752768e 100644
--- a/airflow-core/docs/core-concepts/xcoms.rst
+++ b/airflow-core/docs/core-concepts/xcoms.rst
@@ -25,6 +25,9 @@ XComs (short for "cross-communications") are a mechanism that let :doc:`tasks` t
An XCom is identified by a ``key`` (essentially its name), as well as the ``task_id`` and ``dag_id`` it came from. They can have any serializable value (including objects that are decorated with ``@dataclass`` or ``@attr.define``, see :ref:`TaskFlow arguments `:), but they are only designed for small amounts of data; do not use them to pass around large values, like dataframes.
+XCom operations should be performed through the Task Context using
+:func:`~airflow.sdk.get_current_context`. Directly updating using XCom database model is not possible.
+
XComs are explicitly "pushed" and "pulled" to/from their storage using the ``xcom_push`` and ``xcom_pull`` methods on Task Instances.
To push a value within a task called **"task-1"** that will be used by another task:
@@ -73,8 +76,6 @@ An example of pushing multiple XComs and pulling them individually:
# Pulling entire xcom data from push_multiple task
data = context["ti"].xcom_pull(task_ids="push_multiple", key="return_value")
-
-
.. note::
If the first task run is not succeeded then on every retry task XComs will be cleared to make the task run idempotent.
@@ -91,7 +92,7 @@ Custom XCom Backends
The XCom system has interchangeable backends, and you can set which backend is being used via the ``xcom_backend`` configuration option.
-If you want to implement your own backend, you should subclass :class:`~airflow.models.xcom.BaseXCom`, and override the ``serialize_value`` and ``deserialize_value`` methods.
+If you want to implement your own backend, you should subclass :class:`~airflow.sdk.bases.xcom.BaseXCom`, and override the ``serialize_value`` and ``deserialize_value`` methods.
You can override the ``purge`` method in the ``BaseXCom`` class to have control over purging the xcom data from the custom backend. This will be called as part of ``delete``.
@@ -104,6 +105,6 @@ If you can exec into a terminal in an Airflow container, you can then print out
.. code-block:: python
- from airflow.models.xcom import XCom
+ from airflow.sdk.execution_time.xcom import XCom
print(XCom.__name__)
diff --git a/airflow-core/docs/extra-packages-ref.rst b/airflow-core/docs/extra-packages-ref.rst
index 46166ee46aa0a..47106fab2ed8d 100644
--- a/airflow-core/docs/extra-packages-ref.rst
+++ b/airflow-core/docs/extra-packages-ref.rst
@@ -26,18 +26,18 @@ already existing ``providers`` and the dependencies are isolated and simplified
packages.
While the original installation methods via ``apache-airflow`` distribution package and extras still
-work as previously and it installs complete airflow installation ready to serve as scheduler, webserver, triggerer
+work as previously and it installs complete Airflow installation ready to serve as scheduler, webserver, triggerer
and worker, the ``apache-airflow`` package is now a meta-package that installs all the other distribution
packages, it's also possible to install only the distribution packages that are needed for a specific
-component you want to run airflow with.
+component you want to run Airflow with.
The following distribution packages are available:
+----------------------------+------------------------------------------------------------------+----------------------------------------------------------+
| Distribution package | Purpose | Optional extras |
+----------------------------+------------------------------------------------------------------+----------------------------------------------------------+
-| apache-airflow-core | This is the core distribution package that contains | * Core extras that add optional functionality to airflow |
-| | the airflow scheduler, webserver, triggerer code. | core system - enhancing its functionality across |
+| apache-airflow-core | This is the core distribution package that contains | * Core extras that add optional functionality to Airflow |
+| | the Airflow scheduler, webserver, triggerer code. | core system - enhancing its functionality across |
| | | multiple providers. |
| | | |
| | | * Group ``all`` extra that installs all optional |
@@ -71,7 +71,7 @@ The following distribution packages are available:
As mentioned above, Airflow has a number of optional "extras" that you can use to add features to your
installation when you are installing Airflow. Those extras are a good way for the users to manage their
-installation, but also they are useful for contributors to airflow when they want to contribute some of
+installation, but also they are useful for contributors to Airflow when they want to contribute some of
the features - including optional integrations of Airflow - via providers.
Here's the list of all the extra dependencies of Apache Airflow.
@@ -79,16 +79,44 @@ Here's the list of all the extra dependencies of Apache Airflow.
Core Airflow extras
-------------------
-These are core airflow extras that extend capabilities of core Airflow. They usually do not install provider
-packages (with the exception of ``celery`` and ``cncf.kubernetes`` extras), they just install necessary
-python dependencies for the provided package.
+These are core Airflow extras that extend capabilities of core Airflow. They do not install provider
+packages, they just install necessary
+python dependencies for the provided package. The same extras are available as ``airflow-core`` package extras.
+
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| extra | install command | enables |
++=====================+=====================================================+============================================================================+
+| async | ``pip install 'apache-airflow[async]'`` | Async worker classes for Gunicorn |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| graphviz | ``pip install 'apache-airflow[graphviz]'`` | Graphviz renderer for converting DAG to graphical output |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| kerberos | ``pip install 'apache-airflow[kerberos]'`` | Kerberos integration for Kerberized services (Hadoop, Presto, Trino) |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| otel | ``pip install 'apache-airflow[otel]'`` | Required for OpenTelemetry metrics |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| sentry | ``pip install 'apache-airflow[sentry]'`` | Sentry service for application logging and monitoring |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| standard | ``pip install apache-airflow[standard]'`` | Standard hooks and operators |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| statsd | ``pip install 'apache-airflow[statsd]'`` | Needed by StatsD metrics |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+
+Meta-airflow package extras
+---------------------------
+
+Airflow 3 is released in several packages. The ``apache-airflow`` package is a meta-package that installs
+all the other packages when you run Airflow as a standalone installation, and it also has several extras
+that are not extending Airflow core functionality, but they are useful for the users who want to install
+other packages that can be used by airflow or some of its providers.
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| extra | install command | enables |
+=====================+=====================================================+============================================================================+
| aiobotocore | ``pip install 'apache-airflow[aiobotocore]'`` | Support for asynchronous (deferrable) operators for Amazon integration |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| async | ``pip install 'apache-airflow[async]'`` | Async worker classes for Gunicorn |
+| amazon-aws-auth | ``pip install apache-airflow[amazon-aws-auth]`` | Amazon-aws-auth AWS authentication |
++---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
+| cloudpickle | ``pip install apache-airflow[cloudpickle]`` | Cloudpickle hooks and operators |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| github-enterprise | ``pip install 'apache-airflow[github-enterprise]'`` | GitHub Enterprise auth backend |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
@@ -96,32 +124,22 @@ python dependencies for the provided package.
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| graphviz | ``pip install 'apache-airflow[graphviz]'`` | Graphviz renderer for converting DAG to graphical output |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| kerberos | ``pip install 'apache-airflow[kerberos]'`` | Kerberos integration for Kerberized services (Hadoop, Presto, Trino) |
-+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| ldap | ``pip install 'apache-airflow[ldap]'`` | LDAP authentication for users |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| leveldb | ``pip install 'apache-airflow[leveldb]'`` | Required for use leveldb extra in google provider |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| otel | ``pip install 'apache-airflow[otel]'`` | Required for OpenTelemetry metrics |
-+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| pandas | ``pip install 'apache-airflow[pandas]'`` | Install Pandas library compatible with Airflow |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| rabbitmq | ``pip install 'apache-airflow[rabbitmq]'`` | RabbitMQ support as a Celery backend |
+| polars | ``pip install 'apache-airflow[polars]'`` | Polars hooks and operators |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| sentry | ``pip install 'apache-airflow[sentry]'`` | Sentry service for application logging and monitoring |
+| rabbitmq | ``pip install 'apache-airflow[rabbitmq]'`` | RabbitMQ support as a Celery backend |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| s3fs | ``pip install 'apache-airflow[s3fs]'`` | Support for S3 as Airflow FS |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| saml | ``pip install 'apache-airflow[saml]'`` | Support for SAML authentication in Airflow |
-+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| standard | ``pip install apache-airflow[standard]'`` | Standard hooks and operators |
-+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| statsd | ``pip install 'apache-airflow[statsd]'`` | Needed by StatsD metrics |
+| saml | ``pip install 'apache-airflow[saml]'`` | Support for SAML authentication in Amazon provider |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
| uv | ``pip install 'apache-airflow[uv]'`` | Install uv - fast, Rust-based package installer (experimental) |
+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
-| cloudpickle | ``pip install apache-airflow[cloudpickle]`` | Cloudpickle hooks and operators |
-+---------------------+-----------------------------------------------------+----------------------------------------------------------------------------+
Providers extras
@@ -129,7 +147,7 @@ Providers extras
These providers extras are simply convenience extras to install providers so that you can install the providers with simple command - including
provider package and necessary dependencies in single command, which allows PIP to resolve any conflicting dependencies. This is extremely useful
-for first time installation where you want to repeatably install version of dependencies which are 'valid' for both airflow and providers installed.
+for first time installation where you want to repeatably install version of dependencies which are 'valid' for both Airflow and providers installed.
For example the below command will install:
@@ -146,7 +164,7 @@ with a consistent set of dependencies based on constraint files provided by Airf
:substitutions:
pip install apache-airflow[google,amazon,apache-spark]==|version| \
- --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-|version|/constraints-3.9.txt"
+ --constraint "https://raw.githubusercontent.com/apache/airflow/constraints-|version|/constraints-3.10.txt"
Note, that this will install providers in the versions that were released at the time of Airflow |version| release. You can later
upgrade those providers manually if you want to use latest versions of the providers.
@@ -198,6 +216,8 @@ custom bash/python providers).
+---------------------+-----------------------------------------------------+------------------------------------------------+
| apache-spark | ``pip install 'apache-airflow[apache-spark]'`` | All Spark related operators & hooks |
+---------------------+-----------------------------------------------------+------------------------------------------------+
+| apache-tinkerpop | ``pip install apache-airflow[apache-tinkerpop]`` | Apache-tinkerpop hooks and operators |
++---------------------+-----------------------------------------------------+------------------------------------------------+
| apache-webhdfs | ``pip install 'apache-airflow[apache-webhdfs]'`` | HDFS hooks and operators |
+---------------------+-----------------------------------------------------+------------------------------------------------+
@@ -377,6 +397,8 @@ pre-installed when Airflow is installed.
+---------------------+-----------------------------------------------------+--------------------------------------+--------------+
| jdbc | ``pip install 'apache-airflow[jdbc]'`` | JDBC hooks and operators | |
+---------------------+-----------------------------------------------------+--------------------------------------+--------------+
+| keycloak | ``pip install apache-airflow[keycloak]`` | Keycloak hooks and operators | +
++---------------------+-----------------------------------------------------+--------------------------------------+--------------+
| microsoft-psrp | ``pip install 'apache-airflow[microsoft-psrp]'`` | PSRP hooks and operators | |
+---------------------+-----------------------------------------------------+--------------------------------------+--------------+
| microsoft-winrm | ``pip install 'apache-airflow[microsoft-winrm]'`` | WinRM hooks and operators | |
@@ -402,9 +424,9 @@ Group extras
The group extras are convenience extras. Such extra installs many optional dependencies together.
It is not recommended to use it in production, but it is useful for CI, development and testing purposes.
-+---------+--------------------------------------------+---------------------------------------------------+
-| extra | install command | enables |
-+=========+============================================+===================================================+
++-----------+------------------------------------------+---------------------------------------------------+
+| extra | install command | enables |
++===========+==========================================+===================================================+
| all | ``pip install apache-airflow[all]`` | All optional dependencies including all providers |
+-----------+------------------------------------------+---------------------------------------------------+
| all-core | ``pip install apache-airflow[all-core]`` | All optional core dependencies |
diff --git a/airflow-core/docs/faq.rst b/airflow-core/docs/faq.rst
index e552e024a4925..f74c4194928bb 100644
--- a/airflow-core/docs/faq.rst
+++ b/airflow-core/docs/faq.rst
@@ -31,8 +31,8 @@ There are very many reasons why your task might not be getting scheduled. Here a
- Does your script "compile", can the Airflow engine parse it and find your
DAG object? To test this, you can run ``airflow dags list`` and
confirm that your DAG shows up in the list. You can also run
- ``airflow tasks list foo_dag_id --tree`` and confirm that your task
- shows up in the list as expected. If you use the CeleryExecutor, you
+ ``airflow dags show foo_dag_id`` and confirm that your task
+ shows up in the graphviz format as expected. If you use the CeleryExecutor, you
may want to confirm that this works both where the scheduler runs as well
as where the worker runs.
@@ -206,6 +206,37 @@ until ``min_file_process_interval`` is reached since DAG Parser will look for mo
return dag
+What to do if you see disappearing DAGs on UI?
+----------------------------------------------
+There are several reasons why DAGs might disappear from the UI. Common causes include:
+
+* **Total parsing of all DAGs is too long** - If parsing takes longer than :ref:`config:core__dagbag_import_timeout`,
+ files may not be processed completely. This often occurs when DAGs don't follow
+ :ref:`DAG writing best practices` like:
+
+ * Excessive top-level code execution
+ * External system calls during parsing
+ * Complex dynamic DAG generation
+
+* **Inconsistent dynamic DAG generation** - DAGs created through
+ :doc:`dynamic generation ` must produce stable DAG IDs across parses.
+ Verify consistency by running ``python your_dag_file.py`` repeatedly.
+
+* **File processing configuration issues** - A certain combination of parameters may lead to scenarios which certain DAGs are less likely to be processed at each loop. Check these parameters:
+
+ * :ref:`config:dag_processor__file_parsing_sort_mode` - Ensure sorting method matches your sync strategy
+ * :ref:`config:dag_processor__parsing_processes` - Number of parallel parsers
+ * :ref:`config:scheduler__parsing_cleanup_interval` - Controls stale DAG cleanup frequency
+ * :ref:`config:scheduler__dag_stale_not_seen_duration` - Time threshold for marking DAGs as stale
+
+* **File synchronization problems** - Common with git-sync setups:
+
+ * Symbolic link swapping delays
+ * Permission changes during sync
+ * ``mtime`` preservation issues
+
+* **Time synchronization issues** - Ensure all nodes (database, schedulers, workers) use NTP with <1s clock drift.
+
DAG construction
^^^^^^^^^^^^^^^^
@@ -509,3 +540,38 @@ This means ``explicit_defaults_for_timestamp`` is disabled in your mysql server
#. Set ``explicit_defaults_for_timestamp = 1`` under the ``mysqld`` section in your ``my.cnf`` file.
#. Restart the Mysql server.
+
+Connections
+^^^^^^^^^^^
+
+How can I test a connection or use a Canary Dag?
+------------------------------------------------
+
+For security reasons, the test connection functionality is disabled by default across the Airflow UI,
+API and CLI. This can be modified by setting ref:`config:core__test_connection`.
+
+You can utilize a Dag to regularly test connections. This is referred to as a "Canary Dag" and can detect and
+alert on failures in external systems that your Dags depend on. You can create a simple Dag that tests connections
+such as the following Airflow 3 example:
+
+.. code-block:: python
+
+ from airflow import DAG
+ from airflow.sdk import task
+
+ with DAG(dag_id="canary", schedule="@daily", doc_md="Canary DAG to regularly test connections to systems."):
+
+ @task(doc_md="Test a connection by its Connection ID.")
+ def test_connection(conn_id):
+ from airflow.hooks.base import BaseHook
+
+ ok, status = BaseHook.get_hook(conn_id=conn_id).test_connection()
+ if ok:
+ return status
+ raise RuntimeError(status)
+
+ for conn_id in [
+ # Add more connections here to create tasks to test them.
+ "aws_default",
+ ]:
+ test_connection.override(task_id="test_" + conn_id)(conn_id)
diff --git a/airflow-core/docs/howto/add-owner-links.rst b/airflow-core/docs/howto/add-owner-links.rst
new file mode 100644
index 0000000000000..fbc8445209df1
--- /dev/null
+++ b/airflow-core/docs/howto/add-owner-links.rst
@@ -0,0 +1,50 @@
+ .. 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.
+
+
+
+
+Add Owner Links to DAG
+=======================
+
+.. versionadded:: 2.4.0
+
+You can set the ``owner_links`` argument on your DAG object, which will make the owner a clickable link in the
+main dags view page instead of a search filter.
+
+Two options are supported:
+
+* An HTTP link (e.g. ``https://www.example.com``) which opens the webpage in your default internet client
+* A `mailto `_ link (e.g. ``mailto:example@airflow.com``) which opens your default email client to send an email to the specified address
+
+In your DAG, set the ``owner_links`` argument specifying a dictionary of an owner (key) and its link (value).
+Next define a task using this owner, and the owner in the dags view will link to the specified address.
+
+.. code-block:: python
+ :emphasize-lines: 5
+
+ with DAG(
+ dag_id="example_dag_owners",
+ start_date=datetime(2022, 8, 5),
+ schedule="0 0 * * *",
+ owner_links={"airflow": "https://airflow.apache.org"},
+ ):
+ BashOperator(task_id="task_using_linked_owner", bash_command="echo 1", owner="airflow")
+
+**Screenshot**:
+
+.. image:: ../img/howto-owner-links.gif
diff --git a/airflow-core/docs/howto/connection.rst b/airflow-core/docs/howto/connection.rst
index c753e1342660f..e58d0260db49b 100644
--- a/airflow-core/docs/howto/connection.rst
+++ b/airflow-core/docs/howto/connection.rst
@@ -22,7 +22,7 @@ Managing Connections
For an overview of hooks and connections, see :doc:`/authoring-and-scheduling/connections`.
-Airflow's :class:`~airflow.models.connection.Connection` object is used for storing credentials and other information necessary for connecting to external services.
+Airflow's :class:`~airflow.sdk.Connection` object is used for storing credentials and other information necessary for connecting to external services.
Connections may be defined in the following ways:
@@ -77,7 +77,7 @@ convenience property :py:meth:`~airflow.models.connection.Connection.as_json`. I
.. code-block:: pycon
- >>> from airflow.models.connection import Connection
+ >>> from airflow.sdk import Connection
>>> c = Connection(
... conn_id="some_conn",
... conn_type="mysql",
@@ -94,7 +94,7 @@ In addition, same approach could be used to convert Connection from URI format t
.. code-block:: pycon
- >>> from airflow.models.connection import Connection
+ >>> from airflow.sdk import Connection
>>> c = Connection(
... conn_id="awesome_conn",
... description="Example Connection",
@@ -115,9 +115,16 @@ If serializing with Airflow URI:
See :ref:`Connection URI format ` for more details on how to generate the a valid URI.
-.. note::
+Visibility in UI and CLI
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Connections defined through environment variables are **not displayed** in the Airflow UI or listed using ``airflow connections list``.
+
+This is because these connections are **resolved dynamically at runtime**, typically on the **worker** process executing your task. They are not stored in the metadata database or loaded in the webserver or scheduler environment.
+
+This supports secure deployment patterns where environment-based secrets (e.g. via ``.env`` files, Docker, or Kubernetes secrets) are injected only into runtime components like workers — and not into components exposed to users, like the webserver.
- Connections defined in environment variables will not show up in the Airflow UI or using ``airflow connections list``.
+If you need connections to appear in the UI for visibility or editing, define them using the metadata database instead.
Storing connections in a Secrets Backend
diff --git a/airflow-core/docs/howto/custom-operator.rst b/airflow-core/docs/howto/custom-operator.rst
index b76a2277fbfea..d6206166e1211 100644
--- a/airflow-core/docs/howto/custom-operator.rst
+++ b/airflow-core/docs/howto/custom-operator.rst
@@ -24,7 +24,7 @@ Creating a custom Operator
Airflow allows you to create new operators to suit the requirements of you or your team.
This extensibility is one of the many features which make Apache Airflow powerful.
-You can create any operator you want by extending the :class:`airflow.models.baseoperator.BaseOperator`
+You can create any operator you want by extending the public SDK base class :class:`~airflow.sdk.BaseOperator`.
There are two methods that you need to override in a derived class:
diff --git a/airflow-core/docs/howto/custom-view-plugin.rst b/airflow-core/docs/howto/custom-view-plugin.rst
index e9a5b795e4716..d34548ae58069 100644
--- a/airflow-core/docs/howto/custom-view-plugin.rst
+++ b/airflow-core/docs/howto/custom-view-plugin.rst
@@ -20,57 +20,200 @@ Customize view of Apache from Airflow web UI
============================================
Airflow has feature that allows to integrate a custom UI along with its
-core UI using the Plugin manager
+core UI using the Plugin manager.
-This is an example plugin for Airflow that displays absolutely nothing.
+Plugins integrate with the Airflow core RestAPI. In this plugin,
+three object references are derived from the base class ``airflow.plugins_manager.AirflowPlugin``.
+They are fastapi_apps, fastapi_root_middlewares, external_views and react_apps.
-In this plugin, two object references are derived from the base class
-``airflow.plugins_manager.AirflowPlugin``. They are flask_blueprints and
-appbuilder_views
+Using fastapi_apps in Airflow plugin, the core RestAPI can be extended
+to support extra endpoints to serve custom static file or any other json/application responses.
+In this object reference, the list of dictionaries with FastAPI application and metadata information
+like the name and the url prefix are passed on.
-Using flask_blueprints in Airflow plugin, the core application can be extended
-to support the customized application to view Empty Plugin.
-In this object reference, the list of Blueprint object with the static template for
-rendering the information.
+Using fastapi_root_middlewares in Airflow plugin, allows to register custom middleware at the root of
+the FastAPI application. This middleware can be used to add custom headers, logging, or any other
+functionality to the entire FastAPI application, including core endpoints.
+In this object reference, the list of dictionaries with Middleware factories object,
+initialization parameters and some metadata information like the name are passed on.
-Using appbuilder_views in Airflow plugin, a class that represents a concept is
-added and presented with views and methods to implement it.
-In this object reference, the list of dictionaries with FlaskAppBuilder BaseView object
-and metadata information like name and category is passed on.
+Using external_views in Airflow plugin, allows to register custom views that are rendered in iframes or external link
+in the Airflow UI. This is useful for integrating external applications or custom dashboards into the Airflow UI.
+In this object reference, the list of dictionaries with the view name, href (templatable), destination and
+optional parameters like the icon and url_route are passed on.
+Using react_apps in Airflow plugin, allows to register custom React applications that can be rendered
+in the Airflow UI. This is useful for integrating custom React components or applications into the Airflow UI.
+In this object reference, the list of dictionaries with the app name, bundle_url (where to load the js assets, templatable), destination and
+optional parameters like the icon and url_route are passed on.
-Custom view Registration
-------------------------
-A custom view with object reference to flask_appbuilder and Blueprint from flask
-and be registered as a part of a :doc:`plugin `.
+Information and code samples to register ``fastapi_apps``, ``fastapi_root_middlewares``, ``external_views`` and ``react_apps`` are
+available in :doc:`plugin `.
-The following is a skeleton for us to implement a new custom view:
+Developing React Applications with the Bootstrap Tool
+=====================================================
-.. exampleinclude:: /empty_plugin/empty_plugin.py
- :language: python
+Airflow provides a React plugin bootstrap tool to help developers quickly create, develop, and integrate external React applications into the core UI. This is the most flexible
+and recommended way to customize the Airflow UI.
+This tool generates a complete React project structure that builds as a library compatible with dynamic imports and shares React instances with the host Airflow application.
+Creating a New React Plugin Project
+-----------------------------------
-``Plugins`` specified in the ``category`` key of ``appbuilder_views`` dictionary is
-the name of the tab in the navigation bar of the Airflow UI. ``Empty Plugin``
-is the name of the link under the tab ``Plugins``, which will launch the plugin
+The bootstrap tool is located in ``dev/react-plugin-tools/`` and provides a simple CLI to generate new React plugin projects:
-We need to add Blueprint for generating the part of the application
-that needs to be rendered in Airflow web UI. We can define templates, static files
-and this blueprint will be registered as part of the Airflow application when the
-plugin gets loaded.
+.. code-block:: bash
-The ``$AIRFLOW_HOME/plugins`` folder with custom view UI have the following folder structure.
+ # Navigate to the bootstrap tool directory
+ cd dev/react-plugin-tools
-::
+ # Create a new plugin project
+ python bootstrap.py my-awesome-plugin
- plugins
- ├── empty_plugin.py
- ├── templates
- | └── empty_plugin
- | ├── index.html
- └── README.md
+ # Or specify a custom directory
+ python bootstrap.py my-awesome-plugin --dir /path/to/my-projects/my-awesome-plugin
-The HTML files required to render the views built are added as part of the
-Airflow plugin into ``$AIRFLOW_HOME/plugins/templates`` folder and defined in the
-blueprint.
+This generates a complete React project with Vite, TypeScript, Chakra UI integration, and proper configuration for building as a library that integrates with Airflow's UI.
+
+React Development Workflow
+---------------------------
+
+Once your project is generated, refer to the ``README.md`` file in your project directory for complete development instructions, including:
+
+- Available development scripts (``pnpm dev``, ``pnpm build``, etc.)
+- Project structure explanation
+- Development workflow with hot reload
+- Building for production
+- Troubleshooting common React development issues
+
+The generated project is pre-configured with all necessary tools and follows Airflow's UI development patterns.
+
+Integrating with Airflow
+-------------------------
+
+To integrate your React application with Airflow, you need to:
+
+1. **Serve the built assets** you can do that on your own infrastructure or directly within Airflow using ``fastapi_apps``
+2. **Register the React app** using ``react_apps`` plugin configuration
+
+Example Plugin Implementation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create an Airflow plugin that serves your React application:
+
+.. code-block:: python
+
+ from pathlib import Path
+ from fastapi import FastAPI
+ from starlette.staticfiles import StaticFiles
+ import mimetypes
+
+ from airflow.plugins_manager import AirflowPlugin
+
+ # Ensure proper MIME types for cjs files
+ mimetypes.add_type("application/javascript", ".cjs")
+
+ # Create FastAPI app to serve static files
+ app = FastAPI()
+
+ # Mount your React app's dist folder
+ react_app_directory = Path(__file__).parent.joinpath("my-awesome-plugin", "dist")
+ app.mount(
+ "/my-react-app",
+ StaticFiles(directory=react_app_directory, html=True),
+ name="my_react_app_static",
+ )
+
+
+ class MyReactPlugin(AirflowPlugin):
+ name = "My React Plugin"
+
+ # Serve static files
+ fastapi_apps = [
+ {
+ "app": app,
+ "url_prefix": "/my-plugin",
+ "name": "My Plugin Static Server",
+ }
+ ]
+
+ # Register React application
+ react_apps = [
+ {
+ "name": "My Awesome React App",
+ "url_route": "my-awesome-app",
+ "bundle_url": "https://airflow-domain/my-plugin/my-react-app/main.umd.cjs",
+ "destination": "nav",
+ }
+ ]
+
+Plugin Configuration Options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+React apps support several configuration options, you can take a look at :doc:`plugin ` for more details.
+
+
+Integration Best Practices
+---------------------------
+
+The generated template follows these best practices for Airflow integration:
+
+1. **External Dependencies**: React and common libraries are marked as external to avoid conflicts with the host application
+2. **Global Naming**: Uses standardized global name (``AirflowPlugin``) for consistency
+3. **Library Build**: Configured as UMD library with proper externalization for dynamic imports
+4. **MIME Types**: Proper JavaScript MIME type handling for ``.cjs`` files because FastAPI serves them as plain text by default
+
+Deployment Strategies
+---------------------
+
+External Hosting
+~~~~~~~~~~~~~~~~
+
+You can also host assets on external infrastructure:
+
+.. code-block:: python
+
+ react_apps = [
+ {
+ "name": "My External App",
+ "url_route": "my-external-app",
+ "bundle_url": "https://my-cdn.com/main.umd.cjs",
+ "destination": "nav",
+ }
+ ]
+
+Troubleshooting Integration Issues
+-----------------------------------
+
+Common integration issues and solutions:
+
+**MIME type issues**
+ Ensure ``.js`` and ``.cjs`` files are served with correct MIME type using ``mimetypes.add_type("application/javascript", ".cjs")``.
+
+**Component not loading**
+ Check that the bundle URL is accessible and matches the expected format.
+
+**React development issues**
+ Refer to the ``README.md`` file generated with your project for detailed troubleshooting of React-specific development issues.
+
+Support for Airflow 2 plugins
+=============================
+
+Airflow 2 plugins are still supported with some limitations. More information on such
+plugins can be found in the Airflow 2 documentation.
+
+Adding Rest endpoints through the blueprints is still supported, those endpoints will
+be integrated in the FastAPI application via the WSGI Middleware and accessible
+under ``/pluginsv2``.
+
+Adding Flask-AppBuilder views ( ``appbuilder_views`` ) via the Airflow 2 is still supported in its own iframe.
+
+It is not possible to extend the AF3 core UI, for instance by extending the base template, nonetheless extra menu items
+of the auth managers are added to the core UI security tab and their ``href`` are rendered in iframes.
+This is how the fab provider integrates users, roles, actions, resources and permissions custom views in the Airflow 3 UI.
+
+
+Airflow 3 plugins will be improved to allow UI customization for the entire react app, it is recommended
+to upgrade your plugins to Airflow 3 plugins when possible. Until then for a temporary or custom needs
+it is possible to use a Middleware to inject custom javascript or css to the core UI index request.
diff --git a/airflow-core/docs/howto/customize-ui.rst b/airflow-core/docs/howto/customize-ui.rst
index 2378fe3974751..6d1c444f9a844 100644
--- a/airflow-core/docs/howto/customize-ui.rst
+++ b/airflow-core/docs/howto/customize-ui.rst
@@ -61,6 +61,39 @@ After
.. image:: ../img/change-site-title/example_instance_name_configuration.png
-.. note::
- From version 2.3.0 you can include markup in ``instance_name`` variable for further customization. To enable, set ``instance_name_has_markup`` under the ``[webserver]`` section inside ``airflow.cfg`` to ``True``.
+Add custom alert messages on the dashboard
+------------------------------------------
+
+Extra alert messages can be shown on the UI dashboard. This can be useful for warning about setup issues
+or announcing changes to end users. The following example shows how to add alert messages:
+
+1. Add the following contents to ``airflow_local_settings.py`` file under ``$AIRFLOW_HOME/config``.
+ Each alert message should specify a severity level (``info``, ``warning``, ``error``) using ``category``.
+
+ .. code-block:: python
+
+ from airflow.api_fastapi.common.types import UIAlert
+
+ DASHBOARD_UIALERTS = [
+ UIAlert(text="Welcome to Airflow.", category="info"),
+ UIAlert(text="Airflow server downtime scheduled for tomorrow at 10:00 AM.", category="warning"),
+ UIAlert(text="Critical error detected!", category="error"),
+ ]
+
+ See :ref:`Configuring local settings ` for details on how to
+ configure local settings.
+
+2. Restart Airflow Webserver, and you should now see:
+
+.. image:: ../img/ui-alert-message.png
+
+Alert messages also support Markdown. In the following example, we show an alert message of heading 2 with a link included.
+
+ .. code-block:: python
+
+ DASHBOARD_UIALERTS = [
+ UIAlert(text="## Visit [airflow.apache.org](https://airflow.apache.org)", category="info"),
+ ]
+
+.. image:: ../img/ui-alert-message-markdown.png
diff --git a/airflow-core/docs/howto/define-extra-link.rst b/airflow-core/docs/howto/define-extra-link.rst
index 0a1f1b046897b..83718773a9df8 100644
--- a/airflow-core/docs/howto/define-extra-link.rst
+++ b/airflow-core/docs/howto/define-extra-link.rst
@@ -21,7 +21,7 @@
Define an operator extra link
=============================
-If you want to add further links to operators you can define them via a plugin or provider package.
+If you want to add extra links to operators you can define them via a plugin or provider package.
Extra links will be displayed in task details page in Grid view.
.. image:: ../img/operator_extra_link.png
@@ -60,7 +60,8 @@ The following code shows how to add extra links to an operator via Plugins:
GoogleLink(),
]
-.. note:: Operator Extra Links should be registered via Airflow Plugins or custom Airflow Provider to work.
+The extra links defined via custom Airflow Provider or Airflow operators will be pushed as an xcom to the XCom table in
+metadata DB during task execution. During display in the grid view, this xcom is retrieved and displayed.
You can also add a global operator extra link that will be available to
all the operators through an Airflow plugin or through Airflow providers. You can learn more about it in the
@@ -93,7 +94,7 @@ tasks using :class:`~airflow.providers.amazon.aws.transfers.gcs_to_s3.GCSToS3Ope
class S3LogLink(BaseOperatorLink):
name = "S3"
- # Add list of all the operators to which you want to add this OperatorLinks
+ # Add list of all the operators to which you want to add this extra link
# Example: operators = [GCSToS3Operator, GCSToBigQueryOperator]
operators = [GCSToS3Operator]
@@ -120,9 +121,9 @@ tasks using :class:`~airflow.providers.amazon.aws.transfers.gcs_to_s3.GCSToS3Ope
**Overriding Operator Links of Existing Operators**:
-It is also possible to replace a built in link on an operator via a Plugin. For example
+It is also possible to replace a built-in link on an operator via a Plugin. For example
:class:`~airflow.providers.google.cloud.operators.bigquery.BigQueryExecuteQueryOperator` includes a link to the Google Cloud
-Console, but if we wanted to change that link we could:
+Console, but if we wanted to change that link we could do:
.. code-block:: python
@@ -173,7 +174,7 @@ specify the list of operators that provide extra link capability. This happens b
class name in the ``provider-info`` information stored in your Provider's package meta-data:
Example meta-data required in your provider-info dictionary (this is part of the meta-data returned
-by ``apache-airflow-providers-google`` provider currently:
+by ``apache-airflow-providers-google`` provider currently):
.. code-block:: yaml
diff --git a/airflow-core/docs/howto/docker-compose/docker-compose.yaml b/airflow-core/docs/howto/docker-compose/docker-compose.yaml
index d00db43cb1af9..2c2a614c9ef72 100644
--- a/airflow-core/docs/howto/docker-compose/docker-compose.yaml
+++ b/airflow-core/docs/howto/docker-compose/docker-compose.yaml
@@ -71,8 +71,7 @@ x-airflow-common:
# for other purpose (development, test and especially production usage) build/extend Airflow image.
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-}
# The following line can be used to set a custom config file, stored in the local config folder
- # If you want to use it, outcomment it and replace airflow.cfg with the name of your config file
- # AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'
+ AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'
volumes:
- ${AIRFLOW_PROJ_DIR:-.}/dags:/opt/airflow/dags
- ${AIRFLOW_PROJ_DIR:-.}/logs:/opt/airflow/logs
@@ -88,7 +87,7 @@ x-airflow-common:
services:
postgres:
- image: postgres:13
+ image: postgres:16
environment:
POSTGRES_USER: airflow
POSTGRES_PASSWORD: airflow
@@ -218,6 +217,7 @@ services:
echo "For other operating systems you can get rid of the warning with manually created .env file:"
echo " See: https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#setting-the-right-airflow-user"
echo
+ export AIRFLOW_UID=$$(id -u)
fi
one_meg=1048576
mem_available=$$(($$(getconf _PHYS_PAGES) * $$(getconf PAGE_SIZE) / one_meg))
@@ -252,9 +252,38 @@ services:
echo " https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#before-you-begin"
echo
fi
- mkdir -p /sources/logs /sources/dags /sources/plugins
- chown -R "${AIRFLOW_UID}:0" /sources/{logs,dags,plugins}
- exec /entrypoint airflow version
+ echo
+ echo "Creating missing opt dirs if missing:"
+ echo
+ mkdir -v -p /opt/airflow/{logs,dags,plugins,config}
+ echo
+ echo "Airflow version:"
+ /entrypoint airflow version
+ echo
+ echo "Files in shared volumes:"
+ echo
+ ls -la /opt/airflow/{logs,dags,plugins,config}
+ echo
+ echo "Running airflow config list to create default config file if missing."
+ echo
+ /entrypoint airflow config list >/dev/null
+ echo
+ echo "Files in shared volumes:"
+ echo
+ ls -la /opt/airflow/{logs,dags,plugins,config}
+ echo
+ echo "Change ownership of files in /opt/airflow to ${AIRFLOW_UID}:0"
+ echo
+ chown -R "${AIRFLOW_UID}:0" /opt/airflow/
+ echo
+ echo "Change ownership of files in shared volumes to ${AIRFLOW_UID}:0"
+ echo
+ chown -v -R "${AIRFLOW_UID}:0" /opt/airflow/{logs,dags,plugins,config}
+ echo
+ echo "Files in shared volumes:"
+ echo
+ ls -la /opt/airflow/{logs,dags,plugins,config}
+
# yamllint enable rule:line-length
environment:
<<: *airflow-common-env
@@ -264,8 +293,6 @@ services:
_AIRFLOW_WWW_USER_PASSWORD: ${_AIRFLOW_WWW_USER_PASSWORD:-airflow}
_PIP_ADDITIONAL_REQUIREMENTS: ''
user: "0:0"
- volumes:
- - ${AIRFLOW_PROJ_DIR:-.}:/sources
airflow-cli:
<<: *airflow-common
@@ -279,6 +306,8 @@ services:
- bash
- -c
- airflow
+ depends_on:
+ <<: *airflow-common-depends-on
# You can enable flower by adding "--profile flower" option e.g. docker-compose --profile flower up
# or by explicitly targeted on the command line e.g. docker-compose up flower.
diff --git a/airflow-core/docs/howto/docker-compose/index.rst b/airflow-core/docs/howto/docker-compose/index.rst
index 1e60262da14a0..62382469df793 100644
--- a/airflow-core/docs/howto/docker-compose/index.rst
+++ b/airflow-core/docs/howto/docker-compose/index.rst
@@ -89,7 +89,7 @@ This file contains several service definitions:
- ``airflow-scheduler`` - The :doc:`scheduler ` monitors all tasks and dags, then triggers the
task instances once their dependencies are complete.
- ``airflow-dag-processor`` - The DAG processor parses DAG files.
-- ``airflow-webserver`` - The webserver is available at ``http://localhost:8080``.
+- ``airflow-api-server`` - The api server is available at ``http://localhost:8080``.
- ``airflow-worker`` - The worker that executes the tasks given by the scheduler.
- ``airflow-triggerer`` - The triggerer runs an event loop for deferrable tasks.
- ``airflow-init`` - The initialization service.
@@ -125,8 +125,8 @@ Setting the right Airflow user
------------------------------
On **Linux**, the quick-start needs to know your host user id and needs to have group id set to ``0``.
-Otherwise the files created in ``dags``, ``logs`` and ``plugins`` will be created with ``root`` user ownership.
-You have to make sure to configure them for the docker-compose:
+Otherwise the files created in ``dags``, ``logs``, ``config`` and ``plugins`` will be created with
+``root`` user ownership. You have to make sure to configure them for the docker-compose:
.. code-block:: bash
@@ -143,6 +143,17 @@ safely ignore it. You can also manually create an ``.env`` file in the same fold
AIRFLOW_UID=50000
+Initialize airflow.cfg (Optional)
+---------------------------------
+
+If you want to initialize ``airflow.cfg`` with default values before launching the airflow service, run.
+
+.. code-block:: bash
+
+ docker compose run airflow-cli airflow config list
+
+This will seed ``airflow.cfg`` with default values in ``config`` folder.
+
Initialize the database
-----------------------
@@ -199,8 +210,8 @@ In a second terminal you can check the condition of the containers and make sure
CONTAINER ID IMAGE |version-spacepad| COMMAND CREATED STATUS PORTS NAMES
247ebe6cf87a apache/airflow:|version| "/usr/bin/dumb-init …" 3 minutes ago Up 3 minutes (healthy) 8080/tcp compose_airflow-worker_1
ed9b09fc84b1 apache/airflow:|version| "/usr/bin/dumb-init …" 3 minutes ago Up 3 minutes (healthy) 8080/tcp compose_airflow-scheduler_1
- 7cb1fb603a98 apache/airflow:|version| "/usr/bin/dumb-init …" 3 minutes ago Up 3 minutes (healthy) 0.0.0.0:8080->8080/tcp compose_airflow-webserver_1
- 74f3bbe506eb postgres:13 |version-spacepad| "docker-entrypoint.s…" 18 minutes ago Up 17 minutes (healthy) 5432/tcp compose_postgres_1
+ 7cb1fb603a98 apache/airflow:|version| "/usr/bin/dumb-init …" 3 minutes ago Up 3 minutes (healthy) 0.0.0.0:8080->8080/tcp compose_airflow-api_server_1
+ 74f3bbe506eb postgres:16 |version-spacepad| "docker-entrypoint.s…" 18 minutes ago Up 17 minutes (healthy) 5432/tcp compose_postgres_1
0bd6576d23cb redis:latest |version-spacepad| "docker-entrypoint.s…" 10 hours ago Up 17 minutes (healthy) 0.0.0.0:6379->6379/tcp compose_redis_1
Accessing the environment
@@ -268,7 +279,7 @@ Here is a sample ``curl`` command, which sends a request to retrieve a pool list
.. code-block:: bash
- ENDPOINT_URL="http://localhost:8080/"
+ ENDPOINT_URL="http://localhost:8080"
curl -X GET \
--user "airflow:airflow" \
"${ENDPOINT_URL}/api/v1/pools"
@@ -296,11 +307,13 @@ Examples of how you can extend the image with custom providers, python packages,
apt packages and more can be found in :doc:`Building the image `.
.. note::
- Creating custom images means that you need to maintain also a level of automation as you need to re-create the images
- when either the packages you want to install or Airflow is upgraded. Please do not forget about keeping these scripts.
- Also keep in mind, that in cases when you run pure Python tasks, you can use the
- `Python Virtualenv functions <_howto/operator:PythonVirtualenvOperator>`_ which will
- dynamically source and install python dependencies during runtime. With Airflow 2.8.0 Virtualenvs can also be cached.
+ Creating custom images means that you need to maintain also a level of
+ automation as you need to re-create the images when either the packages you
+ want to install or Airflow is upgraded. Please do not forget about keeping
+ these scripts. Also keep in mind, that in cases when you run pure Python
+ tasks, you can use :ref:`Python Virtualenv functions `,
+ which will dynamically source and install python dependencies during runtime.
+ With Airflow 2.8.0, virtualenvs can also be cached.
Special case - adding dependencies via requirements.txt file
============================================================
@@ -346,12 +359,9 @@ Special case - Adding a custom config file
If you have a custom config file and wish to use it in your Airflow instance, you need to perform the following steps:
-1) Remove comment from the ``AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'`` line
- in the ``docker-compose.yaml`` file.
-
-2) Place your custom ``airflow.cfg`` file in the local config folder.
+1) Replace the auto-generated ``airflow.cfg`` file in the local config folder with your custom config file.
-3) If your config file has a different name than ``airflow.cfg``, adjust the filename in
+2) If your config file has a different name than ``airflow.cfg``, adjust the filename in
``AIRFLOW_CONFIG: '/opt/airflow/config/airflow.cfg'``
Networking
diff --git a/airflow-core/docs/howto/dynamic-dag-generation.rst b/airflow-core/docs/howto/dynamic-dag-generation.rst
index 814b620ea719b..734e89f5d805d 100644
--- a/airflow-core/docs/howto/dynamic-dag-generation.rst
+++ b/airflow-core/docs/howto/dynamic-dag-generation.rst
@@ -40,7 +40,8 @@ If you want to use variables to configure your code, you should always use
`environment variables `_ in your
top-level code rather than :doc:`Airflow Variables `. Using Airflow Variables
in top-level code creates a connection to the metadata DB of Airflow to fetch the value, which can slow
-down parsing and place extra load on the DB. See the `best practices on Airflow Variables `_
+down parsing and place extra load on the DB. See
+:ref:`best practices on Airflow Variables `
to make the best use of Airflow Variables in your dags using Jinja templates.
For example you could set ``DEPLOYMENT`` variable differently for your production and development
diff --git a/airflow-core/docs/howto/email-config.rst b/airflow-core/docs/howto/email-config.rst
index 82a3e745c1b6e..c3373447654d7 100644
--- a/airflow-core/docs/howto/email-config.rst
+++ b/airflow-core/docs/howto/email-config.rst
@@ -88,7 +88,7 @@ Send email using SendGrid
Using Default SMTP
^^^^^^^^^^^^^^^^^^
-You can use the default airflow SMTP backend to send email with SendGrid
+You can use the default Airflow SMTP backend to send email with SendGrid
.. code-block:: ini
@@ -184,6 +184,14 @@ Follow the steps below to enable it:
email_conn_id = aws_default
from_email = From email
+ Equivalent environment variables looks like
+
+ .. code-block::
+
+ AIRFLOW__EMAIL__EMAIL_BACKEND=airflow.providers.amazon.aws.utils.emailer.send_email
+ AIRFLOW__EMAIL__EMAIL_CONN_ID=aws_default
+ AIRFLOW__EMAIL__FROM_EMAIL=email@example.com
+
Note that for SES, you must configure from_email to the valid email that can send messages from SES.
3. Create a connection called ``aws_default``, or choose a custom connection
diff --git a/airflow-core/docs/howto/export-more-env-vars.rst b/airflow-core/docs/howto/export-more-env-vars.rst
index e393f479302d1..a35b3be6fb5af 100644
--- a/airflow-core/docs/howto/export-more-env-vars.rst
+++ b/airflow-core/docs/howto/export-more-env-vars.rst
@@ -23,7 +23,7 @@ Export dynamic environment variables available for operators to use
The key value pairs returned in ``get_airflow_context_vars`` defined in
-``airflow_local_settings.py`` are injected to default airflow context environment variables,
+``airflow_local_settings.py`` are injected to default Airflow context environment variables,
which are available as environment variables when running tasks. Note, both key and
value are must be string.
diff --git a/airflow-core/docs/howto/index.rst b/airflow-core/docs/howto/index.rst
index aa8372dd9195a..396b0877838f4 100644
--- a/airflow-core/docs/howto/index.rst
+++ b/airflow-core/docs/howto/index.rst
@@ -30,7 +30,9 @@ configuring an Airflow environment.
:maxdepth: 2
Using the CLI
+ Using the REST API <../security/api>
add-dag-tags
+ add-owner-links
notifications
set-config
set-up-database
@@ -51,3 +53,4 @@ configuring an Airflow environment.
email-config
dynamic-dag-generation
docker-compose/index
+ run-with-self-signed-certificate
diff --git a/airflow-core/docs/howto/listener-plugin.rst b/airflow-core/docs/howto/listener-plugin.rst
index 20569a3fc6f8d..9d13909354813 100644
--- a/airflow-core/docs/howto/listener-plugin.rst
+++ b/airflow-core/docs/howto/listener-plugin.rst
@@ -44,14 +44,14 @@ Using this plugin, following events can be listened:
* dag run is in running state.
* dag run is in success state.
* dag run is in failure state.
- * on start before event like airflow job, scheduler
- * before stop for event like airflow job, scheduler
+ * on start before event like Airflow job, scheduler
+ * before stop for event like Airflow job, scheduler
Listener Registration
---------------------
A listener plugin with object reference to listener object is registered
-as part of airflow plugin. The following is a
+as part of Airflow plugin. The following is a
skeleton for us to implement a new listener:
.. code-block:: python
diff --git a/airflow-core/docs/howto/run-behind-proxy.rst b/airflow-core/docs/howto/run-behind-proxy.rst
index 294823753a585..483f3e796904c 100644
--- a/airflow-core/docs/howto/run-behind-proxy.rst
+++ b/airflow-core/docs/howto/run-behind-proxy.rst
@@ -51,6 +51,11 @@ To do so, you need to set the following setting in your ``airflow.cfg``::
}
}
+- Some parts of the UI are rendered inside iframes (Auth managers security links for instance), you need to make sure that you are not setting a restricted CSP for iframe rendering
+ such as ``frame-ancestors 'none'``. You can set the CSP header in your reverse proxy configuration, for example::
+
+ add_header Content-Security-Policy "frame-ancestors 'self';";
+
- Use ``--proxy-headers`` CLI flag to tell Uvicorn to respect these headers: ``airflow api-server --proxy-headers``
- If your proxy server is not on the same host (or in the same docker container) as Airflow, then you will need to
@@ -58,6 +63,9 @@ To do so, you need to set the following setting in your ``airflow.cfg``::
`Uvicorn's docs `_. For the full options you can pass here.
(Please note the ``--forwarded-allow-ips`` CLI option does not exist in Airflow.)
+- Please make sure your proxy does not enforce http-only status on the Set-Cookie headers.
+ Airflow frontend needs to access the cookies through javascript, and a http-only flag would disturb this functionality.
+
.. spelling::
Uvicorn
diff --git a/airflow-core/docs/howto/run-with-self-signed-certificate.rst b/airflow-core/docs/howto/run-with-self-signed-certificate.rst
new file mode 100644
index 0000000000000..53a8446d0f724
--- /dev/null
+++ b/airflow-core/docs/howto/run-with-self-signed-certificate.rst
@@ -0,0 +1,83 @@
+.. 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.
+
+Running Airflow with a self-signed certificate
+##############################################
+
+Airflow can be configured to run with a self-signed certificate but this
+requires a couple of extra steps to enable Workers to trust the API Server.
+This guide is based on the :doc:`docker-compose/index` setup.
+
+.. caution::
+
+ This procedure is intended for learning, exploration and development. It is
+ not suitable for production use.
+
+Generating the certificate
+==========================
+
+The first step is the generation of the certificate. This requires the addition
+of ``localhost`` and ``airflow-apiserver`` as Subject Alternative Names so that
+the health check and Worker to API Server communications function.
+
+.. code-block:: sh
+
+ export AIRFLOW_CN=example-common-name
+ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
+ -sha256 -days 3650 -nodes \
+ -subj "/CN=$AIRFLOW_CN" \
+ -addext "subjectAltName=DNS:localhost,DNS:airflow-apiserver"
+
+Where ``example-common-name`` is the common name of your server. Place
+``cert.pem`` and ``key.pem`` in the ``config`` folder.
+
+Altering ``docker-compose.yaml``
+================================
+
+Add the following two environment variables below and alter the API Server URL
+to HTTPS:
+
+.. code-block:: sh
+
+ AIRFLOW__CORE__EXECUTION_API_SERVER_URL: 'https://airflow-apiserver:8080/execution/'
+ # Added to enable SSL
+ AIRFLOW__API__SSL_CERT: '/opt/airflow/config/cert.pem'
+ AIRFLOW__API__SSL_KEY: '/opt/airflow/config/key.pem'
+
+Alter the API Server health check to trust the certificate:
+
+.. code-block:: sh
+
+ airflow-apiserver:
+ <<: *airflow-common
+ command: api-server
+ ports:
+ - "8080:8080"
+ healthcheck:
+ # Add --cacert to trust certificate
+ test: ["CMD", "curl", "--fail", "--cacert", "${AIRFLOW_PROJ_DIR:-.}/config/cert.pem", "https://localhost:8080/api/v2/version"]
+
+Running Airflow
+===============
+
+Now you can start all services:
+
+.. code-block:: sh
+
+ docker compose up
+
+The webserver is available at: ``https://localhost:8080``
diff --git a/airflow-core/docs/howto/run-with-systemd.rst b/airflow-core/docs/howto/run-with-systemd.rst
index 92dafd5760cd4..1006ce4a06af6 100644
--- a/airflow-core/docs/howto/run-with-systemd.rst
+++ b/airflow-core/docs/howto/run-with-systemd.rst
@@ -27,6 +27,12 @@ In the ``scripts/systemd`` directory, you can find unit files that
have been tested on Redhat based systems. These files can be used as-is by copying them over to
``/usr/lib/systemd/system``.
+You can find the latest systemd unit files on GitHub:
+https://github.com/apache/airflow/tree/main/scripts/systemd
+
+Assumptions
+-----------
+
The following **assumptions** have been made while creating these unit files:
#. Airflow runs as the following ``user:group`` ``airflow:airflow``.
@@ -34,7 +40,32 @@ The following **assumptions** have been made while creating these unit files:
If this is not the case, appropriate changes will need to be made.
+Environment Configuration
+-------------------------
+
Please **note** that environment configuration is picked up from ``/etc/sysconfig/airflow``.
An example file is supplied within ``scripts/systemd``.
You can also define configuration at :envvar:`AIRFLOW_HOME` or :envvar:`AIRFLOW_CONFIG`.
+
+Using Virtual Environments
+--------------------------
+
+.. note::
+ If Airflow is installed inside a virtual environment (e.g. ``venv`` or ``conda``), you must update the ``ExecStart`` line in each systemd unit file to activate the virtualenv first.
+
+ Example:
+
+ .. code-block:: ini
+
+ ExecStart=/bin/bash -c 'source /home/airflow/airflow_venv/bin/activate && airflow scheduler'
+
+ Replace ``/home/airflow/airflow_venv/`` with the path to your virtual environment.
+
+New Airflow 3.0 Services
+------------------------
+
+Since Apache Airflow 3.0, additional components have been split out into separate services. The following new unit files are available:
+
+- ``airflow-triggerer.service`` for deferrable task triggering
+- ``airflow-api.service`` for the standalone REST API server
diff --git a/airflow-core/docs/howto/set-config.rst b/airflow-core/docs/howto/set-config.rst
index b25bf3470a85f..13a46e15f57e7 100644
--- a/airflow-core/docs/howto/set-config.rst
+++ b/airflow-core/docs/howto/set-config.rst
@@ -105,7 +105,7 @@ The following config options support this ``_cmd`` and ``_secret`` version:
* ``result_backend`` in ``[celery]`` section
* ``password`` in ``[atlas]`` section
* ``smtp_password`` in ``[smtp]`` section
-* ``secret_key`` in ``[webserver]`` section
+* ``secret_key`` in ``[api]`` section
The ``_cmd`` config options can also be set using a corresponding environment variable
the same way the usual config options can. For example:
@@ -159,12 +159,12 @@ the example below.
.. note::
Use the same configuration across all the Airflow components. While each component
does not require all, some configurations need to be same otherwise they would not
- work as expected. A good example for that is :ref:`secret_key` which
+ work as expected. A good example for that is :ref:`secret_key` which
should be same on the Webserver and Worker to allow Webserver to fetch logs from Worker.
The webserver key is also used to authorize requests to Celery workers when logs are retrieved. The token
generated using the secret key has a short expiry time though - make sure that time on ALL the machines
- that you run airflow components on is synchronized (for example using ntpd) otherwise you might get
+ that you run Airflow components on is synchronized (for example using ntpd) otherwise you might get
"forbidden" errors when the logs are accessed.
.. _set-config:configuring-local-settings:
@@ -196,27 +196,3 @@ Example settings you can configure this way:
* :ref:`Customize your UI `
* :ref:`Configure more variables to export `
* :ref:`Customize your DB configuration `
-
-
-Configuring Flask Application for Airflow Webserver
-===================================================
-
-Airflow uses Flask to render the web UI. When you initialize the Airflow webserver, predefined configuration
-is used, based on the ``webserver`` section of the ``airflow.cfg`` file. You can override these settings
-and add any extra settings however by adding flask configuration to ``webserver_config.py`` file in your
-``$AIRFLOW_HOME`` directory. This file is automatically loaded by the webserver.
-
-For example if you would like to change rate limit strategy to "moving window", you can set the
-``RATELIMIT_STRATEGY`` to ``moving-window``.
-
-You could also enhance / modify the underlying flask app directly,
-as the `app context `_ is pushed to ``webserver_config.py``:
-
-.. code-block:: python
-
- from flask import current_app as app
-
-
- @app.before_request
- def print_custom_message() -> None:
- print("Executing before every request")
diff --git a/airflow-core/docs/howto/set-up-database.rst b/airflow-core/docs/howto/set-up-database.rst
index 27187006804f0..245a8c912c888 100644
--- a/airflow-core/docs/howto/set-up-database.rst
+++ b/airflow-core/docs/howto/set-up-database.rst
@@ -339,7 +339,7 @@ Migrating off MsSQL Server
As with Airflow 2.9.0 the support of MSSQL has ended, a migration script can help with
Airflow version 2.7.x or 2.8.x to migrate off SQL-Server. The migration script is available in
-`airflow-mssql-migration repo on Github `_.
+`airflow-mssql-migration repo on GitHub `_.
Note that the migration script is provided without support and warranty.
diff --git a/airflow-core/docs/howto/usage-cli.rst b/airflow-core/docs/howto/usage-cli.rst
index a3bb13e075994..a7dcc71abba4d 100644
--- a/airflow-core/docs/howto/usage-cli.rst
+++ b/airflow-core/docs/howto/usage-cli.rst
@@ -44,7 +44,7 @@ For permanent (but not global) airflow activation, use:
register-python-argcomplete airflow >> ~/.bashrc
-For one-time activation of argcomplete for airflow only, use:
+For one-time activation of argcomplete for Airflow only, use:
.. code-block:: bash
@@ -76,7 +76,7 @@ For example, to print the ``example_complex`` DAG to the terminal:
airflow dags show example_complex
-This will print the rendered DAG structure (similar to :ref:`Graph `) to the screen in DOT format.
+This will print the rendered DAG structure to the screen in DOT format.
Multiple file formats are supported. To use them, add the argument ``--save [filename].[format]``.
diff --git a/airflow-core/docs/howto/variable.rst b/airflow-core/docs/howto/variable.rst
index 20c36597c94e6..a07a04a154571 100644
--- a/airflow-core/docs/howto/variable.rst
+++ b/airflow-core/docs/howto/variable.rst
@@ -61,10 +61,20 @@ You can use them in your dags as:
Single underscores surround ``VAR``. This is in contrast with the way ``airflow.cfg``
parameters are stored, where double underscores surround the config section name.
- Variables set using Environment Variables would not appear in the Airflow UI but you will
- be able to use them in your DAG file. Variables set using Environment Variables will also
+ Variables set using Environment Variables will also
take precedence over variables defined in the Airflow UI.
+Visibility in UI and CLI
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Variables defined through environment variables are **not displayed** in the Airflow UI or listed using ``airflow variables list``.
+
+This is because these variables are **resolved dynamically at runtime**, typically on the **worker** process executing your task. They are not stored in the metadata database or loaded in the webserver or scheduler environment.
+
+This supports secure deployment patterns where environment-based secrets (e.g. via ``.env`` files, Docker, or Kubernetes secrets) are injected only into runtime components like workers — and not into components exposed to users, like the webserver.
+
+If you want variables to appear in the UI for visibility or editing, define them in the metadata database instead.
+
Securing Variables
------------------
diff --git a/airflow-core/docs/img/airflow-2-arch.png b/airflow-core/docs/img/airflow-2-arch.png
new file mode 100644
index 0000000000000..1a37ae6748c3b
Binary files /dev/null and b/airflow-core/docs/img/airflow-2-arch.png differ
diff --git a/airflow-core/docs/img/airflow-3-arch.png b/airflow-core/docs/img/airflow-3-arch.png
new file mode 100644
index 0000000000000..c09acad3968d1
Binary files /dev/null and b/airflow-core/docs/img/airflow-3-arch.png differ
diff --git a/airflow-core/docs/img/airflow_erd.sha256 b/airflow-core/docs/img/airflow_erd.sha256
index 33fe09fd943e4..06cc1a78cd12e 100644
--- a/airflow-core/docs/img/airflow_erd.sha256
+++ b/airflow-core/docs/img/airflow_erd.sha256
@@ -1 +1 @@
-bc93e7288a7a8355b15dc721accaf80260f370f3afa0d478248f9fe4692a1f1d
\ No newline at end of file
+ad634ee7ad7d914013df2cddccb47a9a6201ff19680c71089300e61539032293
\ No newline at end of file
diff --git a/airflow-core/docs/img/airflow_erd.svg b/airflow-core/docs/img/airflow_erd.svg
index 7ce02c7187b1a..104180ec20ef5 100644
--- a/airflow-core/docs/img/airflow_erd.svg
+++ b/airflow-core/docs/img/airflow_erd.svg
@@ -4,11 +4,11 @@
-