From 962916e8891332154d1917ee502eca3390aecd42 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Thu, 23 Jul 2026 12:26:57 +0200 Subject: [PATCH 1/2] pw-brancher: set contest failure in case of conflicts When a pull request or a series cannot be applied for some reasons -- e.g. in case of conflicts with pending patches, or with patches applied in net, but not in net-next yet -- the errors were ignored. Because of that, it was easy to miss that a series has not been fully validated as expected, e.g. [1]. When such errors happen, a PatchWork 'contest' check is now created for each patch, with the 'fail' state and a short description. No URL is added, because such logs are currently not publicly available. Link: https://patchwork.kernel.org/project/netdevbpf/patch/20260710134242.216538-10-alice.kernel@fastmail.im/ [1] Signed-off-by: Matthieu Baerts --- pw_brancher.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pw_brancher.py b/pw_brancher.py index 0ac022f7..52114db5 100755 --- a/pw_brancher.py +++ b/pw_brancher.py @@ -119,7 +119,12 @@ def pwe_get_pending(pw, config) -> List: return things -def apply_pending_patches(pw, config, tree) -> Tuple[List, List]: +def pwe_set_apply_error(pw, patch_id, branch_name): + pw.post_check(patch_id, name="contest", state="fail", url="", + desc=f"Conflicts with pending/net patches ({branch_name})") + + +def apply_pending_patches(pw, config, tree, branch_name) -> Tuple[List, List]: log_open_sec("Get pending submissions from patchwork") things = pwe_get_pending(pw, config) log(f"Have {len(things)} pending things from patchwork") @@ -140,7 +145,7 @@ def apply_pending_patches(pw, config, tree) -> Tuple[List, List]: tree.pull(entry["pull_url"], reset=False) applied_prs.add(entry["id"]) except PullError: - pass + pwe_set_apply_error(pw, entry["id"], branch_name) else: log_open_sec("Applying: " + entry["series"][0]["name"]) seen_series.add(series_id) @@ -151,7 +156,9 @@ def apply_pending_patches(pw, config, tree) -> Tuple[List, List]: tree.apply(p) applied_series.add(series_id) except PatchApplyError: - pass + series_pw = pw.get("series", series_id) + for patch in series_pw["patches"]: + pwe_set_apply_error(pw, patch["id"], branch_name) log_end_sec() log_end_sec() @@ -280,7 +287,7 @@ def create_new(pw, config, state, tree, tgt_remote) -> None: state["hashes"][branch_name] = tree.head_hash() - series, prs = apply_pending_patches(pw, config, tree) + series, prs = apply_pending_patches(pw, config, tree, branch_name) state["info"][branch_name] |= {"series": series, "prs": prs} extras = apply_local_patches(config, tree) From 2712d28fab7d06665b4c7632fb62852154a61d19 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Thu, 23 Jul 2026 12:52:20 +0200 Subject: [PATCH 2/2] pw-brancher: add error in contest failure It will not be nicely formatted on PW, but it should help to understand with what it was conflicting. Signed-off-by: Matthieu Baerts --- core/tree.py | 11 ++++++----- pw_brancher.py | 12 ++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/core/tree.py b/core/tree.py index 5844b270..481e3b90 100644 --- a/core/tree.py +++ b/core/tree.py @@ -15,13 +15,14 @@ from core import Patch -# TODO: add patch and CmdError as init here class PatchApplyError(Exception): - pass + def __init__(self, err): + super().__init__(err) class PullError(Exception): - pass + def __init__(self, err): + super().__init__(err) class TreeNotClean(Exception): @@ -237,7 +238,7 @@ def _apply_patch_safe(self, patch): self.git(["am", "--abort"]) except CMD.CmdError: pass - raise PatchApplyError(e) from e + raise PatchApplyError(e.stderr) from e def apply(self, thing): if isinstance(thing, Patch): @@ -278,7 +279,7 @@ def _pull_safe(self, pull_url, trust_rerere, ff): self.git(["merge", "--abort"]) except CMD.CmdError: pass - raise PullError(e) from e + raise PullError(e.stderr) from e def pull(self, pull_url, reset=True, trust_rerere=None, ff=None): core.log_open_sec("Pulling " + pull_url) diff --git a/pw_brancher.py b/pw_brancher.py index 52114db5..40250751 100755 --- a/pw_brancher.py +++ b/pw_brancher.py @@ -119,9 +119,9 @@ def pwe_get_pending(pw, config) -> List: return things -def pwe_set_apply_error(pw, patch_id, branch_name): +def pwe_set_apply_error(pw, patch_id, branch_name, e): pw.post_check(patch_id, name="contest", state="fail", url="", - desc=f"Conflicts with pending/net patches ({branch_name})") + desc=f"Conflicts with pending/net patches ({branch_name}): {e}") def apply_pending_patches(pw, config, tree, branch_name) -> Tuple[List, List]: @@ -144,8 +144,8 @@ def apply_pending_patches(pw, config, tree, branch_name) -> Tuple[List, List]: try: tree.pull(entry["pull_url"], reset=False) applied_prs.add(entry["id"]) - except PullError: - pwe_set_apply_error(pw, entry["id"], branch_name) + except PullError as e: + pwe_set_apply_error(pw, entry["id"], branch_name, e) else: log_open_sec("Applying: " + entry["series"][0]["name"]) seen_series.add(series_id) @@ -155,10 +155,10 @@ def apply_pending_patches(pw, config, tree, branch_name) -> Tuple[List, List]: try: tree.apply(p) applied_series.add(series_id) - except PatchApplyError: + except PatchApplyError as e: series_pw = pw.get("series", series_id) for patch in series_pw["patches"]: - pwe_set_apply_error(pw, patch["id"], branch_name) + pwe_set_apply_error(pw, patch["id"], branch_name, e) log_end_sec() log_end_sec()