DEV Community

Cover image for Let's take a tally on your PR this year!

Posted on

Let's take a tally on your PR this year!

A co-worker posted how many lines she added/deleted to the repo in 2023.

I just wrote a simple Python script to check PRs.

The requirement is GitHub CLI.

GitHub logo cli / cli

GitHub’s official command line tool

GitHub CLI

gh is GitHub on the command line. It brings pull requests, issues, and other GitHub concepts to the terminal next to where you are already working with git and your code.

screenshot of gh pr status

GitHub CLI is supported for users on and GitHub Enterprise Server 2.20+ with support for macOS, Windows, and Linux.


For installation options see below, for usage instructions see the manual.


If anything feels off, or if you feel that some functionality is missing, please check out the contributing page. There you will find instructions for sharing your feedback, building the tool locally, and submitting pull requests to the project.

If you are a hubber and are interested in shipping new commands for the CLI, check out our doc on internal contributions.



gh is available via Homebrew, MacPorts, Conda, Spack, Webi, and as a…

The following script requires github id, repo owner, repo name and limit as input.

The limit option default number is 30 so without this the command cannot take all merged PRs data from GitHub.

  • Display Top 5 PRs (based on additions)
  • Display total addtions
  • Display total deletins
  • Display total merged
import json
import subprocess

# Run the gh command and get the output
user_id = input('Enter your github id: ')
repo_owner = input('Enter repo owner: ')
repo = input('Enter repo name: ')
limit = input('Enter limit num: ')
limit = int(limit)

gh_command = f'gh pr list --repo {repo_owner}/{repo} --author {user_id} --state merged --json url,number,title,createdAt,additions,deletions --search "created:2023-01-01..2023-12-31" --limit {limit}'
gh_output = subprocess.check_output(gh_command, shell=True)

# Parse the JSON output
pr_data = json.loads(gh_output)

# Filter PRs by year and sort by additions
filtered_prs = [pr for pr in pr_data if pr['createdAt'].startswith('2023')]
sorted_prs = sorted(filtered_prs, key=lambda pr: pr['additions'], reverse=True)

# Calculate total additions and deletions
total_additions = sum(pr['additions'] for pr in sorted_prs)
total_deletions = sum(pr['deletions'] for pr in sorted_prs)

# Print the sorted PRs
# print(json.dumps(sorted_prs, indent=2))

# Print the top 5 PRs with the most additions
print(f'Your top 5 PR additions {repo_owner}/{repo}')
for i, pr in enumerate(sorted_prs[:5]):
    print(f'PR #{i+1}:')
    print(f'URL: {pr["url"]}')
    print(f'Number: {pr["number"]}')
    print(f'Title: {pr["title"]}')
    print(f'Created at: {pr["createdAt"]}')
    print(f'Additions: {pr["additions"]}')
    print(f'Deletions: {pr["deletions"]}')

# Print total additions and deletions
print(f'Total additions: {total_additions}')
print(f'Total deletions: {total_deletions}')

# Print total number of merged PRs
print(f'Total merged PRs: {len(sorted_prs)}')
Enter fullscreen mode Exit fullscreen mode

My result

Your top 5 PR additions Opentrons/opentrons
PR #1:
Number: 12327
Title: feat(odd): add running protocol screen
Created at: 2023-03-20T22:37:25Z
Additions: 1242
Deletions: 48

PR #2:
Number: 12632
Title: refactor(app): re-order all text by key's alphabetical order
Created at: 2023-05-04T17:12:36Z
Additions: 1077
Deletions: 1078

PR #3:
Number: 13178
Title: feat(api-client, app, react-api-client) hook up E-stop modals to desktop app and touchscreen app
Created at: 2023-07-27T17:06:55Z
Additions: 946
Deletions: 175

PR #4:
Number: 11982
Title: feat(odd): add software update for the ODD app
Created at: 2023-01-11T18:58:11Z
Additions: 879
Deletions: 15

PR #5:
Number: 12825
Title: feat(app): add modal for deleting protocol in ProtocolDashboard
Created at: 2023-05-31T23:59:33Z
Additions: 703
Deletions: 445

Total additions: 33212
Total deletions: 14004
Total merged PRs: 243
Execution time: 17.30s
Enter fullscreen mode Exit fullscreen mode

Top comments (0)