Last active
January 31, 2026 04:33
-
-
Save Drowze/068e0d896026410a05e72cf3583c6fcb to your computer and use it in GitHub Desktop.
Automatically approve & merge pull requests based on a GitHub search (which can be across repositories).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Example: | |
| # oh_auto_merge 'archived:False org:MyOrg is:pr state:open author:app/dependabot' | |
| function oh_auto_merge --argument-names search_query | |
| set -l graphql_query 'query SearchPullRequests($search_query: String!) { | |
| viewer { | |
| login | |
| } | |
| search( | |
| query: $search_query | |
| type: ISSUE | |
| first: 50 | |
| ) { | |
| nodes { | |
| ... on PullRequest { | |
| number | |
| title | |
| url | |
| mergeable | |
| baseRefName | |
| reviews(states: APPROVED, first: 100) { | |
| totalCount | |
| nodes { | |
| author { | |
| login | |
| } | |
| } | |
| } | |
| headRepository { | |
| branchProtectionRules(first: 10) { | |
| nodes { | |
| pattern | |
| requiredApprovingReviewCount | |
| } | |
| } | |
| } | |
| commits(last: 1) { | |
| nodes { | |
| commit { | |
| statusCheckRollup { | |
| contexts(last: 100) { | |
| nodes { | |
| ... on CheckRun { | |
| name | |
| conclusion | |
| } | |
| ... on StatusContext { | |
| context | |
| state | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }' | |
| # Helper function for colored logging | |
| function __oh_log --argument-names color --argument-names message | |
| set_color $color ; echo $message ; set_color normal | |
| end | |
| set -l response "$(gh api graphql -f "query=$graphql_query" -f "search_query=$search_query")" | |
| set -l gh_viewer "$(echo "$response" | jq -r '.data.viewer.login')" | |
| for pr in (echo "$response" | jq -c '.data.search.nodes[]') | |
| __oh_log cyan "$(echo "$pr" | jq -r '"PR: \(.title) (#\(.number)) (\(.url))"')" | |
| # Check mergeable status, retrying if UNKNOWN (since it is computed by a background job on demand) | |
| set -l mergeable_status (echo "$pr" | jq -r '.mergeable') | |
| if test "$mergeable_status" = "UNKNOWN" | |
| set -l url (echo "$pr" | jq -r '.url') | |
| for i in (seq 1 5) | |
| __oh_log normal "├── waiting for mergeable status: attempt $i / 5" | |
| sleep 2 | |
| set mergeable_status (gh pr view "$url" --json mergeable -q '.mergeable') | |
| if test "$mergeable_status" != "UNKNOWN" | |
| break | |
| end | |
| end | |
| end | |
| # Skip if the PR has merge conflicts | |
| if test "$mergeable_status" = "CONFLICTING" | |
| __oh_log yellow "└── skipping (merge conflicts)" | |
| continue | |
| end | |
| # Skip if the PR has failing or pending statuses/checks | |
| if echo "$pr" | jq -e '.commits.nodes[0].commit.statusCheckRollup.contexts.nodes | any(.conclusion == "FAILURE" or .conclusion == "PENDING")' > /dev/null | |
| __oh_log yellow "└── skipping (checks not passed)" | |
| continue | |
| end | |
| # Approve the PR if not already approved | |
| set -l current_approvals "$(echo "$pr" | jq -r '.reviews.totalCount')" | |
| if echo "$pr" | jq -e --arg gh_viewer "$gh_viewer" '.reviews.nodes | any(.author.login == $gh_viewer)' > /dev/null | |
| __oh_log normal "├── skipping approval (already approved)" | |
| else | |
| __oh_log normal "├── approving ..." | |
| echo gh pr review --approve (echo "$pr" | jq -r '.url') | |
| set current_approvals (math "$current_approvals" + 1) | |
| end | |
| # Skip if not enough approvals (based on branch protection rules) | |
| set -l required_approvals (echo "$pr" | jq -r '.baseRefName as $base_branch | .headRepository.branchProtectionRules.nodes[] | select(.pattern == $base_branch).requiredApprovingReviewCount') | |
| if test -n "$required_approvals" && test "$current_approvals" -lt "$required_approvals" | |
| __oh_log yellow "└── skipping merge (not enough approvals - $current_approvals/$required_approvals)" | |
| continue | |
| end | |
| __oh_log green "└── merging ..." | |
| echo gh pr merge --squash (echo "$pr" | jq -r '.url') | |
| sleep 0.5 # to avoid rate limiting | |
| end | |
| # Cleanup helper function from global scope | |
| functions -e __oh_log | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment