{"id":51858581,"url":"https://github.com/stuttgart-things/homerun2-git-pitcher","last_synced_at":"2026-07-24T03:31:08.140Z","repository":{"id":345241702,"uuid":"1184636669","full_name":"stuttgart-things/homerun2-git-pitcher","owner":"stuttgart-things","description":"Active GitHub repository watcher for homerun2 — polls GitHub API and pitches events to Redis Streams","archived":false,"fork":false,"pushed_at":"2026-07-03T07:05:31.000Z","size":172,"stargazers_count":0,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-03T09:08:57.875Z","etag":null,"topics":["git","git-events","golang","homerun2"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stuttgart-things.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-17T19:29:26.000Z","updated_at":"2026-05-28T07:29:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"9b4964b2-3572-4e39-a7ca-7aecbb7fabc9","html_url":"https://github.com/stuttgart-things/homerun2-git-pitcher","commit_stats":null,"previous_names":["stuttgart-things/homerun2-git-pitcher"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/stuttgart-things/homerun2-git-pitcher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuttgart-things%2Fhomerun2-git-pitcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuttgart-things%2Fhomerun2-git-pitcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuttgart-things%2Fhomerun2-git-pitcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuttgart-things%2Fhomerun2-git-pitcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stuttgart-things","download_url":"https://codeload.github.com/stuttgart-things/homerun2-git-pitcher/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuttgart-things%2Fhomerun2-git-pitcher/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35826032,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-24T02:00:07.870Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["git","git-events","golang","homerun2"],"created_at":"2026-07-24T03:31:06.883Z","updated_at":"2026-07-24T03:31:08.014Z","avatar_url":"https://github.com/stuttgart-things.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# homerun2-git-pitcher\n\n\u003cimg src=\"https://github.com/stuttgart-things/docs/blob/main/hugo/homerun2-git-pitcher.png?raw=true\" alt=\"homerun2-git-pitcher logo\" width=\"300\"\u003e\n\nActive GitHub repository watcher for homerun2 — polls GitHub API and pitches events to Redis Streams.\n\n[![Build \u0026 Test](https://github.com/stuttgart-things/homerun2-git-pitcher/actions/workflows/build-test.yaml/badge.svg)](https://github.com/stuttgart-things/homerun2-git-pitcher/actions/workflows/build-test.yaml)\n\n## What it does\n\nhomerun2-git-pitcher watches configured GitHub repositories for events (pushes, pull requests, releases, workflow runs) and forwards them as structured messages to Redis Streams, where downstream homerun2 catchers can consume them.\n\n```\nGitHub API  ──poll──\u003e  git-pitcher  ──pitch──\u003e  Redis Stream  ──consume──\u003e  catchers\n```\n\n## Usage\n\n### Watch profile\n\nCreate a YAML file defining which repos to watch:\n\n```yaml\ngithub:\n  token: env:GITHUB_TOKEN   # reads from environment variable\n\n  repos:\n    - owner: stuttgart-things\n      name: homerun2-led-catcher\n      interval: 5m\n      events: [push, pull_request, release, workflow_run]\n\n    - owner: stuttgart-things\n      name: homerun2-core-catcher\n      interval: 10m\n      events: [push, release]\n\n    - owner: hzeller\n      name: rpi-rgb-led-matrix\n      interval: 30m\n      events: [release]\n```\n\n**Fields:**\n\n| Field | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `github.token` | yes | — | GitHub PAT or `env:VAR_NAME` to read from env |\n| `repos[].owner` | yes | — | GitHub organization or user |\n| `repos[].name` | yes | — | Repository name |\n| `repos[].interval` | no | `5m` | Poll interval (minimum `30s`) |\n| `repos[].events` | no | all 4 types | Event types to watch |\n\n**Supported event types:** `push`, `pull_request`, `release`, `workflow_run`\n\n**GitHub token permissions:** the watcher only calls `Activity.ListRepositoryEvents` against the configured repos. For an unscoped token, GitHub still grants the authenticated 5000/hr rate limit on public-repo reads, so a token with no permissions is enough for public repos.\n\nIf you prefer to be explicit:\n\n- **Classic PAT:** `public_repo` scope (public repos) or `repo` (also covers private).\n- **Fine-grained PAT** (recommended):\n  - Resource owner: the org whose repos you watch.\n  - Repository access: all (or just the watched ones).\n  - Permissions — repository:\n    - `Metadata`: Read-only — mandatory for any fine-grained PAT.\n    - `Contents`: Read-only — needed for the events API.\n    - `Actions`: Read-only — only required if you want `workflow_run` events on private repos.\n\nNo write permissions, no org/user permissions.\n\n### Run with watcher\n\n```bash\nexport GITHUB_TOKEN=ghp_...\nexport AUTH_TOKEN=mysecret\nexport WATCH_CONFIG=./tests/watch-profile.yaml\nexport DEDUP_STATE_FILE=./dedup-state.json\n\ngo run .\n```\n\n### Run without watcher (HTTP API only)\n\n```bash\nexport REDIS_ADDR=localhost REDIS_PORT=6379 REDIS_STREAM=messages\nexport AUTH_TOKEN=mysecret\ngo run .\n```\n\n### Dev mode (no Redis)\n\n```bash\nPITCHER_MODE=file AUTH_TOKEN=test go run .\n```\n\n## API Endpoints\n\n| Endpoint | Method | Auth | Description |\n|----------|--------|------|-------------|\n| `/health` | `GET` | None | Health check with version, rate limit status |\n| `/pitch` | `POST` | Bearer token | Submit a message to Redis Streams |\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003ePitch a message\u003c/b\u003e\u003c/summary\u003e\n\n```bash\ncurl -X POST http://localhost:8080/pitch \\\n  -H \"Authorization: Bearer $AUTH_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"title\": \"Test Notification\",\n    \"message\": \"Hello from homerun2-git-pitcher\",\n    \"severity\": \"info\",\n    \"author\": \"test\"\n  }'\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eHealth check (with rate limit)\u003c/b\u003e\u003c/summary\u003e\n\n```bash\ncurl -s http://localhost:8080/health | jq .\n```\n\n```json\n{\n  \"status\": \"healthy\",\n  \"version\": \"1.2.0\",\n  \"commit\": \"abc1234\",\n  \"rateLimit\": {\n    \"limit\": 5000,\n    \"remaining\": 4850,\n    \"reset\": \"2026-03-18T09:00:00Z\",\n    \"backingOff\": false\n  }\n}\n```\n\n\u003c/details\u003e\n\n## Event message mapping\n\n| GitHub Event | Title | Severity | URL |\n|-------------|-------|----------|-----|\n| Push | `Push to {branch} on {repo}` | info | compare URL |\n| Pull Request | `PR #{n}: {title} ({action})` | info / success (merged) / warning (closed) | PR URL |\n| Release | `Release {tag} on {repo}` | success | release URL |\n| Workflow Run | `Workflow {name} {conclusion}` | success / error / warning | run URL |\n\n## Configuration reference\n\n### Core\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `PORT` | HTTP server port | `8080` |\n| `AUTH_TOKEN` | Bearer token for `/pitch` endpoint | **required** |\n| `PITCHER_MODE` | Backend: `redis` or `file` | `redis` |\n| `PITCHER_FILE` | Output file path (file mode only) | `pitched.log` |\n\n### Redis\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `REDIS_ADDR` | Redis server address | `localhost` |\n| `REDIS_PORT` | Redis server port | `6379` |\n| `REDIS_PASSWORD` | Redis password | (empty) |\n| `REDIS_STREAM` | Redis stream name | `messages` |\n\n### Watcher\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `WATCH_CONFIG` | Path to YAML watch profile | (disabled) |\n| `DEDUP_STATE_FILE` | Path to persist dedup state | (in-memory only) |\n\n### Logging\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `LOG_FORMAT` | `json` or `text` | `json` |\n| `LOG_LEVEL` | `debug`, `info`, `warn`, `error` | `info` |\n| `LOG_HEALTH_CHECKS` | Set `true` to log health requests | `false` |\n\n## Development\n\n```bash\n# Unit tests (no Redis needed)\ngo test ./internal/...\n\n# Lint\ntask lint\n\n# Run locally with file backend\ntask run-local\n```\n\n## KCL Deployment\n\nKubernetes manifests are generated using [KCL](https://kcl-lang.io/). See [kcl/README.md](kcl/README.md) for full configuration reference.\n\n```bash\n# Render manifests\nkcl run kcl/ -Y tests/kcl-deploy-profile.yaml\n\n# Apply to cluster\nkcl run kcl/ -Y tests/kcl-deploy-profile.yaml \\\n  -D 'config.namespace=homerun2' \\\n  -D 'config.redisPassword=\u003cpassword\u003e' \\\n  -D 'config.githubToken=\u003ctoken\u003e' \\\n  | python3 -c \"\nimport yaml, sys\ndata = yaml.safe_load(sys.stdin)\nfor m in data['manifests']:\n    print('---')\n    print(yaml.dump(m, default_flow_style=False).rstrip())\n\" | kubectl apply -f -\n```\n\nFor production, use the [Flux component](https://github.com/stuttgart-things/flux/tree/main/apps/homerun2/components/git-pitcher) which references the KCL OCI artifact and applies cluster-specific patches.\n\nSee [docs/](docs/) for full development, deployment, and CI/CD documentation.\n\n## Links\n\n- [Releases](https://github.com/stuttgart-things/homerun2-git-pitcher/releases)\n- [homerun-library](https://github.com/stuttgart-things/homerun-library)\n- [homerun2 Flux app](https://github.com/stuttgart-things/flux/tree/main/apps/homerun2)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuttgart-things%2Fhomerun2-git-pitcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstuttgart-things%2Fhomerun2-git-pitcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuttgart-things%2Fhomerun2-git-pitcher/lists"}