Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ gh-llm issue view 77924 --repo PaddlePaddle/Paddle --show meta,description
```bash
# Edit comment
gh-llm pr comment-edit IC_xxx --body '<new_body>' --pr 77900 --repo PaddlePaddle/Paddle
gh-llm pr comment-edit IC_xxx --body-file edit.md --pr 77900 --repo PaddlePaddle/Paddle
gh-llm issue comment-edit IC_xxx --body '<new_body>' --issue 77924 --repo PaddlePaddle/Paddle
gh-llm issue comment-edit IC_xxx --body-file edit.md --issue 77924 --repo PaddlePaddle/Paddle

# Reply / resolve / unresolve review thread
gh-llm pr thread-reply PRRT_xxx --body '<reply>' --pr 77900 --repo PaddlePaddle/Paddle
Expand Down Expand Up @@ -231,6 +233,14 @@ gh-llm pr review-suggest \
--body-file suggestion-reason.md \
--suggestion 'replacement_code_here' \
--pr 77938 --repo PaddlePaddle/Paddle

gh-llm pr review-suggest \
--path 'path/to/file' \
--line 123 \
--side RIGHT \
--body-file suggestion-reason.md \
--suggestion-file replacement.txt \
--pr 77938 --repo PaddlePaddle/Paddle
```

### 4) Submit review
Expand All @@ -247,7 +257,9 @@ gh-llm pr review-submit \
--pr 77938 --repo PaddlePaddle/Paddle
```

`thread-reply`, `review-comment`, `review-suggest`, and `review-submit` all support `--body-file -` to read multi-line text from standard input.
`pr comment-edit`, `issue comment-edit`, `thread-reply`, `review-comment`, `review-suggest`, and `review-submit` all support `--body-file -` to read multi-line text from standard input. `review-suggest` also supports `--suggestion-file -` for the suggestion block itself.

> Note: `review-suggest --body-file - --suggestion-file -` is intentionally rejected because standard input can only be consumed once. Use separate files when both the reason text and suggestion block need external input.

Submit behavior:

Expand Down
11 changes: 11 additions & 0 deletions skills/github-conversation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ gh-llm issue timeline-expand <page> --issue <issue> --repo <owner/repo>
```bash
gh pr comment <pr> --repo <owner/repo> --body '<comment>'
gh issue comment <issue> --repo <owner/repo> --body '<comment>'
gh-llm pr comment-edit <comment_id> --body-file edit.md --pr <pr> --repo <owner/repo>
gh-llm issue comment-edit <comment_id> --body-file edit.md --issue <issue> --repo <owner/repo>
cat edit.md | gh-llm issue comment-edit <comment_id> --body-file - --issue <issue> --repo <owner/repo>
gh pr edit <pr> --repo <owner/repo> --add-label '<label1>,<label2>'
gh pr edit <pr> --repo <owner/repo> --remove-label '<label1>,<label2>'
gh pr edit <pr> --repo <owner/repo> --add-reviewer '<reviewer1>,<reviewer2>'
Expand Down Expand Up @@ -218,6 +221,14 @@ gh-llm pr review-suggest \
--body '<why>' \
--suggestion '<replacement>' \
--pr <pr> --repo <owner/repo>

