[Bug]: Forgejo merges ignore the repository's delete-branch-after-merge setting#14296

opened24d agobyPpat-s

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to investigate the problem.

Area

apps/server

Steps to reproduce

  1. Enable the default deletion of pull request branches after merge in a Forgejo repository's settings.
  2. Merge a pull request through T3 Code's Pull Requests interface.
  3. Check whether the source branch remains in Forgejo.

Expected behavior

T3 Code respects the target repository's default_delete_branch_after_merge setting when merging. When enabled, request branch deletion through Forgejo's merge endpoint; when disabled, retain the branch. Forgejo should enforce its own branch protection and deletion permissions.

Actual behavior

The source branch is retained. Code inspection on upstream 27bdf1aa1 confirms that ForgejoPullRequestProvider.runAction sends only { Do: input.mergeMethod ?? "merge" } to POST /repos/{owner}/{repo}/pulls/{number}/merge. It never supplies delete_branch_after_merge, and the ForgejoRepository decoder does not include default_delete_branch_after_merge.

Suggested fix

Read the target repository's current setting before submitting the merge and include delete_branch_after_merge in the merge request. Keep branches when the optional setting is absent, and do not proceed with a merge if reading the repository settings fails. Cover enabled, disabled, missing, and failed settings reads with focused regression tests.

Verification

Reported behavior verified against the current merge implementation; no live repository was merged or modified during investigation.

Version or commit

Upstream main at 27bdf1aa1.

Triage

Confirmed. This is a bug in T3's Forgejo/Gitea provider, and there is no existing issue for it.

Forgejo does not apply the repository setting inside the merge call. MergePullRequestForm.DeleteBranchAfterMerge is a plain bool, so an omitted delete_branch_after_merge is false, and POST /repos/{owner}/{repo}/pulls/{index}/merge deletes the head branch only when that flag is true. The web UI is what honors the setting: the merge form is initialized from defaultDeleteBranchAfterMerge on the pull-request unit. Gitea’s merge API behaves the same way, and this provider serves both (fj and tea).

ForgejoPullRequestProvider.runAction sends only { Do: input.mergeMethod ?? "merge" } for a merge, and ForgejoRepository never decodes default_delete_branch_after_merge. A merge from T3 therefore always leaves the source branch, even when the repository default is on. GitHub is different: it applies delete_branch_on_merge on the server, so the GitHub provider does not need to send a flag.

Reading the target repository and passing delete_branch_after_merge is the right fix. getRepo already calls GET /repos/{owner}/{repo}; treat a missing field as false. Two constraints for the implementation:

  • If the flag is true and deletion fails, Forgejo still completes the merge and then returns an error (403 when the head branch is protected, is the default branch, or the merger cannot write to the head repo, which includes many forks). write() treats that as a failed action, so the UI can report a failed merge after the pull request has already landed. The web UI only offers the checkbox when the head branch is deletable. Sending the repository default unconditionally will hit that path.
  • Refusing to merge when that settings read fails avoids silently ignoring an enabled setting. That failure should stay distinct from a merge rejection, so a transient GET does not look like the host refused the merge.

Triage on main at b5a226e49c, Linux VM: neither fj nor tea is installed, and the standard Forgejo CLI and tea credential files are absent. The live reproduction is blocked before enabling the repository setting or merging a PR; no repository was merged or modified. Source inspection still shows the merge request containing only Do, but that is not runtime reproduction. No duplicate found in 949 open issues. Verification needs a writable Forgejo test repository and an authenticated environment; please also provide the Forgejo version used for the reported behavior.

Synced from GitHub

Hard-to-read comment.

The bug is reproducible straightforward and shows up on every instance when merging a PR - the branch is left behind even though "delete branch after merge" is ticked in the repo settings.

Reproduced on Linux with current main 3b95e7831b, Forgejo 14.0.5, and tea 0.16.0. In a disposable local repository, I enabled default_delete_branch_after_merge, then merged a PR through T3’s web Pull Requests detail panel. T3 showed “Merged” and Forgejo returned merged: true; the source branch still existed. No additional reporter information is needed.

Fix opened in #23471, labeled bugfix. Verified with the real T3 web client and Forgejo 14.0.5: enabled deletes the source branch; disabled retains it; a protected source branch remains while T3 correctly reports the completed merge. Runtime evidence. The focused 108 tests and changed-file checks pass. The PR is unmerged.