diff --git a/modules/nf-core/multiqc_sav/environment.yml b/modules/nf-core/multiqc_sav/environment.yml new file mode 100644 index 000000000000..050d188b81ec --- /dev/null +++ b/modules/nf-core/multiqc_sav/environment.yml @@ -0,0 +1,8 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::multiqc=1.33 + - bioconda::multiqc_sav=0.2.1 diff --git a/modules/nf-core/multiqc_sav/main.nf b/modules/nf-core/multiqc_sav/main.nf new file mode 100644 index 000000000000..d137ea6d2562 --- /dev/null +++ b/modules/nf-core/multiqc_sav/main.nf @@ -0,0 +1,56 @@ +process MULTIQC_SAV { + 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/34/34e733a9ae16a27e80fe00f863ea1479c96416017f24a907996126283e7ecd4d/data' : + 'community.wave.seqera.io/library/multiqc:1.33--ee7739d47738383b' }" + + input: + tuple val(meta), path(runinfo_xml), path(interop_bin, stageAs: "InterOp/*") + path(extra_multiqc_files, stageAs: "?/*") + path(multiqc_config) + path(extra_multiqc_config) + path(multiqc_logo) + path(replace_names) + path(sample_names) + + output: + path "*.html" , emit: report + path "*_data" , emit: data + path "*_plots" , optional:true, emit: plots + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), val('multiqc_sav'), eval('python -c "import multiqc_sav; print(multiqc_sav.__version__)"'), emit: versions + // MultiQC should not push its versions to the `versions` topic. Its input depends on the versions topic to be resolved thus outputting to the topic will let the pipeline hang forever + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' + def config = multiqc_config ? "--config ${multiqc_config}" : '' + def extra_config = extra_multiqc_config ? "--config ${extra_multiqc_config}" : '' + def logo = multiqc_logo ? "--cl-config 'custom_logo: \"${multiqc_logo}\"'" : '' + def replace = replace_names ? "--replace-names ${replace_names}" : '' + def samples = sample_names ? "--sample-names ${sample_names}" : '' + """ + multiqc \\ + --force \\ + ${args} \\ + ${config} \\ + ${prefix} \\ + ${extra_config} \\ + ${logo} \\ + ${replace} \\ + ${samples} \\ + . + """ + + stub: + """ + mkdir multiqc_data + touch multiqc_data/.stub + mkdir multiqc_plots + touch multiqc_report.html + """ +} diff --git a/modules/nf-core/multiqc_sav/meta.yml b/modules/nf-core/multiqc_sav/meta.yml new file mode 100644 index 000000000000..38ad7034b5f6 --- /dev/null +++ b/modules/nf-core/multiqc_sav/meta.yml @@ -0,0 +1,112 @@ +name: multiqc_sav +description: Aggregate results from bioinformatics analyses across many samples into a single report, with support for multiqc_sav plugin +keywords: + - QC + - bioinformatics tools + - Beautiful stand-alone HTML report + - Illumina + - Sequencing Analysis Viewer + - SAV +tools: + - multiqc: + description: | + MultiQC searches a given directory for analysis logs and compiles a HTML report. + It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. + homepage: https://multiqc.info/ + documentation: https://multiqc.info/docs/ + licence: ["GPL-3.0-or-later"] + identifier: biotools:multiqc +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - runinfo_xml: + type: file + description: Illumina RunInfo.xml file + pattern: "RunInfo.xml" + ontologies: [http://edamontology.org/format_2332] # XML format + - interop_bin: + type: file + description: Illumina InterOp binary files + pattern: "InterOp/*.bin" + ontologies: [http://edamontology.org/format_2333] # Binary format + - extra_multiqc_files: + type: file + description: | + List of reports / files rec ognised by MultiQC, for example the html and zip output of FastQC + ontologies: [] + - multiqc_config: + type: file + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML + - extra_multiqc_config: + type: file + description: Second optional config yml for MultiQC. Will override common sections + in multiqc_config. + pattern: "*.{yml,yaml}" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML + - multiqc_logo: + type: file + description: Optional logo file for MultiQC + pattern: "*.{png}" + ontologies: [] + - replace_names: + type: file + description: | + Optional two-column sample renaming file. First column a set of + patterns, second column a set of corresponding replacements. Passed via + MultiQC's `--replace-names` option. + pattern: "*.{tsv}" + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + - sample_names: + type: file + description: | + Optional TSV file with headers, passed to the MultiQC --sample_names + argument. + pattern: "*.{tsv}" + ontologies: + - edam: http://edamontology.org/format_3475 # TSV +output: + report: + - "*.html": + type: file + description: MultiQC report file + pattern: ".html" + ontologies: [] + data: + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + plots: + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_data" + ontologies: [] + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - multiqc: + type: string + description: The tool name + - multiqc --version | sed "s/.* //g": + type: eval + description: The expression to obtain the version of the tool + - multiqc_sav: + type: string + description: The tool name + - python -c "import multiqc_sav; print(multiqc_sav.__version__)": + type: eval + description: The expression to obtain the version of the tool +authors: + - "@matthdsm" +maintainers: + - "@matthdsm" diff --git a/modules/nf-core/multiqc_sav/tests/main.nf.test b/modules/nf-core/multiqc_sav/tests/main.nf.test new file mode 100644 index 000000000000..8e10346c6218 --- /dev/null +++ b/modules/nf-core/multiqc_sav/tests/main.nf.test @@ -0,0 +1,65 @@ +nextflow_process { + + name "Test Process MULTIQC_SAV" + script "../main.nf" + process "MULTIQC_SAV" + + tag "modules" + tag "modules_nfcore" + tag "multiqc_sav" + + config "./nextflow.config" + + test("NovaSeq6000") { + setup { + run("UNTAR") { + script "../../untar/main.nf" + process { + """ + input[0] = [[ id: 'NovaSeq6000' ],file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bcl/200624_A00834_0183_BHMTFYDRXX.tar.gz', checkIfExists: true)] + """ + } + } + } + + when { + process { + """ + ch_sav_in = UNTAR.out.untar.map{ meta, untar -> + def xml = untar.eachFileRecurse { file -> + if (file.name == 'RunInfo.xml') { + return file + } + }.findAll{ it != null }[0] + + def interop = [] + untar.eachFileRecurse { file -> + if (file.parentFile.name == 'InterOp') { + interop << file + } + } + return [meta, xml, interop] + } + + input[0] = ch_sav_in + input[1] = [] + input[2] = [] + input[3] = [] + input[4] = [] + input[5] = [] + input[6] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions")}).match() } + ) + } + + } +} diff --git a/modules/nf-core/multiqc_sav/tests/main.nf.test.snap b/modules/nf-core/multiqc_sav/tests/main.nf.test.snap new file mode 100644 index 000000000000..d72d35b74737 --- /dev/null +++ b/modules/nf-core/multiqc_sav/tests/main.nf.test.snap @@ -0,0 +1,61 @@ +{ + "sarscov2 single-end [fastqc]": { + "content": [ + { + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-09T10:10:43.020315838" + }, + "sarscov2 single-end [fastqc] - stub": { + "content": [ + [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + { + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-09T10:11:14.131950776" + }, + "sarscov2 single-end [fastqc] [config]": { + "content": [ + { + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-09T10:11:07.15692209" + } +} \ No newline at end of file diff --git a/modules/nf-core/multiqc_sav/tests/nextflow.config b/modules/nf-core/multiqc_sav/tests/nextflow.config new file mode 100644 index 000000000000..04a9c9159bf1 --- /dev/null +++ b/modules/nf-core/multiqc_sav/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'MULTIQC_SAV' { + ext.prefix = null + } +}