From 23e3faeb7720b310026088c9673285533e810a44 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Thu, 10 Sep 2026 18:27:43 +0200 Subject: [PATCH 1/7] contest: pw: config to change PW's check name To prepare a split between HW and the rest. Signed-off-by: Matthieu Baerts --- pw_contest.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pw_contest.py b/pw_contest.py index f118bb15..1f1b2c36 100755 --- a/pw_contest.py +++ b/pw_contest.py @@ -27,6 +27,8 @@ patch_state=state.json [www] contest=https://server-with-ui/contest.html +[patchwork] +check_name=contest """ class Codes: @@ -223,16 +225,16 @@ def skip_update(outcome) -> bool: return False -def update_one(pw, patch_id, outcome, link): +def update_one(pw, patch_id, outcome, link, check_name): description = outcome['branch'] if outcome["code"] >= 0: description += f' (tests: {outcome["cnt"]})' url = link + '?pw-n=0&branch=' + outcome['branch'] - pw.post_check(patch_id, name="contest", state=code_to_pw[outcome["code"]], + pw.post_check(patch_id, name=check_name, state=code_to_pw[outcome["code"]], url=url, desc=description) -def _patch_state_update(pw, state: dict, link: str): +def _patch_state_update(pw, state: dict, link: str, check_name: str): update_cnt = 0 for series_id, outcome in state["series"].items(): if skip_update(outcome): @@ -242,7 +244,7 @@ def _patch_state_update(pw, state: dict, link: str): log_open_sec('Updating series ' + series_id) series_pw = pw.get("series", series_id) for patch in series_pw["patches"]: - update_one(pw, patch["id"], outcome, link) + update_one(pw, patch["id"], outcome, link, check_name) update_cnt += 1 del outcome["update"] @@ -255,7 +257,7 @@ def _patch_state_update(pw, state: dict, link: str): try: log_open_sec('Updating PR ' + pr_id) - update_one(pw, pr_id, outcome, link) + update_one(pw, pr_id, outcome, link, check_name) update_cnt += 1 del outcome["update"] @@ -265,10 +267,10 @@ def _patch_state_update(pw, state: dict, link: str): print("Updated", update_cnt, "pw things") -def patch_state_update(pw, state: dict, link: str): +def patch_state_update(pw, state: dict, link: str, check_name: str): log_open_sec('Updating patch states') try: - _patch_state_update(pw, state, link) + _patch_state_update(pw, state, link, check_name) finally: log_end_sec() @@ -291,7 +293,8 @@ def main_loop(pw) -> int: results_by_branch = results_pivot(filters, results) branch_outcome = branch_summarize(filters, results_by_branch) patch_state_compute(patch_state, branches, branch_outcome) - patch_state_update(pw, patch_state, config.get('www', 'contest')) + patch_state_update(pw, patch_state, config.get('www', 'contest'), + config.get('patchwork', 'check_name', fallback='contest')) rbb = config.get('output', 'results_by_branch', fallback=None) if rbb: From bdee80caf1cce7b679afe5375f5121d4d3ab5f5d Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Thu, 10 Sep 2026 19:03:41 +0200 Subject: [PATCH 2/7] brancher: write info file atomically This file is read by another service (faker), possibly simultaneously. Signed-off-by: Matthieu Baerts --- pw_brancher.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pw_brancher.py b/pw_brancher.py index 7e5c79f3..fbf3c8e0 100755 --- a/pw_brancher.py +++ b/pw_brancher.py @@ -391,10 +391,7 @@ def dump_branches(config, state) -> None: "url": pub_url + " " + name}) write_json_atomic(config.get("output", "branches"), data) - - info = config.get("output", "info") - with open(info, 'w') as fp: - json.dump(state["info"], fp) + write_json_atomic(config.get("output", "info"), state["info"]) log_end_sec() From 4e2d8ac3d7a5c5be46d38f1228ac843c810177e3 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 11 Sep 2026 16:05:00 +0200 Subject: [PATCH 3/7] contest: collector: skip results not linked to a recent branch This limitation was only done for in progress work, but we don't need the old results. Old results are still on the different runners (and in the DB). (Probably the different runners should also trim their 'results.json' file.) Because of that, 'all-results.json' is currently over 410MB, which takes a bit of time to process here and in pw_contest. The other consequence is that some files for the UI contains info about old branches that are not needed, but are still processed on the client side, e.g. branch-results.json. Signed-off-by: Matthieu Baerts --- contest/results-collector.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contest/results-collector.py b/contest/results-collector.py index c1f30ed5..2c6a9ff5 100755 --- a/contest/results-collector.py +++ b/contest/results-collector.py @@ -494,9 +494,10 @@ def build_combined(fetcher, remote_db): report_broken_remote(remote, error) for entry in results: + if entry['branch'] not in branch_info: + continue + if not entry['url']: # Executor is running - if entry['branch'] not in branch_info: - continue data = entry.copy() when = datetime.datetime.fromisoformat(branch_info[entry['branch']]['date']) data["start"] = str(when) From 9acb9d61112f76031bcd59213c7897200ef6e7ab Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 11 Sep 2026 16:55:20 +0200 Subject: [PATCH 4/7] ui: status: open HW branch results Generated in another file by the dedicated pw-contest service. Note: while this additional pw-contest service is not active, a file containing an empty dictionary ({}) has been added, so this modification can already be deployed. Signed-off-by: Matthieu Baerts --- scripts/ui_assets.sh | 1 + ui/status.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/ui_assets.sh b/scripts/ui_assets.sh index 0fc8e449..19f76bfd 100755 --- a/scripts/ui_assets.sh +++ b/scripts/ui_assets.sh @@ -20,6 +20,7 @@ ASSETS=( "status.json" "issues.json" "contest/branch-results.json" + "contest/branch-results-hw.json" "contest/branches-info.json" "contest/filters.json" "contest/all-results.json" diff --git a/ui/status.js b/ui/status.js index f9ae59ad..822d7870 100644 --- a/ui/status.js +++ b/ui/status.js @@ -1036,7 +1036,7 @@ function load_result_table(data_raw, reload) } } -let xfr_todo = 4; +let xfr_todo = 5; let all_results = null; let branches_info = null; let branches = new Set(); @@ -1307,6 +1307,9 @@ function do_it() $(document).ready(function() { $.get("contest/branch-results.json", branch_res_doit) }); + $(document).ready(function() { + $.get("contest/branch-results-hw.json", branch_res_doit) + }); $(document).ready(function() { $.get("query/results?branches=10&pending=y", results_loaded) }); From 00aee14a4634ddc1d493acd506d5aa9af3a8ee41 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 18 Sep 2026 12:42:43 +0200 Subject: [PATCH 5/7] ui: status: extract base-pulls info at loading time So keep only what is needed from the branches info file. This will simplify the next commit. Signed-off-by: Matthieu Baerts --- ui/status.js | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/ui/status.js b/ui/status.js index 822d7870..edf1d8d4 100644 --- a/ui/status.js +++ b/ui/status.js @@ -862,24 +862,8 @@ function runner_name(v) function load_result_table(data_raw, reload) { - var branch_pull_status = {}; var branch_start = {}; - // Parse branch info to extract pull status - $.each(branches_info, function(i, v) { - let summary = null; - $.each(v['base-pulls'], function(url, res) { - if (res == "okay" && !summary) { - summary = res; - } else if (res == "resolved" && (!summary || summary == "okay")) { - summary = res; - } else { - summary = res; - } - }); - branch_pull_status[i] = summary; - }); - // Decorate branchers and collect branch_start $.each(data_raw, function(i, v) { v.start = new Date(v.start); @@ -1038,7 +1022,7 @@ function load_result_table(data_raw, reload) let xfr_todo = 5; let all_results = null; -let branches_info = null; +let branch_pull_status = {}; let branches = new Set(); let branch_results = {}; @@ -1159,7 +1143,21 @@ function filters_doit(data_raw) function branches_loaded(data_raw) { - branches_info = data_raw; + // Parse branch info to extract pull status + $.each(data_raw, function(i, v) { + let summary = null; + $.each(v['base-pulls'], function(url, res) { + if (res == "okay" && !summary) { + summary = res; + } else if (res == "resolved" && (!summary || summary == "okay")) { + summary = res; + } else { + summary = res; + } + }); + branch_pull_status[i] = summary; + }); + loaded_one(); } From 04ec666e0fff8ad7254c0c10f437d23bbf19bcf4 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 18 Sep 2026 12:46:15 +0200 Subject: [PATCH 6/7] ui: status: open individual branches info No need to used the combined JSON info and depends on multiple services (faker, SW and HW brancher), take the files from each service. If one fails, it doesn't impact the others. The branch names are different, so we can do that without issues. Signed-off-by: Matthieu Baerts --- scripts/ui_assets.sh | 3 ++- ui/status.js | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/ui_assets.sh b/scripts/ui_assets.sh index 19f76bfd..ec4ce6e9 100755 --- a/scripts/ui_assets.sh +++ b/scripts/ui_assets.sh @@ -21,7 +21,8 @@ ASSETS=( "issues.json" "contest/branch-results.json" "contest/branch-results-hw.json" - "contest/branches-info.json" + "contest/branches-info-nn.json" + "contest/branches-info-hw.json" "contest/filters.json" "contest/all-results.json" ) diff --git a/ui/status.js b/ui/status.js index edf1d8d4..2135fa5f 100644 --- a/ui/status.js +++ b/ui/status.js @@ -1020,7 +1020,7 @@ function load_result_table(data_raw, reload) } } -let xfr_todo = 5; +let xfr_todo = 6; let all_results = null; let branch_pull_status = {}; let branches = new Set(); @@ -1312,7 +1312,10 @@ function do_it() $.get("query/results?branches=10&pending=y", results_loaded) }); $(document).ready(function() { - $.get("contest/branches-info.json", branches_loaded) + $.get("contest/branches-info-nn.json", branches_loaded) + }); + $(document).ready(function() { + $.get("contest/branches-info-hw.json", branches_loaded) }); $(document).ready(function() { $.get("query/flaky-tests?group-pfx=1", flakes_doit) From 09f7a7e07feb715cadd15642c6710431980b384c Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 18 Sep 2026 16:44:55 +0200 Subject: [PATCH 7/7] ui: results: identify the brancher from the executor name In most place, the JS code looks at the 'executor' name to identify the brancher, but not in a few places where the 'remote' is used. Uniform that. Currently, the brancher has its 'remote' and 'executor' names set to 'brancher'. But it is going to change for the HW one, with a remote set to 'brancher-hw', but the 'executor' will stay set to 'brancher'. Signed-off-by: Matthieu Baerts --- ui/contest.js | 2 +- ui/status.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/contest.js b/ui/contest.js index d0b0297b..03f18ff4 100644 --- a/ui/contest.js +++ b/ui/contest.js @@ -173,7 +173,7 @@ function load_result_table(data_raw) function find_branch_urls(loaded_data) { $.each(loaded_data, function(i, v) { - if (v.remote == "brancher") + if (v.executor == "brancher") branch_urls[v.branch] = v.results[0].link; }); } diff --git a/ui/status.js b/ui/status.js index 2135fa5f..3a297f19 100644 --- a/ui/status.js +++ b/ui/status.js @@ -735,7 +735,7 @@ function load_result_table_one(data_raw, table, reported, avgs) var a = ""; - if (v.remote != "brancher") { + if (v.executor != "brancher") { var time = row.insertCell(2); if (link) @@ -874,7 +874,7 @@ function load_result_table(data_raw, reload) branches.add(v.branch); - if (v.remote == "brancher") { + if (v.executor == "brancher") { branch_start[v.branch] = v.start; v.pull_status = branch_pull_status[v.branch]; }