|
22 | 22 | from adk_pr_triaging_agent.utils import error_response |
23 | 23 | from adk_pr_triaging_agent.utils import get_diff |
24 | 24 | from adk_pr_triaging_agent.utils import get_request |
| 25 | +from adk_pr_triaging_agent.utils import is_assignable |
25 | 26 | from adk_pr_triaging_agent.utils import post_request |
26 | 27 | from adk_pr_triaging_agent.utils import read_file |
27 | 28 | from adk_pr_triaging_agent.utils import run_graphql_query |
|
41 | 42 | "web", |
42 | 43 | ] |
43 | 44 |
|
| 45 | +# Component label -> GitHub login of the owner who shepherds that component. |
| 46 | +# The owner becomes the PR's assignee so the contributor can see who is |
| 47 | +# handling their PR. github login != corp ldap, so this is the login form. Keep |
| 48 | +# in sync with the OWNERS file (the authority) and adk_triaging_agent's map. |
| 49 | +LABEL_TO_OWNER = { |
| 50 | + "documentation": "joefernandez", |
| 51 | + "services": "DeanChensj", |
| 52 | + "tools": "xuanyang15", |
| 53 | + "mcp": "wukath", |
| 54 | + "eval": "ankursharmas", |
| 55 | + "live": "wuliang229", |
| 56 | + "models": "xuanyang15", |
| 57 | + "tracing": "jawoszek", |
| 58 | + "core": "DeanChensj", |
| 59 | + "web": "wyf7107", |
| 60 | +} |
| 61 | + |
44 | 62 | CONTRIBUTING_MD = read_file( |
45 | 63 | Path(__file__).resolve().parents[4] / "CONTRIBUTING.md" |
46 | 64 | ) |
47 | 65 |
|
48 | 66 | APPROVAL_INSTRUCTION = ( |
49 | | - "Do not ask for user approval for labeling or commenting! If you can't find" |
50 | | - " appropriate labels for the PR, do not label it." |
| 67 | + "Do not ask for user approval for labeling, commenting, or assigning!" |
| 68 | + " If you can't find appropriate labels for the PR, do not label it." |
51 | 69 | ) |
52 | 70 | if IS_INTERACTIVE: |
53 | 71 | APPROVAL_INSTRUCTION = ( |
54 | | - "Only label or comment when the user approves the labeling or commenting!" |
| 72 | + "Only label, comment, or assign when the user approves the action!" |
55 | 73 | ) |
56 | 74 |
|
57 | 75 |
|
@@ -82,6 +100,11 @@ def get_pull_request_details(pr_number: int) -> str: |
82 | 100 | name |
83 | 101 | } |
84 | 102 | } |
| 103 | + assignees(first: 10) { |
| 104 | + nodes { |
| 105 | + login |
| 106 | + } |
| 107 | + } |
85 | 108 | files(last: 50) { |
86 | 109 | nodes { |
87 | 110 | path |
@@ -194,6 +217,48 @@ def add_label_to_pr(pr_number: int, label: str) -> dict[str, Any]: |
194 | 217 | } |
195 | 218 |
|
196 | 219 |
|
| 220 | +def assign_owner_to_pr(pr_number: int, label: str) -> dict[str, Any]: |
| 221 | + """Assign the component owner (the shepherd) to a PR based on its label. |
| 222 | +
|
| 223 | + The owner is looked up from `LABEL_TO_OWNER` so the contributor can see who is |
| 224 | + shepherding their PR. GitHub only allows assigning users with |
| 225 | + repo write/triage access, so a non-assignable owner is reported as skipped |
| 226 | + rather than silently dropped. |
| 227 | +
|
| 228 | + Args: |
| 229 | + pr_number: the number of the GitHub pull request |
| 230 | + label: the component label the PR was triaged into |
| 231 | +
|
| 232 | + Returns: |
| 233 | + The status of this request, with the assigned owner when successful. |
| 234 | + """ |
| 235 | + owner = LABEL_TO_OWNER.get(label) |
| 236 | + if not owner: |
| 237 | + return error_response(f"Error: no owner mapped for label '{label}'.") |
| 238 | + print(f"Attempting to assign owner '{owner}' to PR #{pr_number}") |
| 239 | + if not is_assignable(owner): |
| 240 | + return { |
| 241 | + "status": "skipped", |
| 242 | + "reason": f"'{owner}' is not assignable (needs repo access)", |
| 243 | + "owner": owner, |
| 244 | + } |
| 245 | + |
| 246 | + # Pull Request is a special issue in GitHub, so we can use the issue url. |
| 247 | + assignee_url = ( |
| 248 | + f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{pr_number}/assignees" |
| 249 | + ) |
| 250 | + try: |
| 251 | + response = post_request(assignee_url, {"assignees": [owner]}) |
| 252 | + except requests.exceptions.RequestException as e: |
| 253 | + return error_response(f"Error: {e}") |
| 254 | + |
| 255 | + return { |
| 256 | + "status": "success", |
| 257 | + "assigned_owner": owner, |
| 258 | + "response": response, |
| 259 | + } |
| 260 | + |
| 261 | + |
197 | 262 | def add_comment_to_pr(pr_number: int, comment: str) -> dict[str, Any]: |
198 | 263 | """Add the specified comment to the given PR number. |
199 | 264 |
|
@@ -282,6 +347,7 @@ def list_untriaged_pull_requests(pr_count: int) -> dict[str, Any]: |
282 | 347 | Your core responsibility includes: |
283 | 348 | - Get the pull request details. |
284 | 349 | - Add a label to the pull request. |
| 350 | + - Assign the component owner (the shepherd) to the pull request. |
285 | 351 | - Check if the pull request is following the contribution guidelines. |
286 | 352 | - Add a comment to the pull request if it's not following the guidelines. |
287 | 353 |
|
@@ -337,17 +403,23 @@ def list_untriaged_pull_requests(pr_count: int) -> dict[str, Any]: |
337 | 403 | - Check if the PR is following the contribution guidelines. |
338 | 404 | - If it's not following the guidelines, recommend or add a comment to the PR that points to the contribution guidelines (https://github.com/google/adk-python/blob/main/CONTRIBUTING.md). |
339 | 405 | - If it's following the guidelines, recommend or add a label to the PR. |
| 406 | + - After you add a component label, assign the component owner (the shepherd) to the PR: |
| 407 | + - Call `assign_owner_to_pr` with the same label you applied. |
| 408 | + - Skip assignment if the PR already has an assignee. |
| 409 | + - If the tool reports the owner is not assignable, just note it; do not comment about it. |
340 | 410 |
|
341 | 411 | # 5. Output |
342 | 412 | Present the following in an easy to read format highlighting PR number and your label. |
343 | 413 | - The PR summary in a few sentence |
344 | 414 | - The label you recommended or added with the justification |
| 415 | + - The owner you assigned (or why you did not) |
345 | 416 | - The comment you recommended or added to the PR with the justification |
346 | 417 | """, |
347 | 418 | tools=[ |
348 | 419 | list_untriaged_pull_requests, |
349 | 420 | get_pull_request_details, |
350 | 421 | add_label_to_pr, |
| 422 | + assign_owner_to_pr, |
351 | 423 | add_comment_to_pr, |
352 | 424 | ], |
353 | 425 | ) |
0 commit comments