From 9819ad5417640f9c65b0c34cec6ad311bc35c77b Mon Sep 17 00:00:00 2001 From: Mike Harder Date: Fri, 20 Mar 2026 18:40:35 +0000 Subject: [PATCH 1/3] add script to approve PRs by author and title --- approve-prs.sh | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100755 approve-prs.sh diff --git a/approve-prs.sh b/approve-prs.sh new file mode 100755 index 0000000..ba76646 --- /dev/null +++ b/approve-prs.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + echo "Usage: $0 [-n] [...]" + echo " -n Dry run — list matching PRs without approving" + echo " Example: $0 owner/repo user 'hello world'" + echo " Example: $0 -n owner/repo user 'hello' 'world'" + exit 1 +} + +# --- Dry run flag --- +DRY_RUN=false +if [[ "${1:-}" == "-n" ]]; then + DRY_RUN=true + shift +fi + +if [[ $# -lt 3 ]]; then + usage +fi + +REPO="$1" +AUTHOR="$2" +shift 2 # Remove repo and author from arguments + +# Build search query for multiple title strings (OR logic) +SEARCH_QUERY="" +for TITLE_STRING in "$@"; do + if [[ -z "$SEARCH_QUERY" ]]; then + SEARCH_QUERY="$TITLE_STRING in:title" + else + SEARCH_QUERY="$SEARCH_QUERY OR $TITLE_STRING in:title" + fi +done + +# --- Preflight checks --- +if ! command -v gh &>/dev/null; then + echo "Error: gh CLI is not installed. See https://cli.github.com" + exit 1 +fi + +if ! gh auth status &>/dev/null; then + echo "Error: gh is not authenticated. Run 'gh auth login' first." + exit 1 +fi + +# --- Fetch matching PRs --- +echo "Fetching PRs..." +PR_LIST=$(gh pr list \ + --repo "$REPO" \ + --state open \ + --author "$AUTHOR" \ + --search "$SEARCH_QUERY" \ + --limit 200 \ + --json number,title,reviews \ + --jq '.[] | "\(.number) \(if (.reviews | map(select(.state == "APPROVED")) | length > 0) then "APPROVED" else "PENDING" end) \(.title)"') || { + echo "Error: Failed to fetch PRs. Check that '$REPO' exists and you have access." + exit 1 + } + +if [[ -z "$PR_LIST" ]]; then + echo "No matching PRs found." + exit 0 +fi + +# --- Summary --- +echo "" +echo "Matched PRs:" +while IFS= read -r LINE; do + PR_NUMBER=$(echo "$LINE" | awk '{print $1}') + PR_STATUS=$(echo "$LINE" | awk '{print $2}') + PR_TITLE=$(echo "$LINE" | cut -d' ' -f3-) + echo " #$PR_NUMBER [$PR_STATUS]: $PR_TITLE" +done <<< "$PR_LIST" +echo "" + +if [[ "$DRY_RUN" == true ]]; then + echo "Dry run complete. No PRs were approved." + exit 0 +fi + +# --- Confirm and approve --- +while IFS= read -r LINE; do + PR_NUMBER=$(echo "$LINE" | awk '{print $1}') + PR_STATUS=$(echo "$LINE" | awk '{print $2}') + PR_TITLE=$(echo "$LINE" | cut -d' ' -f3-) + + if [[ "$PR_STATUS" == "APPROVED" ]]; then + echo "Already approved — PR #$PR_NUMBER: $PR_TITLE" + else + echo "PR #$PR_NUMBER: $PR_TITLE" + read -rn 1 -p "Approve this PR? (y/N): " CONFIRM Date: Fri, 20 Mar 2026 11:45:55 -0700 Subject: [PATCH 2/3] Update approve-prs.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- approve-prs.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/approve-prs.sh b/approve-prs.sh index ba76646..272f349 100755 --- a/approve-prs.sh +++ b/approve-prs.sh @@ -25,16 +25,31 @@ REPO="$1" AUTHOR="$2" shift 2 # Remove repo and author from arguments +# Escape a title string for safe use in a GitHub search phrase. +# - Escapes backslashes and double quotes, so the result can be wrapped in " +escape_github_search_phrase() { + local s=$1 + s=${s//\\/\\\\} + s=${s//\"/\\\"} + printf '%s' "$s" +} + # Build search query for multiple title strings (OR logic) SEARCH_QUERY="" +TITLE_COUNT=$# for TITLE_STRING in "$@"; do + ESCAPED_TITLE=$(escape_github_search_phrase "$TITLE_STRING") if [[ -z "$SEARCH_QUERY" ]]; then - SEARCH_QUERY="$TITLE_STRING in:title" + SEARCH_QUERY="\"$ESCAPED_TITLE\" in:title" else - SEARCH_QUERY="$SEARCH_QUERY OR $TITLE_STRING in:title" + SEARCH_QUERY="$SEARCH_QUERY OR \"$ESCAPED_TITLE\" in:title" fi done +# Parenthesize combined OR clauses for clarity when multiple titles are used +if [[ "$TITLE_COUNT" -gt 1 ]]; then + SEARCH_QUERY="($SEARCH_QUERY)" +fi # --- Preflight checks --- if ! command -v gh &>/dev/null; then echo "Error: gh CLI is not installed. See https://cli.github.com" From 153451959c21de6941bb8c42bf361ad4694f43e7 Mon Sep 17 00:00:00 2001 From: Mike Harder Date: Fri, 20 Mar 2026 18:48:40 +0000 Subject: [PATCH 3/3] log query --- approve-prs.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/approve-prs.sh b/approve-prs.sh index 272f349..1388c10 100755 --- a/approve-prs.sh +++ b/approve-prs.sh @@ -62,6 +62,7 @@ if ! gh auth status &>/dev/null; then fi # --- Fetch matching PRs --- +echo "Search query: $SEARCH_QUERY" echo "Fetching PRs..." PR_LIST=$(gh pr list \ --repo "$REPO" \