Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 79 additions & 33 deletions .github/workflows/dependabot-automerge.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: Dependabot Auto-Merge

on:
pull_request:
types: [opened, synchronize, reopened]
workflow_run:
workflows: [Rust CI]
types: [completed]

permissions:
contents: write
Expand All @@ -11,40 +12,85 @@ permissions:
jobs:
dependabot-auto-merge:
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
if: >
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.actor.login == 'dependabot[bot]'
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Get Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v3
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"

# In Cargo's SemVer interpretation, a 0.x.y → 0.z.y bump is breaking
# (https://doc.rust-lang.org/cargo/reference/semver.html). Dependabot
# classifies it as `version-update:semver-minor` per the strict SemVer
# 2.0.0 spec, so we additionally exclude minor bumps when the current
# major is 0 — those land as deliberate, reviewed PRs instead.
- name: Auto-approve safe Cargo updates
if: |
steps.metadata.outputs.package-ecosystem == 'cargo' &&
(steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
(steps.metadata.outputs.update-type == 'version-update:semver-minor' &&
!startsWith(steps.metadata.outputs.previous-version, '0.')))
run: gh pr review --approve "$PR_URL"
- name: Find open PR and check update type
id: check
run: |
pr=$(gh api "repos/$REPO/pulls" \
--jq "[.[] | select(.head.sha == \"$SHA\" and .state == \"open\")] | first")
number=$(echo "$pr" | jq -r '.number // empty')
if [[ -z "$number" ]]; then
echo "No open PR found for SHA $SHA — skipping"
exit 0
fi
echo "number=$number" >> "$GITHUB_OUTPUT"
echo "url=$(echo "$pr" | jq -r '.html_url')" >> "$GITHUB_OUTPUT"

# Dependabot embeds a YAML block in the commit message containing
# update-type and package-ecosystem for each dependency. Only auto-merge
# Cargo updates (GitHub Actions bumps share the same format but are excluded).
# Qualify if every dep is patch or minor, with the exception that
# 0.x minor bumps are excluded: in Cargo's convention a 0.x -> 0.y
# bump is considered breaking.
commit_msg=$(gh api "repos/$REPO/git/commits/$SHA" --jq '.message')

if ! echo "$commit_msg" | grep -q 'package-ecosystem: cargo'; then
echo "Not a Cargo update — skipping"
echo "is_eligible=false" >> "$GITHUB_OUTPUT"
exit 0
fi

is_eligible=true

# Reject if any dep is a major bump
if echo "$commit_msg" | grep 'update-type:' | grep -q 'version-update:semver-major'; then
is_eligible=false
fi

# Reject if any dep is a minor bump whose previous version starts with 0.
# The YAML block lists deps as:
# - dependency-name: foo
# dependency-version: 0.5.0
# previous-version: 0.4.2
# update-type: version-update:semver-minor
# We check each minor-bump entry for a preceding previous-version: 0.*
if [[ "$is_eligible" == "true" ]]; then
while IFS= read -r line; do
if echo "$line" | grep -q 'update-type: version-update:semver-minor'; then
# Look back in the block for the previous-version line
prev=$(echo "$commit_msg" \
| grep -B5 'update-type: version-update:semver-minor' \
| grep 'previous-version:' \
| tail -1 \
| grep -oP '[\d]+\.[\d]+\.[\d]+' \
| head -1)
if [[ "$prev" == 0.* ]]; then
is_eligible=false
break
fi
fi
done <<< "$commit_msg"
fi

# Must have at least one update-type line
has_types=$(echo "$commit_msg" | grep -c 'update-type:' || true)
if [[ "$has_types" -eq 0 ]]; then
is_eligible=false
fi

echo "is_eligible=$is_eligible" >> "$GITHUB_OUTPUT"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
REPO: ${{ github.repository }}
SHA: ${{ github.event.workflow_run.head_sha }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Enable auto-merge for safe Cargo updates
if: |
steps.metadata.outputs.package-ecosystem == 'cargo' &&
(steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
(steps.metadata.outputs.update-type == 'version-update:semver-minor' &&
!startsWith(steps.metadata.outputs.previous-version, '0.')))
run: gh pr merge --auto --squash "$PR_URL"
- name: Merge safe Cargo updates
if: steps.check.outputs.number != '' && steps.check.outputs.is_eligible == 'true'
run: gh pr merge --squash "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
PR_URL: ${{ steps.check.outputs.url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}