# Automerge Workflow

Enable automerge on a PR so it merges automatically when all CI checks pass and required approvals are met. Monitor status, cancel if needed, and verify the result.

## 1. Create PR and Enable Automerge

First, create the PR, then enable automerge:

```bash
OWNER="{owner}"
REPO="{repo}"

# Create the PR
PR=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "feat: add new feature",
    "body": "Description of changes\n\nCloses #42",
    "head": "{head_branch}",
    "base": "{base_branch}"
  }')
PR_INDEX=$(echo "$PR" | jq -r '.number')
echo "Created PR #${PR_INDEX}"

# Enable automerge with squash strategy
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}/merge" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "Do": "squash",
    "merge_when_checks_succeed": true,
    "delete_branch_after_merge": true,
    "MergeTitleField": "feat: add new feature (#'"${PR_INDEX}"')",
    "MergeMessageField": "Detailed description of the squashed changes.\n\nCloses #42"
  }'
echo "Automerge enabled for PR #${PR_INDEX}"
```

### Merge Strategies

| `Do` value | Behavior |
|------------|----------|
| `merge` | Create a merge commit |
| `rebase` | Rebase and fast-forward |
| `rebase-merge` | Rebase and create merge commit |
| `squash` | Squash all commits into one |

### Key Fields

| Field | Description |
|-------|-------------|
| `merge_when_checks_succeed` | Enable automerge — merge when all checks pass |
| `delete_branch_after_merge` | Auto-delete head branch after merge |
| `MergeTitleField` | Custom title for the merge/squash commit |
| `MergeMessageField` | Custom message body for the merge/squash commit |

## 2. Check Automerge Status

There is no dedicated "get automerge status" endpoint. You can infer it from the PR details and by attempting to cancel:

```bash
# Check PR details — look for auto_merge field if available
PR_DETAILS=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}" \
  -H "Authorization: token ${FORGEJO_PAT}")
echo "$PR_DETAILS" | jq '{state, mergeable, merged, head_sha: .head.sha}'

# Check if automerge is scheduled by attempting a cancel (dry check)
# A 204 response means automerge was active and is now cancelled
# A 409 response means there was nothing to cancel
CANCEL_CHECK=$(curl -s -w "\n%{http_code}" -X DELETE \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}/merge" \
  -H "Authorization: token ${FORGEJO_PAT}")
CANCEL_STATUS=$(echo "$CANCEL_CHECK" | tail -n 1)
# Note: This actually cancels automerge if it was active!
# Only use this approach if you intend to cancel or re-enable.
```

## 3. Cancel Automerge

```bash
RESULT=$(curl -s -w "\n%{http_code}" -X DELETE \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}/merge" \
  -H "Authorization: token ${FORGEJO_PAT}")
STATUS=$(echo "$RESULT" | tail -n 1)

case "$STATUS" in
  204)
    echo "Automerge cancelled successfully."
    ;;
  409)
    echo "No automerge was scheduled for this PR."
    ;;
  *)
    BODY=$(echo "$RESULT" | head -n -1)
    echo "Unexpected response (HTTP ${STATUS}): ${BODY}"
    ;;
esac
```

## 4. Monitor CI Status While Waiting for Automerge

Poll CI status to track progress:

```bash
HEAD_SHA=$(echo "$PR" | jq -r '.head.sha')

echo "Monitoring CI for PR #${PR_INDEX} (SHA: ${HEAD_SHA})..."
while true; do
  COMBINED=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/commits/${HEAD_SHA}/status" \
    -H "Authorization: token ${FORGEJO_PAT}")
  STATE=$(echo "$COMBINED" | jq -r '.state')
  TOTAL=$(echo "$COMBINED" | jq -r '.total_count')

  # Count statuses by state
  STATUSES=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/commits/${HEAD_SHA}/statuses" \
    -H "Authorization: token ${FORGEJO_PAT}")
  SUCCESS=$(echo "$STATUSES" | jq '[.[] | select(.state == "success")] | length')
  PENDING=$(echo "$STATUSES" | jq '[.[] | select(.state == "pending")] | length')
  FAILED=$(echo "$STATUSES" | jq '[.[] | select(.state == "failure" or .state == "error")] | length')

  echo "$(date +%H:%M:%S) — State: ${STATE} | Total: ${TOTAL} | Pass: ${SUCCESS} | Pending: ${PENDING} | Failed: ${FAILED}"

  # Check if PR was already merged
  PR_STATE=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}" \
    -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.merged')
  if [ "$PR_STATE" = "true" ]; then
    echo "PR has been merged by automerge!"
    break
  fi

  if [ "$STATE" = "failure" ] || [ "$STATE" = "error" ]; then
    echo "CI failed. Automerge will not proceed."
    echo "Failing checks:"
    echo "$STATUSES" | jq -r '.[] | select(.state == "failure" or .state == "error") | "  \(.context): \(.description // "no description")"'
    break
  fi

  if [ "$STATE" = "success" ]; then
    echo "All checks passed. Waiting for automerge to trigger..."
    sleep 10
    # Check merged status
    MERGED=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}" \
      -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.merged')
    if [ "$MERGED" = "true" ]; then
      echo "PR merged!"
      break
    fi
    echo "Checks passed but PR not yet merged (may be waiting for approvals)."
    break
  fi

  sleep 30
done
```

## 5. Verify Merge After CI Passes

