diff --git a/modules/nf-core/bcl2fastq/main.nf b/modules/nf-core/bcl2fastq/main.nf index f3b0111374f1..a1f568a09f89 100644 --- a/modules/nf-core/bcl2fastq/main.nf +++ b/modules/nf-core/bcl2fastq/main.nf @@ -75,6 +75,8 @@ process BCL2FASTQ { mkdir -p InterOp echo "fake interop file" > InterOp/IndexMetricsOut.bin + mkdir -p flowcell + echo "fake runinfo file" > flowcell/RunInfo.xml mkdir -p output/Reports echo "fake report" > output/Reports/index.html mkdir -p output/Stats diff --git a/modules/nf-core/bcl2fastq/tests/main.nf.test.snap b/modules/nf-core/bcl2fastq/tests/main.nf.test.snap index 544f9ab2977c..6c683bba96cd 100644 --- a/modules/nf-core/bcl2fastq/tests/main.nf.test.snap +++ b/modules/nf-core/bcl2fastq/tests/main.nf.test.snap @@ -63,7 +63,10 @@ "id": "test", "lane": 1 }, - "RunInfo.xml:md5,38623309618e3aee6b10365b49348b87" + [ + "RunInfo.xml:md5,ec995517c9f57a734c620b701522147f", + "RunInfo.xml:md5,38623309618e3aee6b10365b49348b87" + ] ] ], "8": [ @@ -141,16 +144,19 @@ "id": "test", "lane": 1 }, - "RunInfo.xml:md5,38623309618e3aee6b10365b49348b87" + [ + "RunInfo.xml:md5,ec995517c9f57a734c620b701522147f", + "RunInfo.xml:md5,38623309618e3aee6b10365b49348b87" + ] ] ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.4" + "nextflow": "25.10.3" }, - "timestamp": "2026-02-26T21:17:54.287768" + "timestamp": "2026-02-27T22:07:52.116693092" }, "homo sapiens illumina [bcl]": { "content": [ @@ -403,8 +409,8 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.4" + "nextflow": "25.10.3" }, - "timestamp": "2026-02-26T21:14:22.182282" + "timestamp": "2026-02-27T22:07:40.249895733" } } \ No newline at end of file diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index b62b8394d05b..387f37a25ac2 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -15,6 +15,7 @@ process BCLCONVERT { tuple val(meta), path("output/Reports/*.{csv,xml,bin}"), emit: reports tuple val(meta), path("output/Logs/*.{log,txt}"), emit: logs tuple val(meta), path("output/InterOp/*.bin"), emit: interop, optional: true + tuple val(meta), path("output/Reports/RunInfo.xml"), emit: runinfo tuple val("${task.process}"), val('bclconvert'), eval("bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //'"), topic: versions, emit: versions_bclconvert when: diff --git a/modules/nf-core/bclconvert/meta.yml b/modules/nf-core/bclconvert/meta.yml index a483715aca02..0abbb5cda4e3 100644 --- a/modules/nf-core/bclconvert/meta.yml +++ b/modules/nf-core/bclconvert/meta.yml @@ -103,6 +103,16 @@ output: pattern: "InterOp/*.bin" ontologies: - edam: http://edamontology.org/format_2333 #BINARY + runinfo: + - - meta: + type: map + description: Groovy Map containing sample information + - output/Reports/RunInfo.xml: + type: file + description: RunInfo.xml file + pattern: "*.{xml}" + ontologies: + - edam: "http://edamontology.org/format_2332" # XML versions_bclconvert: - - ${task.process}: type: string diff --git a/modules/nf-core/bclconvert/tests/main.nf.test.snap b/modules/nf-core/bclconvert/tests/main.nf.test.snap index 43233d590091..628d53244711 100644 --- a/modules/nf-core/bclconvert/tests/main.nf.test.snap +++ b/modules/nf-core/bclconvert/tests/main.nf.test.snap @@ -160,6 +160,15 @@ ] ], "7": [ + [ + { + "id": "test", + "lane": 1 + }, + "RunInfo.xml:md5,f6efb28f2f9dcd1d0cb85b78f33aa656" + ] + ], + "8": [ [ "BCLCONVERT", "bclconvert", @@ -231,6 +240,15 @@ ] ] ], + "runinfo": [ + [ + { + "id": "test", + "lane": 1 + }, + "RunInfo.xml:md5,f6efb28f2f9dcd1d0cb85b78f33aa656" + ] + ], "undetermined": [ [ { @@ -254,9 +272,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.4" + "nextflow": "25.10.3" }, - "timestamp": "2026-02-17T14:13:11.717962" + "timestamp": "2026-02-19T16:46:51.349435535" }, "homo_sapiens illumina [bcl]": { "content": [ diff --git a/modules/nf-core/multiqcsav/environment.yml b/modules/nf-core/multiqcsav/environment.yml index 092076ffaf95..996cc38f66dc 100644 --- a/modules/nf-core/multiqcsav/environment.yml +++ b/modules/nf-core/multiqcsav/environment.yml @@ -10,4 +10,4 @@ dependencies: - bioconda::multiqc_sav=0.2.0 - pip=25.3 - pip: - - interop==1.9.0 + - interop==1.9.0 \ No newline at end of file diff --git a/modules/nf-core/multiqcsav/main.nf b/modules/nf-core/multiqcsav/main.nf index 833ad6dffee6..e078fa85be2e 100644 --- a/modules/nf-core/multiqcsav/main.nf +++ b/modules/nf-core/multiqcsav/main.nf @@ -3,9 +3,9 @@ process MULTIQCSAV { label 'process_single' conda "${moduleDir}/environment.yml" - container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container - ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/36/3634362a0bf5a0530a6459bdba392622262d6de6cc0062e9a293bacc3098b323/data' - : 'community.wave.seqera.io/library/multiqc_multiqc_sav_pip_interop:b142653b3920c82b'}" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/36/3634362a0bf5a0530a6459bdba392622262d6de6cc0062e9a293bacc3098b323/data' : + 'community.wave.seqera.io/library/multiqc_multiqc_sav_pip_interop:b142653b3920c82b' }" input: tuple val(meta), path(xml), path(interop_bin, stageAs: "InterOp/*"), path(extra_multiqc_files, stageAs: "?/*"), path(multiqc_config, stageAs: "?/*"), path(multiqc_logo), path(replace_names), path(sample_names) @@ -50,4 +50,4 @@ process MULTIQCSAV { touch multiqc_plots/.stub touch multiqc_report.html """ -} +} \ No newline at end of file diff --git a/modules/nf-core/multiqcsav/meta.yml b/modules/nf-core/multiqcsav/meta.yml index 86545841d188..773ab42e7b0a 100644 --- a/modules/nf-core/multiqcsav/meta.yml +++ b/modules/nf-core/multiqcsav/meta.yml @@ -136,4 +136,4 @@ authors: - "@matthdsm" - "@delfiterradas" maintainers: - - "@matthdsm" + - "@matthdsm" \ No newline at end of file diff --git a/modules/nf-core/multiqcsav/tests/main.nf.test.snap b/modules/nf-core/multiqcsav/tests/main.nf.test.snap index 3f3783a13217..bb32739a4eee 100644 --- a/modules/nf-core/multiqcsav/tests/main.nf.test.snap +++ b/modules/nf-core/multiqcsav/tests/main.nf.test.snap @@ -28,10 +28,10 @@ } ], "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2026-02-26T15:17:26.065765698" + "timestamp": "2026-03-02T19:39:58.798414069" }, "NovaSeq6000 - stub": { "content": [ @@ -88,9 +88,9 @@ } ], "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2026-02-26T15:18:42.648653899" + "timestamp": "2026-03-02T19:40:11.70643624" } } \ No newline at end of file diff --git a/subworkflows/nf-core/bcl_demultiplex/main.nf b/subworkflows/nf-core/bcl_demultiplex/main.nf index b283c84bba87..fd65be8bd1b6 100644 --- a/subworkflows/nf-core/bcl_demultiplex/main.nf +++ b/subworkflows/nf-core/bcl_demultiplex/main.nf @@ -4,8 +4,9 @@ // Demultiplex Illumina BCL data using bcl-convert or bcl2fastq // -include { BCLCONVERT } from "../../../modules/nf-core/bclconvert/main" -include { BCL2FASTQ } from "../../../modules/nf-core/bcl2fastq/main" +include { BCLCONVERT } from "../../../modules/nf-core/bclconvert/main" +include { BCL2FASTQ } from "../../../modules/nf-core/bcl2fastq/main" +include { MULTIQCSAV } from "../../../modules/nf-core/multiqcsav/main" workflow BCL_DEMULTIPLEX { take: @@ -18,6 +19,10 @@ workflow BCL_DEMULTIPLEX { ch_stats = channel.empty() ch_interop = channel.empty() ch_logs = channel.empty() + ch_runinfo = channel.empty() + ch_multiqc_report = channel.empty() + ch_multiqc_data = channel.empty() + ch_multiqc_plots = channel.empty() // Split flowcells into separate channels containing run as tar and run as path // https://nextflow.slack.com/archives/C02T98A23U7/p1650963988498929 @@ -49,12 +54,18 @@ workflow BCL_DEMULTIPLEX { ch_interop = ch_interop.mix(BCLCONVERT.out.interop) ch_reports = ch_reports.mix(BCLCONVERT.out.reports) ch_logs = ch_logs.mix(BCLCONVERT.out.logs) + ch_runinfo = ch_runinfo.mix(BCLCONVERT.out.runinfo) ch_fastq_with_meta = ch_fastq_with_meta.mix( generateReadgroupBCLCONVERT( - BCLCONVERT.out.reports.map { meta, reports -> - return [meta, reports.find { report -> report.name == "fastq_list.csv" }] + BCLCONVERT.out.reports + .map { meta, reports_dir -> + def csvFile = reports_dir.find { report -> report.name == "fastq_list.csv"} ?: + reports_dir.eachFileRecurse { report_file -> + report_file.name == "fastq_list.csv" + } + return [meta, csvFile] }, - BCLCONVERT.out.fastq, + BCLCONVERT.out.fastq ) ) } @@ -66,7 +77,7 @@ workflow BCL_DEMULTIPLEX { ch_interop = ch_interop.mix(BCL2FASTQ.out.interop) ch_reports = ch_reports.mix(BCL2FASTQ.out.reports) ch_stats = ch_stats.mix(BCL2FASTQ.out.stats) - + ch_runinfo = ch_runinfo.mix(BCL2FASTQ.out.xml) ch_fastq_with_meta = ch_fastq_with_meta.mix( generateReadgroupBCL2FASTQ( BCL2FASTQ.out.fastq @@ -82,13 +93,29 @@ workflow BCL_DEMULTIPLEX { return [meta, fastq] } + // MODULE: multiqcsav + // Generate MultiQC report for demultiplexing step + ch_sav_input = ch_runinfo.join(ch_interop) + ch_mqc_input = ch_reports.mix(ch_stats).map { meta, files -> [meta, files.flatten()] } + ch_multiqcsav_input = ch_sav_input.join(ch_mqc_input).map{ meta, xml, bin, files -> [meta, xml, bin, files, [], [], [], []]} + MULTIQCSAV( + ch_multiqcsav_input + ) + + ch_multiqc_report = MULTIQCSAV.out.report + ch_multiqc_data = MULTIQCSAV.out.data + ch_multiqc_plots = MULTIQCSAV.out.plots + emit: - fastq = ch_fastq.fastq - empty_fastq = ch_fastq.empty - reports = ch_reports - stats = ch_stats - interop = ch_interop - logs = ch_logs + fastq = ch_fastq.fastq + empty_fastq = ch_fastq.empty + reports = ch_reports + stats = ch_stats + interop = ch_interop + logs = ch_logs + multiqc_report = ch_multiqc_report + multiqc_data = ch_multiqc_data + multiqc_plots = ch_multiqc_plots } def generateReadgroupBCLCONVERT(ch_fastq_list_csv, ch_fastq) { diff --git a/subworkflows/nf-core/bcl_demultiplex/meta.yml b/subworkflows/nf-core/bcl_demultiplex/meta.yml index 856f52048cb1..23ef6e9b496a 100644 --- a/subworkflows/nf-core/bcl_demultiplex/meta.yml +++ b/subworkflows/nf-core/bcl_demultiplex/meta.yml @@ -7,9 +7,11 @@ keywords: - bcl2fastq - demultiplex - fastq + - multiqcsav components: - bcl2fastq - bclconvert + - multiqcsav input: - meta: type: map @@ -52,6 +54,18 @@ output: type: file description: Demultiplexing logs (bclconvert only) pattern: "Logs/*" + - multiqc_report: + type: file + description: Multiqc report + pattern: "*.html" + - multiqc_data: + type: file + description: Multiqc data + pattern: "*_data" + - multiqc_plots: + type: file + description: Multiqc plots + pattern: "*_plots" - versions: type: file description: File containing software versions diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test index 1a1f0c1e39ac..86eab00950cf 100644 --- a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test +++ b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test @@ -11,6 +11,7 @@ nextflow_workflow { tag "subworkflows/bcl_demultiplex" tag "bclconvert" tag "bcl2fastq" + tag "multiqcsav" test("bclconvert") { @@ -32,7 +33,7 @@ nextflow_workflow { assertAll( { assert workflow.success }, { assert snapshot( - sanitizeOutput(workflow.out, unstableKeys: ["empty_fastq", "logs"]).collectEntries { key, val -> + sanitizeOutput(workflow.out, unstableKeys: ["empty_fastq", "logs", "multiqc_data", "multiqc_report"]).collectEntries { key, val -> if (key == "interop") { return [ key, val.collect { meta, files -> [ @@ -75,7 +76,7 @@ nextflow_workflow { assertAll( { assert workflow.success }, { assert snapshot( - sanitizeOutput(workflow.out).collectEntries { key, val -> + sanitizeOutput(workflow.out, unstableKeys: ["empty_fastq", "logs", "multiqc_data", "multiqc_report"]).collectEntries { key, val -> if (key == "fastq") if (key == "interop") { return [ key, val.collect { meta, files -> diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap index f6fafbcc9adc..fb5595d8e435 100644 --- a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap +++ b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap @@ -131,6 +131,27 @@ ] ] ], + "multiqc_data": [ + [ + { + "id": "HMTFYDRXX", + "lane": 1 + }, + "multiqc_data" + ] + ], + "multiqc_plots": [ + + ], + "multiqc_report": [ + [ + { + "id": "HMTFYDRXX", + "lane": 1 + }, + "multiqc_report.html" + ] + ], "reports": [ [ { @@ -161,9 +182,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.4" + "nextflow": "25.10.3" }, - "timestamp": "2026-02-25T11:36:55.329912" + "timestamp": "2026-03-02T21:19:08.54858259" }, "bcl2fastq": { "content": [ @@ -211,6 +232,15 @@ ], "logs": [ + ], + "multiqc_data": [ + + ], + "multiqc_plots": [ + + ], + "multiqc_report": [ + ], "reports": [ [ @@ -281,8 +311,8 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.4" + "nextflow": "25.10.3" }, - "timestamp": "2026-02-17T15:52:15.463745" + "timestamp": "2026-03-02T21:19:26.647089844" } } \ No newline at end of file