This is an automated email from the ASF dual-hosted git repository.
henry3260 pushed a commit to branch v3-3-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-3-test by this push:
new d67566d4b01 [v3-3-test] Show each Dag only once in airflow dags list
(#70934) (#71481)
d67566d4b01 is described below
commit d67566d4b019741ea14efd03ef5f7ac04eb13397
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Aug 12 17:22:28 2026 +0800
[v3-3-test] Show each Dag only once in airflow dags list (#70934) (#71481)
Airflow 3 stores one serialized_dag row per Dag version, so every Dag with
more than one version was listed once per version.
(cherry picked from commit b9ff1d776943c07e09cf541e4f4139e35cfb6570)
Co-authored-by: Y-C <[email protected]>
Co-authored-by: Eason09053360
<[email protected]>
---
.../src/airflow/cli/commands/dag_command.py | 4 ++-
.../tests/unit/cli/commands/test_dag_command.py | 31 ++++++++++++++++++++++
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/airflow-core/src/airflow/cli/commands/dag_command.py
b/airflow-core/src/airflow/cli/commands/dag_command.py
index b6688643c5d..7cfbe294b19 100644
--- a/airflow-core/src/airflow/cli/commands/dag_command.py
+++ b/airflow-core/src/airflow/cli/commands/dag_command.py
@@ -574,7 +574,9 @@ def dag_list_dags(args, *, session: Session = NEW_SESSION)
-> None:
dags_list.extend(list(dagbag.dags.values()))
dagbag_import_errors += len(dagbag.import_errors)
else:
- dags_list.extend(cast("DAG", sm.dag) for sm in
session.scalars(select(SerializedDagModel)))
+ dags_list.extend(
+ cast("DAG", dag) for dag in
SerializedDagModel.read_all_dags(session=session).values()
+ )
pie_stmt = select(func.count()).select_from(ParseImportError)
if args.bundle_name:
pie_stmt =
pie_stmt.where(ParseImportError.bundle_name.in_(args.bundle_name))
diff --git a/airflow-core/tests/unit/cli/commands/test_dag_command.py
b/airflow-core/tests/unit/cli/commands/test_dag_command.py
index 059ce1d2f26..e4d2886faf0 100644
--- a/airflow-core/tests/unit/cli/commands/test_dag_command.py
+++ b/airflow-core/tests/unit/cli/commands/test_dag_command.py
@@ -352,6 +352,37 @@ class TestCliDags:
assert key in dag_list[0]
assert any("airflow/example_dags/example_complex.py" in d["fileloc"]
for d in dag_list)
+ def test_cli_list_dags_with_multiple_dag_versions(self, dag_maker,
stdout_capture, session):
+ clear_db_dags()
+
+ with dag_maker("test_dag_versions", schedule=None,
start_date=DEFAULT_DATE):
+ EmptyOperator(task_id="task1")
+ # A version with task instances is kept rather than updated in place,
so the next sync
+ # adds a second row for the same dag_id.
+ dag_maker.create_dagrun()
+
+ with DAG("test_dag_versions", schedule=None, start_date=DEFAULT_DATE)
as dag:
+ EmptyOperator(task_id="task1")
+ EmptyOperator(task_id="task2")
+ sync_dag_to_db(dag)
+
+ assert (
+ session.scalar(
+ select(func.count())
+ .select_from(SerializedDagModel)
+ .where(SerializedDagModel.dag_id == "test_dag_versions")
+ )
+ == 2
+ )
+
+ args = self.parser.parse_args(["dags", "list", "--columns", "dag_id",
"--output", "json"])
+ with stdout_capture as temp_stdout:
+ dag_command.dag_list_dags(args)
+ assert json.loads(temp_stdout.getvalue()) == [{"dag_id":
"test_dag_versions"}]
+
+ # Rebuild Test DB for other tests
+ self.setup_class()
+
def test_cli_list_local_dags(self, stdout_capture):
# Clear the database
clear_db_dags()