diff --git a/.github/workflows/review.yaml b/.github/workflows/review.yaml index 31d1c982..1d20496a 100644 --- a/.github/workflows/review.yaml +++ b/.github/workflows/review.yaml @@ -8,7 +8,7 @@ jobs: steps: - name: PR Agent action step id: pragent - uses: Codium-ai/pr-agent@feature/github_action + uses: Codium-ai/pr-agent@main env: OPENAI_KEY: ${{ secrets.OPENAI_KEY }} OPENAI_ORG: ${{ secrets.OPENAI_ORG }} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index e69de29b..00000000 diff --git a/Dockerfile.github_action_dockerhub b/Dockerfile.github_action_dockerhub new file mode 100644 index 00000000..61d64e25 --- /dev/null +++ b/Dockerfile.github_action_dockerhub @@ -0,0 +1 @@ +FROM codiumai/pr-agent:github_action diff --git a/README.md b/README.md index f556b13c..00c35c82 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,10 @@ Example results:
- [Live demo](#live-demo) -- [Quickstart](#Quickstart) +- [Overview](#overview) +- [Quickstart](#quickstart) - [Usage and tools](#usage-and-tools) -- [Configuration](#Configuration) +- [Configuration](#configuration) - [How it works](#how-it-works) - [Roadmap](#roadmap) - [Similar projects](#similar-projects) @@ -52,6 +53,25 @@ Experience GPT-4 powered PR review on your public GitHub repository with our hos To set up your own pr-agent, see the [Quickstart](#Quickstart) section --- +## Overview +`pr-agent` offers extensive pull request functionalities across various git providers: +| | | Github | Gitlab | Bitbucket | +|-------|---------------------------------------------|--------|--------|-----------| +| TOOLS | Review | ✓ | ✓ | ✓ | +| | ⮑ Inline review | ✓ | ✓ | | +| | Ask | ✓ | ✓ | | +| | Auto-Description | ✓ | | | +| | Improve Code | ✓ | | | +| | | | | | +| USAGE | CLI | ✓ | ✓ | ✓ | +| | Tagging bot | ✓ | ✓ | | +| | Actions | ✓ | | | +| | | | | | +| CORE | PR compression | ✓ | ✓ | ✓ | +| | Repo language prioritization | ✓ | ✓ | ✓ | +| | Adaptive and token-aware
file patch fitting | ✓ | ✓ | ✓ | + + ## Quickstart diff --git a/action.yaml b/action.yaml index b592abee..a6ffe834 100644 --- a/action.yaml +++ b/action.yaml @@ -2,4 +2,4 @@ name: 'PR Agent' description: 'Summarize, review and suggest improvements for pull requests' runs: using: 'docker' - image: 'Dockerfile.github_action' + image: 'Dockerfile.github_action_dockerhub' diff --git a/pr_agent/cli.py b/pr_agent/cli.py index 78a795ea..da94f9a2 100644 --- a/pr_agent/cli.py +++ b/pr_agent/cli.py @@ -10,29 +10,48 @@ from pr_agent.tools.pr_reviewer import PRReviewer def run(): - parser = argparse.ArgumentParser(description='AI based pull request analyzer') + parser = argparse.ArgumentParser(description='AI based pull request analyzer', usage="""\ +Usage: cli.py --pr-url []. + +Supported commands: +review / review_pr - Add a review that includes a summary of the PR and specific suggestions for improvement. +ask / ask_question [question] - Ask a question about the PR. +describe / describe_pr - Modify the PR title and description based on the PR's contents. +improve / improve_code - Suggest improvements to the code in the PR as pull request comments ready to commit. +""") parser.add_argument('--pr_url', type=str, help='The URL of the PR to review', required=True) - parser.add_argument('--question', type=str, help='Optional question to ask', required=False) - parser.add_argument('--pr_description', action='store_true', required=False) - parser.add_argument('--pr_code_suggestions', action='store_true', required=False) + parser.add_argument('command', type=str, help='The', choices=['review', 'review_pr', + 'ask', 'ask_question', + 'describe', 'describe_pr', + 'improve', 'improve_code'], default='review') + parser.add_argument('rest', nargs=argparse.REMAINDER, default=[]) args = parser.parse_args() logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO")) - if args.question: - print(f"Question: {args.question} about PR {args.pr_url}") - reviewer = PRQuestions(args.pr_url, args.question) + command = args.command.lower() + if command in ['ask', 'ask_question']: + question = ' '.join(args.rest).strip() + if len(question) == 0: + print("Please specify a question") + parser.print_help() + return + print(f"Question: {question} about PR {args.pr_url}") + reviewer = PRQuestions(args.pr_url, question) asyncio.run(reviewer.answer()) - elif args.pr_description: + elif command in ['describe', 'describe_pr']: print(f"PR description: {args.pr_url}") reviewer = PRDescription(args.pr_url) asyncio.run(reviewer.describe()) - elif args.pr_code_suggestions: + elif command in ['improve', 'improve_code']: print(f"PR code suggestions: {args.pr_url}") reviewer = PRCodeSuggestions(args.pr_url) asyncio.run(reviewer.suggest()) - else: + elif command in ['review', 'review_pr']: print(f"Reviewing PR: {args.pr_url}") reviewer = PRReviewer(args.pr_url, cli_mode=True) asyncio.run(reviewer.review()) + else: + print(f"Unknown command: {command}") + parser.print_help() if __name__ == '__main__': diff --git a/pr_agent/servers/github_action_runner.py b/pr_agent/servers/github_action_runner.py index 953b0b8f..ba6ffe9c 100644 --- a/pr_agent/servers/github_action_runner.py +++ b/pr_agent/servers/github_action_runner.py @@ -1,8 +1,11 @@ import asyncio import json import os +import re from pr_agent.config_loader import settings +from pr_agent.tools.pr_code_suggestions import PRCodeSuggestions +from pr_agent.tools.pr_description import PRDescription from pr_agent.tools.pr_questions import PRQuestions from pr_agent.tools.pr_reviewer import PRReviewer @@ -16,10 +19,11 @@ async def run_action(): if not GITHUB_EVENT_PATH: print("GITHUB_EVENT_PATH not set") return - event_payload = json.load(open(GITHUB_EVENT_PATH, 'r')) - RUNNER_DEBUG = os.environ.get('RUNNER_DEBUG', None) - if not RUNNER_DEBUG: - print("RUNNER_DEBUG not set") + try: + event_payload = json.load(open(GITHUB_EVENT_PATH, 'r')) + except json.decoder.JSONDecodeError as e: + print(f"Failed to parse JSON: {e}") + return OPENAI_KEY = os.environ.get('OPENAI_KEY', None) if not OPENAI_KEY: print("OPENAI_KEY not set") @@ -48,10 +52,21 @@ async def run_action(): if comment_body: pr_url = event_payload.get("issue", {}).get("pull_request", {}).get("url", None) if pr_url: - if comment_body.strip().lower() == "review": + body = comment_body.strip().lower() + if any(cmd in body for cmd in ["/review", "/review_pr"]): await PRReviewer(pr_url).review() - elif comment_body.lstrip().lower().startswith("answer"): - await PRQuestions(pr_url, comment_body).answer() + elif any(cmd in body for cmd in ["/describe", "/describe_pr"]): + await PRDescription(pr_url).describe() + elif any(cmd in body for cmd in ["/improve", "/improve_code"]): + await PRCodeSuggestions(pr_url).suggest() + elif any(cmd in body for cmd in ["/ask", "/ask_question"]): + pattern = r'(/ask|/ask_question)\s*(.*)' + matches = re.findall(pattern, comment_body, re.IGNORECASE) + if matches: + question = matches[0][1] + await PRQuestions(pr_url, question).answer() + else: + print(f"Unknown command: {body}") if __name__ == '__main__': diff --git a/pr_agent/tools/pr_reviewer.py b/pr_agent/tools/pr_reviewer.py index e6d001e1..3168e459 100644 --- a/pr_agent/tools/pr_reviewer.py +++ b/pr_agent/tools/pr_reviewer.py @@ -96,15 +96,18 @@ class PRReviewer: if not self.cli_mode: markdown_text += "\n### How to use\n" + commands_text = "> /review - Ask for a new review after your update the PR\n" \ + "> /describe - Modify the PR title and description based " \ + "on the PR's contents.\n" \ + "> /improve - Suggest improvements to the code in the PR as pull " \ + "request comments ready to commit.\n" \ + "> /ask - Ask a question about the PR.\n" if user and '[bot]' not in user: - markdown_text += f"> Tag me in a comment '@{user}' to ask for a new review after you update the PR.\n" - markdown_text += "> You can also tag me and ask any question, " \ - f"for example '@{user} is the PR ready for merge?'" + markdown_text += f"> Tag me in a comment '@{user}' and add one of the following commands:\n" + \ + commands_text else: - markdown_text += "> Add a comment that says 'review' to ask for a new review " \ - "after you update the PR.\n" - markdown_text += "> You can also add a comment that says 'answer QUESTION', " \ - "for example 'answer is the PR ready for merge?'" + markdown_text += "> Add a comment to to invoke PR-Agent, use one of the following commands:\n" + \ + commands_text if settings.config.verbosity_level >= 2: logging.info(f"Markdown response:\n{markdown_text}")