96 lines
2.4 KiB
Bash
Executable File
96 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# review-note: manage code-review notes under refs/notes/review.
|
|
# The protocol lives in REVIEW.md.
|
|
set -euo pipefail
|
|
|
|
NOTES_REF=refs/notes/review
|
|
REMOTE=origin
|
|
|
|
die() { echo "review-note: $*" >&2; exit 1; }
|
|
|
|
usage() {
|
|
cat >&2 <<'EOF'
|
|
usage:
|
|
review-note show [commit]
|
|
review-note write <file> [--force]
|
|
review-note latest [branch]
|
|
review-note push
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
validate() {
|
|
local file="$1"
|
|
grep -q '^branch: .\+' "$file" || die "missing or empty 'branch:' header"
|
|
grep -Eq '^round: [0-9]+$' "$file" || die "missing or invalid 'round:' header"
|
|
grep -Eq '^verdict: (approve|request-changes)$' "$file" \
|
|
|| die "verdict must be 'approve' or 'request-changes'"
|
|
}
|
|
|
|
cmd_show() {
|
|
local commit="${1:-HEAD}"
|
|
git notes --ref="$NOTES_REF" show "$commit" 2>/dev/null \
|
|
|| die "no review note for $commit"
|
|
}
|
|
|
|
cmd_write() {
|
|
local force="" file=""
|
|
local arg
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--force) force=1 ;;
|
|
*) file="$arg" ;;
|
|
esac
|
|
done
|
|
[ -n "$file" ] || usage
|
|
[ -f "$file" ] || die "no such file: $file"
|
|
local tip
|
|
tip=$(git rev-parse HEAD)
|
|
if [ -z "$force" ] && git notes --ref="$NOTES_REF" show "$tip" >/dev/null 2>&1; then
|
|
die "tip $tip already has a review note; pass --force to replace"
|
|
fi
|
|
validate "$file"
|
|
if [ -n "$force" ]; then
|
|
git notes --ref="$NOTES_REF" add -f -F "$file" "$tip"
|
|
else
|
|
git notes --ref="$NOTES_REF" add -F "$file" "$tip"
|
|
fi
|
|
}
|
|
|
|
cmd_latest() {
|
|
local branch="${1:-$(git branch --show-current)}"
|
|
local blob obj note br rnd best="" best_round=-1
|
|
while read -r blob obj; do
|
|
note=$(git notes --ref="$NOTES_REF" show "$obj") || continue
|
|
br=$(sed -n 's/^branch: //p' <<<"$note")
|
|
[ "$br" = "$branch" ] || continue
|
|
rnd=$(sed -n 's/^round: //p' <<<"$note")
|
|
[[ "$rnd" =~ ^[0-9]+$ ]] || continue
|
|
if [ "$rnd" -gt "$best_round" ]; then
|
|
best_round=$rnd
|
|
best=$note
|
|
fi
|
|
done < <(git notes --ref="$NOTES_REF" list)
|
|
[ -n "$best" ] || die "no review notes for branch: $branch"
|
|
printf '%s\n' "$best"
|
|
}
|
|
|
|
cmd_push() {
|
|
git rev-parse -q --verify "$NOTES_REF" >/dev/null || die "no review notes to push"
|
|
git push "$REMOTE" "$NOTES_REF"
|
|
}
|
|
|
|
main() {
|
|
local cmd="${1:-}"
|
|
if [ $# -gt 0 ]; then shift; fi
|
|
case "$cmd" in
|
|
show) cmd_show "$@" ;;
|
|
write) cmd_write "$@" ;;
|
|
latest) cmd_latest "$@" ;;
|
|
push) cmd_push "$@" ;;
|
|
*) usage ;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|