From cc9133fd8b4b5e22ebefe521d047b017d339df07 Mon Sep 17 00:00:00 2001 From: Bryan Montalvan Date: Fri, 6 Jun 2025 00:37:35 -0400 Subject: [PATCH 1/2] Add two-sum example --- .github/workflows/code-review.yml | 15 +++++- reviewbot/__pycache__/main.cpython-310.pyc | Bin 0 -> 1266 bytes reviewbot/__pycache__/utils.cpython-310.pyc | Bin 0 -> 1039 bytes reviewbot/main.py | 7 ++- reviewbot/utils.py | 49 +++++++++++++++++--- test_module/hello.py | 14 ++++-- 6 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 reviewbot/__pycache__/main.cpython-310.pyc create mode 100644 reviewbot/__pycache__/utils.cpython-310.pyc diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml index 8e6b610..0d2d247 100644 --- a/.github/workflows/code-review.yml +++ b/.github/workflows/code-review.yml @@ -7,6 +7,11 @@ on: jobs: review: runs-on: ubuntu-latest + + permissions: + contents: read + pull-requests: read + steps: - name: Checkout code uses: actions/checkout@v3 @@ -20,6 +25,12 @@ jobs: run: | pip install -r requirements.txt - - name: Run code review + - name: Run LLM code review + env: + GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PYTHONPATH: ${{ github.workspace }} + GITHUB_REPOSITORY: ${{ github.repository }} + GITHUB_REF: ${{ github.ref }} run: | - python reviewbot/main.py + python3 -m reviewbot.main diff --git a/reviewbot/__pycache__/main.cpython-310.pyc b/reviewbot/__pycache__/main.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9b088cecc1d54614cd267904f77773cab37f6c1 GIT binary patch literal 1266 zcmYjQQE%He5GEkoLkk$|wk8|8VL;Zk+e7stFyh%(B8e(V zC$nMiC41d3SOz4I`#pQp>z?)(GN9YhYKsuKBY8*izWaD52ZJ8L@vqsRed7}Hx82+v z3^!k*=zUaz2wIS&ooPaG&k9yLi9?BSg!?N=T+tC-oIB7J-U(Cpp>s~qOJ8gx^#8$k z$YDque+niQ`DBt&YkD&}I9oYD(Z8TF#~0!D+85@eq7YB3`;OPDhgimc%!3FBb~{)iS`~HMSBk+$}4TuJTpyKFSLPj z`S7Kj2N*8kfrcuVD$sIb&a4HhX!7`p1Q|oaY z^Ew|*m3%eIWEsmEDxSxudvP}7CPq_TfaOPrtnp^R1t{IPmaOIObAA>)#hZv)*LVcR ziI>e}o`F`jA{y^aXoYo2!d}CqZakdIAg8MQh^Kd{Ia)5`4df_9sz8^jsgr zKOv7gK2i%_mB=kGPI(o71^UFu8h^EnY|yCvi0DX~xLw*+$@6MdFPdR%O3!jLOD%V{ z-t~v5`qXEPc3-oO&u&rnnz`NU;nvXc*#}hZ;(-k1-LS1`@ork>BU~7APS(WG6*DCS z8``_3LFg(QZ-YV&aMgGU>VjtwGPQ&Iq}!&oA*xlk?J?J;ZIja$YnS>Ib9vu-{4}+` zGz~qqg$C6}mF&DDY&17{p>KqJd#mClr0I=7_HWcCn*Ujw#^<(zw6*)hrTAOanXJYLHN7%{A`VCg>r3_8V2h+pC6 z+9oT!3|O$jEWC{xY>~QUvA%6W7X5;M##b3JWDraA2jFjcKT9lmfnE{TX6Z}P1Z=~i z7l>_I4A^-UHQ@v`5!-6wHZsvEv7rrY%xL^mKP{ zwEyJr`0>f%(f4`!#`X1UoL&42viSU4p|vO{-G{bxse_sLPWtY<^6 zy1bkVCCeEvO?OU}pu>Xee!h8C^5pQF{e#7aZ;D;^UVHyHwZCZXa;l*4;x4VKLX4;p zvdrcs>raH4*2Dh%M}(;+0w4nHp2+`&mXSah)`hvur&= zwrFKlT@*T7#MxK?*$WI`{N#cGLd~$E6P_m(R|9W>r#0o2aiv{cQAKCkMHMxpsl#b6 zbwp~{x;g_FOt^882G+*4_kZ+cfV)c+KdZSm+TBo8Xg(NAHPD8dTD#DX;$j$;mkf4N zl)a5S^i=b9r3RO$>>?wd^HQ~eqYG+P?6tkU?WPC^Qx!^zS45fji@}{?HBMRNG&Rqh- z4SZL)e@K4= 3 and parts[-3] == "pull": + pr_number = parts[-2] + else: + raise Exception(f"Unexpected GITHUB_REF format: {ref}") + + token = os.environ.get("GITHUB_TOKEN") + if not token: + raise Exception("Missing GITHUB_TOKEN environment variable.") + + headers = { + "Authorization": f"Bearer {token}", + "Accept": "application/vnd.github.v3+json", + } + + url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}/files" + + diffs = [] + page = 1 + while True: + response = requests.get(url, headers=headers, params={"page": page, "per_page": 100}) + response.raise_for_status() + files = response.json() + if not files: + break + + for f in files: + patch = f.get("patch") + if patch: + diffs.append(patch) + + page += 1 + + return "\n".join(diffs) diff --git a/test_module/hello.py b/test_module/hello.py index 230ef63..e4c12c0 100644 --- a/test_module/hello.py +++ b/test_module/hello.py @@ -1,6 +1,10 @@ -# test_module/hello.py +# Hello.py: A sample python script used for testing reviews -def hello(name): - print("Hello " + name) - -hello("World") +def twoSum(array, targetSum): + for i in range(0, len(array)): + for j in range(i+1, len(array)): + if array[i] + array[j] == targetSum: + return ([array[i], array[j]]) + return [] + +twoSum([2,7,11,15], 9) From 49b3cb4a251196a372e4ab8f3d696015616a9d28 Mon Sep 17 00:00:00 2001 From: Bryan Montalvan Date: Fri, 6 Jun 2025 01:10:14 -0400 Subject: [PATCH 2/2] Allow GH action to post review as comment --- .github/workflows/code-review.yml | 2 +- reviewbot/main.py | 8 +++--- reviewbot/utils.py | 45 ++++++++++++++++++++++--------- test_module/hello.py | 10 +++---- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml index 0d2d247..576479e 100644 --- a/.github/workflows/code-review.yml +++ b/.github/workflows/code-review.yml @@ -10,7 +10,7 @@ jobs: permissions: contents: read - pull-requests: read + pull-requests: write steps: - name: Checkout code diff --git a/reviewbot/main.py b/reviewbot/main.py index a6cff14..0b5c570 100644 --- a/reviewbot/main.py +++ b/reviewbot/main.py @@ -1,6 +1,6 @@ import os import requests -from reviewbot.utils import get_diff +from reviewbot.utils import get_diff, post_pr_comment, get_pr_number def review_with_groq(diff): api_key = os.environ.get("GROQ_API_KEY") @@ -12,23 +12,21 @@ def review_with_groq(diff): "model": "meta-llama/llama-4-scout-17b-16e-instruct", "messages": [ {"role": "system", "content": "You are a senior software engineer doing code reviews."}, - {"role": "user", "content": f"Please review this code diff:\n\n{diff}"} + {"role": "user", "content": f"Please review this code diff, list improvements in bullet points:\n\n{diff}"} ], "temperature": 0.3, } response = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=payload) - # 👇 Print the response for debugging print("Raw Groq response:", response.status_code, response.text) - response.raise_for_status() return response.json()["choices"][0]["message"]["content"] def main(): diff = get_diff() review = review_with_groq(diff) - print("::notice file=test_module/hello.py,line=1::" + review.replace("\n", " ")) + post_pr_comment(review) if __name__ == "__main__": main() diff --git a/reviewbot/utils.py b/reviewbot/utils.py index 87c91b2..9049894 100644 --- a/reviewbot/utils.py +++ b/reviewbot/utils.py @@ -1,19 +1,20 @@ import os import requests +import json -def get_diff(): - repo = os.environ.get("GITHUB_REPOSITORY") # e.g. "owner/repo" - ref = os.environ.get("GITHUB_REF") # e.g. "refs/pull/123/merge" +def get_pr_number(): + event_path = os.getenv("GITHUB_EVENT_PATH") + if not event_path: + raise Exception("GITHUB_EVENT_PATH not set") - if not repo or not ref: - raise Exception("Missing GitHub repository or ref environment variables.") + with open(event_path, 'r') as f: + event = json.load(f) + + return event["pull_request"]["number"] - # Extract PR number safely: - parts = ref.split("/") - if len(parts) >= 3 and parts[-3] == "pull": - pr_number = parts[-2] - else: - raise Exception(f"Unexpected GITHUB_REF format: {ref}") +def get_diff(): + repo = os.environ.get("GITHUB_REPOSITORY") # e.g. "owner/repo" + pr_number = get_pr_number() token = os.environ.get("GITHUB_TOKEN") if not token: @@ -38,8 +39,26 @@ def get_diff(): for f in files: patch = f.get("patch") if patch: - diffs.append(patch) + diffs.append(f"File: {f['filename']}\n{patch}") page += 1 - return "\n".join(diffs) + return "\n\n".join(diffs) + +def post_pr_comment(body: str): + repo = os.getenv("GITHUB_REPOSITORY") + token = os.getenv("GITHUB_TOKEN") + pr_number = get_pr_number() + + url = f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments" + headers = { + "Authorization": f"Bearer {token}", + "Accept": "application/vnd.github+json" + } + payload = { + "body": body + } + + response = requests.post(url, headers=headers, json=payload) + print("GitHub API response:", response.status_code, response.text) + response.raise_for_status() diff --git a/test_module/hello.py b/test_module/hello.py index e4c12c0..eb53221 100644 --- a/test_module/hello.py +++ b/test_module/hello.py @@ -1,10 +1,6 @@ # Hello.py: A sample python script used for testing reviews -def twoSum(array, targetSum): - for i in range(0, len(array)): - for j in range(i+1, len(array)): - if array[i] + array[j] == targetSum: - return ([array[i], array[j]]) - return [] +def helloWorld(): + print("Hello World") -twoSum([2,7,11,15], 9) +helloWorld()