Files
git-contribution-graph/CLAUDE.md
T

3.4 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Development

# Install dependencies (generates composer.lock if missing — commit it)
composer install

# Run dev server
APP_ENV=dev php -S localhost:8080 -t public

# Test the graph endpoint
curl "http://localhost:8080/graph.svg?theme=dark" -o graph.svg
curl "http://localhost:8080/health"

Docker

# Build and run
docker compose up -d --build

# Force cache clear (clears the 1h filesystem cache)
docker compose exec graph rm -rf var/cache/*

# View logs
docker compose logs -f graph

There is no composer.lock in the repo. If you add or change dependencies, run composer install locally and commit the resulting lock file — without it, Docker builds resolve versions fresh each time and may produce inconsistent results.

The Dockerfile runs composer install --no-scripts (skipping Symfony post-install scripts) then composer dump-autoload --optimize --no-dev in the final stage. If bin/console fails with a missing class error inside the container, the most likely cause is the absent lock file causing an incomplete dependency resolution.

Architecture

Single-controller Symfony app with no database. The request flow:

GET /graph.svg?theme=dark|light
  └─ GraphController
       ├─ host check (ALLOWED_HOSTS env, optional)
       ├─ cache lookup (filesystem, 1h TTL, key = "graph_{theme}")
       │    └─ on miss:
       │         ├─ GitHubProvider  → GitHub GraphQL API (contributionCalendar query)
       │         ├─ GitLabProvider  → GitLab REST /users/:id/events (paginated, 100/page)
       │         └─ GiteaProvider   → Gitea REST /api/v1/users/:user/heatmap
       │              each returns array<string, int>  (Y-m-d => count)
       │              failures are caught and logged; remaining providers still render
       │         └─ merge by date (sum counts across providers)
       │         └─ SvgRenderer::render()
       └─ Response: image/svg+xml, Cache-Control: public max-age=3600

Provider activation: a provider only runs when its env vars are non-empty. GitHub and GitLab require _USER + _TOKEN; Gitea additionally requires _URL. GitLab resolves a numeric user ID from the username via a /api/v4/users?username= lookup before fetching events.

SvgRenderer: builds a 53-column × 7-row grid aligned so the last column always ends on the Saturday of the current week. Five intensity levels (0 contributions → level 0, 13 → 1, 46 → 2, 79 → 3, 10+ → 4) mapped to GitHub's exact colour tokens. No external assets — the SVG is fully self-contained.

Cache: filesystem adapter (var/cache/), mounted as a Docker volume to survive container restarts. Theme is part of the cache key so dark and light are cached independently.

Environment variables

Variable Required Notes
APP_SECRET Yes 32+ char random string
GITHUB_USER / GITHUB_TOKEN For GitHub Token scope: read:user
GITLAB_USER / GITLAB_TOKEN For GitLab Token scopes: read_user, read_api
GITLAB_URL No Defaults to https://gitlab.com
GITEA_USER / GITEA_TOKEN / GITEA_URL For Gitea Token scope: read:user
ALLOWED_HOSTS No Comma-separated hostnames; empty = allow all

Copy .env to .env.local for local development — .env.local is gitignored.