feat: repo commit tracking and OpenClaw notification

- Migration 058: repo_commits + openclaw_instances tables (seeded with overwatch)
- POST /api/webhooks/forgejo: receives Forgejo push events, stores commits,
  forwards HMAC-signed payload to all enabled OpenClaw instances, sends Telegram
- GET /api/openclaw/repo-commits: OpenClaw polling endpoint (filters: since, repo, branch, limit)
- GET/POST /api/admin/openclaw-instances: manage instance registry
- PATCH/DELETE /api/admin/openclaw-instances/[id]: update/remove instances
- FORGEJO_WEBHOOK_SECRET in .env.local (leave empty to skip HMAC verification)
This commit is contained in:
lorentz 2026-03-21 18:52:22 -04:00
parent 9459d65e02
commit 414ad78c36
5 changed files with 346 additions and 0 deletions

View file

@ -0,0 +1,42 @@
-- Migration 058: Repo commit tracking and OpenClaw instance registry
CREATE TABLE IF NOT EXISTS repo_commits (
id SERIAL PRIMARY KEY,
repo_name TEXT NOT NULL,
repo_full_name TEXT NOT NULL,
branch TEXT NOT NULL,
commit_sha TEXT NOT NULL,
commit_message TEXT,
author_name TEXT,
author_email TEXT,
committed_at TIMESTAMPTZ,
pushed_by TEXT,
raw_payload JSONB,
received_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
notified_at TIMESTAMPTZ,
UNIQUE (repo_full_name, commit_sha)
);
CREATE INDEX IF NOT EXISTS idx_repo_commits_repo ON repo_commits (repo_name);
CREATE INDEX IF NOT EXISTS idx_repo_commits_received ON repo_commits (received_at DESC);
CREATE INDEX IF NOT EXISTS idx_repo_commits_branch ON repo_commits (branch);
CREATE TABLE IF NOT EXISTS openclaw_instances (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
webhook_url TEXT NOT NULL,
webhook_secret TEXT NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
last_notified_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Seed overwatch instance
INSERT INTO openclaw_instances (name, webhook_url, webhook_secret, enabled)
VALUES (
'overwatch',
'http://100.89.248.105:8420/webhook/git-push',
'e984b79196c91104a7ab8fa7d7f554e7c5b3ba5a4ebddb92f2ae2fbee675c14b',
TRUE
)
ON CONFLICT (name) DO NOTHING;