# Enables GitHub auto-merge for Autopilot PRs once the Product CI gate is green. # Label a pull request with `autopilot` or `automerge` to opt in. # This workflow is informational only — never add it to required status checks. name: autopilot auto-merge on: pull_request: types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review] check_suite: types: [completed] permissions: contents: read pull-requests: write checks: read concurrency: group: autopilot-auto-merge-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: false jobs: auto-merge: name: Autopilot auto-merge runs-on: [self-hosted, evoo-ci, Linux] steps: - name: Resolve pull request id: pr env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail event_name="${{ github.event_name }}" number="" if [[ "$event_name" == "pull_request" ]]; then number="${{ github.event.pull_request.number }}" elif [[ "$event_name" == "check_suite" ]]; then number="$(jq -r '.check_suite.pull_requests[0].number // empty' "$GITHUB_EVENT_PATH")" fi if [[ -z "$number" ]]; then echo "No pull request in event; skipping." echo "enabled=false" >> "$GITHUB_OUTPUT" exit 0 fi pr_json="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${number}")" labels="$(jq -r '[.labels[].name] | join(",")' <<<"$pr_json")" enabled=false if [[ ",${labels}," == *",autopilot,"* || ",${labels}," == *",automerge,"* ]]; then enabled=true fi { echo "number=$number" echo "head_sha=$(jq -r .head.sha <<<"$pr_json")" echo "draft=$(jq -r .draft <<<"$pr_json")" echo "labels=$labels" echo "enabled=$enabled" } >> "$GITHUB_OUTPUT" - name: Skip unless Autopilot label is present if: steps.pr.outputs.enabled != 'true' run: echo "No autopilot/automerge label; skipping." - name: Skip draft pull requests if: steps.pr.outputs.enabled == 'true' && steps.pr.outputs.draft == 'true' run: echo "Draft pull request; auto-merge waits for ready_for_review." - name: Verify Product CI on head commit id: gate if: steps.pr.outputs.enabled == 'true' && steps.pr.outputs.draft != 'true' env: GH_TOKEN: ${{ github.token }} HEAD_SHA: ${{ steps.pr.outputs.head_sha }} run: | set -euo pipefail conclusions=() while IFS= read -r conclusion; do [[ -n "$conclusion" ]] && conclusions+=("$conclusion") done < <( gh api "repos/${GITHUB_REPOSITORY}/commits/${HEAD_SHA}/check-runs" --paginate \ --jq '.check_runs[] | select(.name == "Product CI") | .conclusion' ) if [[ "${#conclusions[@]}" -eq 0 ]]; then echo "Product CI has not finished yet." echo "ready=false" >> "$GITHUB_OUTPUT" exit 0 fi for conclusion in "${conclusions[@]}"; do case "$conclusion" in success) echo "Product CI succeeded." echo "ready=true" >> "$GITHUB_OUTPUT" exit 0 ;; failure|cancelled|timed_out|action_required) echo "Product CI failed ($conclusion); not enabling auto-merge." exit 1 ;; esac done echo "Product CI still pending." echo "ready=false" >> "$GITHUB_OUTPUT" - name: Enable auto-merge if: steps.pr.outputs.enabled == 'true' && steps.pr.outputs.draft != 'true' && steps.gate.outputs.ready == 'true' env: AUTOPILOT_MERGE_TOKEN: ${{ secrets.AUTOPILOT_MERGE_TOKEN }} DRY_RUN: ${{ vars.AUTOPILOT_MERGE_DRY_RUN }} PR_NUMBER: ${{ steps.pr.outputs.number }} run: | set -euo pipefail if [[ "$DRY_RUN" == 'true' ]]; then echo "AUTOPILOT_MERGE_DRY_RUN=true — would run: gh pr merge $PR_NUMBER --auto --squash" exit 0 fi if [[ -n "$AUTOPILOT_MERGE_TOKEN" ]]; then export GH_TOKEN="$AUTOPILOT_MERGE_TOKEN" echo "Using AUTOPILOT_MERGE_TOKEN." else export GH_TOKEN="${{ github.token }}" echo "Using GITHUB_TOKEN. Add AUTOPILOT_MERGE_TOKEN if branch protection requires a PAT." fi gh pr merge "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --auto --squash echo "Auto-merge enabled (squash). GitHub merges when branch protection allows."