From 6fd709892c5b18d6666ebd8f3a03b44e2b4fed07 Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Mon, 6 Jan 2025 16:29:15 +0000 Subject: [PATCH] Update trimgalore module --- modules.json | 2 +- modules/nf-core/trimgalore/environment.yml | 2 +- modules/nf-core/trimgalore/main.nf | 51 ++++---- modules/nf-core/trimgalore/meta.yml | 38 +++--- modules/nf-core/trimgalore/tests/main.nf.test | 46 +++++++- .../trimgalore/tests/main.nf.test.snap | 111 ++++++++++++++---- 6 files changed, 190 insertions(+), 60 deletions(-) diff --git a/modules.json b/modules.json index 496b6a7d9..8f27820f5 100644 --- a/modules.json +++ b/modules.json @@ -254,7 +254,7 @@ }, "trimgalore": { "branch": "master", - "git_sha": "8c5eeedd45e295fc9a4f164631da6a8b37e6b9c6", + "git_sha": "8d3e71002c5008e3f68a691ad8cd32c346356258", "installed_by": ["fastq_fastqc_umitools_trimgalore"] }, "tximeta/tximport": { diff --git a/modules/nf-core/trimgalore/environment.yml b/modules/nf-core/trimgalore/environment.yml index 622407eda..b1efd94c4 100644 --- a/modules/nf-core/trimgalore/environment.yml +++ b/modules/nf-core/trimgalore/environment.yml @@ -1,7 +1,7 @@ channels: - conda-forge - bioconda - dependencies: - bioconda::cutadapt=4.9 - bioconda::trim-galore=0.6.10 + - conda-forge::pigz=2.8 diff --git a/modules/nf-core/trimgalore/main.nf b/modules/nf-core/trimgalore/main.nf index 8a2fc54b3..5fe53669f 100644 --- a/modules/nf-core/trimgalore/main.nf +++ b/modules/nf-core/trimgalore/main.nf @@ -1,22 +1,22 @@ process TRIMGALORE { - tag "$meta.id" + tag "${meta.id}" label 'process_high' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/trim-galore%3A0.6.10--hdfd78af_1' : - 'biocontainers/trim-galore:0.6.10--hdfd78af_1' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/9b/9becad054093ad4083a961d12733f2a742e11728fe9aa815d678b882b3ede520/data' + : 'community.wave.seqera.io/library/cutadapt_trim-galore_pigz:a98edd405b34582d'}" input: tuple val(meta), path(reads) output: - tuple val(meta), path("*{3prime,5prime,trimmed,val}*.fq.gz"), emit: reads - tuple val(meta), path("*report.txt") , emit: log , optional: true - tuple val(meta), path("*unpaired*.fq.gz") , emit: unpaired, optional: true - tuple val(meta), path("*.html") , emit: html , optional: true - tuple val(meta), path("*.zip") , emit: zip , optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*{3prime,5prime,trimmed,val}{,_1,_2}.fq.gz"), emit: reads + tuple val(meta), path("*report.txt") , emit: log, optional: true + tuple val(meta), path("*unpaired{,_1,_2}.fq.gz") , emit: unpaired, optional: true + tuple val(meta), path("*.html") , emit: html, optional: true + tuple val(meta), path("*.zip") , emit: zip, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -24,14 +24,20 @@ process TRIMGALORE { script: def args = task.ext.args ?: '' // Calculate number of --cores for TrimGalore based on value of task.cpus - // See: https://github.com/FelixKrueger/TrimGalore/blob/master/Changelog.md#version-060-release-on-1-mar-2019 + // See: https://github.com/FelixKrueger/TrimGalore/blob/master/CHANGELOG.md#version-060-release-on-1-mar-2019 // See: https://github.com/nf-core/atacseq/pull/65 def cores = 1 if (task.cpus) { cores = (task.cpus as int) - 4 - if (meta.single_end) cores = (task.cpus as int) - 3 - if (cores < 1) cores = 1 - if (cores > 8) cores = 8 + if (meta.single_end) { + cores = (task.cpus as int) - 3 + } + if (cores < 1) { + cores = 1 + } + if (cores > 8) { + cores = 8 + } } // Added soft-links to original fastqs for consistent naming in MultiQC @@ -40,10 +46,10 @@ process TRIMGALORE { def args_list = args.split("\\s(?=--)").toList() args_list.removeAll { it.toLowerCase().contains('_r2 ') } """ - [ ! -f ${prefix}.fastq.gz ] && ln -s $reads ${prefix}.fastq.gz + [ ! -f ${prefix}.fastq.gz ] && ln -s ${reads} ${prefix}.fastq.gz trim_galore \\ ${args_list.join(' ')} \\ - --cores $cores \\ + --cores ${cores} \\ --gzip \\ ${prefix}.fastq.gz @@ -51,15 +57,17 @@ process TRIMGALORE { "${task.process}": trimgalore: \$(echo \$(trim_galore --version 2>&1) | sed 's/^.*version //; s/Last.*\$//') cutadapt: \$(cutadapt --version) + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) END_VERSIONS """ - } else { + } + else { """ [ ! -f ${prefix}_1.fastq.gz ] && ln -s ${reads[0]} ${prefix}_1.fastq.gz [ ! -f ${prefix}_2.fastq.gz ] && ln -s ${reads[1]} ${prefix}_2.fastq.gz trim_galore \\ - $args \\ - --cores $cores \\ + ${args} \\ + --cores ${cores} \\ --paired \\ --gzip \\ ${prefix}_1.fastq.gz \\ @@ -69,6 +77,7 @@ process TRIMGALORE { "${task.process}": trimgalore: \$(echo \$(trim_galore --version 2>&1) | sed 's/^.*version //; s/Last.*\$//') cutadapt: \$(cutadapt --version) + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) END_VERSIONS """ } @@ -78,7 +87,8 @@ process TRIMGALORE { if (meta.single_end) { output_command = "echo '' | gzip > ${prefix}_trimmed.fq.gz ;" output_command += "touch ${prefix}.fastq.gz_trimming_report.txt" - } else { + } + else { output_command = "echo '' | gzip > ${prefix}_1_trimmed.fq.gz ;" output_command += "touch ${prefix}_1.fastq.gz_trimming_report.txt ;" output_command += "echo '' | gzip > ${prefix}_2_trimmed.fq.gz ;" @@ -91,6 +101,7 @@ process TRIMGALORE { "${task.process}": trimgalore: \$(echo \$(trim_galore --version 2>&1) | sed 's/^.*version //; s/Last.*\$//') cutadapt: \$(cutadapt --version) + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) END_VERSIONS """ } diff --git a/modules/nf-core/trimgalore/meta.yml b/modules/nf-core/trimgalore/meta.yml index 576cb4c59..bd793635f 100644 --- a/modules/nf-core/trimgalore/meta.yml +++ b/modules/nf-core/trimgalore/meta.yml @@ -33,21 +33,24 @@ output: description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - "*{3prime,5prime,trimmed,val}*.fq.gz": - type: file + - "*{3prime,5prime,trimmed,val}{,_1,_2}.fq.gz": + type: map description: | - List of input adapter trimmed FastQ files of size 1 and 2 for - single-end and paired-end data, respectively. - pattern: "*{3prime,5prime,trimmed,val}*.fq.gz" + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + pattern: "*{3prime,5prime,trimmed,val}{,_1,_2}.fq.gz" - log: - meta: type: map description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] + pattern: "*_{report.txt}" - "*report.txt": - type: file - description: Trim Galore! trimming report + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] pattern: "*_{report.txt}" - unpaired: - meta: @@ -55,10 +58,11 @@ output: description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - "*unpaired*.fq.gz": - type: file + - "*unpaired{,_1,_2}.fq.gz": + type: map description: | - FastQ files containing unpaired reads from read 1 or read 2 + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] pattern: "*unpaired*.fq.gz" - html: - meta: @@ -66,9 +70,12 @@ output: description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] + pattern: "*_{fastqc.html}" - "*.html": - type: file - description: FastQC report (optional) + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] pattern: "*_{fastqc.html}" - zip: - meta: @@ -76,9 +83,12 @@ output: description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] + pattern: "*_{fastqc.zip}" - "*.zip": - type: file - description: FastQC report archive (optional) + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] pattern: "*_{fastqc.zip}" - versions: - versions.yml: diff --git a/modules/nf-core/trimgalore/tests/main.nf.test b/modules/nf-core/trimgalore/tests/main.nf.test index 4010af8f4..627e83351 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test +++ b/modules/nf-core/trimgalore/tests/main.nf.test @@ -36,7 +36,7 @@ nextflow_process { { assert path(process.out.log.get(0).get(1)).getText().contains(report1_line) } } }, - { assert snapshot(process.out.versions).match() } + { assert snapshot(path(process.out.versions.get(0)).yaml).match() }, ) } } @@ -58,7 +58,10 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out, + path(process.out.versions.get(0)).yaml + ).match() }, ) } } @@ -115,7 +118,41 @@ nextflow_process { { assert path(process.out.log.get(0).get(1).get(1)).getText().contains(report2_line) } } }, - { assert snapshot(process.out.versions).match() } + { assert snapshot(path(process.out.versions.get(0)).yaml).match() }, + ) + } + } + + test("test_trimgalore_paired_end_keep_unpaired") { + + config "./nextflow.config" + + when { + + params { + module_args = '--retain_unpaired --length 150' + } + + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_1.fastq.gz", checkIfExists: true), + file(params.modules_testdata_base_path + "genomics/sarscov2/illumina/fastq/test_2.fastq.gz", checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.versions.get(0)).yaml, + process.out.reads, + process.out.unpaired + ).match() }, ) } } @@ -140,7 +177,8 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match() }, + { assert snapshot(path(process.out.versions.get(0)).yaml).match("versions") }, ) } } diff --git a/modules/nf-core/trimgalore/tests/main.nf.test.snap b/modules/nf-core/trimgalore/tests/main.nf.test.snap index 21da84933..c454ad521 100644 --- a/modules/nf-core/trimgalore/tests/main.nf.test.snap +++ b/modules/nf-core/trimgalore/tests/main.nf.test.snap @@ -1,15 +1,19 @@ { "test_trimgalore_single_end": { "content": [ - [ - "versions.yml:md5,81a0b49f3a9e1315fe564f9946eb8c50" - ] + { + "TRIMGALORE": { + "trimgalore": "0.6.10", + "cutadapt": 4.9, + "pigz": 2.8 + } + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "24.10.3" }, - "timestamp": "2024-10-22T19:23:17.969056957" + "timestamp": "2025-01-06T12:25:01.330769598" }, "test_trimgalore_single_end - stub": { "content": [ @@ -42,7 +46,7 @@ ], "5": [ - "versions.yml:md5,81a0b49f3a9e1315fe564f9946eb8c50" + "versions.yml:md5,5928323d579768de37e83c56c821757f" ], "html": [ @@ -69,18 +73,25 @@ ], "versions": [ - "versions.yml:md5,81a0b49f3a9e1315fe564f9946eb8c50" + "versions.yml:md5,5928323d579768de37e83c56c821757f" ], "zip": [ ] + }, + { + "TRIMGALORE": { + "trimgalore": "0.6.10", + "cutadapt": 4.9, + "pigz": 2.8 + } } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "24.10.3" }, - "timestamp": "2024-10-22T19:23:28.617831159" + "timestamp": "2025-01-06T12:25:15.582246999" }, "test_trimgalore_paired_end - stub": { "content": [ @@ -119,7 +130,7 @@ ], "5": [ - "versions.yml:md5,81a0b49f3a9e1315fe564f9946eb8c50" + "versions.yml:md5,5928323d579768de37e83c56c821757f" ], "html": [ @@ -152,7 +163,7 @@ ], "versions": [ - "versions.yml:md5,81a0b49f3a9e1315fe564f9946eb8c50" + "versions.yml:md5,5928323d579768de37e83c56c821757f" ], "zip": [ @@ -160,21 +171,81 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-06T12:26:05.201562315" + }, + "versions": { + "content": [ + { + "TRIMGALORE": { + "trimgalore": "0.6.10", + "cutadapt": 4.9, + "pigz": 2.8 + } + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" }, - "timestamp": "2024-10-22T19:23:51.539787731" + "timestamp": "2025-01-06T12:26:05.229598492" }, "test_trimgalore_paired_end": { "content": [ + { + "TRIMGALORE": { + "trimgalore": "0.6.10", + "cutadapt": 4.9, + "pigz": 2.8 + } + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.3" + }, + "timestamp": "2025-01-06T12:25:33.510924538" + }, + "test_trimgalore_paired_end_keep_unpaired": { + "content": [ + { + "TRIMGALORE": { + "trimgalore": "0.6.10", + "cutadapt": 4.9, + "pigz": 2.8 + } + }, [ - "versions.yml:md5,81a0b49f3a9e1315fe564f9946eb8c50" + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1_val_1.fq.gz:md5,75413e85910bbc2e1556e12f6479f935", + "test_2_val_2.fq.gz:md5,d3c588c12646ebd36a0812fe02d0bda6" + ] + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1_unpaired_1.fq.gz:md5,17e0e878f6d0e93b9008a05f128660b6", + "test_2_unpaired_2.fq.gz:md5,b09a064368a867e099e66df5ef69b044" + ] + ] ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "24.10.3" }, - "timestamp": "2024-10-22T19:23:41.16485915" + "timestamp": "2025-01-06T12:25:46.461002981" } } \ No newline at end of file