Skip to content

Commit 9779b0e

Browse files
committed
feat: adding action to automerged approved merge requests
1 parent 2dd56b0 commit 9779b0e

2 files changed

Lines changed: 159 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: Automerge
2+
3+
on:
4+
workflow_call:
5+
secrets:
6+
RELEASE_TOKEN:
7+
required: false
8+
APP_ID:
9+
required: false
10+
APP_PRIVATE_KEY:
11+
required: false
12+
inputs:
13+
label:
14+
description: 'Label that marks PRs eligible for automerge'
15+
required: false
16+
default: 'automerge-approved'
17+
type: string
18+
merge_method:
19+
description: 'Merge method to use: merge, squash, or rebase'
20+
required: false
21+
default: 'rebase'
22+
type: string
23+
delete_branch:
24+
description: 'Delete the head branch after merging'
25+
required: false
26+
default: true
27+
type: boolean
28+
runner:
29+
description: 'Runner to use for the job'
30+
required: false
31+
default: 'self-hosted'
32+
type: string
33+
34+
jobs:
35+
automerge:
36+
runs-on: ${{ inputs.runner }}
37+
permissions:
38+
contents: write
39+
pull-requests: write
40+
steps:
41+
- name: Check auth configuration
42+
id: auth-check
43+
env:
44+
APP_ID: ${{ secrets.APP_ID }}
45+
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
46+
run: |
47+
if [ -n "${APP_ID}" ] && [ -n "${APP_PRIVATE_KEY}" ]; then
48+
echo "use_app_auth=true" >> $GITHUB_OUTPUT
49+
else
50+
echo "use_app_auth=false" >> $GITHUB_OUTPUT
51+
fi
52+
53+
- name: Generate a token
54+
id: generate-token
55+
if: steps.auth-check.outputs.use_app_auth == 'true'
56+
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
57+
with:
58+
client-id: ${{ secrets.APP_ID }}
59+
private-key: ${{ secrets.APP_PRIVATE_KEY }}
60+
owner: ${{ github.repository_owner }}
61+
62+
- name: Merge labelled PRs
63+
env:
64+
GH_TOKEN: ${{ steps.generate-token.outputs.token || secrets.RELEASE_TOKEN || github.token }}
65+
GH_REPO: ${{ github.repository }}
66+
LABEL: ${{ inputs.label }}
67+
MERGE_METHOD: ${{ inputs.merge_method }}
68+
DELETE_BRANCH: ${{ inputs.delete_branch }}
69+
run: |
70+
PR_LIST=$(gh pr list \
71+
--label "${LABEL}" \
72+
--state open \
73+
--json number,title,mergeable,mergeStateStatus)
74+
75+
PR_COUNT=$(echo "${PR_LIST}" | jq 'length')
76+
77+
echo "## Automerge Results" >> $GITHUB_STEP_SUMMARY
78+
echo "" >> $GITHUB_STEP_SUMMARY
79+
80+
if [ "${PR_COUNT}" -eq 0 ]; then
81+
echo "No open PRs found with label \`${LABEL}\`." >> $GITHUB_STEP_SUMMARY
82+
echo "No PRs to merge."
83+
exit 0
84+
fi
85+
86+
echo "Found ${PR_COUNT} PR(s) with label \`${LABEL}\`." >> $GITHUB_STEP_SUMMARY
87+
echo "" >> $GITHUB_STEP_SUMMARY
88+
echo "| PR | Title | Status |" >> $GITHUB_STEP_SUMMARY
89+
echo "|----|-------|--------|" >> $GITHUB_STEP_SUMMARY
90+
91+
MERGED=0
92+
SKIPPED=0
93+
FAILED=0
94+
95+
for NUMBER in $(echo "${PR_LIST}" | jq -r '.[].number'); do
96+
TITLE=$(echo "${PR_LIST}" | jq -r ".[] | select(.number == ${NUMBER}) | .title")
97+
MERGEABLE=$(echo "${PR_LIST}" | jq -r ".[] | select(.number == ${NUMBER}) | .mergeable")
98+
STATE=$(echo "${PR_LIST}" | jq -r ".[] | select(.number == ${NUMBER}) | .mergeStateStatus")
99+
100+
MERGE_ARGS=("${NUMBER}" "--${MERGE_METHOD}")
101+
[ "${DELETE_BRANCH}" == "true" ] && MERGE_ARGS+=(--delete-branch)
102+
103+
if [ "${MERGEABLE}" == "MERGEABLE" ] && [ "${STATE}" == "CLEAN" ]; then
104+
if gh pr merge "${MERGE_ARGS[@]}"; then
105+
echo "| [#${NUMBER}](${GITHUB_SERVER_URL}/${GH_REPO}/pull/${NUMBER}) | ${TITLE} | Merged |" >> $GITHUB_STEP_SUMMARY
106+
MERGED=$((MERGED + 1))
107+
else
108+
echo "| [#${NUMBER}](${GITHUB_SERVER_URL}/${GH_REPO}/pull/${NUMBER}) | ${TITLE} | Failed |" >> $GITHUB_STEP_SUMMARY
109+
FAILED=$((FAILED + 1))
110+
fi
111+
else
112+
echo "| [#${NUMBER}](${GITHUB_SERVER_URL}/${GH_REPO}/pull/${NUMBER}) | ${TITLE} | Skipped (${STATE}) |" >> $GITHUB_STEP_SUMMARY
113+
SKIPPED=$((SKIPPED + 1))
114+
fi
115+
done
116+
117+
echo "" >> $GITHUB_STEP_SUMMARY
118+
echo "**Merged:** ${MERGED} | **Skipped:** ${SKIPPED} | **Failed:** ${FAILED}" >> $GITHUB_STEP_SUMMARY
119+
120+
if [ "${FAILED}" -gt 0 ]; then
121+
echo "::warning::${FAILED} PR(s) failed to merge."
122+
fi

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,43 @@ deploy:
165165

