From 2e2960c1593b933302ed7133ffd70841557d2c60 Mon Sep 17 00:00:00 2001 From: Mats Rauhala Date: Fri, 2 Oct 2026 14:36:46 +0300 Subject: [PATCH] Review note script --- scripts/review-note | 70 ++++++++++++++++++++++++++++++++++++++++ scripts/review-note-test | 52 +++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100755 scripts/review-note create mode 100755 scripts/review-note-test diff --git a/scripts/review-note b/scripts/review-note new file mode 100755 index 0000000..24587d3 --- /dev/null +++ b/scripts/review-note @@ -0,0 +1,70 @@ +#!/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 [--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 +} + +main() { + local cmd="${1:-}" + if [ $# -gt 0 ]; then shift; fi + case "$cmd" in + show) cmd_show "$@" ;; + write) cmd_write "$@" ;; + *) usage ;; + esac +} + +main "$@" diff --git a/scripts/review-note-test b/scripts/review-note-test new file mode 100755 index 0000000..4eca429 --- /dev/null +++ b/scripts/review-note-test @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# Round-trip checks for scripts/review-note, in a throwaway temp repo. +set -euo pipefail + +root=$(cd "$(dirname "$0")/.." && pwd -P) +rn="$root/scripts/review-note" +fail() { echo "FAIL: $*" >&2; exit 1; } +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT + +git init -q -b main "$tmp/repo" +cd "$tmp/repo" +git config user.email test@example.com +git config user.name test + +echo one > a.txt && git add a.txt && git commit -qm one +echo two > b.txt && git add b.txt && git commit -qm two + +note="$tmp/note1" +cat > "$note" <<'EOF' +branch: main +round: 1 +verdict: request-changes +previous: none +findings: + - id: F1 + severity: blocker + file: a.txt:1 + title: fix me + status: open +## Details + +Fix it. +EOF + +if "$rn" show >/dev/null 2>&1; then fail "show should exit 1 without a note"; fi + +sed '/^verdict:/d' "$note" > "$tmp/no-verdict" +if "$rn" write "$tmp/no-verdict" >/dev/null 2>&1; then fail "write should refuse a missing verdict"; fi +sed 's/^verdict: request-changes/verdict: maybe/' "$note" > "$tmp/bad-verdict" +if "$rn" write "$tmp/bad-verdict" >/dev/null 2>&1; then fail "write should refuse a bad verdict"; fi + +"$rn" write "$note" +"$rn" show | grep -q '^verdict: request-changes$' || fail "show should print the note" + +if "$rn" write "$note" >/dev/null 2>&1; then fail "write should refuse an existing note"; fi + +sed 's/^verdict: request-changes/verdict: approve/' "$note" > "$tmp/note1b" +"$rn" write "$tmp/note1b" --force +"$rn" show | grep -q '^verdict: approve$' || fail "show should print the replaced note" + +echo "ok: show/write"