Automatically tracks open-source pull request contributions across multiple repositories and generates a visual contribution graph.
🟣 Merged | 🟢 Open
MergeStation uses the GitHub GraphQL API to fetch all pull requests created by a user across any repository on GitHub. It then:
- Collects PR data using cursor-based pagination (fetches ALL PRs, not just the first 100)
- Aggregates stats by organization — counting Merged, Open, and Closed PRs
- Generates a hub-and-spoke SVG visualization showing your contribution network
- Automates daily updates via GitHub Actions
The workflow is split into two jobs with artifact passing:
flowchart LR
A["GitHub API (GraphQL)"] -->|fetch| B["fetch job"]
B -->|upload artifact| C["data.json"]
C -->|download artifact| D["generate job (env: production)"]
D -->|conditional commit| E["contribution_graph.svg"]
- Language: Python 3.11
- API: GitHub GraphQL API v4
- Visualization: SVG (generated programmatically)
- Automation: GitHub Actions (cron + manual dispatch)
- Auth:
GITHUB_TOKEN(built-in)
The main workflow that fetches PR data and generates the contribution graph.
Triggers:
- Daily cron schedule at 2:00 AM UTC
- Manual dispatch with configurable inputs
Workflow Dispatch Inputs:
| Input | Type | Default | Description |
|---|---|---|---|
max_orgs |
string | 8 |
Maximum number of organizations to display |
include_closed |
boolean | false |
Include closed PRs in the chart |
These inputs are passed as environment variables (MAX_ORGS, INCLUDE_CLOSED) to the Python scripts, which fall back to config.json values when not set (so the cron trigger works without inputs).
Two-Job Architecture:
fetchjob — Fetches PR data from GitHub GraphQL API, uploadsdata.jsonas an artifactgeneratejob — Downloads the artifact, generates the SVG chart, conditionally commits only if changes are detected
The generate job uses environment: production, demonstrating understanding of GitHub environment protections used in release pipelines.
Conditional Commit Logic:
The workflow detects whether the chart actually changed before committing:
- If changes are detected → commits and pushes
- If no changes → skips the commit and reports in the job summary
A validation workflow that runs on pull requests touching config.json or scripts/.
Steps:
- Validates
config.jsonschema — checks all required fields exist with correct types - Checks Python syntax — compiles both scripts to catch syntax errors
- Dry-run API test — fetches 1 page of PR data to verify the API connection works, without writing
data.json
git clone https://github.com/Sandesh282/MergeStation.git
cd MergeStationpip install -r requirements.txtEdit config.json to customize:
{
"username": "Sandesh282",
"excluded_orgs": ["Sandesh282", "firstcontributions"],
"max_orgs": 8,
"output_dir": "charts"
}| Field | Description |
|---|---|
username |
Your GitHub username |
excluded_orgs |
Organizations to exclude from the chart |
max_orgs |
Maximum number of orgs to display |
output_dir |
Directory for output files |
Environment variables MAX_ORGS and INCLUDE_CLOSED can override config values at runtime.
export GITHUB_TOKEN="your_personal_access_token"
python scripts/fetch_stats.py
python scripts/generate_chart.pyThe workflow runs daily at 2:00 AM UTC and uses the built-in GITHUB_TOKEN. To trigger manually:
- Go to Actions tab in your repository
- Select Update Contribution Graph
- Click Run workflow
- Optionally configure
max_orgsandinclude_closedinputs
MergeStation/
├── .github/workflows/
│ ├── update.yml # Main workflow (fetch → generate → commit)
│ └── validate.yml # PR validation (config + syntax + dry-run)
├── charts/
│ ├── data.json # PR statistics (auto-generated)
│ └── contribution_graph.svg # Visualization (auto-generated)
├── scripts/
│ ├── fetch_stats.py # Data collection (pagination + retry + dry-run)
│ └── generate_chart.py # SVG generation script
├── config.json # Project configuration
├── requirements.txt # Python dependencies
├── .gitignore
└── README.md
- Full pagination — fetches ALL pull requests, not just the first 100
- Retry logic with exponential backoff for rate limiting
- Configurable org exclusion list
- Hub-and-spoke SVG visualization with GitHub avatars
- Two-job workflow architecture with artifact passing
- Workflow dispatch inputs with env var overrides
- Conditional commits — only pushes when chart actually changes
- PR validation workflow with config schema checks and dry-run mode
- Environment protection on the generate job
- Color-coded stats (🟣 Merged,🟢 Open)