Skip to content

Commit e62091b

Browse files
committed
Add Dependabot auto-merge workflow
1 parent 45fa9e8 commit e62091b

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: Auto Merge Dependabot PR
2+
3+
"on":
4+
workflow_run:
5+
workflows: ["CI"]
6+
types: [completed]
7+
8+
jobs:
9+
auto-merge:
10+
if: github.event.workflow_run.conclusion == 'success' && startsWith(github.event.workflow_run.head_branch, 'dependabot/')
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 10
13+
permissions:
14+
contents: write
15+
pull-requests: write
16+
17+
steps:
18+
- name: Resolve Dependabot PR
19+
id: pr
20+
env:
21+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22+
run: |
23+
set -euo pipefail
24+
BRANCH_NAME="${{ github.event.workflow_run.head_branch }}"
25+
PR_NUMBER=$(gh pr list --repo "${GITHUB_REPOSITORY}" --state open --head "${BRANCH_NAME}" --json number --jq '.[0].number // empty')
26+
if [ -z "${PR_NUMBER}" ]; then
27+
echo "No open Dependabot PR found for ${BRANCH_NAME}." >> "$GITHUB_STEP_SUMMARY"
28+
exit 0
29+
fi
30+
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
31+
32+
- name: Evaluate merge eligibility
33+
id: merge_guard
34+
if: steps.pr.outputs.pr_number != ''
35+
env:
36+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37+
run: |
38+
set -euo pipefail
39+
gh pr view "${{ steps.pr.outputs.pr_number }}" --repo "${GITHUB_REPOSITORY}" --json number,isDraft,author,url,body,labels > pr.json
40+
python3 - <<'PY'
41+
import json
42+
import os
43+
from pathlib import Path
44+
45+
pr = json.loads(Path("pr.json").read_text(encoding="utf-8"))
46+
author = (pr.get("author") or {}).get("login")
47+
labels = {item.get("name", "") for item in pr.get("labels", [])}
48+
body = pr.get("body") or ""
49+
is_major = "update-type: version-update:semver-major" in body
50+
dependabot_authors = {"dependabot[bot]", "app/dependabot"}
51+
is_dependabot = author in dependabot_authors and "dependencies" in labels
52+
should_merge = is_dependabot and not pr.get("isDraft") and not is_major
53+
if should_merge:
54+
reason = "ready"
55+
elif is_major:
56+
reason = "major_update"
57+
else:
58+
reason = "not_eligible_dependabot_pr"
59+
60+
summary_lines = [
61+
"## Auto-Merge Gate",
62+
f"- PR: {pr['url']}",
63+
f"- Author: `{author or '<unknown>'}`",
64+
f"- Draft: `{'yes' if pr.get('isDraft') else 'no'}`",
65+
f"- Dependabot label: `{'yes' if 'dependencies' in labels else 'no'}`",
66+
f"- Major update: `{'yes' if is_major else 'no'}`",
67+
f"- Final merge decision: `{'merge' if should_merge else 'skip'}`",
68+
f"- Reason: `{reason}`",
69+
]
70+
Path("pr-summary.md").write_text("\n".join(summary_lines).strip() + "\n", encoding="utf-8")
71+
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
72+
print(f"should_merge={'true' if should_merge else 'false'}", file=output)
73+
print(f"reason={reason}", file=output)
74+
PY
75+
76+
- name: Append merge summary
77+
if: steps.pr.outputs.pr_number != ''
78+
run: cat pr-summary.md >> "$GITHUB_STEP_SUMMARY"
79+
80+
- name: Merge Dependabot PR
81+
if: steps.merge_guard.outputs.should_merge == 'true'
82+
env:
83+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84+
run: gh pr merge "${{ steps.pr.outputs.pr_number }}" --repo "${GITHUB_REPOSITORY}" --rebase --delete-branch

0 commit comments

Comments
 (0)