#!/usr/bin/env bash
# Prints a PR's reviews, and optionally waits for one against the current head.
# Exists because twenty PRs merged with their reviews unread; see
# context/code/pr-review.md.
set -euo pipefail

usage() {
  cat >&2 <<'EOF'
usage: pr-reviews <pr-number> [--wait <sec>] [--interval <sec>]

  --wait <sec>      wait up to this long for a review whose commit is the
                    current head (default 0 = print what exists and exit)
  --interval <sec>  seconds between polls (default 30)

exit 0  a review against the current head exists (or --wait was 0)
exit 1  --wait elapsed with no review against the current head
exit 4  usage or environment error

DO NOT PIPE THIS INTO head/tail. `$?` is then the pager's status, not this
script's, and a --wait that timed out reads as success. That trap has cost
this repo four separate diagnoses. Redirect to a file and read it instead.

A review may target an EARLIER head, which is why the head is compared rather
than the count: a finding against an old commit may be fixed or still live, and
only reading it tells you which.
EOF
  exit 4
}

PR=""; WAIT=0; INTERVAL=30
while [ $# -gt 0 ]; do
  case "$1" in
    --wait)     WAIT="${2:-}"; shift 2 ;;
    --interval) INTERVAL="${2:-}"; shift 2 ;;
    -h|--help)  usage ;;
    *)          [ -z "$PR" ] || usage; PR="$1"; shift ;;
  esac
done
[ -n "$PR" ] || usage

# `gh` is shell-aliased to a different tool in this repo's shells, so the name
# is never trusted: a real gh is located explicitly.
gh_() {
  if command -v gh >/dev/null 2>&1 && gh --version 2>/dev/null | grep -q '^gh version'; then
    gh "$@"
  else
    nix shell nixpkgs#gh --command gh "$@"
  fi
}

fetch() { gh_ pr view "$PR" --json headRefOid,reviews; }

report() {
  local json="$1" head
  head=$(printf '%s' "$json" | jq -r '.headRefOid')
  printf 'pr-reviews: #%s head=%s\n' "$PR" "${head:0:8}"
  printf '%s' "$json" | jq -r --arg head "$head" '
    if (.reviews | length) == 0 then "  (no reviews)"
    else .reviews[] |
      "  [\(.state)] \(.submittedAt) commit=\(.commit.oid[0:8])" +
      (if .commit.oid == $head then " <- CURRENT HEAD" else " <- an EARLIER head; verify whether it still applies" end) +
      "\n" + (.body | split("\n") | map("    " + .) | join("\n"))
    end'
}

has_head_review() {
  printf '%s' "$1" | jq -e --arg h "$(printf '%s' "$1" | jq -r .headRefOid)" \
    'any(.reviews[]?; .commit.oid == $h)' >/dev/null 2>&1
}

json=$(fetch)
report "$json"

[ "$WAIT" -gt 0 ] || exit 0

if has_head_review "$json"; then exit 0; fi

deadline=$(( $(date +%s) + WAIT ))
while [ "$(date +%s)" -lt "$deadline" ]; do
  sleep "$INTERVAL"
  json=$(fetch)
  if has_head_review "$json"; then
    printf '\npr-reviews: a review against the current head arrived.\n\n'
    report "$json"
    exit 0
  fi
done

printf '\npr-reviews: waited %ss; no review against the current head.\n' "$WAIT"
printf 'Reviews arrive as the owner quota allows, so absence is not approval.\n'
exit 1
