diff --git a/runbot_merge/models/patcher.py b/runbot_merge/models/patcher.py index ef11588b..2f523a73 100644 --- a/runbot_merge/models/patcher.py +++ b/runbot_merge/models/patcher.py @@ -266,11 +266,19 @@ class Patch(models.Model): patch.target.display_name, patch.repository.name, ) + + info = r.check(True).stdout().with_config(encoding="utf-8") + t = info.show('--no-patch', '--pretty=%T', patch.target.name).stdout.strip() try: if patch.commit: c = patch._apply_commit(r) else: c = patch._apply_patch(r) + if t == info.show('--no-patch', '--pretty=%T', c).stdout.strip(): + raise PatchFailure( + "Patch results in an empty commit when applied, " + "it is likely a duplicate of a merged commit." + ) except Exception as e: if isinstance(e, PatchFailure): subject = "Unable to apply patch" diff --git a/runbot_merge/tests/test_patching.py b/runbot_merge/tests/test_patching.py index 9b57041c..0c03bf27 100644 --- a/runbot_merge/tests/test_patching.py +++ b/runbot_merge/tests/test_patching.py @@ -135,6 +135,26 @@ def test_apply_commit(env, project, repo, users): assert HEAD.author['email'] == "dustsuckinghose@example.org" assert not p.active + # try to apply a dupe version + p = env['runbot_merge.patch'].create({ + 'target': project.branch_ids.id, + 'repository': project.repo_ids.id, + 'commit': c, + }) + + env.run_crons() + + # the patch should have been rejected since it leads to an empty commit + NEW_HEAD = repo.commit('master') + assert NEW_HEAD.id == HEAD.id + assert not p.active + assert p.message_ids.mapped('body')[::-1] == [ + '

Unstaged direct-application patch created

', + "

Patch results in an empty commit when applied, " + "it is likely a duplicate of a merged commit.

", + "", # empty message alongside active tracking value + ] + def test_commit_conflict(env, project, repo, users): with repo: [c] = repo.make_commits("x", Commit("x", tree={"b": "3"}))