128 lines
2.8 KiB
Markdown
128 lines
2.8 KiB
Markdown
# git-activity-merge
|
|
|
|
Small self-hosted FastAPI service that merges GitHub + Gitea contribution data and returns embeddable contribution heatmap images.
|
|
|
|
Example for GitHub profile README:
|
|
|
|
```md
|
|

|
|
```
|
|
|
|
## What It Does
|
|
|
|
- Fetches contribution data from:
|
|
- GitHub GraphQL API (`GITHUB_USERNAME`, optional `GITHUB_TOKEN`)
|
|
- Gitea heatmap API (`{GITEA_BASE_URL}/api/v1/users/{GITEA_USERNAME}/heatmap`)
|
|
- Normalizes into date-based counts:
|
|
- `github`
|
|
- `gitea`
|
|
- `total`
|
|
- Caches source responses and rendered images on disk.
|
|
- Returns:
|
|
- merged JSON
|
|
- GitHub-style SVG heatmap
|
|
- PNG heatmap
|
|
|
|
## API Routes
|
|
|
|
- `GET /health`
|
|
- `GET /activity.json`
|
|
- `GET /activity.svg`
|
|
- `GET /activity.png`
|
|
|
|
Supported query params:
|
|
|
|
- `year=YYYY` or `days=365` (mutually exclusive)
|
|
- `theme=dark|light`
|
|
- `source=all|github|gitea`
|
|
|
|
Examples:
|
|
|
|
```bash
|
|
curl "http://localhost:8000/activity.json?days=365&source=all"
|
|
curl "http://localhost:8000/activity.svg?year=2026&theme=dark"
|
|
curl "http://localhost:8000/activity.png?days=180&source=gitea"
|
|
```
|
|
|
|
## Setup
|
|
|
|
### 1. Install
|
|
|
|
```bash
|
|
python -m venv .venv
|
|
. .venv/bin/activate # or .venv\Scripts\activate on Windows
|
|
pip install -e ".[dev]"
|
|
```
|
|
|
|
### 2. Configure
|
|
|
|
Copy `.env.example` to `.env` and edit values.
|
|
|
|
Required:
|
|
|
|
- `GITHUB_USERNAME`
|
|
- `GITEA_BASE_URL`
|
|
- `GITEA_USERNAME`
|
|
|
|
Optional:
|
|
|
|
- `GITHUB_TOKEN`
|
|
- `GITEA_TOKEN`
|
|
- `CACHE_TTL_SECONDS` and `CACHE_DIR` enable caching when both are set
|
|
- `DEFAULT_THEME` (`light` or `dark`, default: `light`)
|
|
- `SERVICE_TITLE` (default: `git-activity-merge`)
|
|
|
|
If you leave `CACHE_TTL_SECONDS` and `CACHE_DIR` undefined, the app skips caching entirely.
|
|
|
|
### 3. Run
|
|
|
|
```bash
|
|
uvicorn app.main:app --reload --port 8000
|
|
```
|
|
|
|
## Docker
|
|
|
|
Build and run the container image directly:
|
|
|
|
```bash
|
|
docker build -t registry.reversed.dev/registry/git-activity-merger:latest .
|
|
docker run --rm -p 8000:8000 \
|
|
--env-file .env \
|
|
registry.reversed.dev/registry/git-activity-merger:latest
|
|
```
|
|
|
|
Or use Compose:
|
|
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
Container serves on port `8000`. Compose mounts a named cache volume at `/app/cache`.
|
|
|
|
## Reverse Proxy Example (Nginx)
|
|
|
|
```nginx
|
|
server {
|
|
server_name example.com;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:8000;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
}
|
|
}
|
|
```
|
|
|
|
Then embed directly:
|
|
|
|
```md
|
|

|
|
```
|
|
|
|
## Notes
|
|
|
|
- GitHub GraphQL without token is possible but lower-rate/less reliable. Set `GITHUB_TOKEN` for stability.
|
|
- Gitea instances may require `GITEA_TOKEN` for private activity or stricter rate limits.
|
|
- If upstream APIs fail and stale cache exists, `/activity.json` includes `"stale": true` and stale data is served.
|