```bash
PR_FINAL=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}" \
  -H "Authorization: token ${FORGEJO_PAT}")

MERGED=$(echo "$PR_FINAL" | jq -r '.merged')
STATE=$(echo "$PR_FINAL" | jq -r '.state')

if [ "$MERGED" = "true" ]; then
  echo "PR #${PR_INDEX} was merged successfully."
  echo "Merged by: $(echo "$PR_FINAL" | jq -r '.merged_by.login')"
  echo "Merge SHA: $(echo "$PR_FINAL" | jq -r '.merge_commit_sha')"
  echo "Merged at: $(echo "$PR_FINAL" | jq -r '.merged')"

  # Verify branch was deleted
  BRANCH_CHECK=$(curl -s -w "\n%{http_code}" \
    "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/branches/{branch}" \
    -H "Authorization: token ${FORGEJO_PAT}")
  BRANCH_STATUS=$(echo "$BRANCH_CHECK" | tail -n 1)
  if [ "$BRANCH_STATUS" = "404" ]; then
    echo "Branch was auto-deleted."
  else
    echo "Branch still exists (auto-delete may not be configured)."
  fi
else
  echo "PR #${PR_INDEX} has not been merged yet."
  echo "Current state: ${STATE}"

  # Check what's blocking the merge
  echo "Checking requirements..."

  # Check CI
  HEAD_SHA=$(echo "$PR_FINAL" | jq -r '.head.sha')
  CI_STATE=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/commits/${HEAD_SHA}/status" \
    -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.state')
  echo "  CI status: ${CI_STATE}"

  # Check reviews
  REVIEWS=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}/reviews" \
    -H "Authorization: token ${FORGEJO_PAT}")
  APPROVALS=$(echo "$REVIEWS" | jq '[.[] | select(.state == "APPROVED")] | length')
  CHANGES_REQUESTED=$(echo "$REVIEWS" | jq '[.[] | select(.state == "REQUEST_CHANGES")] | length')
  echo "  Approvals: ${APPROVALS}"
  echo "  Changes requested: ${CHANGES_REQUESTED}"
fi
```

## Complete Workflow Script

```bash
#!/bin/bash
set -euo pipefail

OWNER="${1:?Usage: $0 <owner> <repo> <pr_index>}"
REPO="${2:?}"
PR_INDEX="${3:?}"
MERGE_STYLE="${4:-squash}"  # merge, rebase, rebase-merge, squash

echo "=== Automerge Workflow for ${OWNER}/${REPO}#${PR_INDEX} ==="

# Get PR details
PR=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}" \
  -H "Authorization: token ${FORGEJO_PAT}")
PR_STATE=$(echo "$PR" | jq -r '.state')
PR_MERGED=$(echo "$PR" | jq -r '.merged')
PR_TITLE=$(echo "$PR" | jq -r '.title')
HEAD_SHA=$(echo "$PR" | jq -r '.head.sha')
HEAD_BRANCH=$(echo "$PR" | jq -r '.head.ref')

if [ "$PR_MERGED" = "true" ]; then
  echo "PR is already merged."
  exit 0
fi
if [ "$PR_STATE" != "open" ]; then
  echo "PR is ${PR_STATE}. Cannot enable automerge."
  exit 1
fi

echo "PR: ${PR_TITLE}"
echo "Head: ${HEAD_BRANCH} (${HEAD_SHA})"

# Enable automerge
echo ""
echo "Enabling automerge (${MERGE_STYLE})..."
RESULT=$(curl -s -w "\n%{http_code}" -X POST \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}/merge" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "Do": "'"${MERGE_STYLE}"'",
    "merge_when_checks_succeed": true,
    "delete_branch_after_merge": true
  }')
STATUS=$(echo "$RESULT" | tail -n 1)

if [ "$STATUS" = "200" ] || [ "$STATUS" = "204" ]; then
  echo "Automerge enabled."
elif [ "$STATUS" = "405" ]; then
  echo "Automerge not available (branch protection may not be configured)."
  echo "$(echo "$RESULT" | head -n -1 | jq -r '.message // .')"
  exit 1
else
  echo "Failed to enable automerge (HTTP ${STATUS})."
  echo "$(echo "$RESULT" | head -n -1 | jq -r '.message // .')"
  exit 1
fi

# Monitor
echo ""
echo "Monitoring CI and merge status..."
TIMEOUT=1800  # 30 minutes
ELAPSED=0
INTERVAL=30

while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
  # Check if merged
  CURRENT=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}" \
    -H "Authorization: token ${FORGEJO_PAT}")
  if [ "$(echo "$CURRENT" | jq -r '.merged')" = "true" ]; then
    echo ""
    echo "PR #${PR_INDEX} merged successfully!"
    echo "Merged by: $(echo "$CURRENT" | jq -r '.merged_by.login')"
    exit 0
  fi

  # Check CI
  CI=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/commits/${HEAD_SHA}/status" \
    -H "Authorization: token ${FORGEJO_PAT}")
  CI_STATE=$(echo "$CI" | jq -r '.state')

  echo "$(date +%H:%M:%S) — CI: ${CI_STATE}"

  if [ "$CI_STATE" = "failure" ] || [ "$CI_STATE" = "error" ]; then
    echo "CI failed. Cancelling automerge."
    curl -s -X DELETE "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}/merge" \
      -H "Authorization: token ${FORGEJO_PAT}" > /dev/null 2>&1
    exit 1
  fi

  sleep "$INTERVAL"
  ELAPSED=$((ELAPSED + INTERVAL))
done

echo "Timeout reached (${TIMEOUT}s). PR not yet merged."
echo "Automerge is still active and will proceed when checks pass."
```