166166
---
167167

168+
### `automerge-approved.yml` — Automerge
169+
170+
Scans all open PRs in the repository and merges those carrying a configurable label (default: `automerge-approved`). Only PRs in a `CLEAN` merge state (all checks passed, no conflicts) are merged; others are reported as skipped. Supports GitHub App auth, a PAT, or the default `GITHUB_TOKEN`.
171+
172+
#### Secrets
173+
174+
| Name | Description |
175+
|------|-------------|
176+
| `APP_ID` | GitHub App client ID (use with `APP_PRIVATE_KEY`) |
177+
| `APP_PRIVATE_KEY` | GitHub App private key |
178+
| `RELEASE_TOKEN` | PAT alternative to App auth |
179+
180+
All secrets are optional. When none are provided the job uses the default `GITHUB_TOKEN`.
181+
182+
#### Inputs
183+
184+
| Name | Required | Default | Description |
185+
|------|----------|---------|-------------|
186+
| `label` | no | `'automerge-approved'` | Label that marks PRs eligible for merging |
187+
| `merge_method` | no | `'squash'` | Merge method: `merge`, `squash`, or `rebase` |
188+
| `delete_branch` | no | `true` | Delete the head branch after a successful merge |
189+
| `runner` | no | `'self-hosted'` | Runner label |
190+
191+
#### Example
192+
193+
```yaml
194+
automerge:
195+
uses: mogenius/github-actions/.github/workflows/automerge-approved.yml@<sha> # main
196+
secrets:
197+
APP_ID: ${{ secrets.RELEASE_APP_ID }}
198+
APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_SECRET }}
199+
with:
200+
merge_method: squash
201+
```
202+
203+
---
204+
168205
### `go-build.yml` — Go Build
169206

170207
Compiles all packages in a Go module with `go build ./...`.

0 commit comments

Comments
 (0)