|  | 
|  | 1 | +#!/bin/bash | 
|  | 2 | +set -e | 
|  | 3 | +set -o pipefail | 
|  | 4 | + | 
|  | 5 | +# This script checks for open PRs from dependabot that have all checks passing and have not been | 
|  | 6 | +# modified by another user, and approves+merges them automatically. | 
|  | 7 | +# To be run as a GitHub action. | 
|  | 8 | + | 
|  | 9 | +# Check if repository argument is provided | 
|  | 10 | +if [ -z "$1" ]; then | 
|  | 11 | +    echo "Error: Repository name not provided." | 
|  | 12 | +    echo "Usage: $0 <owner/repo>" | 
|  | 13 | +    echo "Example: $0 hyperlight-dev/hyperlight" | 
|  | 14 | +    exit 1 | 
|  | 15 | +fi | 
|  | 16 | + | 
|  | 17 | +REPO="$1" | 
|  | 18 | +echo "Checking for open Dependabot PRs to approve and merge in $REPO..." | 
|  | 19 | + | 
|  | 20 | +# Get all open PRs from dependabot | 
|  | 21 | +dependabot_prs=$(gh pr list -R "$REPO" --author "dependabot[bot]" --state open --json number,title,reviews) | 
|  | 22 | + | 
|  | 23 | +# Exit early if no PRs found | 
|  | 24 | +if [ -z "$dependabot_prs" ] || [ "$dependabot_prs" = "[]" ]; then | 
|  | 25 | +    echo "No open Dependabot PRs found in $REPO" | 
|  | 26 | +    exit 0 | 
|  | 27 | +fi | 
|  | 28 | + | 
|  | 29 | +# Count how many PRs we found | 
|  | 30 | +pr_count=$(echo "$dependabot_prs" | jq 'length') | 
|  | 31 | +echo "Found $pr_count open Dependabot PRs in $REPO" | 
|  | 32 | + | 
|  | 33 | +# Process each PR | 
|  | 34 | +echo "$dependabot_prs" | jq -c '.[]' | while read -r pr; do | 
|  | 35 | +    pr_number=$(echo "$pr" | jq -r '.number') | 
|  | 36 | +    pr_title=$(echo "$pr" | jq -r '.title') | 
|  | 37 | +     | 
|  | 38 | +    echo "Processing PR #$pr_number: $pr_title" | 
|  | 39 | +     | 
|  | 40 | +    # Check if PR only modifies allowed files | 
|  | 41 | +    pr_files=$(gh pr view "$pr_number" -R "$REPO" --json files) | 
|  | 42 | +    invalid_files=$(echo "$pr_files" | jq -r '.files[].path' | grep -v -E '(Cargo\.toml|Cargo\.lock|\.github/workflows/.+)' || true) | 
|  | 43 | +     | 
|  | 44 | +    if [ -n "$invalid_files" ]; then | 
|  | 45 | +        echo "  ❌ PR #$pr_number modifies files that are not allowed for auto-merge:" | 
|  | 46 | +        echo ${invalid_files/#/    - } | 
|  | 47 | +        echo "  ℹ️ Only changes to Cargo.toml, Cargo.lock, or .github/workflows/ files are allowed" | 
|  | 48 | +        continue | 
|  | 49 | +    fi | 
|  | 50 | +     | 
|  | 51 | +    echo "  ✅ PR #$pr_number only modifies allowed files (Cargo.toml, Cargo.lock, or .github/workflows/)" | 
|  | 52 | +     | 
|  | 53 | +    # First, get detailed PR information including all checks | 
|  | 54 | +    pr_details=$(gh pr view "$pr_number" -R "$REPO" --json statusCheckRollup,state) | 
|  | 55 | +     | 
|  | 56 | +    # Check if all status checks have passed (regardless of required or not) | 
|  | 57 | +    all_checks_pass=true | 
|  | 58 | +    has_pending_checks=false | 
|  | 59 | +    failed_checks="" | 
|  | 60 | +     | 
|  | 61 | +    # First identify checks that are still in progress | 
|  | 62 | +    pending_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] | select(.status == "IN_PROGRESS" or .status == "QUEUED" or .status == "PENDING") | .name') | 
|  | 63 | +     | 
|  | 64 | +    if [ -n "$pending_checks" ]; then | 
|  | 65 | +        echo "  ⏳ PR #$pr_number has pending checks:" | 
|  | 66 | +        echo "$pending_checks" | sed 's/^/    - /' | 
|  | 67 | +        echo "  ℹ️ We will still approve the PR so it can merge automatically once all checks pass" | 
|  | 68 | +        has_pending_checks=true | 
|  | 69 | +    fi | 
|  | 70 | +     | 
|  | 71 | +    # Check for failed checks - only include checks that have a conclusion and are not still running | 
|  | 72 | +    # Explicitly exclude checks with status IN_PROGRESS, QUEUED, or PENDING | 
|  | 73 | +    failed_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] |  | 
|  | 74 | +        select(.conclusion != null and  | 
|  | 75 | +               .conclusion != "SUCCESS" and  | 
|  | 76 | +               .conclusion != "NEUTRAL" and  | 
|  | 77 | +               .conclusion != "SKIPPED" and | 
|  | 78 | +               .status != "IN_PROGRESS" and  | 
|  | 79 | +               .status != "QUEUED" and  | 
|  | 80 | +               .status != "PENDING") | .name') | 
|  | 81 | +     | 
|  | 82 | +    if [ -n "$failed_checks" ]; then | 
|  | 83 | +        echo "  ❌ PR #$pr_number has failed checks:" | 
|  | 84 | +        echo "$failed_checks" | sed 's/^/    - /' | 
|  | 85 | +        all_checks_pass=false | 
|  | 86 | +        continue | 
|  | 87 | +    fi | 
|  | 88 | +     | 
|  | 89 | +    # If we've reached here, either all checks have passed or some are pending | 
|  | 90 | +    if [ "$has_pending_checks" = false ]; then | 
|  | 91 | +        echo "  ✅ All status checks passed for PR #$pr_number" | 
|  | 92 | +    fi | 
|  | 93 | +     | 
|  | 94 | +    # Check if PR has been modified by someone other than dependabot | 
|  | 95 | +    pr_commits=$(gh pr view "$pr_number" -R "$REPO" --json commits) | 
|  | 96 | +    non_dependabot_authors=$(echo "$pr_commits" | jq -r '.commits[].authors[].login' | grep -v -e "dependabot\[bot\]" -e "^$" || true) | 
|  | 97 | +     | 
|  | 98 | +    if [ -n "$non_dependabot_authors" ]; then | 
|  | 99 | +        echo "  ❌ PR #$pr_number has been modified by users other than dependabot: $non_dependabot_authors" | 
|  | 100 | +        continue | 
|  | 101 | +    fi | 
|  | 102 | +     | 
|  | 103 | +    # Check if PR needs approval (i.e., hasn't been approved already) | 
|  | 104 | +    already_approved=$(echo "$pr" | jq -r '.reviews[] | select(.state == "APPROVED") | .state' | grep -c "APPROVED" || true) | 
|  | 105 | +     | 
|  | 106 | +    if [ "$already_approved" -eq 0 ]; then | 
|  | 107 | +        echo "  ✅ Approving PR #$pr_number" | 
|  | 108 | +        gh pr review "$pr_number" -R "$REPO" --approve -b "Automatically approved by dependabot auto-approve workflow" | 
|  | 109 | +    else | 
|  | 110 | +        echo "  ℹ️ PR #$pr_number is already approved" | 
|  | 111 | +    fi | 
|  | 112 | +     | 
|  | 113 | +    if [ "$has_pending_checks" = true ] || [ "$all_checks_pass" = true ]; then | 
|  | 114 | +        echo "  ✅ Adding merge comment to PR #$pr_number" | 
|  | 115 | +        gh pr comment "$pr_number" -R "$REPO" -b "@dependabot merge" | 
|  | 116 | +        echo "  ✅ Merge command issued for PR #$pr_number" | 
|  | 117 | +    fi | 
|  | 118 | +     | 
|  | 119 | +done | 
|  | 120 | + | 
|  | 121 | +echo "Finished processing Dependabot PRs for $REPO" | 
0 commit comments