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

jasonliu 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 df111d6a11e Ensure all the PR links in auto-triage are clickable 
(#63241)
df111d6a11e is described below

commit df111d6a11eb37fb0c69315b08f4aa99b7e3307a
Author: Jason(Zhe-You) Liu <[email protected]>
AuthorDate: Tue Mar 10 12:13:20 2026 +0800

    Ensure all the PR links in auto-triage are clickable (#63241)
---
 .../src/airflow_breeze/commands/pr_commands.py     | 108 +++++++++++----------
 1 file changed, 55 insertions(+), 53 deletions(-)

diff --git a/dev/breeze/src/airflow_breeze/commands/pr_commands.py 
b/dev/breeze/src/airflow_breeze/commands/pr_commands.py
index 04cba80fd8d..288dbb7e7c0 100644
--- a/dev/breeze/src/airflow_breeze/commands/pr_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/pr_commands.py
@@ -945,6 +945,11 @@ def _compute_default_action(
     return action, f"{reason} — suggesting {action_label}"
 
 
+def _pr_link(pr: PRData) -> str:
+    """Return a Rich-markup clickable link for a PR: 
[link=url]#number[/link]."""
+    return f"[link={pr.url}]#{pr.number}[/link]"
+
+
 def _display_pr_info_panels(pr: PRData, author_profile: dict | None):
     """Display PR info and author panels (shared by flagged-PR and 
workflow-approval flows)."""
     console = get_console()
@@ -1098,10 +1103,10 @@ def _close_suspicious_prs(
         node_id = pr_info["node_id"]
 
         if _close_pr(token, node_id):
-            get_console().print(f"  [success]PR #{pr_num} closed.[/]")
+            get_console().print(f"  [success]PR 
[link={pr_info['url']}]#{pr_num}[/link] closed.[/]")
             closed += 1
         else:
-            get_console().print(f"  [error]Failed to close PR #{pr_num}.[/]")
+            get_console().print(f"  [error]Failed to close PR 
[link={pr_info['url']}]#{pr_num}[/link].[/]")
             continue
 
         _add_label(token, github_repository, node_id, 
_SUSPICIOUS_CHANGES_LABEL)
@@ -1322,7 +1327,7 @@ def auto_triage(
             overall = "[green]OK[/]"
 
         pr_table.add_row(
-            f"[link={pr.url}]#{pr.number}[/link]",
+            _pr_link(pr),
             pr.title[:50],
             pr.author_login,
             pr.author_association.lower(),
@@ -1345,22 +1350,18 @@ def auto_triage(
             total_skipped_collaborator += 1
             if verbose:
                 get_console().print(
-                    f"  [dim]Skipping PR [link={pr.url}]#{pr.number}[/link] by 
"
+                    f"  [dim]Skipping PR {_pr_link(pr)} by "
                     f"{pr.author_association.lower()} {pr.author_login}[/]"
                 )
         elif _is_bot_account(pr.author_login):
             total_skipped_bot += 1
             if verbose:
-                get_console().print(
-                    f"  [dim]Skipping PR [link={pr.url}]#{pr.number}[/link] — "
-                    f"bot account {pr.author_login}[/]"
-                )
+                get_console().print(f"  [dim]Skipping PR {_pr_link(pr)} — bot 
account {pr.author_login}[/]")
         elif _READY_FOR_REVIEW_LABEL in pr.labels:
             total_skipped_accepted += 1
             if verbose:
                 get_console().print(
-                    f"  [dim]Skipping PR [link={pr.url}]#{pr.number}[/link] — "
-                    f"already has '{_READY_FOR_REVIEW_LABEL}' label[/]"
+                    f"  [dim]Skipping PR {_pr_link(pr)} — already has 
'{_READY_FOR_REVIEW_LABEL}' label[/]"
                 )
         else:
             candidate_prs.append(pr)
@@ -1394,7 +1395,7 @@ def auto_triage(
         for pr in candidate_prs:
             if pr.checks_state == "FAILURE" and not pr.failed_checks and 
pr.head_sha:
                 get_console().print(
-                    f"  [dim]Fetching full check details for PR #{pr.number} "
+                    f"  [dim]Fetching full check details for PR {_pr_link(pr)} 
"
                     f"(failures beyond first 100 checks)...[/]"
                 )
                 pr.failed_checks = _fetch_failed_checks(token, 
github_repository, pr.head_sha)
@@ -1474,9 +1475,7 @@ def auto_triage(
                     total_llm_errors += 1
                     continue
                 if not assessment.should_flag:
-                    get_console().print(
-                        f"  [success]PR [link={pr.url}]#{pr.number}[/link] 
passes quality check.[/]"
-                    )
+                    get_console().print(f"  [success]PR {_pr_link(pr)} passes 
quality check.[/]")
                     continue
                 assessments[pr.number] = assessment
 
@@ -1549,7 +1548,9 @@ def auto_triage(
             continue
 
         action = prompt_triage_action(
-            f"Action for PR #{pr.number}?", default=default_action, 
forced_answer=answer_triage
+            f"Action for PR {_pr_link(pr)}?",
+            default=default_action,
+            forced_answer=answer_triage,
         )
 
         if action == TriageAction.QUIT:
@@ -1558,60 +1559,60 @@ def auto_triage(
             break
 
         if action == TriageAction.SKIP:
-            get_console().print(f"  [info]Skipping PR #{pr.number} — no action 
taken.[/]")
+            get_console().print(f"  [info]Skipping PR {_pr_link(pr)} — no 
action taken.[/]")
             total_skipped_action += 1
             continue
 
         if action == TriageAction.READY:
             get_console().print(
-                f"  [info]Marking PR #{pr.number} as ready — adding 
'{_READY_FOR_REVIEW_LABEL}' label.[/]"
+                f"  [info]Marking PR {_pr_link(pr)} as ready — adding 
'{_READY_FOR_REVIEW_LABEL}' label.[/]"
             )
             if _add_label(token, github_repository, pr.node_id, 
_READY_FOR_REVIEW_LABEL):
                 get_console().print(
-                    f"  [success]Label '{_READY_FOR_REVIEW_LABEL}' added to PR 
#{pr.number}.[/]"
+                    f"  [success]Label '{_READY_FOR_REVIEW_LABEL}' added to PR 
{_pr_link(pr)}.[/]"
                 )
                 total_ready += 1
             else:
-                get_console().print(f"  [warning]Failed to add label to PR 
#{pr.number}.[/]")
+                get_console().print(f"  [warning]Failed to add label to PR 
{_pr_link(pr)}.[/]")
             continue
 
         if action == TriageAction.DRAFT:
-            get_console().print(f"  Converting PR #{pr.number} to draft...")
+            get_console().print(f"  Converting PR {_pr_link(pr)} to draft...")
             if _convert_pr_to_draft(token, pr.node_id):
-                get_console().print(f"  [success]PR #{pr.number} converted to 
draft.[/]")
+                get_console().print(f"  [success]PR {_pr_link(pr)} converted 
to draft.[/]")
             else:
-                get_console().print(f"  [error]Failed to convert PR 
#{pr.number} to draft.[/]")
+                get_console().print(f"  [error]Failed to convert PR 
{_pr_link(pr)} to draft.[/]")
                 continue
 
-            get_console().print(f"  Posting comment on PR #{pr.number}...")
+            get_console().print(f"  Posting comment on PR {_pr_link(pr)}...")
             if _post_comment(token, pr.node_id, comment):
-                get_console().print(f"  [success]Comment posted on PR 
#{pr.number}.[/]")
+                get_console().print(f"  [success]Comment posted on PR 
{_pr_link(pr)}.[/]")
                 total_converted += 1
             else:
-                get_console().print(f"  [error]Failed to post comment on PR 
#{pr.number}.[/]")
+                get_console().print(f"  [error]Failed to post comment on PR 
{_pr_link(pr)}.[/]")
             continue
 
         if action == TriageAction.CLOSE:
-            get_console().print(f"  Closing PR #{pr.number}...")
+            get_console().print(f"  Closing PR {_pr_link(pr)}...")
             if _close_pr(token, pr.node_id):
-                get_console().print(f"  [success]PR #{pr.number} closed.[/]")
+                get_console().print(f"  [success]PR {_pr_link(pr)} closed.[/]")
             else:
-                get_console().print(f"  [error]Failed to close PR 
#{pr.number}.[/]")
+                get_console().print(f"  [error]Failed to close PR 
{_pr_link(pr)}.[/]")
                 continue
 
             if _add_label(token, github_repository, pr.node_id, 
_CLOSED_QUALITY_LABEL):
                 get_console().print(
-                    f"  [success]Label '{_CLOSED_QUALITY_LABEL}' added to PR 
#{pr.number}.[/]"
+                    f"  [success]Label '{_CLOSED_QUALITY_LABEL}' added to PR 
{_pr_link(pr)}.[/]"
                 )
             else:
-                get_console().print(f"  [warning]Failed to add label to PR 
#{pr.number}.[/]")
+                get_console().print(f"  [warning]Failed to add label to PR 
{_pr_link(pr)}.[/]")
 
-            get_console().print(f"  Posting comment on PR #{pr.number}...")
+            get_console().print(f"  Posting comment on PR {_pr_link(pr)}...")
             if _post_comment(token, pr.node_id, close_comment):
-                get_console().print(f"  [success]Comment posted on PR 
#{pr.number}.[/]")
+                get_console().print(f"  [success]Comment posted on PR 
{_pr_link(pr)}.[/]")
                 total_closed += 1
             else:
-                get_console().print(f"  [error]Failed to post comment on PR 
#{pr.number}.[/]")
+                get_console().print(f"  [error]Failed to post comment on PR 
{_pr_link(pr)}.[/]")
 
     # Phase 6: Present NOT_RUN PRs for workflow approval
     total_workflows_approved = 0
@@ -1642,7 +1643,7 @@ def auto_triage(
                     continue
 
                 action = prompt_triage_action(
-                    f"Action for PR #{pr.number}?",
+                    f"Action for PR {_pr_link(pr)}?",
                     default=TriageAction.CLOSE,
                     forced_answer=answer_triage,
                 )
@@ -1651,27 +1652,27 @@ def auto_triage(
                     quit_early = True
                     break
                 if action == TriageAction.SKIP:
-                    get_console().print(f"  [info]Skipping PR #{pr.number} — 
no action taken.[/]")
+                    get_console().print(f"  [info]Skipping PR {_pr_link(pr)} — 
no action taken.[/]")
                     continue
                 if action == TriageAction.CLOSE:
-                    get_console().print(f"  Closing PR #{pr.number}...")
+                    get_console().print(f"  Closing PR {_pr_link(pr)}...")
                     if _close_pr(token, pr.node_id):
-                        get_console().print(f"  [success]PR #{pr.number} 
closed.[/]")
+                        get_console().print(f"  [success]PR {_pr_link(pr)} 
closed.[/]")
                     else:
-                        get_console().print(f"  [error]Failed to close PR 
#{pr.number}.[/]")
+                        get_console().print(f"  [error]Failed to close PR 
{_pr_link(pr)}.[/]")
                         continue
                     if _add_label(token, github_repository, pr.node_id, 
_CLOSED_QUALITY_LABEL):
                         get_console().print(
-                            f"  [success]Label '{_CLOSED_QUALITY_LABEL}' added 
to PR #{pr.number}.[/]"
+                            f"  [success]Label '{_CLOSED_QUALITY_LABEL}' added 
to PR {_pr_link(pr)}.[/]"
                         )
                     else:
-                        get_console().print(f"  [warning]Failed to add label 
to PR #{pr.number}.[/]")
-                    get_console().print(f"  Posting comment on PR 
#{pr.number}...")
+                        get_console().print(f"  [warning]Failed to add label 
to PR {_pr_link(pr)}.[/]")
+                    get_console().print(f"  Posting comment on PR 
{_pr_link(pr)}...")
                     if _post_comment(token, pr.node_id, close_comment):
-                        get_console().print(f"  [success]Comment posted on PR 
#{pr.number}.[/]")
+                        get_console().print(f"  [success]Comment posted on PR 
{_pr_link(pr)}.[/]")
                         total_closed += 1
                     else:
-                        get_console().print(f"  [error]Failed to post comment 
on PR #{pr.number}.[/]")
+                        get_console().print(f"  [error]Failed to post comment 
on PR {_pr_link(pr)}.[/]")
                     continue
                 # For DRAFT or READY, fall through to normal workflow approval
                 # (approve workflows first, then triage later)
@@ -1682,13 +1683,13 @@ def auto_triage(
 
             if not pending_runs:
                 get_console().print(
-                    f"  [dim]No pending workflow runs found for PR 
#{pr.number}. "
+                    f"  [dim]No pending workflow runs found for PR 
{_pr_link(pr)}. "
                     f"Workflows may need to be triggered manually.[/]"
                 )
                 continue
 
             answer = user_confirm(
-                f"Review diff for PR #{pr.number} before approving workflows?",
+                f"Review diff for PR {_pr_link(pr)} before approving 
workflows?",
                 forced_answer=answer_triage,
             )
             if answer == Answer.QUIT:
@@ -1696,10 +1697,10 @@ def auto_triage(
                 quit_early = True
                 break
             if answer == Answer.NO:
-                get_console().print(f"  [info]Skipping workflow approval for 
PR #{pr.number}.[/]")
+                get_console().print(f"  [info]Skipping workflow approval for 
PR {_pr_link(pr)}.[/]")
                 continue
 
-            get_console().print(f"  Fetching diff for PR #{pr.number}...")
+            get_console().print(f"  Fetching diff for PR {_pr_link(pr)}...")
             diff_text = _fetch_pr_diff(token, github_repository, pr.number)
             if diff_text:
                 from rich.syntax import Syntax
@@ -1707,18 +1708,18 @@ def auto_triage(
                 get_console().print(
                     Panel(
                         Syntax(diff_text, "diff", theme="monokai", 
word_wrap=True),
-                        title=f"Diff for PR #{pr.number}",
+                        title=f"Diff for PR {_pr_link(pr)}",
                         border_style="bright_cyan",
                     )
                 )
             else:
                 get_console().print(
-                    f"  [warning]Could not fetch diff for PR #{pr.number}. "
+                    f"  [warning]Could not fetch diff for PR {_pr_link(pr)}. "
                     f"Review manually at: {pr.url}/files[/]"
                 )
 
             answer = user_confirm(
-                f"No suspicious changes found in PR #{pr.number}? "
+                f"No suspicious changes found in PR {_pr_link(pr)}? "
                 f"Approve {len(pending_runs)} workflow {'runs' if 
len(pending_runs) != 1 else 'run'}?",
                 forced_answer=answer_triage,
             )
@@ -1728,7 +1729,7 @@ def auto_triage(
                 break
             if answer == Answer.NO:
                 get_console().print(
-                    f"\n  [bold red]Suspicious changes detected in PR 
#{pr.number} by {pr.author_login}.[/]"
+                    f"\n  [bold red]Suspicious changes detected in PR 
{_pr_link(pr)} by {pr.author_login}.[/]"
                 )
                 get_console().print(f"  Fetching all open PRs by 
{pr.author_login}...")
                 author_prs = _fetch_author_open_prs(token, github_repository, 
pr.author_login)
@@ -1774,11 +1775,12 @@ def auto_triage(
             if approved:
                 get_console().print(
                     f"  [success]Approved {approved}/{len(pending_runs)} 
workflow "
-                    f"{'runs' if len(pending_runs) != 1 else 'run'} for PR 
#{pr.number}.[/]"
+                    f"{'runs' if len(pending_runs) != 1 else 'run'} for PR "
+                    f"{_pr_link(pr)}.[/]"
                 )
                 total_workflows_approved += 1
             else:
-                get_console().print(f"  [error]Failed to approve workflow runs 
for PR #{pr.number}.[/]")
+                get_console().print(f"  [error]Failed to approve workflow runs 
for PR {_pr_link(pr)}.[/]")
 
     # Summary
     get_console().print()

Reply via email to