Repository navigation
Explain ruleset and branch protection push rejections - #73
Draft
aiolibsbot wants to merge 3 commits into
Draft
aiolibsbot wants to merge 3 commits into
aiolibsbot wants to merge 3 commits into
Conversation
The bot spawned every git invocation through `check_call()`, which lets the child inherit the parent's stdout and stderr. Nothing was captured, so `CalledProcessError.stdout` was always `None` and the push-failure report rendered an empty `[OUTPUT]` block — the one place the template promised details. A cherry-pick conflict was even thinner: a bare `Failed to cleanly apply ... on top of ...`, with the conflicting paths and hunks only discoverable by replaying the backport by hand. Capture the output instead — stderr merged into stdout, decoded leniently because git happily emits non-UTF-8 — and carry it into every exception the backport raises: the fetch and checkout lookups, the conflict, and the push. The conflict additionally reports `git diff --diff-filter=U` in a collapsed section, which is where the actual collision lives. Everything is clipped to stay inside GitHub's 65535-character cap on check-run output and comment bodies, and passed through the token mask first. The plumbing moves to `patchback.backport`, which imports nothing but the stdlib. That keeps it reachable without a web framework in the way, and drops `event_handlers` from 505 to 351 lines. Refs sanitizers#18, sanitizers#54
The repo had no tests and no CI job running them, for a bot whose core operation force-pushes branches into other people's repositories. Cover `patchback.backport` against real local repositories — a bare remote, a clean target branch and a diverging one — so the cherry-pick, the merge-commit mainline handling and each failure report are exercised for real rather than mocked. No network and no third-party imports beyond pytest are involved, which is what makes the split in the previous commit worth having. Test dependencies are installed unpinned in CI on purpose: the suite needs only pytest, and threading it through the hash-pinned pip-tools lock buys nothing until it grows real dependencies.
A push that GitHub turns down was always reported as a missing GitHub App Installation permission. Rulesets and classic branch protection reject pushes the installation is otherwise entitled to make, and each needs the maintainer to act somewhere else entirely -- the app settings advice sends them looking in the wrong place. Classify the rejection from what the remote sent back and render the matching remediation: adding Patchback to the ruleset bypass list, or moving the backport branches out of the branch protection pattern. Refs sanitizers#48
This was referenced Sep 16, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on #72 — branched off
koan/expose-cherry-pick-conflicts, whichintroduces
patchback/backport.pyand the test suite this builds on. Reviewthat one first; the diff here is the last two commits only.
What: Diagnose why GitHub rejected the backport branch push instead of
always blaming the App Installation permissions.
Why: Rulesets and classic branch protection turn down pushes the
installation is perfectly entitled to make. The current message sends the
maintainer to the App settings page, where there is nothing to fix — see the
ansible-builder case in #48.
How:
explain_push_rejection()matches the remote's side-band output(
GH013/GH006/ the workflows refusal) and renders the matchingremediation — add Patchback to the ruleset Bypass list, or stop the branch
protection pattern from matching
patchback/*. Classic branch protection hasno App bypass list at all, so that hint says so rather than pretending. The
existing permissions text stays as the fallback. Pure function, no new deps.
Testing:
python -m pytest— 21 passed. Six new tests: one per rejectionclass, plus an end-to-end one that installs a rejecting
pre-receivehook onthe fixture remote and asserts the advice reaches the raised
PermissionError.Refs #48
Quality Report
Changes: 5 files changed, 648 insertions(+), 154 deletions(-)
Code scan: 1 issue(s) found
patchback/backport.py:23— TODO commentTests: failed (command not found)
Branch hygiene: clean
Generated by Kōan