gh-llm pr review-suggest \
--path 'path/to/file' \
--line <line> \
--side RIGHT \
--body-file reason.md \
--suggestion-file replacement.txt \
--pr <pr> --repo <owner/repo>
```

Then submit one review:
Expand Down
15 changes: 12 additions & 3 deletions src/gh_llm/commands/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any

from gh_llm.commands.options import raise_unknown_option_value
from gh_llm.commands.options import raise_unknown_option_value, resolve_file_or_inline_text
from gh_llm.github_api import GitHubClient
from gh_llm.pager import DEFAULT_PAGE_SIZE, TimelinePager
from gh_llm.render import (
Expand Down Expand Up @@ -86,7 +86,13 @@ def register_issue_parser(subparsers: Any) -> None:

comment_edit_parser = issue_subparsers.add_parser("comment-edit", help="edit one issue comment by node id")
comment_edit_parser.add_argument("comment_id", help="comment id, e.g. IC_xxx")
comment_edit_parser.add_argument("--body", required=True, help="new comment body")
comment_edit_body_group = comment_edit_parser.add_mutually_exclusive_group(required=True)
comment_edit_body_group.add_argument("--body", help="new comment body")
comment_edit_body_group.add_argument(
"-F",
"--body-file",
help="read new comment body from file (use `-` to read from standard input)",
)
comment_edit_parser.add_argument("--issue", help="Issue number/url")
comment_edit_parser.add_argument("--repo", help="repository in OWNER/REPO format")
comment_edit_parser.set_defaults(handler=cmd_issue_comment_edit)
Expand Down Expand Up @@ -230,7 +236,10 @@ def cmd_issue_comment_edit(args: Any) -> int:
raise RuntimeError("`--issue` is required when `--repo` is provided")
if args.issue is not None:
client.resolve_issue(selector=args.issue, repo=args.repo)
updated_comment_id = client.edit_comment(comment_id=str(args.comment_id), body=str(args.body))
updated_comment_id = client.edit_comment(
comment_id=str(args.comment_id),
body=resolve_file_or_inline_text(args, text_attr="body", file_attr="body_file"),
)
print(f"comment: {updated_comment_id}")
print("status: edited")
return 0
Expand Down
26 changes: 25 additions & 1 deletion src/gh_llm/commands/options.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
from __future__ import annotations

import sys
from difflib import get_close_matches
from typing import NoReturn
from pathlib import Path
from typing import Any, NoReturn


def read_text_from_path_or_stdin(path: str) -> str:
if path == "-":
return sys.stdin.read()
return Path(path).read_text(encoding="utf-8")


def resolve_file_or_inline_text(
args: Any,
*,
text_attr: str,
file_attr: str,
default: str = "",
) -> str:
file_path = getattr(args, file_attr, None)
if file_path is not None:
return read_text_from_path_or_stdin(str(file_path))
text = getattr(args, text_attr, None)
if text is None:
return default
return str(text)


def raise_unknown_option_value(
Expand Down
47 changes: 28 additions & 19 deletions src/gh_llm/commands/pr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import os
import re
import shlex
import sys
import tempfile
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, Any

from gh_llm.commands.options import raise_unknown_option_value
from gh_llm.commands.options import raise_unknown_option_value, resolve_file_or_inline_text
from gh_llm.github_api import GitHubClient
from gh_llm.invocation import display_command_with
from gh_llm.models import PullRequestDiffPage
Expand Down Expand Up @@ -221,7 +220,13 @@ def register_pr_parser(subparsers: Any) -> None:

comment_edit_parser = pr_subparsers.add_parser("comment-edit", help="edit one issue/review comment by node id")
comment_edit_parser.add_argument("comment_id", help="comment id, e.g. IC_xxx or PRRC_xxx")
comment_edit_parser.add_argument("--body", required=True, help="new comment body")
comment_edit_body_group = comment_edit_parser.add_mutually_exclusive_group(required=True)
comment_edit_body_group.add_argument("--body", help="new comment body")
comment_edit_body_group.add_argument(
"-F",
"--body-file",
help="read new comment body from file (use `-` to read from standard input)",
)
comment_edit_parser.add_argument("--pr", help="PR number/url/branch")
comment_edit_parser.add_argument("--repo", help="repository in OWNER/REPO format")
comment_edit_parser.set_defaults(handler=cmd_pr_comment_edit)
Expand Down Expand Up @@ -313,11 +318,15 @@ def register_pr_parser(subparsers: Any) -> None:
"--body-file",
help="read review comment body from file (use `-` to read from standard input)",
)
review_suggest_parser.add_argument(
review_suggest_suggestion_group = review_suggest_parser.add_mutually_exclusive_group(required=True)
review_suggest_suggestion_group.add_argument(
"--suggestion",
required=True,
help="replacement content inserted inside ```suggestion block",
)
review_suggest_suggestion_group.add_argument(
"--suggestion-file",
help="read replacement content from file (use `-` to read from standard input)",
)
review_suggest_parser.add_argument("--head", help="expected PR head sha for stale-snapshot protection")
review_suggest_parser.add_argument("--pr", help="PR number/url/branch")
review_suggest_parser.add_argument("--repo", help="repository in OWNER/REPO format")
Expand All @@ -344,20 +353,19 @@ def register_pr_parser(subparsers: Any) -> None:
review_submit_parser.set_defaults(handler=cmd_pr_review_submit)


def _read_body_file(path: str) -> str:
if path == "-":
return sys.stdin.read()
return Path(path).read_text(encoding="utf-8")
def _resolve_body_argument(args: Any, *, default: str = "") -> str:
return resolve_file_or_inline_text(args, text_attr="body", file_attr="body_file", default=default)


def _resolve_suggestion_argument(args: Any) -> str:
return resolve_file_or_inline_text(args, text_attr="suggestion", file_attr="suggestion_file")

def _resolve_body_argument(args: Any, *, default: str = "") -> str:
body_file = getattr(args, "body_file", None)
if body_file:
return _read_body_file(str(body_file))
body = getattr(args, "body", None)
if body is None:
return default
return str(body)

def _validate_review_suggest_stdin_sources(args: Any) -> None:
if getattr(args, "body_file", None) == "-" and getattr(args, "suggestion_file", None) == "-":
raise RuntimeError(
"`--body-file -` cannot be combined with `--suggestion-file -`; standard input can only be consumed once"
)


def _resolve_review_submit_body(args: Any) -> str:
Expand Down Expand Up @@ -746,7 +754,7 @@ def cmd_pr_comment_edit(args: Any) -> int:
raise RuntimeError("`--pr` is required when `--repo` is provided")
if args.pr is not None:
client.resolve_pull_request(selector=args.pr, repo=args.repo)
updated_comment_id = client.edit_comment(comment_id=str(args.comment_id), body=str(args.body))
updated_comment_id = client.edit_comment(comment_id=str(args.comment_id), body=_resolve_body_argument(args))
print(f"comment: {updated_comment_id}")
print("status: edited")
return 0
Expand Down Expand Up @@ -1082,6 +1090,7 @@ def cmd_pr_review_comment(args: Any) -> int:


def cmd_pr_review_suggest(args: Any) -> int:
_validate_review_suggest_stdin_sources(args)
client = GitHubClient()
meta = _resolve_pr_meta(client=client, args=args)
_validate_pr_head_snapshot(meta=meta, requested_head=_resolve_requested_head(args))
Expand All @@ -1096,7 +1105,7 @@ def cmd_pr_review_suggest(args: Any) -> int:
start_line=start_line,
start_side=start_side,
)
suggestion = str(args.suggestion).rstrip("\n")
suggestion = _resolve_suggestion_argument(args).rstrip("\n")
body = _resolve_body_argument(args, default="Suggested change")
full_body = f"{body.rstrip()}\n\n```suggestion\n{suggestion}\n```"
thread_id, comment_id = client.add_pull_request_review_thread_comment(
Expand Down
Loading
Loading