# git-contribution-graph
A self-hosted Symfony service that merges contribution data from **GitHub**, **GitLab** and **Gitea** into a single GitHub-style heatmap SVG you can embed anywhere.
```
https://your-host/graph.svg?github_user=you&github_token=ghp_…&gitea_user=you&gitea_token=…&gitea_url=https://git.example.com
```

---
## Features
- **Three platforms** — GitHub, GitLab (cloud or self-hosted), Gitea (self-hosted)
- **Merged heatmap** — contributions from all sources are summed per day
- **GitHub colour palette** — exact dark/light theme tokens
- **Embeddable** — returns `image/svg+xml`, works in any `
` tag or Markdown
- **Cached** — responses cached for 1 hour, safe to embed in public READMEs
- **Graceful degradation** — if one platform fails, the others still render
---
## Deploy
### Requirements
- Docker + Docker Compose
### 1. Clone and configure
```bash
git clone https://git.arthurerlich.de/haylan/git-contribution-graph.git
cd git-contribution-graph
cp .env .env.local
```
Edit `.env.local`:
```dotenv
APP_ENV=prod
APP_DEBUG=0
APP_SECRET=
```
### 2. Start
```bash
docker compose up -d
```
The service listens on **port 8080** by default. Put Traefik or nginx in front of it for HTTPS.
### 3. Health check
```
GET /health → {"status":"ok"}
```
---
## API
### `GET /graph.svg`
| Parameter | Required | Description |
|---|---|---|
| `github_user` | ✗ | GitHub username |
| `github_token` | ✗ | GitHub PAT — scope: `read:user` |
| `gitlab_user` | ✗ | GitLab username |
| `gitlab_token` | ✗ | GitLab PAT — scope: `read_user`, `read_api` |
| `gitlab_url` | ✗ | GitLab base URL (default: `https://gitlab.com`) |
| `gitea_user` | ✗ | Gitea username |
| `gitea_token` | ✗ | Gitea PAT — scope: `read:user` |
| `gitea_url` | ✗ | Gitea instance URL, e.g. `https://git.example.com` |
| `theme` | ✗ | `dark` (default) or `light` |
All platform parameters are optional — include only the ones you use. At least one platform must be configured for a non-empty graph.
---
## Embedding in a README
### GitHub-only
```markdown

```
### GitHub + Gitea
```markdown

```
### All three platforms
```markdown

```
### Dark vs Light theme
```markdown


```
> **Security note:** API tokens embedded in public Markdown URLs are visible to anyone. Use read-only fine-grained tokens with minimal scopes. For private repos or sensitive setups, proxy the request server-side and keep tokens in environment variables.
---
## Token setup
### GitHub
1. Go to **Settings → Developer settings → Personal access tokens → Fine-grained tokens**
2. Set **Resource owner** to your account
3. Under **Permissions → Account permissions**, set **Contribution activity** → Read-only
4. Generate and copy the token
### GitLab
1. Go to **User Settings → Access Tokens**
2. Add a token with scopes: `read_user`, `read_api`
3. Generate and copy the token
### Gitea
1. Go to **Settings → Applications → Manage Access Tokens**
2. Add a token with permission: **user** → Read
3. Generate and copy the token
---
## Development
```bash
# Install deps
composer install
# Run dev server
APP_ENV=dev php -S localhost:8080 -t public
# Test endpoint
curl "http://localhost:8080/graph.svg?gitea_user=haylan&gitea_token=YOUR_TOKEN&gitea_url=https://git.arthurerlich.de" -o graph.svg
```
---
## Architecture
```
GET /graph.svg
│
├─ GitHubProvider → GitHub GraphQL API (contributionCalendar)
├─ GitLabProvider → GitLab REST API (/users/:id/events)
└─ GiteaProvider → Gitea REST API (/users/:user/heatmap)
│
merge by date (sum counts)
│
SvgRenderer
│
image/svg+xml (cached 1h)
```
---
## License
MIT