Files
kandev/scripts/resolve-go-lint-base
2026-08-27 10:08:04 +00:00

99 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# resolve-go-lint-base prints the local remote-tracking ref used by the
# pre-commit Go lint hook. Fork worktrees conventionally retain the canonical
# repository as `upstream`; do not silently fall back when the base is unclear.
set -euo pipefail
canonical_repository='kdlbs/kandev'
comparison_base=false
die() {
echo "Go lint base resolution failed: $*" >&2
exit 1
}
case "${1:-}" in
'') ;;
--comparison-base) comparison_base=true; shift ;;
*) die "unknown argument: $1" ;;
esac
[ "$#" -eq 0 ] || die "unexpected arguments: $*"
normalize_remote_ref() {
local ref=$1 remote_branch remote branch normalized
case "$ref" in
refs/remotes/*) remote_branch=${ref#refs/remotes/} ;;
refs/*) die "base ref must be a remote-tracking ref: $ref" ;;
*/*) remote_branch=$ref ;;
*) die "base ref must be a remote-tracking ref: $ref" ;;
esac
remote=${remote_branch%%/*}
branch=${remote_branch#*/}
[ -n "$remote" ] && [ "$branch" != "$remote_branch" ] && [ -n "$branch" ] || die "base ref must name a remote and branch: $ref"
normalized="refs/remotes/$remote/$branch"
git check-ref-format "$normalized" >/dev/null 2>&1 || die "base ref does not have a safe ref format: $ref"
printf '%s\n' "$normalized"
}
is_canonical_remote() {
local url=$1 path
case "$url" in
https://github.com/*) path=${url#https://github.com/} ;;
http://github.com/*) path=${url#http://github.com/} ;;
ssh://git@github.com/*) path=${url#ssh://git@github.com/} ;;
git+ssh://git@github.com/*) path=${url#git+ssh://git@github.com/} ;;
git://github.com/*) path=${url#git://github.com/} ;;
git@github.com:*) path=${url#git@github.com:} ;;
*) return 1 ;;
esac
path=${path%.git}
path=${path%/}
[ "$(printf '%s' "$path" | tr '[:upper:]' '[:lower:]')" = "$canonical_repository" ]
}
configured_refs=()
while IFS= read -r ref; do
[ -n "$ref" ] && configured_refs+=("$ref")
done < <(git config --get-all kandev.lintBaseRef || true)
if [ "${#configured_refs[@]}" -gt 1 ]; then
die "ambiguous kandev.lintBaseRef values: ${configured_refs[*]}"
fi
if [ "${#configured_refs[@]}" -eq 1 ]; then
base_ref=$(normalize_remote_ref "${configured_refs[0]}")
else
origin_head=$(git symbolic-ref --quiet refs/remotes/origin/HEAD || true)
[ -n "$origin_head" ] || die "origin's default branch is unavailable; set kandev.lintBaseRef to a local remote-tracking ref"
case "$origin_head" in
refs/remotes/origin/*) base_branch=${origin_head#refs/remotes/origin/} ;;
*) die "origin's default ref is invalid: $origin_head" ;;
esac
[ -n "$base_branch" ] || die "origin's default ref is invalid: $origin_head"
if upstream_url=$(git remote get-url upstream 2>/dev/null); then
is_canonical_remote "$upstream_url" || die "upstream remote is not the canonical $canonical_repository repository"
base_ref=$(normalize_remote_ref "refs/remotes/upstream/$base_branch")
git rev-parse --verify --quiet "$base_ref^{commit}" >/dev/null || die "canonical upstream ref does not resolve locally: $base_ref"
else
base_ref=$(normalize_remote_ref "$origin_head")
fi
fi
git rev-parse --verify --quiet "$base_ref^{commit}" >/dev/null || die "base ref does not resolve locally: $base_ref"
if [ "$comparison_base" = true ]; then
merge_head=$(git rev-parse --verify MERGE_HEAD 2>/dev/null || true)
base_tip=$(git rev-parse --verify --quiet "$base_ref^{commit}")
if [ -n "$merge_head" ] && [ "$merge_head" = "$base_tip" ]; then
printf '%s\n' "$merge_head"
else
merge_base=$(git merge-base HEAD "$base_ref" 2>/dev/null) || die "base ref has no merge base with HEAD: $base_ref"
printf '%s\n' "$merge_base"
fi
else
printf '%s\n' "$base_ref"
fi