shoc-pr-review-runner/scripts/resolve-pr-head.sh

60 lines
2.6 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Resolve a PR's exact head (spec §10.1) and record its metadata + CI status.
#
# Usage: resolve-pr-head.sh <side: frontend|backend> <repo owner/name> <pr-number>
# Reads: GH_TOKEN (read-only App installation token)
# Writes: $ARTIFACTS_DIR/<side>-pr.json (metadata consumed by evidence + agent)
# <side>_sha / <side>_short_sha to $GITHUB_OUTPUT when present.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$SCRIPT_DIR/lib.sh"
side="${1:?side required}"
repo="${2:?repo required}"
pr="${3:?pr number required}"
require_env GH_TOKEN
pr_json="$(gh api "repos/$repo/pulls/$pr")" || die "failed to fetch $repo PR #$pr"
state="$(jq -r '.state' <<<"$pr_json")"
head_sha="$(jq -r '.head.sha // empty' <<<"$pr_json")"
head_repo="$(jq -r '.head.repo.full_name // empty' <<<"$pr_json")"
[ -n "$head_sha" ] || die "$repo PR #$pr has an empty head"
[ "$state" = "open" ] || log "WARNING: $repo PR #$pr state is '$state', not open"
[ "$head_repo" = "$repo" ] || die "$repo PR #$pr head lives in '$head_repo' (fork heads are not supported)"
short_sha="${head_sha:0:7}"
# CI status on the exact head: green / red / pending / missing (never omitted).
checks_json="$(gh api "repos/$repo/commits/$head_sha/check-runs" --jq '{total: .total_count, runs: [.check_runs[] | {name, status, conclusion}]}' 2>/dev/null)" \
|| checks_json='{"total":0,"runs":[]}'
ci_status="$(jq -r '
if .total == 0 then "missing"
elif ([.runs[] | select(.status != "completed")] | length) > 0 then "pending"
elif ([.runs[] | select(.conclusion != "success" and .conclusion != "neutral" and .conclusion != "skipped")] | length) > 0 then "red"
else "green" end' <<<"$checks_json")"
jq -n \
--arg side "$side" --arg repo "$repo" --argjson pr "$pr" \
--arg title "$(jq -r '.title' <<<"$pr_json")" \
--arg head_ref "$(jq -r '.head.ref' <<<"$pr_json")" \
--arg base_ref "$(jq -r '.base.ref' <<<"$pr_json")" \
--arg head_sha "$head_sha" --arg short_sha "$short_sha" \
--arg state "$state" --arg ci_status "$ci_status" \
--argjson mergeable "$(jq '.mergeable' <<<"$pr_json")" \
--argjson checks "$checks_json" \
'{side: $side, repo: $repo, pr: $pr, title: $title, head_ref: $head_ref,
base_ref: $base_ref, head_sha: $head_sha, short_sha: $short_sha,
state: $state, mergeable: $mergeable, ci_status: $ci_status, checks: $checks}' \
>"$ARTIFACTS_DIR/$side-pr.json"
out="${GITHUB_OUTPUT:-/dev/stdout}"
{
printf '%s_sha=%s\n' "$side" "$head_sha"
printf '%s_short_sha=%s\n' "$side" "$short_sha"
} >>"$out"
log "$side: $repo#$pr head=$short_sha base=$(jq -r '.base.ref' <<<"$pr_json") ci=$ci_status"