This is an automated email from the ASF dual-hosted git repository.
kaxilnaik pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 530f6d0d97d Consolidate unreleased Execution API versions under
2026-04-06 (#64480)
530f6d0d97d is described below
commit 530f6d0d97d3ed79bb4e698fb43d469c8d58e821
Author: Rahul Vats <[email protected]>
AuthorDate: Mon Mar 30 20:10:22 2026 +0530
Consolidate unreleased Execution API versions under 2026-04-06 (#64480)
---
.../api_fastapi/execution_api/versions/__init__.py | 19 ++--
.../execution_api/versions/v2025_11_07.py | 54 -----------
.../execution_api/versions/v2025_12_08.py | 41 --------
.../versions/{v2026_03_31.py => v2026_04_06.py} | 105 ++++++++++++++++-----
.../execution_api/versions/v2026_04_13.py | 28 ------
.../execution_api/versions/head/test_dag_runs.py | 2 +-
.../execution_api/versions/v2026_03_31/__init__.py | 16 ----
.../{v2025_11_07 => v2026_04_06}/__init__.py | 0
.../{v2025_11_07 => v2026_04_06}/test_dag_runs.py | 3 +-
.../{v2026_03_31 => v2026_04_06}/test_dags.py | 3 +-
.../test_task_instances.py | 4 +-
.../src/airflow/sdk/api/datamodels/_generated.py | 2 +-
12 files changed, 100 insertions(+), 177 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/execution_api/versions/__init__.py
b/airflow-core/src/airflow/api_fastapi/execution_api/versions/__init__.py
index 2cbe2e3007b..646831501a7 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/versions/__init__.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/versions/__init__.py
@@ -28,31 +28,30 @@ from airflow.api_fastapi.execution_api.versions.v2025_08_10
import (
from airflow.api_fastapi.execution_api.versions.v2025_09_23 import
AddDagVersionIdField
from airflow.api_fastapi.execution_api.versions.v2025_10_27 import
MakeDagRunConfNullable
from airflow.api_fastapi.execution_api.versions.v2025_11_05 import
AddTriggeringUserNameField
-from airflow.api_fastapi.execution_api.versions.v2025_11_07 import
AddPartitionKeyField
-from airflow.api_fastapi.execution_api.versions.v2025_12_08 import (
+from airflow.api_fastapi.execution_api.versions.v2026_04_06 import (
+ AddDagEndpoint,
AddDagRunDetailEndpoint,
- MovePreviousRunEndpoint,
-)
-from airflow.api_fastapi.execution_api.versions.v2026_03_31 import (
AddNoteField,
+ AddPartitionKeyField,
MakeDagRunStartDateNullable,
ModifyDeferredTaskKwargsToJsonValue,
+ MovePreviousRunEndpoint,
RemoveUpstreamMapIndexesField,
)
-from airflow.api_fastapi.execution_api.versions.v2026_04_13 import
AddDagEndpoint
bundle = VersionBundle(
HeadVersion(),
- Version("2026-04-13", AddDagEndpoint),
Version(
- "2026-03-31",
+ "2026-04-06",
+ AddPartitionKeyField,
+ MovePreviousRunEndpoint,
+ AddDagRunDetailEndpoint,
MakeDagRunStartDateNullable,
ModifyDeferredTaskKwargsToJsonValue,
RemoveUpstreamMapIndexesField,
AddNoteField,
+ AddDagEndpoint,
),
- Version("2025-12-08", MovePreviousRunEndpoint, AddDagRunDetailEndpoint),
- Version("2025-11-07", AddPartitionKeyField),
Version("2025-11-05", AddTriggeringUserNameField),
Version("2025-10-27", MakeDagRunConfNullable),
Version("2025-09-23", AddDagVersionIdField),
diff --git
a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2025_11_07.py
b/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2025_11_07.py
deleted file mode 100644
index 117ba492455..00000000000
--- a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2025_11_07.py
+++ /dev/null
@@ -1,54 +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.
-
-from __future__ import annotations
-
-from cadwyn import ResponseInfo, VersionChange,
convert_response_to_previous_version_for, schema
-
-from airflow.api_fastapi.execution_api.datamodels.asset_event import (
- AssetEventResponse,
- AssetEventsResponse,
- DagRunAssetReference,
-)
-from airflow.api_fastapi.execution_api.datamodels.dagrun import
TriggerDAGRunPayload
-from airflow.api_fastapi.execution_api.datamodels.taskinstance import DagRun,
TIRunContext
-
-
-class AddPartitionKeyField(VersionChange):
- """Add the `partition_key` field to DagRun model."""
-
- description = __doc__
-
- instructions_to_migrate_to_previous_version = (
- schema(DagRun).field("partition_key").didnt_exist,
- schema(AssetEventResponse).field("partition_key").didnt_exist,
- schema(TriggerDAGRunPayload).field("partition_key").didnt_exist,
- schema(DagRunAssetReference).field("partition_key").didnt_exist,
- )
-
- @convert_response_to_previous_version_for(TIRunContext) # type:
ignore[arg-type]
- def remove_partition_key_from_dag_run(response: ResponseInfo) -> None: #
type: ignore[misc]
- """Remove the `partition_key` field from the dag_run object when
converting to the previous version."""
- if "dag_run" in response.body and isinstance(response.body["dag_run"],
dict):
- response.body["dag_run"].pop("partition_key", None)
-
- @convert_response_to_previous_version_for(AssetEventsResponse) # type:
ignore[arg-type]
- def remove_partition_key_from_asset_events(response: ResponseInfo) ->
None: # type: ignore[misc]
- """Remove the `partition_key` field from the dag_run object when
converting to the previous version."""
- events = response.body["asset_events"]
- for elem in events:
- elem.pop("partition_key", None)
diff --git
a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2025_12_08.py
b/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2025_12_08.py
deleted file mode 100644
index 3394036bf15..00000000000
--- a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2025_12_08.py
+++ /dev/null
@@ -1,41 +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.
-
-from __future__ import annotations
-
-from cadwyn import VersionChange, endpoint
-
-
-class MovePreviousRunEndpoint(VersionChange):
- """Add new previous-run endpoint and migrate old endpoint."""
-
- description = __doc__
-
- instructions_to_migrate_to_previous_version = (
- endpoint("/dag-runs/previous", ["GET"]).didnt_exist,
- endpoint("/dag-runs/{dag_id}/previous", ["GET"]).existed,
- )
-
-
-class AddDagRunDetailEndpoint(VersionChange):
- """Add dag run detail endpoint."""
-
- description = __doc__
-
- instructions_to_migrate_to_previous_version = (
- endpoint("/dag-runs/{dag_id}/{run_id}", ["GET"]).didnt_exist,
- )
diff --git
a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_03_31.py
b/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_04_06.py
similarity index 62%
rename from
airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_03_31.py
rename to
airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_04_06.py
index 2d14493e81f..85ec1f2a608 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_03_31.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_04_06.py
@@ -19,9 +19,15 @@ from __future__ import annotations
from typing import Any
-from cadwyn import ResponseInfo, VersionChange,
convert_response_to_previous_version_for, schema
+from cadwyn import ResponseInfo, VersionChange,
convert_response_to_previous_version_for, endpoint, schema
from airflow.api_fastapi.common.types import UtcDateTime
+from airflow.api_fastapi.execution_api.datamodels.asset_event import (
+ AssetEventResponse,
+ AssetEventsResponse,
+ DagRunAssetReference,
+)
+from airflow.api_fastapi.execution_api.datamodels.dagrun import
TriggerDAGRunPayload
from airflow.api_fastapi.execution_api.datamodels.taskinstance import (
DagRun,
TIDeferredStatePayload,
@@ -29,6 +35,79 @@ from
airflow.api_fastapi.execution_api.datamodels.taskinstance import (
)
+class AddPartitionKeyField(VersionChange):
+ """Add the `partition_key` field to DagRun model."""
+
+ description = __doc__
+
+ instructions_to_migrate_to_previous_version = (
+ schema(DagRun).field("partition_key").didnt_exist,
+ schema(AssetEventResponse).field("partition_key").didnt_exist,
+ schema(TriggerDAGRunPayload).field("partition_key").didnt_exist,
+ schema(DagRunAssetReference).field("partition_key").didnt_exist,
+ )
+
+ @convert_response_to_previous_version_for(TIRunContext) # type:
ignore[arg-type]
+ def remove_partition_key_from_dag_run(response: ResponseInfo) -> None: #
type: ignore[misc]
+ """Remove the `partition_key` field from the dag_run object when
converting to the previous version."""
+ if "dag_run" in response.body and isinstance(response.body["dag_run"],
dict):
+ response.body["dag_run"].pop("partition_key", None)
+
+ @convert_response_to_previous_version_for(AssetEventsResponse) # type:
ignore[arg-type]
+ def remove_partition_key_from_asset_events(response: ResponseInfo) ->
None: # type: ignore[misc]
+ """Remove the `partition_key` field from the dag_run object when
converting to the previous version."""
+ events = response.body["asset_events"]
+ for elem in events:
+ elem.pop("partition_key", None)
+
+
+class MovePreviousRunEndpoint(VersionChange):
+ """Add new previous-run endpoint and migrate old endpoint."""
+
+ description = __doc__
+
+ instructions_to_migrate_to_previous_version = (
+ endpoint("/dag-runs/previous", ["GET"]).didnt_exist,
+ endpoint("/dag-runs/{dag_id}/previous", ["GET"]).existed,
+ )
+
+
+class AddDagRunDetailEndpoint(VersionChange):
+ """Add dag run detail endpoint."""
+
+ description = __doc__
+
+ instructions_to_migrate_to_previous_version = (
+ endpoint("/dag-runs/{dag_id}/{run_id}", ["GET"]).didnt_exist,
+ )
+
+
+class MakeDagRunStartDateNullable(VersionChange):
+ """Make DagRun.start_date field nullable for runs that haven't started
yet."""
+
+ description = __doc__
+
+ instructions_to_migrate_to_previous_version =
(schema(DagRun).field("start_date").had(type=UtcDateTime),)
+
+ @convert_response_to_previous_version_for(TIRunContext) # type:
ignore[arg-type]
+ def ensure_start_date_in_ti_run_context(response: ResponseInfo) -> None:
# type: ignore[misc]
+ """
+ Ensure start_date is never None in DagRun for previous API versions.
+
+ Older Task SDK clients expect start_date to be non-nullable. When the
+ DagRun hasn't started yet (e.g. queued), fall back to run_after.
+ """
+ dag_run = response.body.get("dag_run")
+ if isinstance(dag_run, dict) and dag_run.get("start_date") is None:
+ dag_run["start_date"] = dag_run.get("run_after")
+
+ @convert_response_to_previous_version_for(DagRun) # type: ignore[arg-type]
+ def ensure_start_date_in_dag_run(response: ResponseInfo) -> None: # type:
ignore[misc]
+ """Ensure start_date is never None in direct DagRun responses for
previous API versions."""
+ if response.body.get("start_date") is None:
+ response.body["start_date"] = response.body.get("run_after")
+
+
class ModifyDeferredTaskKwargsToJsonValue(VersionChange):
"""Change the types of `trigger_kwargs` and `next_kwargs` in
TIDeferredStatePayload to JsonValue."""
@@ -71,27 +150,9 @@ class AddNoteField(VersionChange):
response.body["dag_run"].pop("note", None)
-class MakeDagRunStartDateNullable(VersionChange):
- """Make DagRun.start_date field nullable for runs that haven't started
yet."""
+class AddDagEndpoint(VersionChange):
+ """Add the `/dags/{dag_id}` endpoint."""
description = __doc__
- instructions_to_migrate_to_previous_version =
(schema(DagRun).field("start_date").had(type=UtcDateTime),)
-
- @convert_response_to_previous_version_for(TIRunContext) # type:
ignore[arg-type]
- def ensure_start_date_in_ti_run_context(response: ResponseInfo) -> None:
# type: ignore[misc]
- """
- Ensure start_date is never None in DagRun for previous API versions.
-
- Older Task SDK clients expect start_date to be non-nullable. When the
- DagRun hasn't started yet (e.g. queued), fall back to run_after.
- """
- dag_run = response.body.get("dag_run")
- if isinstance(dag_run, dict) and dag_run.get("start_date") is None:
- dag_run["start_date"] = dag_run.get("run_after")
-
- @convert_response_to_previous_version_for(DagRun) # type: ignore[arg-type]
- def ensure_start_date_in_dag_run(response: ResponseInfo) -> None: # type:
ignore[misc]
- """Ensure start_date is never None in direct DagRun responses for
previous API versions."""
- if response.body.get("start_date") is None:
- response.body["start_date"] = response.body.get("run_after")
+ instructions_to_migrate_to_previous_version = (endpoint("/dags/{dag_id}",
["GET"]).didnt_exist,)
diff --git
a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_04_13.py
b/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_04_13.py
deleted file mode 100644
index 95da513d7bc..00000000000
--- a/airflow-core/src/airflow/api_fastapi/execution_api/versions/v2026_04_13.py
+++ /dev/null
@@ -1,28 +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.
-
-from __future__ import annotations
-
-from cadwyn import VersionChange, endpoint
-
-
-class AddDagEndpoint(VersionChange):
- """Add the `/dags/{dag_id}` endpoint."""
-
- description = __doc__
-
- instructions_to_migrate_to_previous_version = (endpoint("/dags/{dag_id}",
["GET"]).didnt_exist,)
diff --git
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_dag_runs.py
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_dag_runs.py
index 2aa3be51220..a2910313951 100644
---
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_dag_runs.py
+++
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_dag_runs.py
@@ -264,7 +264,7 @@ class TestDagRunDetail:
def test_get_state(self, client, session, dag_maker):
dag_id = "test_dag_id"
# Named deliberately to check if this routes correctly.
- # See v2025_11_07.test_dag_runs::test_get_previous_dag_run_redirect
+ # See v2026_04_06.test_dag_runs::test_get_previous_dag_run_redirect
run_id = "previous"
with dag_maker(dag_id=dag_id, schedule=None, session=session,
serialized=True):
diff --git
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/__init__.py
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/__init__.py
deleted file mode 100644
index 13a83393a91..00000000000
---
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/__init__.py
+++ /dev/null
@@ -1,16 +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.
diff --git
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2025_11_07/__init__.py
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/__init__.py
similarity index 100%
rename from
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2025_11_07/__init__.py
rename to
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/__init__.py
diff --git
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2025_11_07/test_dag_runs.py
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_dag_runs.py
similarity index 93%
rename from
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2025_11_07/test_dag_runs.py
rename to
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_dag_runs.py
index c2821dce55b..a3c7ff77d14 100644
---
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2025_11_07/test_dag_runs.py
+++
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_dag_runs.py
@@ -27,7 +27,8 @@ pytestmark = pytest.mark.db_test
@pytest.fixture
def ver_client(client):
- client.headers["Airflow-API-Version"] = "2025-11-07"
+ """Last released execution API (before 2026-04-06); uses legacy
previous-run path."""
+ client.headers["Airflow-API-Version"] = "2025-11-05"
return client
diff --git
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/test_dags.py
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_dags.py
similarity index 89%
rename from
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/test_dags.py
rename to
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_dags.py
index 72693443944..5fe7fb26fda 100644
---
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/test_dags.py
+++
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_dags.py
@@ -24,7 +24,8 @@ pytestmark = pytest.mark.db_test
@pytest.fixture
def old_ver_client(client):
- client.headers["Airflow-API-Version"] = "2026-03-31"
+ """Last released execution API before `/dags/{dag_id}` was added."""
+ client.headers["Airflow-API-Version"] = "2025-11-05"
return client
diff --git
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/test_task_instances.py
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_task_instances.py
similarity index 96%
rename from
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/test_task_instances.py
rename to
airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_task_instances.py
index 7fb44ce7ebe..8117ac6b69c 100644
---
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_03_31/test_task_instances.py
+++
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/v2026_04_06/test_task_instances.py
@@ -40,8 +40,8 @@ RUN_PATCH_BODY = {
@pytest.fixture
def old_ver_client(client):
- """Client configured to use API version before start_date nullable
change."""
- client.headers["Airflow-API-Version"] = "2025-12-08"
+ """Last released execution API before nullable DagRun.start_date
(2026-04-06 bundle)."""
+ client.headers["Airflow-API-Version"] = "2025-11-05"
return client
diff --git a/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
b/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
index b6c08e9d76c..e08f00562d3 100644
--- a/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
+++ b/task-sdk/src/airflow/sdk/api/datamodels/_generated.py
@@ -27,7 +27,7 @@ from uuid import UUID
from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, JsonValue,
RootModel
-API_VERSION: Final[str] = "2026-04-13"
+API_VERSION: Final[str] = "2026-04-06"
class AssetAliasReferenceAssetEventDagRun(BaseModel):