Automating PR Descriptions with GitHub Actions and Python: Let the Bots Do the Talking

Austin Hunt
5 min readSep 10, 2024

--

Example Pull Request Described with OpenAI ChatGPT via GitHub Action Workflow

If you’ve ever found yourself staring at a blank “Description” box on a GitHub Pull Request, hoping a well-formed PR summary will magically appear, then my friend, you’re in good company. Writing good PR descriptions is an art that somehow always feels more like homework that I wish my dog would eat. What if we could make GitHub itself do the heavy lifting? Enter the magical combo of GitHub Actions, Python, OpenAI, and a sprinkle of GitHub Secrets.

We’re gonna walk through how you can set up a GitHub Action triggered by labeling a PR with pr-description (or really any label of your choosing) which uses a Python script to summon OpenAI to write your PR descriptions for you.

If Skynet’s going to rise, it might as well start by writing your release notes.

Why Automate PR Descriptions?

Let’s face it — developers are often better at writing code than explaining it. I’ve been guilty of this, but I like to think I’m getting better. Writing this kind of thing helps! Summarizing a PR can feel like writing a book report. Sometimes you may feel like you only remember half the book. On that note, I do want to mention something important here:

If you keep your pull requests small, writing clear, clean, and helpful PR descriptions is way easier.

I’m guilty of creating large PRs because of the snowbally nature of a good flow-state development session. Trimming large PRs back into small ones is a more difficult task than keeping them small to begin with.

Regardless of PR size, automating PR descriptions saves you from burning those extra brain cells and ensures that your team (and future you) gets a clear summary of what’s going on in a PR.

Step 1: Setting Up Your GitHub Action

First off, we need a GitHub Action to trigger the magic. We’ll use labels as our signaling mechanism — specifically, the pr-description label. Again, you can use whatever label you’d like. Well, really, you can use any signal you like, it doesn’t have to be a label; we (Ayman Hajja and myself, who work together on dev ops processes frequently) find that labels work well for our purposes, and that’s what dev ops is all about.

When this pr-description label gets slapped onto a PR, our GitHub Action will kick in, run a Python script, and voila — auto-generated PR description.

Here’s a basic GitHub Action YAML file that does just that. Throw this into .github/workflows/auto-pr-description.yml:

name: Generate PR Description

on:
pull_request:
types: [labeled]

jobs:
generate-pr-description:
if: github.event.label.name == 'pr-description'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'

- name: Install dependencies
run: |
pip install openai PyGithub

- name: Generate PR Description
run: python scripts/generate_pr_description.py
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

This action listens for the labeled event and only runs if the label is pr-description. Once triggered, it installs the necessary Python dependencies, and then calls our Python script that will, in turn, call OpenAI to do its thing.

Now, on to the juicy part: the Python script.

Step 2: Writing the Python Script

The script we’re going to write will use OpenAI’s API to generate a description based on the PR’s diff, title, and commit messages. It’ll also use GitHub’s API (via PyGithub) to grab PR details and update the PR with the generated description.

Here’s a basic Python script to handle that, saved as scripts/generate_pr_description.py:

import os
import openai
from github import Github

# Set up OpenAI and GitHub credentials
openai.api_key = os.getenv('OPENAI_API_KEY')
gh = Github(os.getenv('GITHUB_TOKEN'))

# Get PR details
repo_name = os.getenv('GITHUB_REPOSITORY')
pr_number = os.getenv('GITHUB_REF').split('/')[-1]

repo = gh.get_repo(repo_name)
pr = repo.get_pull(int(pr_number))

# Gather the PR data (diff, title, commits)
pr_title = pr.title
pr_commits = "\n".join([commit.commit.message for commit in pr.get_commits()])
pr_diff = pr.diff_url # We’ll pass the diff URL to OpenAI for context

# Prepare the prompt for OpenAI
prompt = f"Summarize the following pull request:\n\nTitle: {pr_title}\n\nCommits:\n{pr_commits}\n\nDiff: {pr_diff}"

# Generate the description using OpenAI
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
max_tokens=150
)

# Extract the generated description
generated_description = response.choices[0].text.strip()

# Update the PR description on GitHub
pr.edit(body=generated_description)

print(f"Updated PR #{pr_number} with generated description.")

Here’s what’s happening in the script:

  1. API Keys: It pulls in your OpenAI API key and GitHub token using environment variables (OPENAI_API_KEY and GITHUB_TOKEN). We’ll store those as GitHub Secrets (more on that in a sec).
  2. PR Data: We grab the PR title, commit messages, and the diff URL to use as context for generating the description.
  3. OpenAI Magic: We construct a prompt and feed it to OpenAI, which responds with a beautifully crafted description. It’s basically your own little assistant, but without the salary requirements.
  4. PR Update: Finally, we update the PR description with the OpenAI-generated text using GitHub’s API.

Step 3: Adding Your GitHub Secrets

We don’t want to hardcode sensitive values like our OpenAI API key or our GitHub Token in our workflow file, especially if the repo is public. We don’t want to do that for private repositories either, but public is a definite hazard. So, we store those secrets using GitHub Secrets by doing the following.

  1. Head to your repo on GitHub.
  2. Click on Settings > Secrets > Actions.
  3. Add the following secrets:
  • OPENAI_API_KEY: Your OpenAI API key.
  • GITHUB_TOKEN: This should already be available as a secret, but if not, generate a new GitHub token with the necessary permissions. You can do this at https://github.com/settings/tokens. For the permissions, repo should be sufficient.

Boom. Now GitHub knows how to talk to OpenAI and make things happen.

Step 4: Testing It Out

Label a PR with pr-description, and sit back as your GitHub Action and Python script come together to write a PR description that’s so good, you’ll forget a robot wrote it.

If something goes wrong, check the Actions tab for logs that might help pinpoint what’s happening. The usual culprits are missing secrets, API issues, or typos (the ones you swore you didn’t make). Or it could just be a fluke, like an action runner failing to start or a network timeout issue.

Conclusion

Congratulations, you’ve just automated the last step of creating a solid Pull Request. Now you can focus on what matters: writing code, fixing bugs, Googling obscure error messages, and answering those telemarketer calls. Your car’s extended warranty needs attention.

PR descriptions no longer need to be a burden. With a combination of GitHub Actions, OpenAI, and Python, you can let the machines handle it while you enjoy that extra cup of coffee or knock out the next feature on your roadmap.

And hey, if you really don’t like the generated descriptions, just tell the AI that. For instance, you may like your descriptions to follow a very specific format. You can just modify the prompt in the Python file to include those formatting rules, and the response will be more in line with what you’re looking for. AI is a decent listener.

--

--

Austin Hunt
Austin Hunt

Written by Austin Hunt

Portrait artist programmer. College of Charleston ’19. Vanderbilt Univ. CS ’22. I love art, music, the web, coding, automation, & most importantly, challenges.

Responses (1)