Comprehensive tool for generating monthly tax deductible reports based on GitHub pull requests.
Automatically downloads diff files and creates organized summaries for tax reporting purposes.
By default it produces .txt files, but can be configured to generate .pdf files as well.
Supports flexible organization targeting - either specify the organization as a parameter or set a default in the script.
- Bash shell (macOS/Linux) or Git Bash/WSL (Windows)
- GitHub CLI
ghinstalled and authenticated jqcommand-line JSON processor
macOS (Homebrew):
brew install gh jqUbuntu/Debian:
sudo apt update && apt install gh && apt install jqWindows:
# Using winget (Windows 10 1709+)
winget install --id GitHub.cli && winget install stedolan.jq
# Using Chocolatey
choco install gh && choco install jqOther platforms: Visit https://cli.github.com/ for installation instructions
Initial GitHub CLI auth:
# Authenticate with GitHub
gh auth loginFollow prompts to:
- Choose GitHub.com
- Select HTTPS or SSH protocol
- Authenticate via web browser or personal access token
- Choose your preferred git protocol
Required permissions: The authenticated user needs:
- Read access to repositories in the target organization
- Ability to view pull requests and their diffs
More details
Make script executable (macOS/Linux):
chmod +x generate-report.shWindows setup: For Windows users, you have several options:
-
Git Bash (Recommended):
- Install Git for Windows (includes Git Bash)
- Open Git Bash terminal
- Navigate to script directory and run as shown in usage examples
-
Windows WSL:
- Install WSL2 with Ubuntu
- Install dependencies within WSL environment
- Run script from WSL terminal
-
PowerShell with Git Bash:
# Run from PowerShell bash ./generate-report.sh
You have two options for specifying the target GitHub organization:
Simply provide the organization name as the first parameter when running the script:
./generate-report.sh my-org-nameAlternatively, you can set a default organization by editing the script:
# Modify this line in generate-report.sh:
repositoryOwner="your-org-name"Tip
Using the parameter approach (Option 1) is more flexible as it allows you to work with different organizations without modifying the script.
To generate diff files as PDF documents, you need to install the following dependencies via Homebrew:
brew install enscript ghostscriptmacOS/Linux/Windows (Git Bash):
# Generate report for current month with specific organization
./generate-report.sh my-org-name
# Generate report for specific month with organization
./generate-report.sh my-org-name 2025-07
# Generate report for custom date range with organization
./generate-report.sh my-org-name 2025-07-01 2025-07-31Windows (PowerShell):
# Generate report for current month with specific organization
bash ./generate-report.sh my-org-name
# Generate report for specific month with organization
bash ./generate-report.sh my-org-name 2025-07
# Generate report for custom date range with organization
bash ./generate-report.sh my-org-name 2025-07-01 2025-07-31macOS/Linux/Windows (Git Bash):
# Generate report for current month (uses default org from script)
./generate-report.sh
# Generate report for specific month (uses default org)
./generate-report.sh 2025-07
# Generate report for custom date range (uses default org)
./generate-report.sh 2025-07-01 2025-07-31Windows (PowerShell):
# Generate report for current month (uses default org from script)
bash ./generate-report.sh
# Generate report for specific month (uses default org)
bash ./generate-report.sh 2025-07
# Generate report for custom date range (uses default org)
bash ./generate-report.sh 2025-07-01 2025-07-31- Console log: Detailed PR information with repository, title, PR number, close date, diff URL, and PR URL
- Summary by repository: Count of PRs per repository
- Diff file downloads: Individual diff files saved locally in organized directory structure
- Summary file: Master list linking PR titles to their corresponding diff files
More details
Generating report for period: 2025-07-01 to 2025-07-31
======================================================
Fetching merged pull requests...
Found 8 merged pull requests
PR DIFFS FOR TAX DEDUCTIBLE REPORT
==================================
Repository: your-org-name/repositoryExample
Title: prefix-168: Fix export and release o pkg
PR number: #218
Closed at: 2025-04-29T11:25:40Z
Diff URL: https://github.com/your-org-name/repositoryExample/pull/218.diff
PR URL: https://github.com/your-org-name/repositoryExample/pull/218
------------------------------------------------------------
SUMMARY BY REPOSITORY
====================
6 PRs: your-org-name/repositoryExample
1 PRs: your-org-name/repositoryExample2
1 PRs: your-org-name/repositoryExample3
DIFF URLS
================================
https://github.com/your-org-name/repositoryExample/pull/218.diff
...
GENERATING DIFFs
===============================================
✓✓✓ Generated: diffs/2025-07-01_2025-07-31/repositoryExample-217.......txt
...
✓✓✓ Generated summary: diffs/2025-07-01_2025-07-31/summary.txt
- Organization targeting: Pass organization name as parameter or use default from script
- Smart date from/to handling: Automatically detects month boundaries and handles edge cases
- Local diffs storage: Downloads actual diff files and stores them in organized directory structure
- File organization: Creates time-stamped directories (
YYYY-MM-DD_YYYY-MM-DD) for easy archiving - Summary generation: Creates master summary file linking PR titles to their diff files
- Multiple outputs: Console report, individual diff files, and summary file
- Error handling: Gracefully handles missing PRs, network issues, and invalid dates
- Filename sanitization: Cleans PR titles for safe filesystem usage
The script creates the following directory structure:
diffs/
└── YYYY-MM-DD_YYYY-MM-DD/
├── summary.txt
├── repo-name-123-PR_Title_Sanitized.txt
├── repo-name-124-Another_PR_Title.txt
└── ...
- summary.txt: Master file with format
[PR Title]-[filename]for each diff - Individual diffs files: Named as
{repo-short-name}-{pr-number}-{sanitized-title}.txt
The script uses these GitHub CLI commands internally:
# Search for merged PRs
gh search prs --author=@me --owner="your-org-name" --merged --created="YYYY-MM-DD..YYYY-MM-DD" --json title,repository,url,closedAt,number
# Download individual diff files
gh pr diff "PR_NUMBER" --repo "REPO_NAME"The script need to configure organization / repo owner.
To use with a different organization, modify the repositoryOwner variable at the top of the script.