From 29122506be064dbecfcb376d45a00106f762db26 Mon Sep 17 00:00:00 2001 From: Fernando Serboncini Date: Mon, 4 May 2026 12:38:28 -0400 Subject: [PATCH] misc/git_hook: propagate shared HOOK_VERSION (#19476) Move HOOK_VERSION into the githook package and export it as githook.HookVersion, so tailscale/corp can reference it via the shared-code bump instead of having to bump HOOK_VERSION by hand. New launcher.sh composes the wanted version from 2 sources: the shared HOOK_VERSION and an optional repo local version, misc/git_hook/HOOK_VERSION, for repo-specific config bumps. Updates tailscale/corp#40381 Change-Id: I7cf16889ba53cb564cc2df7dfd7588748f542c55 Signed-off-by: Fernando Serboncini --- misc/git_hook/README.md | 17 +++++++++-------- misc/git_hook/git-hook.go | 6 +----- misc/git_hook/{ => githook}/HOOK_VERSION | 0 misc/git_hook/githook/githook.go | 6 ++++++ misc/git_hook/githook/launcher.sh | 22 +++++++++++++--------- 5 files changed, 29 insertions(+), 22 deletions(-) rename misc/git_hook/{ => githook}/HOOK_VERSION (100%) diff --git a/misc/git_hook/README.md b/misc/git_hook/README.md index 81c15dc58..49d768937 100644 --- a/misc/git_hook/README.md +++ b/misc/git_hook/README.md @@ -22,13 +22,14 @@ script after a built-in hook. For example, put a custom check in only if the built-in hook succeeds; failure aborts the git operation. -## Changing the shared code +## Version bumps -When you change anything under `githook/` or `launcher.sh`, bump -`HOOK_VERSION` in the same commit so every dev auto rebuilds on their next -git operation. +The launcher rebuilds when the installed binary's version differs from +the concatenation of two files: -Because `tailscale/corp` imports `githook/`, also plan the downstream -update: after landing here, bump corp's `tailscale.com` dependency and -bump corp's own `misc/git_hook/HOOK_VERSION` on a separate commit. Both are -required. +* `githook/HOOK_VERSION` (shared): bump when changing anything under + `githook/` or `git-hook.go`. Downstream repos pick it up after + bumping their `tailscale.com` dependency. +* `misc/git_hook/HOOK_VERSION` (repo-local, optional): bump to force a + rebuild for repo-specific config changes without touching the shared + version. This repo does not use one. diff --git a/misc/git_hook/git-hook.go b/misc/git_hook/git-hook.go index 4af11c065..2cf3ff421 100644 --- a/misc/git_hook/git-hook.go +++ b/misc/git_hook/git-hook.go @@ -14,7 +14,6 @@ package main import ( - _ "embed" "fmt" "log" "os" @@ -23,9 +22,6 @@ import ( "tailscale.com/misc/git_hook/githook" ) -//go:embed HOOK_VERSION -var compiledHookVersion string - var pushRemotes = []string{ "git@github.com:tailscale/tailscale", "git@github.com:tailscale/tailscale.git", @@ -47,7 +43,7 @@ func main() { var err error switch cmd { case "version": - fmt.Print(strings.TrimSpace(compiledHookVersion)) + fmt.Print(strings.TrimSpace(githook.HookVersion) + ":0") case "install": err = githook.WriteHooks(hooks) case "pre-commit": diff --git a/misc/git_hook/HOOK_VERSION b/misc/git_hook/githook/HOOK_VERSION similarity index 100% rename from misc/git_hook/HOOK_VERSION rename to misc/git_hook/githook/HOOK_VERSION diff --git a/misc/git_hook/githook/githook.go b/misc/git_hook/githook/githook.go index de5d7e4c2..aa44051fc 100644 --- a/misc/git_hook/githook/githook.go +++ b/misc/git_hook/githook/githook.go @@ -22,6 +22,12 @@ import ( //go:embed launcher.sh var Launcher []byte +// HookVersion is the shared version of this package and launcher.sh. +// Bump HOOK_VERSION on any change under this package. +// +//go:embed HOOK_VERSION +var HookVersion string + // RunLocalHook runs an optional user-supplied hook at // .git/hooks/.local, if present. func RunLocalHook(hookName string, args []string) error { diff --git a/misc/git_hook/githook/launcher.sh b/misc/git_hook/githook/launcher.sh index 1171bc7b1..eddab585e 100755 --- a/misc/git_hook/githook/launcher.sh +++ b/misc/git_hook/githook/launcher.sh @@ -4,13 +4,12 @@ # Written by misc/install-git-hooks.go from the canonical copy embedded # in tailscale.com/misc/git_hook/githook. On every invocation it: # -# 1. Compares misc/git_hook/HOOK_VERSION against the binary's version. -# 2. If stale or missing: rebuilds .git/hooks/ts-git-hook-bin and runs -# `ts-git-hook-bin install` to refresh the launcher and per-hook -# wrappers. +# 1. Compares the binary's reported version against the shared +# githook HOOK_VERSION (resolved via `go list -m tailscale.com`) +# plus the repo-local HOOK_VERSION. +# 2. If stale or missing: rebuilds ts-git-hook-bin and runs +# `ts-git-hook-bin install`. # 3. Execs the binary with the hook's args. -# -# Any change to this file or the binary must bump HOOK_VERSION. set -euo pipefail REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || { @@ -29,12 +28,17 @@ EXE="" case "$(uname -s)" in MINGW* | MSYS* | CYGWIN*) EXE=".exe" ;; esac BINARY="$HOOK_DIR/ts-git-hook-bin$EXE" -WANT="$(cat "$REPO_ROOT/misc/git_hook/HOOK_VERSION" 2>/dev/null || echo 0)" + +GO="$REPO_ROOT/tool/go$EXE" +if [ ! -x "$GO" ]; then GO=go; fi + +OSS_DIR="$(cd "$REPO_ROOT" && GOWORK=off "$GO" list -m -f '{{.Dir}}' tailscale.com 2>/dev/null || true)" +SHARED_VER="$(cat "$OSS_DIR/misc/git_hook/githook/HOOK_VERSION" 2>/dev/null || echo 0)" +LOCAL_VER="$(cat "$REPO_ROOT/misc/git_hook/HOOK_VERSION" 2>/dev/null || echo 0)" +WANT="$SHARED_VER:$LOCAL_VER" HAVE="$("$BINARY" version 2>/dev/null || echo none)" if [ "$WANT" != "$HAVE" ]; then - GO="$REPO_ROOT/tool/go$EXE" - if [ ! -x "$GO" ]; then GO=go; fi echo "git-hook: rebuilding ts-git-hook-bin..." >&2 (cd "$REPO_ROOT" && GOWORK=off "$GO" build -o "$BINARY" ./misc/git_hook) || { echo "git-hook: rebuild failed, run: ./tool/go run ./misc/install-git-hooks.go" >&2