Commit 7a019c7
Eric Bower
·
2026-05-07 15:38:52 -0400 EDT
parent bcba2bc
feat: git post-receive hook
2 files changed,
+124,
-0
+31,
-0
1@@ -0,0 +1,31 @@
2+#!/usr/bin/env bash
3+# post-receive hook — publishes build events to pici via ssh pipe.
4+#
5+# Install: ./install-hooks.sh /path/to/bare-repos
6+#
7+# stdin format (per ref pushed): <old-sha> <new-sha> <ref-name>
8+
9+set -euo pipefail
10+
11+PIPE_HOST="${PIPE_HOST:-pipe}"
12+
13+while read -r old_sha new_sha ref; do
14+ # Skip delete refs
15+ if [ "$new_sha" = "0000000000000000000000000000000000000000" ]; then
16+ continue
17+ fi
18+
19+ # Extract branch name from ref (e.g. refs/heads/main → main)
20+ branch="${ref#refs/heads/}"
21+
22+ # Repo name from the bare repo directory
23+ repo="$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)" .git)"
24+
25+ # Workspace is the bare repo itself (runner rsyncs from here)
26+ workspace="$(git rev-parse --git-dir 2>/dev/null || pwd)"
27+
28+ event=$(printf '{"type":"git.push","name":"%s","workspace":"%s","branch":"%s","commit":"%s"}' \
29+ "$repo" "$workspace" "$branch" "$new_sha")
30+
31+ echo "$event" | ssh "$PIPE_HOST" pub -b=false build.event
32+done
+93,
-0
1@@ -0,0 +1,93 @@
2+#!/usr/bin/env bash
3+# install-hooks.sh — sync the post-receive hook to all bare repos in a directory.
4+#
5+# Usage:
6+# ./install-hooks.sh /path/to/bare-repos
7+# ./install-hooks.sh /path/to/repo1.git /path/to/repo2.git
8+# ./install-hooks.sh --force /path/to/bare-repos # overwrite existing hooks
9+#
10+# The hook is read from hooks/post-receive relative to this script.
11+# Errors if a repo already has a different post-receive hook (use --force to overwrite).
12+
13+set -euo pipefail
14+
15+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
16+HOOK="$SCRIPT_DIR/hooks/post-receive"
17+FORCE=false
18+
19+if [ "${1:-}" = "--force" ]; then
20+ FORCE=true
21+ shift
22+fi
23+
24+if [ ! -f "$HOOK" ]; then
25+ echo "error: $HOOK not found" >&2
26+ exit 1
27+fi
28+
29+if [ $# -eq 0 ]; then
30+ echo "usage: $0 [--force] <repo.git ... | repos-dir>" >&2
31+ exit 1
32+fi
33+
34+repos=()
35+for arg in "$@"; do
36+ # Strip trailing slash to avoid double slashes in paths
37+ arg="${arg%/}"
38+ if [ -d "$arg" ] && [ ! -d "$arg/hooks" ]; then
39+ # Looks like a directory containing repos, not a repo itself
40+ for repo in "$arg"/*.git; do
41+ [ -d "$repo" ] && repos+=("$repo")
42+ done
43+ else
44+ repos+=("$arg")
45+ fi
46+done
47+
48+if [ ${#repos[@]} -eq 0 ]; then
49+ echo "no repos found" >&2
50+ exit 1
51+fi
52+
53+installed=0
54+skipped=0
55+overwritten=0
56+errors=0
57+
58+for repo in "${repos[@]}"; do
59+ hooks_dir="$repo/hooks"
60+ existing="$hooks_dir/post-receive"
61+ mkdir -p "$hooks_dir"
62+
63+ if [ -f "$existing" ]; then
64+ if diff -q "$HOOK" "$existing" >/dev/null 2>&1; then
65+ echo " = $repo (up to date)"
66+ skipped=$((skipped + 1))
67+ continue
68+ fi
69+
70+ if [ "$FORCE" = true ]; then
71+ cp "$HOOK" "$existing"
72+ chmod +x "$existing"
73+ echo " ⚡ $repo (overwritten)"
74+ overwritten=$((overwritten + 1))
75+ continue
76+ fi
77+
78+ echo " ✗ $repo (existing hook differs)" >&2
79+ errors=$((errors + 1))
80+ continue
81+ fi
82+
83+ cp "$HOOK" "$existing"
84+ chmod +x "$existing"
85+ echo " ✓ $repo"
86+ installed=$((installed + 1))
87+done
88+
89+echo ""
90+echo "installed: $installed skipped: $skipped overwritten: $overwritten errors: $errors"
91+
92+if [ "$errors" -gt 0 ]; then
93+ exit 1
94+fi