This is an automated email from the ASF dual-hosted git repository.

vatsrahul1001 pushed a commit to branch v3-4-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-4-test by this push:
     new c07dc92d5dc [v3-4-test] Fix tasks clear --task-regex matching as a 
plain substring (#72941) (#75325)
c07dc92d5dc is described below

commit c07dc92d5dcdb107628a30fa067573bbe8d4f518
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Oct 22 23:53:10 2026 +0530

    [v3-4-test] Fix tasks clear --task-regex matching as a plain substring 
(#72941) (#75325)
    
    * Fix tasks clear --task-regex matching as a plain substring
    
    The flag, its help text and the docs all promise a regular expression,
    but since #47360 removed regex support from partial_subset (to stop the
    REST API root parameter from being parsed as a regex) the CLI passed the
    pattern straight through and it was matched as a literal substring. Any
    pattern with metacharacters silently matched nothing and cleared nothing.
    
    Resolve the regex in the CLI, the only caller that promises one, and
    hand partial_subset a concrete set of task ids so the shared method
    keeps its non-regex contract. An invalid pattern now exits with a
    one-line error instead of a traceback.
    
    * Validate --task-regex before looking up the Dag
    
    A mistyped Dag id hid an invalid task pattern until the Dag id was fixed,
    and with --dag-regex every Dag file was parsed before the pattern error
    was reported.
    
    ---------
    (cherry picked from commit aee2d4d512209c112c7df1efc6260bf534615102)
    
    Co-authored-by: Y-C <[email protected]>
    Co-authored-by: Eason09053360 
<[email protected]>
---
 .../src/airflow/cli/commands/task_command.py       | 12 +++++++++--
 .../tests/unit/cli/commands/test_task_command.py   | 23 ++++++++++++++++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/airflow-core/src/airflow/cli/commands/task_command.py 
b/airflow-core/src/airflow/cli/commands/task_command.py
index 550f8f64519..365278a4b5f 100644
--- a/airflow-core/src/airflow/cli/commands/task_command.py
+++ b/airflow-core/src/airflow/cli/commands/task_command.py
@@ -23,6 +23,7 @@ import importlib
 import json
 import logging
 import os
+import re
 import textwrap
 from contextlib import redirect_stdout
 from typing import TYPE_CHECKING, Protocol, cast
@@ -592,6 +593,13 @@ def task_render(args, dag: DAG | None = None) -> None:
 def task_clear(args) -> None:
     """Clear all task instances or only those matched by regex for a DAG(s)."""
     logging.basicConfig(level=logging.INFO, format=settings.SIMPLE_LOG_FORMAT)
+    task_pattern = None
+    if args.task_regex:
+        try:
+            task_pattern = re.compile(args.task_regex)
+        except re.error as e:
+            raise SystemExit(f"Invalid --task-regex {args.task_regex!r}: {e}")
+
     if args.dag_id and not args.bundle_name and not args.dag_regex and not 
args.task_regex:
         dags = [get_db_dag(bundle_names=args.bundle_name, dag_id=args.dag_id)]
     else:
@@ -599,10 +607,10 @@ def task_clear(args) -> None:
         # Reading from_db because clear method still not implemented in Task 
SDK DAG
         dags = get_dags(args.bundle_name, args.dag_id, 
use_regex=args.dag_regex, from_db=True)
 
-        if args.task_regex:
+        if task_pattern:
             for idx, dag in enumerate(dags):
                 dags[idx] = dag.partial_subset(
-                    task_ids=args.task_regex,
+                    task_ids={task_id for task_id in dag.task_ids if 
task_pattern.search(task_id)},
                     include_downstream=args.downstream,
                     include_upstream=args.upstream,
                 )
diff --git a/airflow-core/tests/unit/cli/commands/test_task_command.py 
b/airflow-core/tests/unit/cli/commands/test_task_command.py
index a71fb78ca2f..0e305084977 100644
--- a/airflow-core/tests/unit/cli/commands/test_task_command.py
+++ b/airflow-core/tests/unit/cli/commands/test_task_command.py
@@ -810,6 +810,29 @@ class TestCliTasks:
             "end_date": ti_end.isoformat(),
         }
 
+    @pytest.mark.parametrize(
+        ("task_regex", "expected_task_ids"),
+        [
+            ("^runme_[02]$", {"runme_0", "runme_2"}),
+            ("unme_[02]", {"runme_0", "runme_2"}),
+            ("runme_0|also_run_this", {"runme_0", "also_run_this"}),
+        ],
+    )
+    @mock.patch("airflow.cli.commands.task_command.SerializedDAG.clear_dags", 
autospec=True)
+    def test_task_clear_task_regex_matches_as_regex(self, mock_clear_dags, 
task_regex, expected_task_ids):
+        args = self.parser.parse_args(
+            ["tasks", "clear", "example_bash_operator", "--task-regex", 
task_regex, "--yes"]
+        )
+        task_command.task_clear(args)
+
+        (dags,) = mock_clear_dags.call_args.args
+        assert set(dags[0].task_ids) == expected_task_ids
+
+    def 
test_task_clear_task_regex_invalid_pattern_reported_before_dag_lookup(self):
+        args = self.parser.parse_args(["tasks", "clear", "no_such_dag", 
"--task-regex", "runme_[", "--yes"])
+        with pytest.raises(SystemExit, match=r"Invalid --task-regex 
'runme_\['"):
+            task_command.task_clear(args)
+
     def test_task_states_for_dag_run_when_dag_run_not_exists(self):
         """
         task_states_for_dag_run should return an AirflowException when invalid 
dag id is passed

Reply via email to