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