(ywc) Use when the user wants to merge Dependabot PRs, batch-process dependency updates, or clean up accumulated Dependabot PRs. Triggers: "merge dependabot", "dependabot PR", "dependency updates", "security updates merge", "디펜다봇 머지", "依存関係更新マージ". Do not use for non-Dependabot PRs, manual dependency upgrades, or for merging feature PRs (use ywc-create-pr or platform tools).
Scanned 9/2/2026
Install to Claude Code
npx -y skills add yongwoon/ywc-agent-toolkit --skill ywc-merge-dependabot --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ywc Merge Dependabot?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/yongwoon-ywc-merge-dependabot)More formats (shields.io, HTML) on the badges page.
---
name: ywc-merge-dependabot
version: 1.0.0
description: (ywc) Use when the user wants to merge Dependabot PRs, batch-process dependency updates, or clean up accumulated Dependabot PRs. Triggers: "merge dependabot", "dependabot PR", "dependency updates", "security updates merge", "디펜다봇 머지", "依存関係更新マージ". Do not use for non-Dependabot PRs, manual dependency upgrades, or for merging feature PRs (use ywc-create-pr or platform tools).
category: release
phase: release
requires: []
advisor_budget: 0
allowed tools: Bash, Read
---
# Merge Dependabot Pull Requests
**Announce at start:** "I'm using the ywc-merge-dependabot skill to merge Dependabot PRs with CI verification — sequential by default, or parallel-auto (ecosystem-grouped queue) when requested."
Safely merge Dependabot PRs with CI verification, conflict resolution, and clear reporting.
## Rationalization Defense
When tempted to skip a step, check this table first:
| Excuse | Reality |
|---|---|
| "All ecosystems can run in parallel — fire all merges at once without grouping" | No. Within an ecosystem (e.g., multiple npm PRs all touching `package-lock.json`) merges still serialize via GitHub's auto-merge queue. parallel-auto only fans out across non-overlapping ecosystems, not within one. |
| "Mixed-ecosystem PR (touches both `package.json` and `pom.xml`) is fine to auto-merge" | No. Mixed PRs go to a final sequential pass; `--auto` cannot guarantee ordering when a single PR crosses two parallel groups. |
| "Just queue everything with `--auto` and walk away" | The polling loop and final summary are non-optional. Without them users have no audit trail of which PRs failed, why, or whether the queue stalled. |
| "Repo doesn't have auto-merge enabled, fall through silently" | If `parallel-auto` is requested but `gh repo view --json autoMergeAllowed` returns `false`, fall back to sequential mode and tell the user — never pretend the queue is running. |
| "CI is green but lockfile shows different hash, merge anyway" | Lockfile mismatch indicates dirty working state. Stop and rebase the PR first. |
| "Major version bump looks safe, just merge" | Major bumps need explicit user confirmation. Default action: skip and report for human review. |
| "Conflicts with main, force-push my own resolution" | Use Dependabot's `@dependabot rebase` comment instead. Hand-resolved conflicts in dep PRs hide breaking changes. |
| "Security mode, but PR has no CVE link" | If `security` mode is requested and CVE/advisory is missing, skip the PR and report it. |
| "All passed, no need for a final summary" | Always emit a per-PR result table (merged / skipped / failed) at the end. |
**Violating the letter of these rules is violating the spirit.** Dependabot velocity is worthless if a bad merge silently breaks main.
## Context
- Repository: !`gh repo view --json nameWithOwner --jq .nameWithOwner`
- Default branch: !`gh repo view --json defaultBranchRef --jq .defaultBranchRef.name`
## Mode Selection
This skill supports two orthogonal flags inside `$ARGUMENTS`. Parse the argument string as a set of space-separated tokens.
**Scope flag** — controls which PRs are eligible:
| Token | Scope |
| --- | --- |
| `security` | Security-related Dependabot PRs only |
| _(token absent)_ | All Dependabot PRs |
**Execution flag** — controls how eligible PRs are processed:
| Token | Execution | When to use |
| --- | --- | --- |
| `parallel-auto` | Group eligible PRs by lockfile ecosystem; queue every PR with `gh pr merge --auto`; GitHub serializes within each ecosystem and processes ecosystems in parallel; one final sequential pass clears the `mixed` bucket | Many PRs (≥ 5) across multiple ecosystems (npm + github-actions + python …) where wall-clock CI wait is the bottleneck |
| _(token absent)_ | Sequential — one PR at a time, ascending PR number | Small batches, repos with strict branch protection, or environments where auto-merge is disabled |
Examples:
- `(empty)` → all PRs, sequential (default)
- `security` → security PRs only, sequential
- `parallel-auto` → all PRs, ecosystem-grouped auto-merge
- `security parallel-auto` → security PRs only, ecosystem-grouped auto-merge
Security-related PRs are identified by labels like `security`, PR title containing "security", or Dependabot's security advisory metadata. When in doubt about whether a PR is security-related, check the PR body for CVE references or GitHub Security Advisory links.
**Parallel-auto prerequisite:** before entering parallel-auto mode, verify the repository allows auto-merge:
```bash
gh repo view --json autoMergeAllowed --jq .autoMergeAllowed
```
If the value is `false`, announce the fallback ("Auto-merge is not enabled on this repository — falling back to sequential mode") and proceed as if `parallel-auto` were absent. Never silently skip the queueing and pretend the work is in progress.
## Task
### 1. List Dependabot PRs
Retrieve all open PRs created by Dependabot:
```bash
gh pr list --author "app/dependabot" --state open --json number,title,labels,body --limit 100
```
If in **security-only mode**, filter to PRs that match any of:
- Have a `security` label
- Title or body contains "security advisory", "CVE-", "GHSA-", or "vulnerability"
- Created by `dependabot[bot]` with security update metadata in the body
Sort the resulting list by PR number ascending — processing order matters because earlier merges can affect later PRs.
### 2. Pre-Merge Checks
For each PR, run these checks **before** attempting to merge. If any check fails, skip the PR.
| Check | Skip condition | Skip label |
| --- | --- | --- |
| **Dockerfile FROM change** | PR modifies a `FROM` image version in any Dockerfile | `Skipped (Dockerfile)` |
| **Major version upgrade** | PR bumps a major version (e.g. 2.x → 3.x), which risks breaking changes | `Skipped (Major version upgrade)` |
| **CI status** | Required CI checks have not all passed | `Failed (CI not passing)` |
To detect a Dockerfile FROM change:
```bash
gh pr diff {number} --name-only | grep -qE '(^|/)(Dockerfile|Dockerfile\.[^/]*)$' && \
gh pr diff {number} | grep -qE '^[-+]FROM ' && \
echo "Dockerfile FROM change detected — skip"
```
To detect major version bumps, compare the version numbers in the PR title (Dependabot titles typically follow the pattern "Bump X from A to B"). A major bump means the leftmost non-zero version segment changed.
### 2.5. Ecosystem Grouping (parallel-auto mode only)
Skip this step in sequential mode. In parallel-auto mode, classify the eligible PR list by lockfile ecosystem using the bundled script. Resolve the script path relative to this skill folder (the directory containing this `SKILL.md`), not relative to the target repository.
```bash
python3 /path/to/ywc-merge-dependabot/scripts/group-by-ecosystem.py {pr_numbers...}
```
Replace `/path/to/ywc-merge-dependabot` with the actual skill directory path.
The script returns single-line JSON of the shape `{"groups": {ecosystem: [pr...]}, "errors": [...]}`. Recognised ecosystems: `npm`, `github-actions`, `python`, `go`, `cargo`, `maven`, `gradle`, `docker`. PRs touching no recognised marker, or markers from two or more ecosystems, land in the `mixed` group.
The grouping serves two purposes:
1. **Audit trail** — the final summary records which ecosystem each PR belonged to and which ones GitHub serialized vs parallelized.
2. **Mixed-bucket isolation** — `mixed` PRs are deliberately held back to a final sequential pass (Step 3b stage 3) so a single PR that crosses two parallel groups cannot race with itself.
Surface the grouping breakdown to the user before merging:
```
Ecosystem grouping (8 PRs eligible):
- npm: #201, #205, #207
- github-actions: #203, #209
- python: #204, #208
- mixed: #211
```
### 3. Merge Process
Choose the flow based on the execution flag from Mode Selection. Both flows preserve the same safety contract — only the merge invocation and waiting strategy differ.
#### 3a. Sequential Flow (default)
Process PRs one at a time in ascending PR number order. This is important because merging one PR can create conflicts in subsequent PRs.
For each PR that passes pre-merge checks:
```bash
# Check CI status
gh pr checks {number} --required
# Attempt merge
gh pr merge {number} --merge
```
**If a merge conflict occurs**, resolve it in this order. First, comment `@dependabot rebase` on the PR, then poll for the rebase to land (consistent with the Rationalization Defense above) — do not guess at how long to wait:
```bash
gh pr comment {number} --body "@dependabot rebase"
# Wait up to 10 minutes for Dependabot's rebase, polling every 30 seconds.
deadline=$(( $(date +%s) + 600 ))
lookup_failures=0
while [ "$(date +%s)" -lt "$deadline" ]; do
merge_status=$(gh pr view {number} --json mergeStateStatus --jq '.mergeStateStatus' 2>/dev/null)
if [ -z "$merge_status" ]; then
lookup_failures=$((lookup_failures + 1))
sleep 30
continue
fi
lookup_failures=0
if [ "$merge_status" != "CONFLICTING" ] && [ "$merge_status" != "DIRTY" ] && [ "$merge_status" != "UNKNOWN" ]; then
echo "rebase landed, mergeStateStatus=$merge_status"
break
fi
sleep 30
done
```
A failed `gh pr view` lookup (empty output) is **not** evidence of a resolved conflict — it continues polling rather than exiting the loop. If lookups keep failing, treat it as a degraded/unknown state, not a safe merge signal.
If the loop exits at the deadline still `CONFLICTING`/`DIRTY`/`UNKNOWN`, or lookups kept failing, the rebase did **not** confirm-clear the conflict — fall back to the manual path.
> **Action required**: Read [`../references/pr-conflict-resolution.md`](../references/pr-conflict-resolution.md) and follow **Update Branch From Base** for the manual fallback — merge the base into the Dependabot branch (never rebase, it orphans review threads), push, and re-verify CI before merging. Do not inline or approximate that procedure here.
**If CI fails** after conflict resolution or at any point, skip the PR and record the failure.
After each successful merge, note it — the next PR in the queue may now have conflicts caused by this merge.
#### 3b. Parallel-Auto Flow
In parallel-auto mode the client offloads serialization to GitHub's auto-merge queue. The flow has three stages and the client never blocks on per-PR CI manually — GitHub handles rebase and CI orchestration.
**Stage 1 — Queue every non-mixed PR for auto-merge:**
For each ecosystem group's PRs (the order across groups does not matter — they are non-conflicting by construction), queue them all at once:
```bash
gh pr merge {number} --auto --merge
```
This sets the PR to merge automatically as soon as its CI is green and the branch is up to date. PRs sharing a lockfile (same ecosystem) automatically serialize because each merge invalidates the next PR's branch state, and Dependabot rebases the affected PRs; PRs in different ecosystems progress in parallel because GitHub processes them independently.
**Stage 2 — Poll the queue until it drains:**
Track each queued PR's state until it reaches a terminal state. Use a single bounded loop (do not spin in tight retries):
```bash
# Wait up to 30 minutes total, polling every 60 seconds.
deadline=$(( $(date +%s) + 1800 ))
remaining=(101 105 107 203 209 204 208) # queued PR numbers
declare -A status
while [ ${#remaining[@]} -gt 0 ] && [ "$(date +%s)" -lt "$deadline" ]; do
next=()
for pr in "${remaining[@]}"; do
pr_state=$(gh pr view "$pr" --json state --jq '.state' 2>/dev/null || echo UNKNOWN)
merge_status=$(gh pr view "$pr" --json mergeStateStatus --jq '.mergeStateStatus' 2>/dev/null || echo UNKNOWN)
if [ "$pr_state" = "MERGED" ]; then
status[$pr]="merged"
elif [ "$pr_state" = "CLOSED" ]; then
status[$pr]="closed"
elif [ "$merge_status" = "CONFLICTING" ] || [ "$merge_status" = "DIRTY" ]; then
# Stay in queue — Dependabot or a maintainer may rebase before the deadline.
next+=("$pr")
else
next+=("$pr")
fi
done
remaining=("${next[@]}")
[ ${#remaining[@]} -gt 0 ] && sleep 60
done
# Any PR still in `remaining` after the loop is recorded as queue-stalled.
for pr in "${remaining[@]}"; do
status[$pr]="stalled"
done
```
PRs that reach `MERGED` are recorded as `Merged`. PRs still in the `remaining` list after the deadline are recorded as `Failed (queue stalled)` so the user can investigate. Do not extend the deadline silently — if the queue genuinely needs more time, the user can rerun the skill.
**Stage 3 — Final sequential pass for the mixed bucket:**
After the parallel queue has drained (Stage 2 returned), process the `mixed` group using the same logic as Sequential Flow (3a). Mixed PRs run last because earlier merges may have changed the conflict surface they would land in.
### 4. Final Summary
After processing all PRs, report results in this format:
```
## Dependabot Merge Results
Mode: parallel-auto (security)
Ecosystem groups processed: npm (3), github-actions (2), python (2), mixed (1)
- ✅ Merged (npm) : #123 Bump axios from 1.6.0 to 1.7.2
- ✅ Merged (npm) : #125 Bump lodash from 4.17.20 to 4.17.21
- ✅ Merged (github-actions) : #129 Bump actions/checkout from 4.1.1 to 4.2.0
- ⏭️ Skipped (Dockerfile) : #127 Bump node from 18 to 20
- ⏭️ Skipped (Major version) : #130 Bump webpack from 4.46.0 to 5.90.0
- ❌ Failed (queue stalled) : #132 Bump express from 4.18.0 to 4.19.2 — CONFLICTING after 30 min
- ❌ Failed (mixed pass) : #135 Bump aws-sdk + boto3 — manual conflict resolution required
Total: 3 merged / 2 skipped / 2 failed
```
Include:
- Mode line — scope flag + execution flag, so the reader can reproduce the run
- Ecosystem group summary — only when parallel-auto was used; the count tells the reader how many groups GitHub serialized in parallel
- Per-PR result — for parallel-auto, annotate each line with the ecosystem; for sequential, omit the annotation
- If a previous merge affected a subsequent PR, note which PR caused the issue
- Total counts: merged / skipped / failed
## Error Handling
| Error | Action |
| --- | --- |
| `gh` CLI not authenticated | Stop and ask user to run `gh auth login` |
| No Dependabot PRs found | Report "No Dependabot PRs found" and stop |
| Rate limit hit | Wait and retry, or stop and report progress so far |
| Branch protection prevents merge | Skip PR and note the protection rule in the report |
## Notes
- Follow any additional instructions in `$ARGUMENTS`
- Never force-merge or bypass branch protection rules
- If the number of PRs is large (>20), ask the user for confirmation before proceeding. For batches of that size, also recommend `parallel-auto` mode if the eligible PRs span more than one ecosystem
- `parallel-auto` reduces wall-clock time by letting GitHub run the CI cycle for non-conflicting groups concurrently. It does not reduce the *per-PR* CI cost, the safety surface, or the conflict-resolution requirements — it only changes how the queue is orchestrated
## Integration
- **upstream**: None — this skill is triggered directly by the user or a scheduled workflow when Dependabot PRs accumulate
- **downstream**: /ywc-gen-testcase (optional — run after merging dependency updates to verify the updated packages do not break existing test coverage)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!