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 |