From 18d7f394fc55084c1fbd95f0f37caded6ac3dd5a Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 31 Aug 2026 18:25:37 -0500 Subject: [PATCH 1/2] Fix check-upstream-sync to resolve its own repo, add error exit code The script located remotes via `git remote -v` in the caller's cwd, but CLAUDE.md documents invoking it as `../ai/bin/check-upstream-sync` from a consuming repo's root -- where none of that repo's remotes point at Postgres-Extensions/ai, so the script always aborted. Derive the repo root from the script's own path instead and pass it to every git call via `-C`. Also split what was a single non-zero exit status into two: 1 for new commits found (with the list on stdout), 2 for the check itself failing (message on stderr) -- so a caller can't mistake a broken check for a permanent stream of new content. --- CLAUDE.md | 7 +++++-- bin/check-upstream-sync | 34 ++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f26ea1e..d40ec03 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,8 +33,11 @@ directly: ../ai/bin/check-upstream-sync ``` -It prints the new commits and exits non-zero when there are any it -hasn't seen; it prints nothing and exits 0 otherwise. +It exits 0 with no output when there are no new commits, exits 1 with +the new commits on stdout when there are, and exits 2 with an error on +stderr if the check itself fails (e.g. no remote points at +`Postgres-Extensions/ai`) — don't mistake a broken check for a +permanent stream of new content. Note the commit `../ai/` is at the first time you read its docs each session, and pass that noted commit to the script on every later check. diff --git a/bin/check-upstream-sync b/bin/check-upstream-sync index 5932b8d..416fde9 100755 --- a/bin/check-upstream-sync +++ b/bin/check-upstream-sync @@ -10,29 +10,47 @@ # compares against that, so it works the same whether this checkout's # `origin` is the fork or upstream itself. # +# Operates on this script's own repo (resolved from its own path), not +# on the caller's cwd -- so it can be invoked as `../ai/bin/check- +# upstream-sync` from a consuming repo, same as running it directly +# inside the ai checkout. +# # Usage: bin/check-upstream-sync # # baseline-sha Commit previously noted as "read up to". Commits # reachable from upstream's default branch but not from # this SHA are printed. # -# Exits non-zero and prints the new commits when there are any; exits 0 -# with no output when there are none. +# Exit codes: +# 0 up to date, no new commits (nothing printed) +# 1 new commits found (printed to stdout, one per line) +# 2 the check itself failed (message printed to stderr) set -euo pipefail baseline="${1:?usage: bin/check-upstream-sync }" -remote=$(git remote -v | awk '$2 ~ /[\/:]Postgres-Extensions\/ai(\.git)?$/ { print $1; exit }') -: "${remote:?no remote points at Postgres-Extensions/ai}" +repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) + +remote=$(git -C "$repo" remote -v | awk '$2 ~ /[\/:]Postgres-Extensions\/ai(\.git)?$/ { print $1; exit }') +if [[ -z "$remote" ]]; then + echo "check-upstream-sync: no remote points at Postgres-Extensions/ai" >&2 + exit 2 +fi -git fetch --quiet "$remote" +git -C "$repo" fetch --quiet "$remote" -default_branch=$(git ls-remote --symref "$remote" HEAD | +default_branch=$(git -C "$repo" ls-remote --symref "$remote" HEAD | awk '/^ref:/ { sub("refs/heads/", "", $2); print $2 }') -: "${default_branch:?could not determine default branch for $remote}" +if [[ -z "$default_branch" ]]; then + echo "check-upstream-sync: could not determine default branch for $remote" >&2 + exit 2 +fi -new_commits=$(git log --oneline "$baseline..$remote/$default_branch") +if ! new_commits=$(git -C "$repo" log --oneline "$baseline..$remote/$default_branch" 2>&1); then + echo "check-upstream-sync: $new_commits" >&2 + exit 2 +fi if [[ -n "$new_commits" ]]; then echo "$new_commits" From ee3c3d4ac9c4373c341d65929a66eea273467fb8 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 31 Aug 2026 18:30:34 -0500 Subject: [PATCH 2/2] Map fetch/ls-remote failures to exit 2 too, not git's raw status The fetch and ls-remote calls ran unguarded under set -e, so a network/TLS failure propagated git's own exit status (e.g. 128) instead of the documented 2 -- the most likely real-world failure mode wasn't actually covered by the exit-code contract. Capture their output and check the result explicitly, same as the git-log call already did, so any failure of the check itself lands on 2 with the message on stderr. --- bin/check-upstream-sync | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bin/check-upstream-sync b/bin/check-upstream-sync index 416fde9..3a15a11 100755 --- a/bin/check-upstream-sync +++ b/bin/check-upstream-sync @@ -38,10 +38,17 @@ if [[ -z "$remote" ]]; then exit 2 fi -git -C "$repo" fetch --quiet "$remote" +if ! fetch_err=$(git -C "$repo" fetch --quiet "$remote" 2>&1); then + echo "check-upstream-sync: $fetch_err" >&2 + exit 2 +fi + +if ! ls_remote_out=$(git -C "$repo" ls-remote --symref "$remote" HEAD 2>&1); then + echo "check-upstream-sync: $ls_remote_out" >&2 + exit 2 +fi -default_branch=$(git -C "$repo" ls-remote --symref "$remote" HEAD | - awk '/^ref:/ { sub("refs/heads/", "", $2); print $2 }') +default_branch=$(awk '/^ref:/ { sub("refs/heads/", "", $2); print $2 }' <<<"$ls_remote_out") if [[ -z "$default_branch" ]]; then echo "check-upstream-sync: could not determine default branch for $remote" >&2 exit 2