diff --git a/modules/nf-core/samtools/multicommand/environment.yml b/modules/nf-core/samtools/multicommand/environment.yml new file mode 100644 index 000000000000..dc6ea0f7e982 --- /dev/null +++ b/modules/nf-core/samtools/multicommand/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - "bioconda::samtools=1.23.1" diff --git a/modules/nf-core/samtools/multicommand/main.nf b/modules/nf-core/samtools/multicommand/main.nf new file mode 100644 index 000000000000..b80ccafbbe51 --- /dev/null +++ b/modules/nf-core/samtools/multicommand/main.nf @@ -0,0 +1,185 @@ +process SAMTOOLS_MULTICOMMAND { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/8c/8c5d2818c8b9f58e1fba77ce219fdaf32087ae53e857c4a496402978af26e78c/data' + : 'community.wave.seqera.io/library/htslib_samtools:1.23.1--5b6bb4ede7e612e5'}" + + input: + tuple val(meta), path(input), path(index) + tuple val(meta2), path(fasta), path(fai) + val(pipeline) + + output: + // Alignment format outputs (view, sort, markdup, merge, cat, collate) + tuple val(meta), path("*.bam"), optional: true, emit: bam + tuple val(meta), path("*.cram"), optional: true, emit: cram + tuple val(meta), path("*.sam"), optional: true, emit: sam + tuple val(meta), path("*.{bai,csi,crai}"), optional: true, emit: index + + // Sequence outputs (fasta, fastq) + tuple val(meta), path("*.fasta.gz") , emit: fasta , optional: true + tuple val(meta), path("*.fastq.gz") , emit: fastq , optional: true + tuple val(meta), path("*_{1,2}.fasta.gz") , emit: fasta_pair , optional: true + tuple val(meta), path("*_interleaved.fasta.gz"), emit: fasta_interleaved, optional: true + tuple val(meta), path("*_singleton.fasta.gz") , emit: fasta_singleton , optional: true + tuple val(meta), path("*_other.fasta.gz") , emit: fasta_other , optional: true + tuple val(meta), path("*_{1,2}.fastq.gz") , emit: fastq_pair , optional: true + tuple val(meta), path("*_interleaved.fastq") , emit: fastq_interleaved, optional: true + tuple val(meta), path("*_singleton.fastq.gz") , emit: fastq_singleton , optional: true + tuple val(meta), path("*_other.fastq.gz") , emit: fastq_other , optional: true + + tuple val("${task.process}"), val('samtools'), eval('samtools version | sed "1!d;s/.* //"'), emit: versions_samtools, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + if (pipeline.size() <=1) { + error("Error: SAMTOOLS_MULTICOMMAND requires at least two commands!") + } + + def valid_options = ['view', 'sort', 'markdup', 'fixmate', 'merge', 'cat', 'collate', 'fastq', 'fasta'] + pipeline.collect { tool -> + if (!(tool in valid_options)) { + error("Error: ${tool} not a valid pipeline argument for SAMTOOLS_MULTICOMMAND! Valid options are: ${valid_options.join(", ")}") + } + } + + def n_commands = pipeline.size() + def final_command = pipeline[n_commands - 1] + + // Build output string based on final command + def output_string = "" + def input_reference = (fasta && input.getExtension() == "cram") ? "--reference ${fasta}" : "" + def output_reference = "" + + if (final_command in ['view', 'sort', 'merge', 'cat', 'markdup', 'fixmate', 'merge', 'cat', 'collate']) { + // These produce alignment files + def argsKey = n_commands == 1 ? "args" : "args${n_commands}" + def argsLast = task.ext[argsKey] ?: "" + def extension = argsLast.contains("--output-fmt sam") + ? "sam" + : argsLast.contains("--output-fmt cram") + ? "cram" + : "bam" + output_reference = (fasta && input.getExtension() == "cram") ? "--reference ${fasta}" : "" + output_string = "-o ${prefix}.${extension}" + } else if (final_command == "fasta") { + // fasta produces multiple files with special output flags + output_string = "-0 ${prefix}_other.fasta.gz" + if (!meta.single_end) { + output_string = output_string + " -1 ${prefix}_1.fasta.gz -2 ${prefix}_2.fasta.gz -s ${prefix}_singleton.fasta.gz" + } else { + output_string = output_string + " -1 ${prefix}_1.fasta.gz -s ${prefix}_singleton.fasta.gz" + } + } else if (final_command == "fastq") { + // fastq produces multiple files with special output flags + output_string = "-0 ${prefix}_other.fastq.gz" + if (!meta.single_end) { + output_string = output_string + " -1 ${prefix}_1.fastq.gz -2 ${prefix}_2.fastq.gz -s ${prefix}_singleton.fastq.gz" + } else { + output_string = output_string + " -1 ${prefix}_1.fastq.gz -s ${prefix}_singleton.fastq.gz" + } + } + + // Build the pipeline command + def pipeline_command = pipeline.withIndex().collect { subcommand, idx -> + def argsKey = idx == 0 ? "args" : "args${idx + 1}" + def taskArgs = task.ext[argsKey] ?: "" + def lastCommand = (idx == n_commands - 1) + + def cmd_parts = ["samtools", subcommand] + if(subcommand != "cat") { cmd_parts << "-@ ${task.cpus}" } + if (taskArgs) { + cmd_parts << taskArgs + } + if (idx == 0) { + if (input_reference) { + cmd_parts << input_reference + } + cmd_parts << (input instanceof List ? input.join(" ") : input) + } + if (!lastCommand) { + if (subcommand != "cat") { cmd_parts << "-u" } + } else { + if (output_reference) { + cmd_parts << output_reference + } + cmd_parts << output_string + } + + return cmd_parts.join(" ") + }.join(" |\\\n") + + // EXAMPLE: + // + // This module will construct a samtools pipeline command from an input list of + // subtools, such as [view, sort, markdup]: + // + // samtools view ${args} input.bam |\ + // samtools sort ${args2} |\ + // samtools markdup ${args3} -o output.bam + // + // The args are numbered sequenctially for each tool in the sequence and CRAM references + // are automatically applied if needed. FASTA and FASTQ outputs are also available. + """ + ${pipeline_command} + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + def valid_options = ['view', 'sort', 'markdup', 'fixmate', 'merge', 'cat', 'collate', 'fastq', 'fasta'] + pipeline.collect { tool -> + if (!(tool in valid_options)) { + error("Error: ${tool} not a valid pipeline argument for SAMTOOLS_PIPELINE! Valid options are: ${valid_options.join(", ")}") + } + } + + def n_commands = pipeline.size() + def final_command = pipeline[n_commands - 1] + + def stub_outputs = [] + + if (final_command in ['view', 'sort', 'merge', 'cat', 'markdup', 'fixmate', 'collate']) { + def argsKey = n_commands == 1 ? "args" : "args${n_commands}" + def argsLast = task.ext[argsKey] ?: "" + def extension = argsLast.contains("--output-fmt sam") + ? "sam" + : argsLast.contains("--output-fmt cram") + ? "cram" + : "bam" + stub_outputs << "touch ${prefix}.${extension}" + } else if (final_command == "fasta") { + if (meta.single_end) { + stub_outputs << "echo | gzip > ${prefix}_1.fasta.gz" + stub_outputs << "echo | gzip > ${prefix}_singleton.fasta.gz" + } else { + stub_outputs << "echo | gzip > ${prefix}_1.fasta.gz" + stub_outputs << "echo | gzip > ${prefix}_2.fasta.gz" + stub_outputs << "echo | gzip > ${prefix}_singleton.fasta.gz" + } + stub_outputs << "echo | gzip > ${prefix}_other.fasta.gz" + } else if (final_command == "fastq") { + if (meta.single_end) { + stub_outputs << "echo | gzip > ${prefix}_1.fastq.gz" + stub_outputs << "echo | gzip > ${prefix}_singleton.fastq.gz" + } else { + stub_outputs << "echo | gzip > ${prefix}_1.fastq.gz" + stub_outputs << "echo | gzip > ${prefix}_2.fastq.gz" + stub_outputs << "echo | gzip > ${prefix}_singleton.fastq.gz" + } + stub_outputs << "echo | gzip > ${prefix}_other.fastq.gz" + } + + """ + ${stub_outputs.join("\n")} + """ +} diff --git a/modules/nf-core/samtools/multicommand/meta.yml b/modules/nf-core/samtools/multicommand/meta.yml new file mode 100644 index 000000000000..56192ed85778 --- /dev/null +++ b/modules/nf-core/samtools/multicommand/meta.yml @@ -0,0 +1,284 @@ +name: "samtools_multicommand" +description: | + Execute a series of samtools commands in a pipeline, allowing flexible composition of + samtools operations such as view, sort, markdup, merge, fastq conversion and more. + + The exact order of operations is specified by the pipeline input, which takes a list such as + [view, sort, markdup]. This is then interpolated to a script where the output of each command + is streamed to the next before being written to disk. The script can handle references being passed, + as well as writing indexes, outputting in CRAM format, and conversion to FASTA and FASTQ. + + samtools view ${args} input.bam |\ + samtools sort ${args2} |\ + samtools markdup ${args3} -o output.bam +keywords: + - view + - sort + - markdup + - fixmate + - merge + - cat + - collate + - fastq + - fasta + - bam + - sam + - cram +tools: + - samtools: + description: | + SAMtools is a set of utilities for interacting with and post-processing + short DNA sequence read alignments in the SAM, BAM and CRAM formats, written by Heng Li. + These files are generated as output by short read aligners like BWA. + homepage: http://www.htslib.org/ + documentation: http://www.htslib.org/doc/samtools.html + doi: 10.1093/bioinformatics/btp352 + licence: + - "MIT" + identifier: biotools:samtools +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: BAM/CRAM/SAM file + pattern: "*.{bam,cram,sam}" + ontologies: + - edam: http://edamontology.org/data_0924 + - edam: http://edamontology.org/format_2572 + - edam: http://edamontology.org/format_3462 + - edam: http://edamontology.org/format_2573 + - index: + type: file + description: BAM.BAI/BAM.CSI/CRAM.CRAI file (optional) + pattern: "*.{bai,csi,crai}" + ontologies: + - edam: http://edamontology.org/format_3326 + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - fasta: + type: file + description: Fasta reference file + pattern: "*.{fasta,fa}" + ontologies: + - edam: http://edamontology.org/format_1929 + - fai: + type: file + description: Fasta reference file index + pattern: "*.{fai}" + ontologies: + - edam: http://edamontology.org/format_3326 + - pipeline: + type: list + description: | + List of samtools commands to execute in sequence. + Valid options: view, sort, markdup, fixmate, merge, cat, collate, fastq, fasta +output: + bam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.bam": + type: file + description: optional BAM file output + pattern: "*.{bam}" + ontologies: + - edam: http://edamontology.org/data_0924 + - edam: http://edamontology.org/format_2572 + cram: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.cram": + type: file + description: optional CRAM file output + pattern: "*.{cram}" + ontologies: + - edam: http://edamontology.org/data_0924 + - edam: http://edamontology.org/format_3462 + sam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.sam": + type: file + description: optional SAM file output + pattern: "*.{sam}" + ontologies: + - edam: http://edamontology.org/data_0924 + - edam: http://edamontology.org/format_2573 + index: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.{bai,csi,crai}": + type: file + description: optional index file for alignment output + pattern: "*.{bai,csi,crai}" + ontologies: + - edam: http://edamontology.org/format_3326 + fasta: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.fasta.gz": + type: file + description: FASTA files output when final command is "fasta". + pattern: "*.fasta.gz" + ontologies: + - edam: http://edamontology.org/format_1929 + - edam: http://edamontology.org/format_3989 + fastq: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.fastq.gz": + type: file + description: FASTQ file output when final command is "fastq". + pattern: "*.fastq.gz" + ontologies: + - edam: http://edamontology.org/format_1930 + - edam: http://edamontology.org/format_3989 + fasta_pair: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_{1,2}.fasta.gz": + type: file + description: Compressed FASTA file(s) with reads with either the READ1 or + READ2 flag set in separate files. + pattern: "*_{1,2}.fasta.gz" + ontologies: [] + fasta_interleaved: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_interleaved.fasta.gz": + type: file + description: Compressed FASTA file with reads with either the READ1 or READ2 + flag set in a combined file. Needs collated input file. + pattern: "*_interleaved.fasta.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + fasta_singleton: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_singleton.fasta.gz": + type: file + description: Compressed FASTA file with singleton reads + pattern: "*_singleton.fasta.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + fasta_other: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_other.fasta.gz": + type: file + description: Compressed FASTA file with reads with either both READ1 and READ2 + flags set or unset + pattern: "*_other.fasta.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + fastq_pair: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_{1,2}.fastq.gz": + type: file + description: Compressed FASTQ file(s) with reads with either the READ1 + or READ2 flag set in separate files. + pattern: "*_{1,2}.fastq.gz" + ontologies: [] + fastq_interleaved: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_interleaved.fastq": + type: file + description: Compressed FASTQ file with reads with either the READ1 or + READ2 flag set in a combined file. Needs collated input file. + pattern: "*_interleaved.fastq.gz" + ontologies: + - edam: http://edamontology.org/format_3989 + fastq_singleton: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_singleton.fastq.gz": + type: file + description: Compressed FASTQ file with singleton reads + pattern: "*_singleton.fastq.gz" + ontologies: + - edam: http://edamontology.org/format_3989 + fastq_other: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_other.fastq.gz": + type: file + description: Compressed FASTQ file with reads with either both READ1 and + READ2 flags set or unset + pattern: "*_other.fastq.gz" + ontologies: + - edam: http://edamontology.org/format_3989 + versions_samtools: + - - ${task.process}: + type: string + description: Name of the process + - samtools: + type: string + description: Name of the tool + - samtools version | sed "1!d;s/.* //": + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: Name of the process + - samtools: + type: string + description: Name of the tool + - samtools version | sed "1!d;s/.* //": + type: eval + description: The expression to obtain the version of the tool +authors: + - "@prototaxites" +maintainers: + - "@prototaxites" diff --git a/modules/nf-core/samtools/multicommand/tests/main.nf.test b/modules/nf-core/samtools/multicommand/tests/main.nf.test new file mode 100644 index 000000000000..1b6f2300c000 --- /dev/null +++ b/modules/nf-core/samtools/multicommand/tests/main.nf.test @@ -0,0 +1,343 @@ +nextflow_process { + + name "Test Process SAMTOOLS_MULTICOMMAND" + script "../main.nf" + config "./nextflow.config" + process "SAMTOOLS_MULTICOMMAND" + + tag "modules" + tag "modules_nfcore" + tag "samtools" + tag "samtools/multicommand" + + test("bam - view, sort") { + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "--write-index" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), + [] + ] + input[1] = [[],[],[]] + input[2] = ["view", "sort"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out, unstableKeys: ["bam", "cram", "index"])).match()} + ) + } + } + + test("bam - view, sort - to cram") { + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "-n --output-fmt cram" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), + [] + ] + input[1] = [ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[2] = ["view", "sort"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out, unstableKeys: ["bam", "cram"])).match()} + ) + } + } + + test("bam - view, fastq") { + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), + [] + ] + input[1] = [[],[],[]] + input[2] = ["view", "fastq"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out, unstableKeys: ["fastq", "fastq_other"])).match()} + ) + } + } + + test("cram - view, fasta") { + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[2] = ["view", "fasta"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out, unstableKeys: ["fasta", "fasta_other"])).match()} + ) + } + } + + test("bam - cat, view, sort") { + + when { + + params { + pipeline_args = "" + pipeline_args2 = "-h -F4" + pipeline_args3 = "-n" + } + + process { + """ + input[0] = [ + [ id:'test' ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ], + [] + ] + input[1] = [[],[],[]] + input[2] = ["cat", "view", "sort"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out, unstableKeys: ["bam", "cram", "index"])).match()} + ) + } + } + + test("cram - view, stats - invalid arg") { + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "" + pipeline_args3 = "" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[2] = ["view", "stats"] + """ + } + } + + then { + { assert process.success == false } + } + } + + test("bam - view, sort - stub") { + + options "-stub" + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "-n" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), + [] + ] + input[1] = [[],[],[]] + input[2] = ["view", "sort"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match()} + ) + } + } + + test("bam - view, sort - to cram - stub") { + + options "-stub" + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "-n --output-fmt cram" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), + [] + ] + input[1] = [ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[2] = ["view", "sort"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match()} + ) + } + } + + test("cram - view, fasta - stub") { + + options "-stub" + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/cram/test.paired_end.sorted.cram.crai', checkIfExists: true) + ] + input[1] = [ + [ id:'genome' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + input[2] = ["view", "fasta"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match()} + ) + } + } + + test("bam - view, fastq - stub") { + + options "-stub" + + when { + + params { + pipeline_args = "-h -F4" + pipeline_args2 = "" + } + + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), + [] + ] + input[1] = [[],[],[]] + input[2] = ["view", "fastq"] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match()} + ) + } + } + +} diff --git a/modules/nf-core/samtools/multicommand/tests/main.nf.test.snap b/modules/nf-core/samtools/multicommand/tests/main.nf.test.snap new file mode 100644 index 000000000000..488c982c72d7 --- /dev/null +++ b/modules/nf-core/samtools/multicommand/tests/main.nf.test.snap @@ -0,0 +1,684 @@ +{ + "cram - view, fasta": { + "content": [ + { + "bam": [ + + ], + "cram": [ + + ], + "fasta": [ + [ + { + "id": "test" + }, + [ + "test_1.fasta.gz", + "test_2.fasta.gz", + "test_other.fasta.gz", + "test_singleton.fasta.gz" + ] + ] + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + [ + { + "id": "test" + }, + "test_other.fasta.gz" + ] + ], + "fasta_pair": [ + [ + { + "id": "test" + }, + [ + "test_1.fasta.gz:md5,1ec036ad586c3f7ed822526dcede9a86", + "test_2.fasta.gz:md5,2ee17b7f212ade40541b3c74a53786b5" + ] + ] + ], + "fasta_singleton": [ + [ + { + "id": "test" + }, + "test_singleton.fasta.gz:md5,eb5ffa2e84dd8eff7dc1096e07439ec2" + ] + ], + "fastq": [ + + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + + ], + "fastq_pair": [ + + ], + "fastq_singleton": [ + + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:31:17.920686", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "bam - view, sort - stub": { + "content": [ + { + "bam": [ + [ + { + "id": "test" + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "cram": [ + + ], + "fasta": [ + + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + + ], + "fasta_pair": [ + + ], + "fasta_singleton": [ + + ], + "fastq": [ + + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + + ], + "fastq_pair": [ + + ], + "fastq_singleton": [ + + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:13:20.400143", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "cram - view, fasta - stub": { + "content": [ + { + "bam": [ + + ], + "cram": [ + + ], + "fasta": [ + [ + { + "id": "test" + }, + [ + "test_1.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_other.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_singleton.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + [ + { + "id": "test" + }, + "test_other.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "fasta_pair": [ + [ + { + "id": "test" + }, + [ + "test_1.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "fasta_singleton": [ + [ + { + "id": "test" + }, + "test_singleton.fasta.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "fastq": [ + + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + + ], + "fastq_pair": [ + + ], + "fastq_singleton": [ + + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:13:30.82469", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "bam - view, sort - to cram - stub": { + "content": [ + { + "bam": [ + + ], + "cram": [ + [ + { + "id": "test" + }, + "test.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "fasta": [ + + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + + ], + "fasta_pair": [ + + ], + "fasta_singleton": [ + + ], + "fastq": [ + + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + + ], + "fastq_pair": [ + + ], + "fastq_singleton": [ + + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:13:25.789164", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "bam - view, sort - to cram": { + "content": [ + { + "bam": [ + + ], + "cram": [ + [ + { + "id": "test" + }, + "test.cram" + ] + ], + "fasta": [ + + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + + ], + "fasta_pair": [ + + ], + "fasta_singleton": [ + + ], + "fastq": [ + + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + + ], + "fastq_pair": [ + + ], + "fastq_singleton": [ + + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:21:52.709644", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "bam - view, fastq": { + "content": [ + { + "bam": [ + + ], + "cram": [ + + ], + "fasta": [ + + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + + ], + "fasta_pair": [ + + ], + "fasta_singleton": [ + + ], + "fastq": [ + [ + { + "id": "test" + }, + [ + "test_1.fastq.gz", + "test_2.fastq.gz", + "test_other.fastq.gz", + "test_singleton.fastq.gz" + ] + ] + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + [ + { + "id": "test" + }, + "test_other.fastq.gz" + ] + ], + "fastq_pair": [ + [ + { + "id": "test" + }, + [ + "test_1.fastq.gz:md5,84747fd2f74f1c69e26b2a2700b9bd12", + "test_2.fastq.gz:md5,1f7475e8cc710e158d7b1469b5f29483" + ] + ] + ], + "fastq_singleton": [ + [ + { + "id": "test" + }, + "test_singleton.fastq.gz:md5,09643fe0c4a8bf5a0650452ac758bf2f" + ] + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:31:12.50357", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "bam - cat, view, sort": { + "content": [ + { + "bam": [ + [ + { + "id": "test" + }, + "test.bam" + ] + ], + "cram": [ + + ], + "fasta": [ + + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + + ], + "fasta_pair": [ + + ], + "fasta_singleton": [ + + ], + "fastq": [ + + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + + ], + "fastq_pair": [ + + ], + "fastq_singleton": [ + + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:24:39.736586", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "bam - view, sort": { + "content": [ + { + "bam": [ + [ + { + "id": "test" + }, + "test.bam" + ] + ], + "cram": [ + + ], + "fasta": [ + + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + + ], + "fasta_pair": [ + + ], + "fasta_singleton": [ + + ], + "fastq": [ + + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + + ], + "fastq_pair": [ + + ], + "fastq_singleton": [ + + ], + "index": [ + [ + { + "id": "test" + }, + "test.bam.csi" + ] + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:21:47.787828", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "bam - view, fastq - stub": { + "content": [ + { + "bam": [ + + ], + "cram": [ + + ], + "fasta": [ + + ], + "fasta_interleaved": [ + + ], + "fasta_other": [ + + ], + "fasta_pair": [ + + ], + "fasta_singleton": [ + + ], + "fastq": [ + [ + { + "id": "test" + }, + [ + "test_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_other.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_singleton.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "fastq_interleaved": [ + + ], + "fastq_other": [ + [ + { + "id": "test" + }, + "test_other.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "fastq_pair": [ + [ + { + "id": "test" + }, + [ + "test_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "fastq_singleton": [ + [ + { + "id": "test" + }, + "test_singleton.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "index": [ + + ], + "sam": [ + + ], + "versions_samtools": [ + [ + "SAMTOOLS_MULTICOMMAND", + "samtools", + "1.23.1" + ] + ] + } + ], + "timestamp": "2026-05-07T13:13:35.285053", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/multicommand/tests/nextflow.config b/modules/nf-core/samtools/multicommand/tests/nextflow.config new file mode 100644 index 000000000000..bf95f4409cb2 --- /dev/null +++ b/modules/nf-core/samtools/multicommand/tests/nextflow.config @@ -0,0 +1,11 @@ +process { + withName: SAMTOOLS_MULTICOMMAND { + ext.args = { params.pipeline_args ?: "" } + ext.args2 = { params.pipeline_args2 ?: "" } + ext.args3 = { params.pipeline_args3 ?: "" } + ext.args4 = { params.pipeline_args4 ?: "" } + ext.args5 = { params.pipeline_args5 ?: "" } + ext.args6 = { params.pipeline_args6 ?: "" } + ext.args7 = { params.pipeline_args7 ?: "" } + } +}