Skip to content

Commit 1a76126

Browse files
authored
Merge pull request #130 from seqeralabs/edmundmiller/pass-or-fail-stack
fix(report): show failed and cancelled runs in overview
2 parents 929f688 + d712eeb commit 1a76126

12 files changed

Lines changed: 220 additions & 84 deletions

File tree

.nf-core.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
lint:
2+
base_config: false
3+
files_exist: false
4+
files_unchanged: false
5+
modules_config: false
6+
multiqc_config: false
7+
nextflow_config:
8+
- custom_config
9+
- manifest.homePage
10+
- manifest.name
11+
- process.cpus
12+
- process.memory
13+
- process.time
14+
pipeline_name_conventions: false
15+
schema_lint: false
16+
template_strings:
17+
- bin/benchmark_report_template.html
18+
- assets/AGENTS.md
19+
nf_test_content:
20+
- tests/nextflow.config
21+
nf_core_version: 3.3.1
22+
repository_type: pipeline
23+
template:
24+
author: SciDev Team
25+
description: Pipeline to aggregate pertinent metrics across pipeline runs on the Seqera Platform.
26+
force: false
27+
is_nfcore: false
28+
name: nf-aggregate
29+
org: seqeralabs
30+
outdir: .
31+
skip_features:
32+
- ci
33+
- igenomes
34+
- nf_core_configs
35+
version: 0.7.0

.prettierignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ testing/
77
testing*
88
*.pyc
99
bin/
10-
# Large single-line fixture JSON (Prettier would expand to thousands of lines)
11-
workflows/nf_aggregate/assets/log_dirs/**/*.json
10+
**/AGENTS.md
11+
docs/DESIGN.md
12+
renovate.json
13+
workflows/nf_aggregate/assets/log_dirs/

bin/benchmark_report_aggregate.py

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,24 +78,56 @@ def _is_highlight_process(process: str) -> bool:
7878
return any(keyword in process_lc for keyword in _HIGHLIGHT_KEYWORDS)
7979

8080

81+
def _classify_workflow_status(status: str | None) -> tuple[str, str, bool]:
82+
normalized = (status or "").strip().upper()
83+
if normalized in {"FAILED", "ERROR", "FAILING"}:
84+
return ("Failed", "failed", False)
85+
if normalized in {"CANCELLED", "CANCELED", "ABORTED", "ABORT", "STOPPED"}:
86+
return ("Cancelled", "cancelled", False)
87+
if normalized in {"SUCCEEDED", "SUCCESS", "COMPLETED"}:
88+
return ("Succeeded", "success", True)
89+
if not normalized:
90+
return ("Unknown", "unknown", True)
91+
return (normalized.title(), "other", True)
92+
93+
8194
def build_report_data(jsonl_dir: Path) -> dict[str, Any]:
8295
benchmark_overview: list[dict[str, Any]] = []
8396
run_summary: list[dict[str, Any]] = []
8497
run_metrics: list[dict[str, Any]] = []
8598

8699
run_cost_acc: dict[tuple[str, str], dict[str, Any]] = {}
87100
run_pipeline: dict[str, str] = {}
101+
included_run_ids: set[str] = set()
88102

89103
for r in _iter_jsonl(jsonl_dir / "runs.jsonl"):
90-
benchmark_overview.append({"pipeline": r.get("pipeline"), "group": r.get("group"), "run_id": r.get("run_id")})
91-
run_pipeline[str(r.get("run_id", ""))] = str(r.get("pipeline") or "unknown")
104+
run_id = str(r.get("run_id", ""))
105+
group = str(r.get("group", ""))
106+
run_pipeline[run_id] = str(r.get("pipeline") or "unknown")
107+
status_label, status_category, report_included = _classify_workflow_status(r.get("status"))
108+
109+
benchmark_overview.append(
110+
{
111+
"pipeline": r.get("pipeline"),
112+
"group": group,
113+
"run_id": run_id,
114+
"status": r.get("status"),
115+
"status_label": status_label,
116+
"status_category": status_category,
117+
"report_included": report_included,
118+
}
119+
)
92120

93121
run_summary.append(
94122
{
95123
"pipeline": r.get("pipeline"),
96-
"group": r.get("group"),
97-
"run_id": r.get("run_id"),
124+
"group": group,
125+
"run_id": run_id,
98126
"username": r.get("username"),
127+
"status": r.get("status"),
128+
"status_label": status_label,
129+
"status_category": status_category,
130+
"report_included": report_included,
99131
"Version": r.get("pipeline_version"),
100132
"Nextflow_version": r.get("nextflow_version"),
101133
"platform_version": r.get("platform_version"),
@@ -110,11 +142,16 @@ def build_report_data(jsonl_dir: Path) -> dict[str, Any]:
110142
}
111143
)
112144

145+
if not report_included:
146+
continue
147+
148+
included_run_ids.add(run_id)
149+
113150
run_metrics.append(
114151
{
115152
"pipeline": r.get("pipeline"),
116-
"group": r.get("group"),
117-
"run_id": r.get("run_id"),
153+
"group": group,
154+
"run_id": run_id,
118155
"duration": int(r.get("duration_ms") or 0),
119156
"cpuTime": _round((float(r.get("cpu_time_ms") or 0) / 1000.0) / 3600.0, 1),
120157
"pipeline_runtime": int(r.get("cpu_time_ms") or 0),
@@ -125,7 +162,7 @@ def build_report_data(jsonl_dir: Path) -> dict[str, Any]:
125162
}
126163
)
127164

128-
key = (str(r.get("run_id", "")), str(r.get("group", "")))
165+
key = (run_id, group)
129166
run_cost_acc[key] = {
130167
"run_id": key[0],
131168
"group": key[1],
@@ -181,6 +218,9 @@ def build_report_data(jsonl_dir: Path) -> dict[str, Any]:
181218

182219
for t in _iter_jsonl(jsonl_dir / "tasks.jsonl"):
183220
run_id = str(t.get("run_id", ""))
221+
if run_id not in included_run_ids:
222+
continue
223+
184224
group = str(t.get("group", ""))
185225
process = str(t.get("process", ""))
186226
process_short = str(t.get("process_short", ""))

0 commit comments

Comments
 (0)