How to Improve Your GitHub PR after Review with One Command Using GPT

Wacław The Developer
5 min readFeb 4, 2024

Hi everybody. If you have read my posts before, you may have noticed that I primarily write about Go, but today I am going to show you how to use OpenAI APIs to refactor your code after a code review.

Image generated by AI

Example project

I created an example repository to show how to perform automatic refactoring using OpenAI’s GPT. The repository contains only one script, main.py, that downloads the mocked data from https://randomuser.me/, displays the summary, and saves it in a JSON file.

import json
import requests


def fetch_random_user():
response = requests.get("https://randomuser.me/api/")
return response.json()


def save_user_to_file(user_data, filename):
with open(filename, "w") as file:
json.dump(user_data, file, indent=4)


def read_user_from_file(filename):
with open(filename, "r") as file:
return json.load(file)


def print_user(user):
name = user["results"][0]["name"]
print(f"Name: {name['title']} {name['first']} {name['last']}")
email = user["results"][0]["email"]
print(f"Email: {email}")


def main():
user_data = fetch_random_user()
file_name = "random_user.json"

save_user_to_file(user_data, file_name)
print(f"User data has been saved to {file_name}")

saved_user_data = read_user_from_file(file_name)

print("Here is the fetched user data:")
print_user(saved_user_data)


if __name__ == "__main__":
main()

Let’s imagine that we have a task to add displaying of the phone too in function print_user()

So, I am adding the changes:

  • Add printing the phone field from JSON with mocked user data
  • Add the types of arguments for functions for better code reading

Next, let’s open PR.

Code review

In this code I’d like to improve these moments:

  • Add a check on data instead of directly accessing the field because we have the risk of getting an exception if the field is not there (comment)
  • Measure how much time a get request took (comment)
  • Add exception handling for the case if a file not found in read_user_from_file (comment)

Let’s improve the code

Let’s install the tool first. All we need is Python (I strongly recommend using venv) and installing gptmypr:

pip install gptmypr

Next, we need to configure gptmypr. To operate, we need GitHub Token to have access to your PR and OpenAI API key to use GPT models.

Generating GitHub Token

Let’s go to https://github.com/settings/tokens and choose the Fine-grained tokens:

Enter the name for your new token and the repository you want to access (or select All repositories):

Then, tap on Repository permissions dropdown and select these two permissions:
Content (read only). Gptmypr requires that to read the latest version of source code:

And Pull requests (read and write). Write permission will be used to mark comments with reactions as already procesed:

Finally, tap “Generate token”

Generating OpenAI API key

Here it’s much easier: just go to https://platform.openai.com/api-keys and tap “Create new secret key”

Running refactoring

Attention! Local uncommitted changes will be lost, so I advise to stash local changes.

Make sure that you are in the root directory of the project and run:

gptmypr --pr 1

Note that 1 is number of PR. You can find it at the end of URL: https://github.com/waclawthedev/demo_repo_for_gptmypr/pull/1)

First time configuration

If you start gptmypr for the first time, it will ask for some configuration parameters:

  1. The GitHub Token you generated before
  2. Reaction name to mark the comments as processed. Default “eyes” will look something like this under a comment after it has been procesed: 👀
  3. The OpenAI API key you generated before
  4. The GPT model name. I like gpt-4-1106-preview because it’s fast, intelligent and has a fresh knowledge base. The gpt-4–0125-preview was recently released, and OpenAI says, “the model intended to reduce cases of “laziness” where the model doesn’t complete a task”. You can try experimenting with that model instead of gpt-4–1106-preview.

Note that I write this article on Feb 2024. Maybe some better model already exists.

Result

Let’s see how code was refactored:

Comment “measure and print how much time get request took” was fulfilled:

def fetch_random_user() -> dict:
start_time = time.time()
response = requests.get("https://randomuser.me/api/")
elapsed_time = time.time() - start_time
print(f"GET request took {elapsed_time} seconds")
return response.json()

Comment “Add exception handling for case of non-existing file” was fulfilled too:

def read_user_from_file(filename: str) -> dict:
try:
with open(filename, "r") as file:
return json.load(file)
except FileNotFoundError:
print(f"Error: The file {filename} does not exist.")
return {}

Here is result for the comment “Avoid directly getting elements and fields from dictionary. Make it safe here and everywhere in this function. Refactor this function.”:

def print_user(user: dict):
try:
results = user.get("results", [])
if not results:
raise ValueError("No results found")
result = results[0]
name = result.get("name")
if not name:
raise ValueError("No name found")
title = name.get("title", "")
first = name.get("first", "")
last = name.get("last", "")
print(f"Name: {title} {first} {last}")
email = result.get("email", "No email found")
print(f"Email: {email}")
phone = result.get("phone", "No phone found")
print(f"Phone: {phone}")
except ValueError as e:
print(f"Error: {e}")

Now, take a look at comment on GitHub:

Processed comment marked with eyes emoji, and if you try to run gptmypr again, you will see:

So, to run refactoring again, unselect ‘eyes’ reaction on the comment. Also, remember that any uncommited local changes will be rewritten:

Take a note that every result after running gptmypr will be unique. Obviously, the results quality hardly depends on the GPT model. I advise using these results to get fresh ideas and speed up your code improvements, not for blindly committing changes to abranch.

Conclusion

I hope that method will bring you a lot of fun and new ideas for coding, but remember, that all the code will be transferred thought OpenAI API according to OpenAI’s terms of use and privacy policies. Make sure, that you authorized by code owner/client/employer to do that. Also, feel free to propose the fixes or new ideas for future releases — just open an issue here.

--

--