From 52175ab4ee897c9a6dd150b2506b8de3ec318144 Mon Sep 17 00:00:00 2001 From: Denis_Drobyshev Date: Sun, 20 Sep 2026 18:53:55 +0300 Subject: [PATCH] mlango was the one repository where dependency bumps waited on a person Seven of the eight repositories run this workflow. mlango does not, and that is why an actions bump has been sitting open with sixteen green checks: everywhere else `github_actions` is the first case the policy matches and merges unattended, and here there was no policy to match it. The file is the one the others run, byte for byte apart from the paragraph each copy uses to say what Dependabot is allowed to reach in that repository. Here that is: torch, transformers and scikit-learn never arrive, because dependabot.yml ignores them as optional extras with their own release cadence, and everything that does arrive is covered by required checks that run the suite on four Pythons across three operating systems, scaffold a project and drive it end to end, and fine-tune a real checkpoint. What it merges is unchanged from the others: actions bumps, patch bumps, and a group in which every member is a patch. Anything with a minor or a major in it still waits for a person. Auto-merge is queued rather than immediate, so the required checks still have to pass and a red build leaves the pull request open. --- .github/workflows/dependabot-auto-merge.yml | 121 ++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 .github/workflows/dependabot-auto-merge.yml diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..6becdf1 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,121 @@ +name: Dependabot auto-merge + +# What this does and does not do: +# +# auto-merged - GitHub Actions bumps, and patch bumps of anything else +# left for you - anything with a minor or major in it +# +# A patch release and an action bump are the updates that pile up unread until +# the queue is too long to review honestly. A minor bump can change behaviour, +# so it keeps a human. Auto-merge is queued, not immediate: GitHub still waits +# for the required checks to pass, and a red build leaves the PR open. +# +# torch, transformers and scikit-learn never reach this workflow: +# dependabot.yml ignores them, because they are optional extras with their own +# release cadence, pinned deliberately by whoever installs them. +# +# Everything else has real cover here. The required checks run the suite on four +# Pythons across three operating systems, scaffold a project and drive it end to +# end, and fine-tune a real checkpoint -- so a bump that breaks the framework +# fails before it merges rather than after. + +on: pull_request_target + +permissions: + contents: read + +jobs: + auto-merge: + # Who opened the pull request, not who triggered the event. `github.actor` + # is whoever caused this run, so the moment a person touches a Dependabot + # pull request - reopening it, or nudging it after a base change - the job + # skips and the update sits there looking merged-ready and never merging. + # The author never changes, which is the thing actually being asserted. + if: github.event.pull_request.user.login == 'dependabot[bot]' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + # Reads the update metadata from the PR that Dependabot opened. Nothing + # from the branch is checked out or executed, which is what makes + # pull_request_target safe to use here. + - id: metadata + uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3 + + - id: verdict + name: Decide whether this one can merge itself + env: + ECOSYSTEM: ${{ steps.metadata.outputs.package-ecosystem }} + UPDATE_TYPE: ${{ steps.metadata.outputs.update-type }} + UPDATED: ${{ steps.metadata.outputs.updated-dependencies-json }} + # A grouped pull request has no single update type: fetch-metadata + # leaves `update-type` empty and puts one entry per dependency in + # `updated-dependencies-json`. Reading only `update-type` sent every + # grouped bump to a human, including a group where all seven were + # patches - which is exactly the group worth merging unattended, and the + # reason the groups exist at all. + run: | + PATCH="version-update:semver-patch" + + if [ "$ECOSYSTEM" = "github_actions" ]; then + echo "auto=true" >> "$GITHUB_OUTPUT" + echo "reason=an actions bump" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if [ -n "$UPDATE_TYPE" ] && [ "$UPDATE_TYPE" != "null" ]; then + if [ "$UPDATE_TYPE" = "$PATCH" ]; then + echo "auto=true" >> "$GITHUB_OUTPUT" + echo "reason=a patch bump" >> "$GITHUB_OUTPUT" + else + echo "auto=false" >> "$GITHUB_OUTPUT" + echo "reason=${UPDATE_TYPE#version-update:semver-} is not a patch" >> "$GITHUB_OUTPUT" + fi + exit 0 + fi + + total=$(jq 'length' <<<"$UPDATED") + if [ "$total" -eq 0 ]; then + # No metadata to read. Refusing is the only safe reading of silence. + echo "auto=false" >> "$GITHUB_OUTPUT" + echo "reason=no update metadata to read" >> "$GITHUB_OUTPUT" + exit 0 + fi + + patches=$(jq --arg p "$PATCH" '[.[] | select(.updateType == $p)] | length' <<<"$UPDATED") + if [ "$total" -eq "$patches" ]; then + echo "auto=true" >> "$GITHUB_OUTPUT" + echo "reason=a group of $total, every one a patch" >> "$GITHUB_OUTPUT" + else + echo "auto=false" >> "$GITHUB_OUTPUT" + echo "reason=a group of $total, $((total - patches)) beyond patch" >> "$GITHUB_OUTPUT" + fi + + - name: Queue the merge + if: steps.verdict.outputs.auto == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR: ${{ github.event.pull_request.html_url }} + REASON: ${{ steps.verdict.outputs.reason }} + # No `gh pr review --approve`. This organisation does not permit Actions + # to approve pull requests, so that call fails with + # + # GitHub Actions is not permitted to approve pull requests + # + # and under `bash -e` it took the whole step down before the merge was + # ever queued - which is how auto-merge came to be broken in every + # repository at once. + # + # The approval was never needed: branch protection here requires the CI + # check and no reviews. If a review requirement is ever added, this needs + # a token that is not GITHUB_TOKEN, not a retry. + run: | + echo "auto-merging: $REASON" + gh pr merge --auto --squash "$PR" + + - name: Explain why this one was left alone + if: steps.verdict.outputs.auto != 'true' + env: + REASON: ${{ steps.verdict.outputs.reason }} + run: echo "not auto-merged ($REASON); this pull request needs a human."