├── .github └── workflows │ └── test-action.yml ├── LICENSE ├── README.md ├── action.yml └── review.py /.github/workflows/test-action.yml: -------------------------------------------------------------------------------- 1 | on: [pull_request] 2 | 3 | jobs: 4 | add_pr_comment: 5 | permissions: write-all 6 | runs-on: ubuntu-latest 7 | name: OpenAI PR Comment 8 | steps: 9 | - uses: actions/checkout@v3 10 | with: 11 | ref: ${{ github.event.pull_request.head.sha }} 12 | fetch-depth: 2 13 | - id: patch 14 | run: | 15 | patch_output=$(curl --silent --request GET \ 16 | --url https://api.github.com/repos/$PATCH_REPO/pulls/$PATCH_PR \ 17 | --header "Accept: application/vnd.github.v3.patch" \ 18 | --header "Authorization: Bearer $PATCH_GITHUB_TOKEN") 19 | echo $patch_output 20 | echo "GIT_PATCH_OUTPUT=$(echo $patch_output)" >> $GITHUB_ENV 21 | env: 22 | PATCH_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | PATCH_PR: ${{ github.event.pull_request.number }} 24 | PATCH_REPO: ${{ github.repository }} 25 | - id: review 26 | uses: MXCzkEVM/GPTReviewWorkflow@main 27 | with: 28 | GIT_COMMIT_HASH: ${{ github.event.pull_request.head.sha }} 29 | GIT_PATCH_OUTPUT: ${{ env.GIT_PATCH_OUTPUT }} 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} 32 | OPENAI_ORG_KEY: ${{ secrets.OPENAI_ORG_KEY }} 33 | PR_NUMBER: ${{ github.event.pull_request.number }} 34 | PR_TITLE: ${{ github.event.pull_request.title }} 35 | REPOSITORY_NAME: ${{ github.repository }} 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Maciej Kilian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GPTReview Workflow 🤖🔍 2 | 3 | Get OpenAI GPT models to suggest changes on your pull request in the comments. 4 | 5 | ## How to integrate into your repo: 6 | 7 | 1. Copy the workflow from this repo's .github/workflows/test-action.yml into your project in the same location and modify it to suit your needs, if you'd like. 8 | 2. Get an [OpenAI API Key here](https://beta.openai.com/account/api-keys) 9 | 3. Get an [OpenAI Org ID here](https://beta.openai.com/account/org-settings) 10 | 4. Create two secrets in your project's settings called OPENAI_API_KEY for your OpenAI API Key and OPENAI_ORG_KEY for your OpenAI Organization ID.. -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'GPTReviewWorkflow' 2 | description: 'GPT-3.5 reviews your PR' 3 | branding: 4 | icon: 'eye' 5 | color: 'gray-dark' 6 | inputs: 7 | GIT_COMMIT_HASH: 8 | description: 'SHA of the pull request-head to attach a review comment' 9 | required: true 10 | GIT_PATCH_OUTPUT: 11 | description: 'The pull request in patch format for prompt interpretation' 12 | required: true 13 | GITHUB_TOKEN: 14 | description: 'Derivative token for using the GitHub REST API' 15 | required: true 16 | OPENAI_API_KEY: 17 | description: 'OpenAI API Key' 18 | required: true 19 | OPENAI_ORG_KEY: 20 | description: 'OpenAI Organization ID' 21 | required: true 22 | PR_NUMBER: 23 | description: 'The pull request id (ie: 17)' 24 | required: true 25 | PR_TITLE: 26 | description: 'The pull request title' 27 | required: true 28 | REPOSITORY_NAME: 29 | description: 'The repository name (ie: octocat/hello-world)' 30 | required: true 31 | runs: 32 | using: "composite" 33 | steps: 34 | - name: Set up Python 3.8 35 | uses: actions/setup-python@v4 36 | with: 37 | python-version: '3.10' 38 | - name: Install 39 | shell: bash 40 | run: | 41 | sudo apt-get update 42 | python3 -m venv .env2 43 | source .env2/bin/activate 44 | python -m pip install -U pip 45 | pip install openai 46 | pip install requests 47 | - name: Fetch review logic 48 | uses: wei/wget@v1 49 | with: 50 | args: -O review.py https://raw.githubusercontent.com/mono-chrome/GPTReviewWorkflow/main/review.py 51 | - name: Review PR and make comment 52 | shell: bash 53 | run: | 54 | source .env2/bin/activate 55 | python review.py 56 | env: 57 | GIT_COMMIT_HASH: ${{ inputs.GIT_COMMIT_HASH }} 58 | GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }} 59 | LINK: "https://github.com/${{ inputs.REPOSITORY_NAME }}/pull/${{ inputs.PR_NUMBER }}" 60 | OPENAI_API_KEY: ${{ inputs.OPENAI_API_KEY }} 61 | OPENAI_ORG_KEY: ${{ inputs.OPENAI_ORG_KEY }} 62 | PR_TITLE: ${{ inputs.PR_TITLE }} 63 | GIT_PATCH_OUTPUT: ${{ inputs.GIT_PATCH_OUTPUT }} 64 | 65 | -------------------------------------------------------------------------------- /review.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import json 4 | import subprocess # is this still needed? 5 | import openai 6 | 7 | 8 | def get_review(): 9 | ACCESS_TOKEN = os.getenv("GITHUB_TOKEN") 10 | GIT_COMMIT_HASH = os.getenv("GIT_COMMIT_HASH") 11 | PR_PATCH = os.getenv("GIT_PATCH_OUTPUT") 12 | model = "gpt-3.5-turbo" 13 | openai.api_key = os.getenv("OPENAI_API_KEY") 14 | openai.organization = os.getenv("OPENAI_ORG_KEY") 15 | pr_link = os.getenv("LINK") 16 | 17 | headers = { 18 | "Accept": "application/vnd.github.v3.patch", 19 | "authorization": f"Bearer {ACCESS_TOKEN}", 20 | } 21 | 22 | intro = f"Act as a code reviewer of a Pull Request, providing feedback on the code changes below. You are provided with the Pull Request changes in a patch format.\n" 23 | explanation = f"Each patch entry has the commit message in the Subject line followed by the code changes (diffs) in a unidiff format.\n" 24 | patch_info = f"Patch of the Pull Request to review:\n\n{PR_PATCH}\n" 25 | task_headline = f"As a code reviewer, your task is:\n" 26 | task_list = f"- Review the code changes (diffs) and provide feedback.\n- If there are any bugs, highlight them.\n- Do not highlight minor issues and nitpicks.\n- View this as one pull request and don't mention individual patches.\n- Look out for typos in repeating variables.\n- Use markdown formatting.\n- Use bullet points if you have multiple comments.\n" 27 | prompt = intro + explanation + patch_info + task_headline + task_list 28 | 29 | print(f"\nPrompt sent to GPT-3.5: {prompt}\n") 30 | 31 | response = openai.Completion.create( 32 | engine=model, 33 | prompt=prompt, 34 | temperature=0.55, 35 | max_tokens=2048, 36 | top_p=1, 37 | frequency_penalty=0.3, 38 | presence_penalty=0.0, 39 | ) 40 | review = response["choices"][0]["text"] 41 | 42 | data = {"body": review, "commit_id": GIT_COMMIT_HASH, "event": "COMMENT"} 43 | data = json.dumps(data) 44 | print(f"\nResponse from GPT-3: {data}\n") 45 | 46 | OWNER = pr_link.split("/")[-4] 47 | REPO = pr_link.split("/")[-3] 48 | PR_NUMBER = pr_link.split("/")[-1] 49 | 50 | # https://api.github.com/repos/OWNER/REPO/pulls/PULL_NUMBER/reviews 51 | response = requests.post( 52 | f"https://api.github.com/repos/{OWNER}/{REPO}/pulls/{PR_NUMBER}/reviews", 53 | headers=headers, 54 | data=data, 55 | ) 56 | print(response.json()) 57 | 58 | 59 | if __name__ == "__main__": 60 | get_review() 61 | --------------------------------------------------------------------------------