Git & Repository Activity
Notify your team about pull requests, merges, releases, and code reviews.
Keep your team in the loop on repository activity without everyone watching GitHub. Route important events — merged PRs, new releases, review requests — to the channels where your team already communicates.
GitHub Webhooks
GitHub can send webhook events to Alphorn. Set up a small proxy to transform GitHub's payload format into Alphorn's.
Proxy example (Node.js)
app.post("/github-webhook", (req, res) => {
const event = req.headers["x-github-event"];
const payload = req.body;
let title, message, priority, tags;
switch (event) {
case "pull_request":
if (payload.action === "opened") {
title = `PR opened: ${payload.pull_request.title}`;
message = `${payload.pull_request.user.login} opened #${payload.number} in ${payload.repository.full_name}`;
priority = 2;
tags = ["git", "pr", "opened"];
} else if (payload.action === "closed" && payload.pull_request.merged) {
title = `PR merged: ${payload.pull_request.title}`;
message = `#${payload.number} merged by ${payload.pull_request.merged_by.login}`;
priority = 2;
tags = ["git", "pr", "merged"];
} else {
return res.sendStatus(200);
}
break;
case "release":
title = `Release: ${payload.release.tag_name}`;
message = `${payload.repository.full_name} — ${payload.release.name || "New release"}`;
priority = 3;
tags = ["git", "release"];
break;
case "push":
if (payload.ref === "refs/heads/main") {
title = `Push to main: ${payload.repository.name}`;
message = `${payload.commits.length} commit(s) by ${payload.pusher.name}`;
priority = 2;
tags = ["git", "push", "main"];
} else {
return res.sendStatus(200);
}
break;
default:
return res.sendStatus(200);
}
fetch("https://app.alphorn.dev/api/webhooks/wh_abc123", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title, message, priority, tags }),
});
res.sendStatus(200);
});Post-merge hook (local)
Notify after merging to main locally:
#!/bin/bash
BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [ "$BRANCH" = "main" ]; then
COMMIT=$(git log -1 --pretty=format:"%s (%an)")
curl -s -X POST "https://app.alphorn.dev/api/webhooks/wh_abc123" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Merged to main\",
\"message\": \"$COMMIT\",
\"priority\": 2,
\"tags\": [\"git\", \"merge\", \"main\"]
}"
fiRelease notifications (CI)
After creating a Git tag, notify the team:
VERSION=$(git describe --tags --exact-match 2>/dev/null)
if [ -n "$VERSION" ]; then
CHANGELOG=$(git log --oneline "$(git describe --tags --abbrev=0 HEAD^)..HEAD" | head -10)
curl -s -X POST "https://app.alphorn.dev/api/webhooks/wh_abc123" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Release $VERSION\",
\"message\": \"Changes:\n$CHANGELOG\",
\"priority\": 3,
\"tags\": [\"git\", \"release\", \"$VERSION\"]
}"
fiRouting examples
| Channel | Filter | Purpose |
|---|---|---|
| Slack (#dev) | tags CONTAINS "pr" AND tags CONTAINS "merged" | Merged PRs only |
| Slack (#releases) | tags CONTAINS "release" | New releases |
| Discord | tags CONTAINS "git" | All repository activity |
tags CONTAINS "release" | Release archive |