From ea5d11aa93bebf2ffa8a28195b42764334f3db5e Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 23 Jun 2025 12:49:27 +0200 Subject: [PATCH 001/228] back to dev --- assets/multiqc_config.yml | 2 +- nextflow.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 53ed49db..e8d8173d 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,5 +1,5 @@ report_comment: > - This report has been generated by the nf-cmgg/preprocessing analysis pipeline. report_section_order: "nf-cmgg-preprocessing-methods-description": diff --git a/nextflow.config b/nextflow.config index cb90bae7..27cb9abd 100644 --- a/nextflow.config +++ b/nextflow.config @@ -255,7 +255,7 @@ manifest { description = """Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.""" mainScript = 'main.nf' nextflowVersion = '!>=25.04.0' - version = '2.0.6' + version = 'dev' doi = '' } From cf1da3083adf3830447acb495669a7188bd8b0c5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 23 Jun 2025 14:52:13 +0200 Subject: [PATCH 002/228] coverage - filter seqcap genelists --- modules/local/panelcoverage/main.nf | 3 +- subworkflows/local/coverage/main.nf | 28 ++- .../subworkflows/local/coverage/main.nf.test | 35 ++- .../local/coverage/main.nf.test.snap | 238 +++++++++++++++++- 4 files changed, 282 insertions(+), 22 deletions(-) diff --git a/modules/local/panelcoverage/main.nf b/modules/local/panelcoverage/main.nf index 992d4b99..7b38328a 100644 --- a/modules/local/panelcoverage/main.nf +++ b/modules/local/panelcoverage/main.nf @@ -8,8 +8,7 @@ process PANELCOVERAGE { 'biocontainers/bedtools:2.31.1--hf5e1c6e_1' }" input: - tuple val(meta), path(perbase), path(perbase_index) - path(genelists) + tuple val(meta), path(perbase), path(perbase_index), path(genelists) output: tuple val(meta), path("*.mosdepth.region.dist.txt"), emit: regiondist diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 331d9d60..634ecf02 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -16,7 +16,7 @@ workflow COVERAGE { MOSDEPTH( ch_meta_cram_crai_fasta_fai_roi.map{ - meta, cram, crai, fasta, fai, roi -> + meta, cram, crai, fasta, _fai, roi -> return [meta, cram, crai, roi, fasta] } ) @@ -24,17 +24,37 @@ workflow COVERAGE { SAMTOOLS_COVERAGE( ch_meta_cram_crai_fasta_fai_roi.map{ - meta, cram, crai, fasta, fai, roi -> + meta, cram, crai, fasta, fai, _roi -> return [meta, cram, crai, fasta, fai] } ) ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) ch_coverageqc_files = ch_coverageqc_files.merge(SAMTOOLS_COVERAGE.out.coverage) + ch_genelists.view() + PANELCOVERAGE( MOSDEPTH.out.per_base_bed - .join(MOSDEPTH.out.per_base_csi), - ch_genelists + .join(MOSDEPTH.out.per_base_csi) + .combine(ch_genelists) + .map{meta, bed, index, genelists -> + if (genelists !instanceof List){ + // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... + genelists = [genelists] + } + def filtered_genelists = meta.tag.toLowerCase() == "seqcap" ? + genelists.findAll{it.name.toLowerCase().contains("seqcap")} : + genelists.findAll{!it.name.toLowerCase().contains("seqcap")} + + if (filtered_genelists.size() > 0) { + return [ + meta, + bed, + index, + filtered_genelists + ] + } + } ) ch_versions = ch_versions.mix(PANELCOVERAGE.out.versions.first()) ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) diff --git a/tests/subworkflows/local/coverage/main.nf.test b/tests/subworkflows/local/coverage/main.nf.test index 17e8b833..8792b87c 100644 --- a/tests/subworkflows/local/coverage/main.nf.test +++ b/tests/subworkflows/local/coverage/main.nf.test @@ -8,14 +8,14 @@ nextflow_workflow { tag "subworkflows/local" tag "subworkflows/local/coverage" - test("Coverage") { + test("Coverage - seqcap") { when { workflow { """ // ch_meta_cram_crai_fasta_fai_roi input[0] = Channel.of([ - [id: "test", single_end: false], // meta + [id: "test", single_end: false, tag: "seqcap"], // meta file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram.crai", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", checkIfExists: true), @@ -23,7 +23,36 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - input[1] = Channel.of([ + input[1] = Channel.value([ + file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) + ]) + """ + } + } + + then { + assert workflow.success + assert snapshot(workflow.out).match() + } + + } + + test("Coverage - WES") { + + when { + workflow { + """ + // ch_meta_cram_crai_fasta_fai_roi + input[0] = Channel.of([ + [id: "test", single_end: false, tag: "WES"], // meta + file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram", checkIfExists: true), + file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram.crai", checkIfExists: true), + file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", checkIfExists: true), + file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", checkIfExists: true), + file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), + ]) + // genelists + input[1] = Channel.value([ file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) ]) """ diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 068dc48d..5e1a6c31 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -1,12 +1,13 @@ { - "Coverage": { + "Coverage - WES": { "content": [ { "0": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" ] @@ -15,7 +16,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" ] @@ -24,7 +26,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" ] @@ -33,7 +36,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] @@ -42,7 +46,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" ] @@ -56,7 +61,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" ] @@ -65,7 +71,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" ] @@ -74,7 +81,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" ] @@ -83,7 +91,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" ] @@ -92,7 +101,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "WES" }, "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] @@ -106,8 +116,210 @@ ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.1" + "nextflow": "25.04.4" + }, + "timestamp": "2025-06-23T14:45:47.730036" + }, + "Coverage - seqcap": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" + ] + ], + "3": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + ] + ], + "4": [ + + ], + "5": [ + "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + ], + "mosdepth_global": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + ] + ], + "mosdepth_regions": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" + ] + ], + "mosdepth_summary": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + ] + ], + "panelcoverage": [ + + ], + "samtools_coverage": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + ] + ], + "versions": [ + "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.2" + }, + "timestamp": "2025-06-23T13:40:00.179558" + }, + "Coverage": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" + ] + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + ] + ], + "4": [ + + ], + "5": [ + "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + ], + "mosdepth_global": [ + [ + { + "id": "test", + "single_end": false + }, + "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + ] + ], + "mosdepth_regions": [ + [ + { + "id": "test", + "single_end": false + }, + "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" + ] + ], + "mosdepth_summary": [ + [ + { + "id": "test", + "single_end": false + }, + "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + ] + ], + "panelcoverage": [ + + ], + "samtools_coverage": [ + [ + { + "id": "test", + "single_end": false + }, + "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + ] + ], + "versions": [ + "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.2" }, - "timestamp": "2024-11-19T15:25:37.147132" + "timestamp": "2025-06-23T13:34:58.331928" } } \ No newline at end of file From 0c8f087d9aa31bb0006b36677c0525e658472a19 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 23 Jun 2025 14:54:17 +0200 Subject: [PATCH 003/228] fix module tests --- tests/modules/local/panelcoverage/main.nf.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/modules/local/panelcoverage/main.nf.test b/tests/modules/local/panelcoverage/main.nf.test index 3d3f351d..4a2dd77d 100644 --- a/tests/modules/local/panelcoverage/main.nf.test +++ b/tests/modules/local/panelcoverage/main.nf.test @@ -17,9 +17,9 @@ nextflow_process { [id: "test", single_end: false ], file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/bed/sample1.per-base.bed.gz", checkIfExists:true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/bed/sample1.per-base.bed.gz.csi", checkIfExists:true), - ] - input[1] = [ - file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) + [ + file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) + ] ] """ } From 503fa15976c9a96de25f12005268b382a6c994fa Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:13:33 +0200 Subject: [PATCH 004/228] MQC: disable plot export --- assets/multiqc_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index e8d8173d..f0b699ec 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -8,7 +8,7 @@ report_section_order: order: -1001 "nf-cmgg-preprocessing-summary": order: -1002 -export_plots: true +export_plots: false disable_version_detection: true bclconvert: create_undetermined_barcode_barplots: true From f9ad2f137525e5122a670d4fde367a9197d21f62 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 5 Sep 2025 16:31:38 +0200 Subject: [PATCH 005/228] only use first versions of modules --- nextflow_schema.json | 4 ++ subworkflows/local/bam_qc/main.nf | 18 ++++---- subworkflows/local/coverage/main.nf | 4 +- subworkflows/local/fastq_align_rna/main.nf | 2 +- .../local/fastq_to_aligned_cram/main.nf | 11 ++--- .../local/fastq_to_unaligned_cram/main.nf | 4 +- subworkflows/nf-core/bcl_demultiplex/main.nf | 4 +- subworkflows/nf-core/fastq_align_dna/main.nf | 10 ++--- workflows/preprocessing.nf | 41 ++++++++++--------- 9 files changed, 52 insertions(+), 46 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 6a2a3685..266484fe 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -38,6 +38,10 @@ "type": "string", "description": "MultiQC report title. Printed as page header, used for filename if not otherwise specified.", "fa_icon": "fas fa-file-signature" + }, + "genomes": { + "type": "object", + "hidden": true } } }, diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index 392bcd10..0cb82f0c 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -17,21 +17,21 @@ workflow BAM_QC { ch_versions = Channel.empty() ch_bam_bai_roi_fasta_fai_dict - .map{ meta, bam, bai, roi, fasta, fai, dict -> return [meta, bam, bai, fasta]} + .map{ meta, bam, bai, _roi, fasta, _fai, _dict -> return [meta, bam, bai, fasta]} .set{ ch_bam_bai_fasta } SAMTOOLS_STATS ( ch_bam_bai_fasta ) - ch_versions = ch_versions.mix(SAMTOOLS_STATS.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_STATS.out.versions.first()) ch_bam_bai_fasta - .map{ meta, bam, bai, fasta -> return [meta, bam, bai]} + .map{ meta, bam, bai, _fasta -> return [meta, bam, bai]} .set{ ch_bam_bai } SAMTOOLS_FLAGSTAT ( ch_bam_bai ) - ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions.first()) SAMTOOLS_IDXSTATS ( ch_bam_bai ) - ch_versions = ch_versions.mix(SAMTOOLS_IDXSTATS.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_IDXSTATS.out.versions.first()) ch_picard_hsmetrics = Channel.empty() ch_picard_multiplemetrics = Channel.empty() @@ -39,11 +39,11 @@ workflow BAM_QC { if (!disable_picard) { ch_bam_bai_roi_fasta_fai_dict - .map{ meta, bam, bai, roi, fasta, fai, dict -> return [meta, bam, bai, fasta, fai]} + .map{ meta, bam, bai, _roi, fasta, fai, _dict -> return [meta, bam, bai, fasta, fai]} .set{ ch_bam_bai_fasta_fai } PICARD_COLLECTMULTIPLEMETRICS ( ch_bam_bai_fasta_fai ) - ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions) + ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions.first()) ch_picard_multiplemetrics = ch_picard_multiplemetrics.mix(PICARD_COLLECTMULTIPLEMETRICS.out.metrics) ch_bam_bai_roi_fasta_fai_dict @@ -56,11 +56,11 @@ workflow BAM_QC { .set{ch_picard} PICARD_COLLECTWGSMETRICS ( ch_picard.wgsmetrics, [] ) - ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions) + ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) ch_picard_wgsmetrics = ch_picard_wgsmetrics.mix(PICARD_COLLECTWGSMETRICS.out.metrics) PICARD_COLLECTHSMETRICS ( ch_picard.hsmetrics ) - ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions) + ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions.first()) ch_picard_hsmetrics = ch_picard_hsmetrics.mix(PICARD_COLLECTHSMETRICS.out.metrics) } diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 331d9d60..a5aedeae 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -16,7 +16,7 @@ workflow COVERAGE { MOSDEPTH( ch_meta_cram_crai_fasta_fai_roi.map{ - meta, cram, crai, fasta, fai, roi -> + meta, cram, crai, fasta, _fai, roi -> return [meta, cram, crai, roi, fasta] } ) @@ -24,7 +24,7 @@ workflow COVERAGE { SAMTOOLS_COVERAGE( ch_meta_cram_crai_fasta_fai_roi.map{ - meta, cram, crai, fasta, fai, roi -> + meta, cram, crai, fasta, fai, _roi -> return [meta, cram, crai, fasta, fai] } ) diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index 5ec99dc9..e78ec428 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -36,7 +36,7 @@ workflow FASTQ_ALIGN_RNA { STAR_ALIGN.out.log_progress, STAR_ALIGN.out.log_out ) - ch_versions = ch_versions.mix(STAR_ALIGN.out.versions) + ch_versions = ch_versions.mix(STAR_ALIGN.out.versions.first()) emit: bam = ch_bam // channel: [ [meta], bam ] diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index ee57fd08..2ec92389 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -103,21 +103,21 @@ workflow FASTQ_TO_CRAM { // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) BIOBAMBAM_BAMSORMADUP(ch_bam_fasta) ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch:true, failOnDuplicate:true)) - ch_multiqc_files = ch_multiqc_files.mix( BIOBAMBAM_BAMSORMADUP.out.metrics.map { meta, metrics -> return metrics} ) - ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions) + ch_multiqc_files = ch_multiqc_files.mix( BIOBAMBAM_BAMSORMADUP.out.metrics.map { _meta, metrics -> return metrics} ) + ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions.first()) } else if ( markdup == "samtools") { SAMTOOLS_SORMADUP(ch_bam_fasta) ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch:true, failOnDuplicate:true)) - ch_multiqc_files = ch_multiqc_files.mix( SAMTOOLS_SORMADUP.out.metrics.map { meta, metrics -> return metrics} ) - ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions) + ch_multiqc_files = ch_multiqc_files.mix( SAMTOOLS_SORMADUP.out.metrics.map { _meta, metrics -> return metrics} ) + ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions.first()) } else if ( markdup == "false" || markdup == false) { // Merge bam files and compress // SAMTOOLS_SORT([meta, [bam, bam], fasta]) SAMTOOLS_SORT(ch_bam_fasta) ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORT.out.cram.join(SAMTOOLS_SORT.out.crai, failOnMismatch:true, failOnDuplicate:true)) - ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions.first()) } else { error "markdup: ${markdup} not supported" @@ -146,6 +146,7 @@ workflow FASTQ_TO_CRAM { .set {ch_bam_bai_fasta_fai} SAMTOOLS_CONVERT(ch_bam_bai_fasta_fai) + ch_versions = ch_versions.mix(SAMTOOLS_CONVERT.out.versions.first()) ch_markdup_index.cram .mix( diff --git a/subworkflows/local/fastq_to_unaligned_cram/main.nf b/subworkflows/local/fastq_to_unaligned_cram/main.nf index 28bdcbfe..8cb1911b 100644 --- a/subworkflows/local/fastq_to_unaligned_cram/main.nf +++ b/subworkflows/local/fastq_to_unaligned_cram/main.nf @@ -27,7 +27,7 @@ workflow FASTQ_TO_UCRAM { // SAMTOOLS_IMPORT([meta, fastq]) SAMTOOLS_IMPORT(ch_fastq) - ch_versions = ch_versions.mix(SAMTOOLS_IMPORT.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_IMPORT.out.versions.first()) SAMTOOLS_IMPORT.out.cram .map { @@ -66,7 +66,7 @@ workflow FASTQ_TO_UCRAM { // Merge bam files per sample SAMTOOLS_CAT(ch_ubam_per_sample) - ch_versions = ch_versions.mix(SAMTOOLS_CAT.out.versions) + ch_versions = ch_versions.mix(SAMTOOLS_CAT.out.versions.first()) emit: cram = SAMTOOLS_CAT.out.cram // [meta, cram] diff --git a/subworkflows/nf-core/bcl_demultiplex/main.nf b/subworkflows/nf-core/bcl_demultiplex/main.nf index 5526fc41..e7905cdb 100644 --- a/subworkflows/nf-core/bcl_demultiplex/main.nf +++ b/subworkflows/nf-core/bcl_demultiplex/main.nf @@ -49,7 +49,7 @@ workflow BCL_DEMULTIPLEX { ch_fastq = ch_fastq.mix(BCLCONVERT.out.fastq) ch_interop = ch_interop.mix(BCLCONVERT.out.interop) ch_reports = ch_reports.mix(BCLCONVERT.out.reports) - ch_versions = ch_versions.mix(BCLCONVERT.out.versions) + ch_versions = ch_versions.mix(BCLCONVERT.out.versions.first()) } // MODULE: bcl2fastq @@ -60,7 +60,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_versions = ch_versions.mix(BCL2FASTQ.out.versions) + ch_versions = ch_versions.mix(BCL2FASTQ.out.versions.first()) } // Generate meta for each fastq diff --git a/subworkflows/nf-core/fastq_align_dna/main.nf b/subworkflows/nf-core/fastq_align_dna/main.nf index 80414235..e6636ae8 100644 --- a/subworkflows/nf-core/fastq_align_dna/main.nf +++ b/subworkflows/nf-core/fastq_align_dna/main.nf @@ -48,26 +48,26 @@ workflow FASTQ_ALIGN_DNA { // Align fastq files to reference genome and (optionally) sort BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) - ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions) + ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions.first()) BWAMEM1_MEM (ch_to_align.bwamem, sort) // If aligner is bwa-mem ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) - ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions) + ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions.first()) BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) - ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions) + ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions.first()) DRAGMAP_ALIGN(ch_to_align.dragmap, sort) // If aligner is dragmap ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) - ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions) + ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) SNAP_ALIGN(ch_to_align.snap) // If aligner is snap ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) ch_bam_index.mix(SNAP_ALIGN.out.bai) - ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions) + ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions.first()) emit: bam = ch_bam // channel: [ [meta], bam ] diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index d23a17b1..36f6fe4c 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -79,8 +79,8 @@ workflow PREPROCESSING { BCL_DEMULTIPLEX(ch_illumina_flowcell.flowcell, "bclconvert") BCL_DEMULTIPLEX.out.fastq.dump(tag: "DEMULTIPLEX: fastq",pretty: true) ch_multiqc_files = ch_multiqc_files.mix( - BCL_DEMULTIPLEX.out.reports.map { meta, reports -> return reports}, - BCL_DEMULTIPLEX.out.stats.map { meta, stats -> return stats } + BCL_DEMULTIPLEX.out.reports.map { _meta, reports -> return reports}, + BCL_DEMULTIPLEX.out.stats.map { _meta, stats -> return stats } ) ch_versions = ch_versions.mix(BCL_DEMULTIPLEX.out.versions) @@ -180,7 +180,7 @@ workflow PREPROCESSING { // Count the number of samples per samplename .map{ meta, reads -> [meta.samplename, [meta, reads]]} .groupTuple() - .map{ samplename, meta_fastq -> [meta_fastq, meta_fastq.size()]} + .map{ _samplename, meta_fastq -> [meta_fastq, meta_fastq.size()]} .transpose() .map{meta_fastq, count -> [meta_fastq[0] + ['count': count], meta_fastq[1]]} // Clean up metadata @@ -202,8 +202,8 @@ workflow PREPROCESSING { // Run QC, trimming and adapter removal // FASTP([meta, fastq], adapter_fasta, save_trimmed, save_merged) FASTP(ch_fastq_per_sample, [], false, false, false) - ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json.map { meta, json -> return json} ) - ch_versions = ch_versions.mix(FASTP.out.versions) + ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json.map { _meta, json -> return json} ) + ch_versions = ch_versions.mix(FASTP.out.versions.first()) // edit meta.id to match sample name FASTP.out.reads @@ -225,7 +225,7 @@ workflow PREPROCESSING { ] } // split samples into human and non human data - .branch { meta, reads -> + .branch { meta, _reads -> supported: meta.genome_data instanceof Map && meta.genome_data.size() > 0 other: true } @@ -281,7 +281,7 @@ workflow PREPROCESSING { */ FASTQ_TO_CRAM.out.cram_crai - .filter{ meta, cram, crai -> + .filter{ meta, _cram, _crai -> meta.tag != "SNP" } .set{ch_no_snp_samples} @@ -318,10 +318,10 @@ workflow PREPROCESSING { if (params.run_coverage == true || params.run_coverage == "true") { COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) ch_multiqc_files = ch_multiqc_files.mix( - COVERAGE.out.mosdepth_summary .map{ meta, txt -> return txt }, - COVERAGE.out.mosdepth_global .map{ meta, txt -> return txt }, - COVERAGE.out.mosdepth_regions .map{ meta, txt -> return txt }, - COVERAGE.out.samtools_coverage.map{ meta, txt -> return txt }, + COVERAGE.out.mosdepth_summary .map{ _meta, txt -> return txt }, + COVERAGE.out.mosdepth_global .map{ _meta, txt -> return txt }, + COVERAGE.out.mosdepth_regions .map{ _meta, txt -> return txt }, + COVERAGE.out.samtools_coverage.map{ _meta, txt -> return txt }, ) ch_versions = ch_versions.mix(COVERAGE.out.versions) } @@ -359,12 +359,12 @@ workflow PREPROCESSING { BAM_QC(ch_cram_crai_roi_fasta_fai_dict, params.disable_picard_metrics) ch_multiqc_files = ch_multiqc_files.mix( - BAM_QC.out.samtools_stats .map{ meta, txt -> return txt }, - BAM_QC.out.samtools_flagstat .map{ meta, txt -> return txt }, - BAM_QC.out.samtools_idxstats .map{ meta, txt -> return txt }, - BAM_QC.out.picard_multiplemetrics .map{ meta, txt -> return txt }, - BAM_QC.out.picard_wgsmetrics .map{ meta, txt -> return txt }, - BAM_QC.out.picard_hsmetrics .map{ meta, txt -> return txt }, + BAM_QC.out.samtools_stats .map{ _meta, txt -> return txt }, + BAM_QC.out.samtools_flagstat .map{ _meta, txt -> return txt }, + BAM_QC.out.samtools_idxstats .map{ _meta, txt -> return txt }, + BAM_QC.out.picard_multiplemetrics .map{ _meta, txt -> return txt }, + BAM_QC.out.picard_wgsmetrics .map{ _meta, txt -> return txt }, + BAM_QC.out.picard_hsmetrics .map{ _meta, txt -> return txt }, ) ch_versions = ch_versions.mix(BAM_QC.out.versions) @@ -374,7 +374,8 @@ workflow PREPROCESSING { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - MD5SUM(FASTQ_TO_CRAM.out.cram_crai.map{ meta, cram, crai -> return [meta,cram] }, false) + MD5SUM(FASTQ_TO_CRAM.out.cram_crai.map{ meta, cram, _crai -> return [meta,cram] }, false) + ch_versions = ch_versions.mix(MD5SUM.out.versions.first()) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -445,8 +446,8 @@ def readgroup_from_fastq(path) { if (fields.size() >= 7) { // CASAVA 1.8+ format, from https://support.illumina.com/help/BaseSpace_OLH_009008/Content/Source/Informatics/BS/FileFormat_FASTQ-files_swBS.htm // "@::::::: :::" - def sequencer_serial = fields[0] - def run_nubmer = fields[1] + // def sequencer_serial = fields[0] + // def run_number = fields[1] def fcid = fields[2] def lane = fields[3] def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" From b69fc6a0f7d7cd6d34e0d1d7e09ebeae14ba8667 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 11 Sep 2025 11:32:45 +0200 Subject: [PATCH 006/228] Update regex pattern for BED file path validation Fixes #131 --- assets/schema_input.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index beaa2eb6..c6521e05 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -69,7 +69,7 @@ "type": "string", "format": "file-path", "description": "Region of interest BED file for coverage analysis", - "pattern": "^[a-zA-Z0-9_]+.bed$", + "pattern": "^.*/[^/]+\.bed$", "default": null }, "lane": { From d931a683e5af5371440f5c80724b1a9811603624 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:14:09 +0200 Subject: [PATCH 007/228] linting --- assets/multiqc_config.yml | 2 +- assets/schema_input.json | 2 +- nextflow.config | 4 ++-- nf-test.config | 7 +++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index f0b699ec..e8d8173d 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -8,7 +8,7 @@ report_section_order: order: -1001 "nf-cmgg-preprocessing-summary": order: -1002 -export_plots: false +export_plots: true disable_version_detection: true bclconvert: create_undetermined_barcode_barplots: true diff --git a/assets/schema_input.json b/assets/schema_input.json index c6521e05..0e0d30d9 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -69,7 +69,7 @@ "type": "string", "format": "file-path", "description": "Region of interest BED file for coverage analysis", - "pattern": "^.*/[^/]+\.bed$", + "pattern": "^.*/[^/]+\\.bed$", "default": null }, "lane": { diff --git a/nextflow.config b/nextflow.config index 27cb9abd..3aeba7ac 100644 --- a/nextflow.config +++ b/nextflow.config @@ -66,8 +66,8 @@ params { // Load base.config by default for all pipelines includeConfig 'conf/base.config' -// Load nf-core custom profiles from different Institutions -includeConfig "${params.custom_config_base}/nfcore_custom.config" +// Load nf-core custom profiles from different institutions +includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" // Load nf-cmgg cluster profiles includeConfig !System.getenv('NXF_OFFLINE') ? "https://raw.githubusercontent.com/nf-cmgg/configs/main/clusters/cmgg_clusters.config" : "/dev/null" diff --git a/nf-test.config b/nf-test.config index 0688f302..aa727c88 100644 --- a/nf-test.config +++ b/nf-test.config @@ -1,8 +1,7 @@ config { - - testsDir "tests" - workDir ".nf-test" - configFile "tests/config/nf-test.config" + testsDir "." + workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + configFile "tests/nextflow.config" profile "docker" options "-dump-channels" From 4292758404aec0ff7a0bb75b1954cafbcb497fd3 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:09:24 +0200 Subject: [PATCH 008/228] Update assets/schema_input.json Co-authored-by: Nicolas Vannieuwkerke <101190534+nvnieuwk@users.noreply.github.com> --- assets/schema_input.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index 0e0d30d9..e0ba1632 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -69,7 +69,7 @@ "type": "string", "format": "file-path", "description": "Region of interest BED file for coverage analysis", - "pattern": "^.*/[^/]+\\.bed$", + "pattern": "^\\S+\\.bed$", "default": null }, "lane": { From b173054a50c9d14a3b480b63968be633a9c0dbff Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 11 Sep 2025 11:32:45 +0200 Subject: [PATCH 009/228] Update regex pattern for BED file path validation Fixes #131 --- assets/schema_input.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index beaa2eb6..c6521e05 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -69,7 +69,7 @@ "type": "string", "format": "file-path", "description": "Region of interest BED file for coverage analysis", - "pattern": "^[a-zA-Z0-9_]+.bed$", + "pattern": "^.*/[^/]+\.bed$", "default": null }, "lane": { From 1b340515f7f47e3f17c62e9f39566193140c0aca Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:14:09 +0200 Subject: [PATCH 010/228] linting --- assets/multiqc_config.yml | 2 +- assets/schema_input.json | 2 +- nextflow.config | 4 ++-- nf-test.config | 7 +++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index f0b699ec..e8d8173d 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -8,7 +8,7 @@ report_section_order: order: -1001 "nf-cmgg-preprocessing-summary": order: -1002 -export_plots: false +export_plots: true disable_version_detection: true bclconvert: create_undetermined_barcode_barplots: true diff --git a/assets/schema_input.json b/assets/schema_input.json index c6521e05..0e0d30d9 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -69,7 +69,7 @@ "type": "string", "format": "file-path", "description": "Region of interest BED file for coverage analysis", - "pattern": "^.*/[^/]+\.bed$", + "pattern": "^.*/[^/]+\\.bed$", "default": null }, "lane": { diff --git a/nextflow.config b/nextflow.config index 27cb9abd..3aeba7ac 100644 --- a/nextflow.config +++ b/nextflow.config @@ -66,8 +66,8 @@ params { // Load base.config by default for all pipelines includeConfig 'conf/base.config' -// Load nf-core custom profiles from different Institutions -includeConfig "${params.custom_config_base}/nfcore_custom.config" +// Load nf-core custom profiles from different institutions +includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" // Load nf-cmgg cluster profiles includeConfig !System.getenv('NXF_OFFLINE') ? "https://raw.githubusercontent.com/nf-cmgg/configs/main/clusters/cmgg_clusters.config" : "/dev/null" diff --git a/nf-test.config b/nf-test.config index 0688f302..aa727c88 100644 --- a/nf-test.config +++ b/nf-test.config @@ -1,8 +1,7 @@ config { - - testsDir "tests" - workDir ".nf-test" - configFile "tests/config/nf-test.config" + testsDir "." + workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + configFile "tests/nextflow.config" profile "docker" options "-dump-channels" From 2dfe6e8273236404bb88c1cd9a197143f3a83af5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:09:24 +0200 Subject: [PATCH 011/228] Update assets/schema_input.json Co-authored-by: Nicolas Vannieuwkerke <101190534+nvnieuwk@users.noreply.github.com> --- assets/schema_input.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index 0e0d30d9..e0ba1632 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -69,7 +69,7 @@ "type": "string", "format": "file-path", "description": "Region of interest BED file for coverage analysis", - "pattern": "^.*/[^/]+\\.bed$", + "pattern": "^\\S+\\.bed$", "default": null }, "lane": { From b4c6e2b7a3b4f802498a0fbe9f72b3184b1a039b Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:10:25 +0200 Subject: [PATCH 012/228] nextflow lint all the things --- conf/base.config | 40 +- conf/igenomes.config | 137 +++-- conf/modules.config | 313 +++++------ conf/profiles/WES.config | 10 +- conf/profiles/WGS.config | 10 +- conf/profiles/copgt.config | 16 +- conf/profiles/s3_ugent.config | 4 +- conf/profiles/sWGS.config | 7 +- conf/test.config | 20 +- conf/test_full.config | 4 +- main.nf | 81 ++- modules/local/panelcoverage/main.nf | 14 +- nextflow.config | 2 +- subworkflows/local/bam_qc/main.nf | 64 ++- subworkflows/local/coverage/main.nf | 100 ++-- subworkflows/local/fastq_align_rna/main.nf | 52 +- .../local/fastq_to_aligned_cram/main.nf | 186 +++---- .../local/fastq_to_unaligned_cram/main.nf | 61 +-- .../main.nf | 67 ++- tests/config/igenomes_test.config | 16 +- tests/config/nf-test.config | 6 +- workflows/preprocessing.nf | 496 +++++++++--------- 22 files changed, 862 insertions(+), 844 deletions(-) diff --git a/conf/base.config b/conf/base.config index 5008f965..2caf89e5 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,45 +10,45 @@ process { - cpus = { 1 * task.attempt } - memory = { 8.GB * task.attempt } - time = { 4.h * task.attempt } + cpus = { 1 * task.attempt } + memory = { 8.GB * task.attempt } + time = { 4.h * task.attempt } errorStrategy = { task.exitStatus in ((130..145) + 104) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' // Process-specific resource requirements - withLabel:process_single { - cpus = { 1 } + withLabel: process_single { + cpus = { 1 } memory = { 8.GB * task.attempt } - time = { 4.h * task.attempt } + time = { 4.h * task.attempt } } - withLabel:process_low { - cpus = { 2 * task.attempt } + withLabel: process_low { + cpus = { 2 * task.attempt } memory = { 16.GB * task.attempt } - time = { 4.h * task.attempt } + time = { 4.h * task.attempt } } - withLabel:process_medium { - cpus = { 8 * task.attempt } + withLabel: process_medium { + cpus = { 8 * task.attempt } memory = { 64.GB * task.attempt } - time = { 8.h * task.attempt } + time = { 8.h * task.attempt } } - withLabel:process_high { - cpus = { 16 * task.attempt } + withLabel: process_high { + cpus = { 16 * task.attempt } memory = { 128.GB * task.attempt } - time = { 16.h * task.attempt } + time = { 16.h * task.attempt } } - withLabel:process_long { - time = { 72.h * task.attempt } + withLabel: process_long { + time = { 72.h * task.attempt } } - withLabel:process_high_memory { + withLabel: process_high_memory { memory = { 200.GB * task.attempt } } - withLabel:error_ignore { + withLabel: error_ignore { errorStrategy = 'ignore' } - withLabel:error_retry { + withLabel: error_retry { errorStrategy = 'retry' maxRetries = 2 } diff --git a/conf/igenomes.config b/conf/igenomes.config index 07e67809..27ed34c8 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -10,97 +10,96 @@ params { genomes { - "GRCh38" { + GRCh38 { // Genome reference - fai = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set.fna.fai" - fasta = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set.fna" - dict = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set.dict" - gtf = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_analysis_set.refseq_annotation.gtf" + fai = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set.fna.fai" + fasta = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set.fna" + dict = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set.dict" + gtf = "${params.igenomes_base}/Hsapiens/GRCh38/seq/GCA_000001405.15_GRCh38_full_analysis_set.refseq_annotation.gtf" // Aligner reference - bowtie2 = "${params.igenomes_base}/Hsapiens/GRCh38/bowtie2" - bwamem = "${params.igenomes_base}/Hsapiens/GRCh38/bwa" - bwamem2 = "${params.igenomes_base}/Hsapiens/GRCh38/bwamem2" - dragmap = "${params.igenomes_base}/Hsapiens/GRCh38/dragmap" - snap = "${params.igenomes_base}/Hsapiens/GRCh38/snapaligner" - star = "${params.igenomes_base}/Hsapiens/GRCh38/star" + bowtie2 = "${params.igenomes_base}/Hsapiens/GRCh38/bowtie2" + bwamem = "${params.igenomes_base}/Hsapiens/GRCh38/bwa" + bwamem2 = "${params.igenomes_base}/Hsapiens/GRCh38/bwamem2" + dragmap = "${params.igenomes_base}/Hsapiens/GRCh38/dragmap" + snap = "${params.igenomes_base}/Hsapiens/GRCh38/snapaligner" + star = "${params.igenomes_base}/Hsapiens/GRCh38/star" // ROI's - roi_copgt = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_coPGT-M_analyses_ROI_v1.bed" - roi_wes = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v6.bed" + roi_copgt = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_coPGT-M_analyses_ROI_v1.bed" + roi_wes = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v6.bed" } - "GRCm39" { + GRCm39 { // Genome reference - fai = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.fna.fai" - fasta = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.fna" - dict = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.dict" - gtf = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.gtf" + fai = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.fna.fai" + fasta = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.fna" + dict = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.dict" + gtf = "${params.igenomes_base}/Mmusculus/GRCm39/seq/GCF_000001635.27_GRCm39_genomic.gtf" // Aligner reference - bowtie2 = "${params.igenomes_base}/Mmusculus/GRCm39/bowtie2" - bwamem = "${params.igenomes_base}/Mmusculus/GRCm39/bwa" - bwamem2 = "${params.igenomes_base}/Mmusculus/GRCm39/bwamem2" - dragmap = "${params.igenomes_base}/Mmusculus/GRCm39/dragmap" - snap = "${params.igenomes_base}/Mmusculus/GRCm39/snapaligner" - star = "${params.igenomes_base}/Mmusculus/GRCm39/star" + bowtie2 = "${params.igenomes_base}/Mmusculus/GRCm39/bowtie2" + bwamem = "${params.igenomes_base}/Mmusculus/GRCm39/bwa" + bwamem2 = "${params.igenomes_base}/Mmusculus/GRCm39/bwamem2" + dragmap = "${params.igenomes_base}/Mmusculus/GRCm39/dragmap" + snap = "${params.igenomes_base}/Mmusculus/GRCm39/snapaligner" + star = "${params.igenomes_base}/Mmusculus/GRCm39/star" } - "mm10" { + mm10 { // Genome reference - fai = "${params.igenomes_base}/Mmusculus/mm10/seq/mm10.fa.fai" - fasta = "${params.igenomes_base}/Mmusculus/mm10/seq/mm10.fa" - dict = "${params.igenomes_base}/Mmusculus/mm10/seq/mm10.dict" - gtf = "${params.igenomes_base}/Mmusculus/mm10/seq/Mus_musculus.GRCm38.102.chr.gtf" + fai = "${params.igenomes_base}/Mmusculus/mm10/seq/mm10.fa.fai" + fasta = "${params.igenomes_base}/Mmusculus/mm10/seq/mm10.fa" + dict = "${params.igenomes_base}/Mmusculus/mm10/seq/mm10.dict" + gtf = "${params.igenomes_base}/Mmusculus/mm10/seq/Mus_musculus.GRCm38.102.chr.gtf" // Aligner reference - bowtie2 = "${params.igenomes_base}/Mmusculus/mm10/bowtie2" - bwamem = "${params.igenomes_base}/Mmusculus/mm10/bwa" - bwamem2 = "${params.igenomes_base}/Mmusculus/mm10/bwamem2" - dragmap = "${params.igenomes_base}/Mmusculus/mm10/dragmap" - snap = "${params.igenomes_base}/Mmusculus/mm10/snapaligner" - star = "${params.igenomes_base}/Mmusculus/mm10/star" + bowtie2 = "${params.igenomes_base}/Mmusculus/mm10/bowtie2" + bwamem = "${params.igenomes_base}/Mmusculus/mm10/bwa" + bwamem2 = "${params.igenomes_base}/Mmusculus/mm10/bwamem2" + dragmap = "${params.igenomes_base}/Mmusculus/mm10/dragmap" + snap = "${params.igenomes_base}/Mmusculus/mm10/snapaligner" + star = "${params.igenomes_base}/Mmusculus/mm10/star" } - "GRCz11" { + GRCz11 { // Genome reference - fai = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.fna.fai" - fasta = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.fna" - dict = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.dict" - gtf = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.gtf" + fai = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.fna.fai" + fasta = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.fna" + dict = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.dict" + gtf = "${params.igenomes_base}/Drerio/GRCz11/seq/GCF_000002035.6_GRCz11_genomic.gtf" // Aligner reference - bowtie2 = "${params.igenomes_base}/Drerio/GRCz11/bowtie2" - bwamem = "${params.igenomes_base}/Drerio/GRCz11/bwa" - bwamem2 = "${params.igenomes_base}/Drerio/GRCz11/bwamem2" - dragmap = "${params.igenomes_base}/Drerio/GRCz11/dragmap" - snap = "${params.igenomes_base}/Drerio/GRCz11/snapaligner" - star = "${params.igenomes_base}/Drerio/GRCz11/star" + bowtie2 = "${params.igenomes_base}/Drerio/GRCz11/bowtie2" + bwamem = "${params.igenomes_base}/Drerio/GRCz11/bwa" + bwamem2 = "${params.igenomes_base}/Drerio/GRCz11/bwamem2" + dragmap = "${params.igenomes_base}/Drerio/GRCz11/dragmap" + snap = "${params.igenomes_base}/Drerio/GRCz11/snapaligner" + star = "${params.igenomes_base}/Drerio/GRCz11/star" } // Legacy bcbio references - "hg38" { - fai = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.fa.fai" - fasta = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.fa" - dict = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.dict" - gtf = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.gtf" + hg38 { + fai = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.fa.fai" + fasta = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.fa" + dict = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.dict" + gtf = "${params.igenomes_base}/Hsapiens/hg38/seq/hg38.gtf" - bowtie2 = "${params.igenomes_base}/Hsapiens/hg38/bowtie2" - bwamem = "${params.igenomes_base}/Hsapiens/hg38/bwa" - bwamem2 = "${params.igenomes_base}/Hsapiens/hg38/bwamem2" - dragmap = "${params.igenomes_base}/Hsapiens/hg38/dragmap" - snap = "${params.igenomes_base}/Hsapiens/hg38/snapaligner" - star = "${params.igenomes_base}/Hsapiens/hg38/star" + bowtie2 = "${params.igenomes_base}/Hsapiens/hg38/bowtie2" + bwamem = "${params.igenomes_base}/Hsapiens/hg38/bwa" + bwamem2 = "${params.igenomes_base}/Hsapiens/hg38/bwamem2" + dragmap = "${params.igenomes_base}/Hsapiens/hg38/dragmap" + snap = "${params.igenomes_base}/Hsapiens/hg38/snapaligner" + star = "${params.igenomes_base}/Hsapiens/hg38/star" } - "hg38-noalt" { - fai = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.fa.fai" - fasta = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.fa" - dict = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.dict" - gtf = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.gtf" + 'hg38-noalt' { + fai = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.fa.fai" + fasta = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.fa" + dict = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.dict" + gtf = "${params.igenomes_base}/Hsapiens/hg38-noalt/seq/hg38-noalt.gtf" - bowtie2 = "${params.igenomes_base}/Hsapiens/hg38-noalt/bowtie2" - bwamem = "${params.igenomes_base}/Hsapiens/hg38-noalt/bwa" - bwamem2 = "${params.igenomes_base}/Hsapiens/hg38-noalt/bwamem2" - dragmap = "${params.igenomes_base}/Hsapiens/hg38-noalt/dragmap" - snap = "${params.igenomes_base}/Hsapiens/hg38-noalt/snapaligner" - star = "${params.igenomes_base}/Hsapiens/hg38-noalt/star" + bowtie2 = "${params.igenomes_base}/Hsapiens/hg38-noalt/bowtie2" + bwamem = "${params.igenomes_base}/Hsapiens/hg38-noalt/bwa" + bwamem2 = "${params.igenomes_base}/Hsapiens/hg38-noalt/bwamem2" + dragmap = "${params.igenomes_base}/Hsapiens/hg38-noalt/dragmap" + snap = "${params.igenomes_base}/Hsapiens/hg38-noalt/snapaligner" + star = "${params.igenomes_base}/Hsapiens/hg38-noalt/star" } } } - diff --git a/conf/modules.config b/conf/modules.config index 3def8896..4860b8e9 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -13,93 +13,93 @@ process { publishDir = [ - path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}"}, + path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals("versions.yml") ? null : filename } + saveAs: { filename -> filename.equals("versions.yml") ? null : filename }, ] // BCL convert withName: BCLCONVERT { - ext.args = {[ - meta.lane ? "--bcl-only-lane ${meta.lane}" : "", - "--force", - "--bcl-num-parallel-tiles ${task.cpus}", - "--bcl-num-conversion-threads ${task.cpus}", - "--bcl-num-compression-threads ${task.cpus}", - ].join(" ").trim()} + ext.args = { + [ + meta.lane ? "--bcl-only-lane ${meta.lane}" : "", + "--force", + "--bcl-num-parallel-tiles ${task.cpus}", + "--bcl-num-conversion-threads ${task.cpus}", + "--bcl-num-compression-threads ${task.cpus}", + ].join(" ").trim() + } publishDir = [ [ - // Gather and write InterOp files path: { "${params.outdir}/InterOp" }, mode: params.publish_dir_mode, overwrite: true, pattern: "**.bin", - saveAs: {filename -> filename.split("/")[-1] } + saveAs: { filename -> filename.split("/")[-1] }, ], [ - // Fetch RunInfo.xml path: { meta.lane ? "${params.outdir}/Reports/L00${meta.lane}" : "${params.outdir}/Reports/" }, mode: params.publish_dir_mode, pattern: "RunInfo.xml", overwrite: true, - saveAs: {filename -> filename.split("/")[-1] } + saveAs: { filename -> filename.split("/")[-1] }, ], [ - // Gather and write Reports path: { meta.lane ? "${params.outdir}/Reports/L00${meta.lane}" : "${params.outdir}/Reports/" }, mode: params.publish_dir_mode, pattern: "Reports", overwrite: true, - saveAs: {filename -> filename.split("/")[-1] } + saveAs: { filename -> filename.split("/")[-1] }, ], [ - // Gather and write Logs path: { meta.lane ? "${params.outdir}/Logs/L00${meta.lane}" : "${params.outdir}/Logs/" }, mode: params.publish_dir_mode, pattern: "Logs", overwrite: true, - saveAs: {filename -> filename.split("/")[-1] } + saveAs: { filename -> filename.split("/")[-1] }, ], [ - // don't write the fastq's pattern: "**.fastq.gz", - enabled: false - ] + enabled: false, + ], ] } // FastP withName: FASTP { - ext.args = {[ - meta.single_end && reads.size() > 5000000000 ? "--split_by_lines 400000000": "", - !meta.single_end && reads.any{ f -> f.size() > 5000000000 } ? "--split_by_lines 400000000": "", - params.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", - params.trim_front > 0 ? "--trim_front1 ${params.trim_front}" : "", - params.trim_tail > 0 ? "--trim_tail1 ${params.trim_tail}" : "", - params.adapter_R1 ? "--adapter_sequence ${params.adapter_R1}" : "", - params.adapter_R2 ? "--adapter_sequence_r2 ${params.adapter_R2}" : "", - "--compression 1" - ].join(" ").trim()} + ext.args = { + [ + meta.single_end && reads.size() > 5000000000 ? "--split_by_lines 400000000" : "", + !meta.single_end && reads.any { f -> f.size() > 5000000000 } ? "--split_by_lines 400000000" : "", + params.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", + params.trim_front > 0 ? "--trim_front1 ${params.trim_front}" : "", + params.trim_tail > 0 ? "--trim_tail1 ${params.trim_tail}" : "", + params.adapter_R1 ? "--adapter_sequence ${params.adapter_R1}" : "", + params.adapter_R2 ? "--adapter_sequence_r2 ${params.adapter_R2}" : "", + "--compression 1", + ].join(" ").trim() + } publishDir = [ [ path: { "${params.outdir}/${meta.samplename}" }, mode: params.publish_dir_mode, - pattern: "*.{html,json}" - ], + pattern: "*.{html,json}", + ] ] } // FASTQ_TO_UCRAM //// Samtools Import - withName: ".*FASTQ_TO_UCRAM:SAMTOOLS_IMPORT" { - label = "process_medium" - // WARNING: Do NOT escape the RG tag tabs when adding a readgroup - ext.args = {[ - meta.readgroup ? "--rg-line \"@RG\t" + meta.readgroup.findResults{ it.value?.trim() ? "$it.key:$it.value" : null }.join("\t") + "\"" : "", - "--output-fmt cram", - "--output-fmt-option archive" - ].join(" ").trim()} - publishDir = [ enabled: false ] + withName: '.*FASTQ_TO_UCRAM:SAMTOOLS_IMPORT' { + label = "process_medium" + ext.args = { + [ + meta.readgroup ? "--rg-line \"@RG\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\t") + "\"" : "", + "--output-fmt cram", + "--output-fmt-option archive", + ].join(" ").trim() + } + publishDir = [enabled: false] } // FASTQ_TO_CRAM @@ -115,44 +115,50 @@ process { // FASTQ_ALIGN_DNA - withName:".*:FASTQ_ALIGN_DNA:.*" { - publishDir = [ enabled: false ] + withName: '.*:FASTQ_ALIGN_DNA:.*' { + publishDir = [enabled: false] } //// Bowtie2 withName: BOWTIE2_ALIGN { - ext.args = {[ - "--local", - "--fast-local", - meta.readgroup ? "--rg-id ${meta.readgroup.ID}": "", - meta.readgroup ? "--rg " + meta.readgroup.findResults{ it.value?.trim() ? "$it.key:$it.value" : null }.join(" --rg ") : "" - ].join(" ").trim()} - ext.args2 = "--fast" + ext.args = { + [ + "--local", + "--fast-local", + meta.readgroup ? "--rg-id ${meta.readgroup.ID}" : "", + meta.readgroup ? "--rg " + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join(" --rg ") : "", + ].join(" ").trim() + } + ext.args2 = "--fast" publishDir = [ - path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}"}, + path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}" }, mode: params.publish_dir_mode, - pattern: "*.log" + pattern: "*.log", ] } //// BWA mem/BWA mem2 - withName: "BWAMEM.*_MEM" { - ext.args = {[ - "-K 100000000", - "-p", - "-v 3", - "-Y", - "-c 250", - meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults{ it.value?.trim() ? "$it.key:$it.value" : null }.join("\\t") + "\"" : "" - ].join(" ").trim()} + withName: 'BWAMEM.*_MEM' { + ext.args = { + [ + "-K 100000000", + "-p", + "-v 3", + "-Y", + "-c 250", + meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\\t") + "\"" : "", + ].join(" ").trim() + } ext.args2 = "--fast" } //// DRAGEN withName: DRAGMAP_ALIGN { - ext.args = {[ - meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults{ it.value?.trim() ? "$it.key:$it.value" : null }.join("\\t") + "\"" : "" - ].join(" ").trim()} + ext.args = { + [ + meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\\t") + "\"" : "" + ].join(" ").trim() + } ext.args2 = "--fast" } @@ -166,151 +172,147 @@ process { //// SNAP withName: SNAP_ALIGN { - ext.args = {[ - "-b-", - "-sm 20", - "-I", - "-hc-", - "-S id", - "-sa", - "-xf 2", - meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults{ it.value?.trim() ? "$it.key:$it.value" : null }.join("\\t") + "\"" : "" - ].join(" ").trim()} + ext.args = { + [ + "-b-", + "-sm 20", + "-I", + "-hc-", + "-S id", + "-sa", + "-xf 2", + meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\\t") + "\"" : "", + ].join(" ").trim() + } } // FASTQ_ALIGN_RNA - withName:".*FASTQ_ALIGN_RNA:.*" { - publishDir = [ enabled: false ] + withName: '.*FASTQ_ALIGN_RNA:.*' { + publishDir = [enabled: false] } withName: STAR_ALIGN { - ext.args = {[ - // support compressed inputs - "--readFilesCommand gunzip -c", - // basic 2-pass mapping, with all 1st pass junctions inserted into the genome indices on the fly - "--twopassMode Basic", - // output unsorted BAM - "--outSAMtype BAM Unsorted", - // output unmapped reads in the unsorted bam file - "--outSAMunmapped Within", - // output all the fields in the SAM format - "--outSAMattributes All", - // the minimum mapped length of two segments in a chimeric alignment - "--chimSegmentMin 20", - // alignment will be output only if it has no more mismatches than this value. - "--outFilterMismatchNmax 4", - // set the readgroup info, if available. Flag arg MUST start with 'ID' tag - meta.readgroup ? "--outSAMattrRGline \"ID:${meta.readgroup.ID}" + meta.readgroup.findResults{ it.value?.trim() && it.key != "ID" ? "$it.key:$it.value" : null }.join(" ") + "\"" : "" - ].join(" ").trim()} + ext.args = { + [ + "--readFilesCommand gunzip -c", + "--twopassMode Basic", + "--outSAMtype BAM Unsorted", + "--outSAMunmapped Within", + "--outSAMattributes All", + "--chimSegmentMin 20", + "--outFilterMismatchNmax 4", + meta.readgroup ? "--outSAMattrRGline \"ID:${meta.readgroup.ID}" + meta.readgroup.findResults { it.value?.trim() && it.key != "ID" ? "${it.key}:${it.value}" : null }.join(" ") + "\"" : "", + ].join(" ").trim() + } } //// Samtools sormadup - withName: ".*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP" { - ext.prefix = {"${meta.id}.merged"} - ext.args5 = {[ - "-s", // print some stats - "--json", // output stats in json format for MultiQC - "-d 2500", // The optical duplicate distance - params.umi_aware ? "--barcode-name" : "", // Use the UMI/barcode embedded in the read name (eigth colon delimited part). - "--write-index", // Write csi/crai index - "--output-fmt cram", // Output format - "--output-fmt-option archive" // Cram compression level - ].join(" ").trim()} + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { + ext.prefix = { "${meta.id}.merged" } + ext.args5 = { + [ + "-s", + "--json", + "-d 2500", + params.umi_aware ? "--barcode-name" : "", + "--write-index", + "--output-fmt cram", + "--output-fmt-option archive", + ].join(" ").trim() + } publishDir = [ [ path: { "${params.outdir}/${meta.samplename}" }, mode: params.publish_dir_mode, pattern: "*metrics*", - saveAs: {filename -> filename.replace("metrics", "duplicate_metrics").replace(".merged","")} + saveAs: { filename -> filename.replace("metrics", "duplicate_metrics").replace(".merged", "") }, ], [ path: { "${params.outdir}/${meta.samplename}" }, mode: params.publish_dir_mode, pattern: "*cram*", - saveAs: {filename -> filename.replace(".merged", "")} + saveAs: { filename -> filename.replace(".merged", "") }, ], ] } //// Samtools multisort - withName: ".*FASTQ_TO_CRAM:SAMTOOLS_SORT" { - ext.prefix = {"${meta.id}.merged"} - ext.args = {[ - "--write-index", - "--output-fmt cram", - "--output-fmt-option archive" - ].join(" ").trim()} + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { + ext.prefix = { "${meta.id}.merged" } + ext.args = { + [ + "--write-index", + "--output-fmt cram", + "--output-fmt-option archive", + ].join(" ").trim() + } publishDir = [ [ path: { "${params.outdir}/${meta.samplename}" }, mode: params.publish_dir_mode, pattern: "*cram*", - saveAs: {filename -> filename.replace(".merged", "")} - ], + saveAs: { filename -> filename.replace(".merged", "") }, + ] ] } //// BioBamBam Bamsormadup - withName: ".*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP" { - ext.prefix = {"${meta.id}.merged"} - ext.args = {[ - "indexfilename=${meta.id}.merged.bam.bai", - "optminpixeldif=2500" - ].join(" ").trim()} - ext.args2 = "exclude=QCFAIL" + withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' { + ext.prefix = { "${meta.id}.merged" } + ext.args = { + [ + "indexfilename=${meta.id}.merged.bam.bai", + "optminpixeldif=2500", + ].join(" ").trim() + } + ext.args2 = "exclude=QCFAIL" publishDir = [ [ path: { "${params.outdir}/${meta.samplename}" }, mode: params.publish_dir_mode, pattern: "*metrics*", - saveAs: {filename -> filename.replace("metrics", "duplicate_metrics").replace(".merged","")} + saveAs: { filename -> filename.replace("metrics", "duplicate_metrics").replace(".merged", "") }, ] ] } //// Samtools convert - withName: ".*FASTQ_TO_CRAM:SAMTOOLS_CONVERT" { - cpus = 8 - memory = 64.GB - ext.args = {[ - "-C", - "--output-fmt cram", - "--output-fmt-option archive" - ].join(" ").trim()} + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' { + cpus = 8 + memory = 64.GB + ext.args = { + [ + "-C", + "--output-fmt cram", + "--output-fmt-option archive", + ].join(" ").trim() + } publishDir = [ [ path: { "${params.outdir}/${meta.samplename}" }, mode: params.publish_dir_mode, pattern: "*cram*", - saveAs: {filename -> filename.replace(".merged", "")} - ], + saveAs: { filename -> filename.replace(".merged", "") }, + ] ] } // coverage //// Mosdepth - withName: ".*COVERAGE:MOSDEPTH" { - cpus = 4 - memory = { 4.GB * task.attempt } - // filter reads with flag 1804 - // read unmapped (0x4) - // mate unmapped (0x8)* - // not primary alignment (0x100) - // read fails platform/vendor quality checks (0x200) - // read is PCR or optical duplicate (0x400) - // filter reads with MAPQ < 1 - // quantize coverage to 4 bins + withName: '.*COVERAGE:MOSDEPTH' { + cpus = 4 + memory = { 4.GB * task.attempt } ext.args = [ "--flag 1804", "--mapq 1", - "--quantize 0:1:4:" + "--quantize 0:1:4:", ].join(" ").trim() } //// Samtools coverage - withName: ".*:COVERAGE:SAMTOOLS_COVERAGE" { - ext.prefix = {"${meta.id}.coverage"} + withName: '.*:COVERAGE:SAMTOOLS_COVERAGE' { + ext.prefix = { "${meta.id}.coverage" } } //// CoverageQC (Multiqc) @@ -325,34 +327,33 @@ process { path: { "${params.outdir}/${meta.samplename}" }, mode: params.publish_dir_mode, pattern: "*.md5", - saveAs: {filename -> filename.replace(".merged", "")} + saveAs: { filename -> filename.replace(".merged", "") }, ] ] } // QC - withName: ".*BAM_QC.*" { + withName: '.*BAM_QC.*' { cpus = 1 } //// Picard - withName: ".*PICARD.*" { - memory = { 8.GB * task.attempt } + withName: '.*PICARD.*' { + memory = { 8.GB * task.attempt } ext.args = "--MAX_RECORDS_IN_RAM 15000000" } // MultiQC - withName: 'MULTIQC' { - ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } + withName: MULTIQC { + ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } publishDir = [ path: { "${params.outdir}/multiqc" }, mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, ] } - } env { diff --git a/conf/profiles/WES.config b/conf/profiles/WES.config index ea2298c4..cc0a4acc 100644 --- a/conf/profiles/WES.config +++ b/conf/profiles/WES.config @@ -1,7 +1,7 @@ params { - aligner = "snap" - run_coverage = true - disable_picard_metrics = false - roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v6.bed" - genelists = "${params.igenomes_base}/Hsapiens/GRCh38/regions/genelists" + aligner = "snap" + run_coverage = true + disable_picard_metrics = false + roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v6.bed" + genelists = "${params.igenomes_base}/Hsapiens/GRCh38/regions/genelists" } diff --git a/conf/profiles/WGS.config b/conf/profiles/WGS.config index 39180f15..2e1f2c11 100644 --- a/conf/profiles/WGS.config +++ b/conf/profiles/WGS.config @@ -1,7 +1,7 @@ params { - aligner = "snap" - markdup = "samtools" - umi_aware = true - run_coverage = true - disable_picard_metrics = false + aligner = "snap" + markdup = "samtools" + umi_aware = true + run_coverage = true + disable_picard_metrics = false } diff --git a/conf/profiles/copgt.config b/conf/profiles/copgt.config index 71ba2c69..21a5bb45 100644 --- a/conf/profiles/copgt.config +++ b/conf/profiles/copgt.config @@ -1,14 +1,14 @@ params { - aligner = "snap" - run_coverage = true - disable_picard_metrics = true - roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_coPGT-M_analyses_ROI_v1.bed" + aligner = "snap" + run_coverage = true + disable_picard_metrics = true + roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_coPGT-M_analyses_ROI_v1.bed" // trimming options - skip_trimming = false - trim_front = 6 - adapter_R1 = "CAGATC" + skip_trimming = false + trim_front = 6 + adapter_R1 = "CAGATC" // markduplicates options - markdup = false + markdup = false } diff --git a/conf/profiles/s3_ugent.config b/conf/profiles/s3_ugent.config index 12648118..d29f80a0 100644 --- a/conf/profiles/s3_ugent.config +++ b/conf/profiles/s3_ugent.config @@ -1,7 +1,7 @@ aws { client { - endpoint = "https://s3.ugent.be" - protocol = "https" + endpoint = "https://s3.ugent.be" + protocol = "https" s3PathStyleAccess = true connectionTimeout = 60000 } diff --git a/conf/profiles/sWGS.config b/conf/profiles/sWGS.config index f34e5eb0..11be5b28 100644 --- a/conf/profiles/sWGS.config +++ b/conf/profiles/sWGS.config @@ -1,6 +1,5 @@ params { - aligner = "bowtie2" - run_coverage = false - disable_picard_metrics = true + aligner = "bowtie2" + run_coverage = false + disable_picard_metrics = true } - diff --git a/conf/test.config b/conf/test.config index 4b9d390e..930c4538 100644 --- a/conf/test.config +++ b/conf/test.config @@ -15,24 +15,26 @@ params { config_profile_description = 'Minimal test dataset to check pipeline function' // Input data - input = "${projectDir}/tests/inputs/fastq.yml" - igenomes_base = "s3://reference-data/genomes" - aligner = "bwamem" + input = "${projectDir}/tests/inputs/fastq.yml" + igenomes_base = "s3://reference-data/genomes" + aligner = "bwamem" } process { resourceLimits = [ cpus: 2, memory: 6.GB, - time: 6.h + time: 6.h, ] withName: BCLCONVERT { - ext.args = {[ - meta.lane ? "--bcl-only-lane ${meta.lane}" : "", - "--force", - "--first-tile-only true" - ].join(" ").trim()} + ext.args = { + [ + meta.lane ? "--bcl-only-lane ${meta.lane}" : "", + "--force", + "--first-tile-only true", + ].join(" ").trim() + } } } diff --git a/conf/test_full.config b/conf/test_full.config index 07c5c697..1d49a288 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -17,8 +17,8 @@ params { // Input data for full size test // TODO nf-core: Specify the paths to your full test data ( on nf-core/test-datasets or directly in repositories, e.g. SRA) // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' + input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' // Genome references - genome = 'R64-1-1' + genome = 'R64-1-1' } diff --git a/main.nf b/main.nf index 466854ee..4ef95130 100644 --- a/main.nf +++ b/main.nf @@ -18,43 +18,6 @@ nextflow.enable.dsl = 2 include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_preprocessing_pipeline' include { PREPROCESSING } from './workflows/preprocessing' include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_preprocessing_pipeline' - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - NAMED WORKFLOWS FOR PIPELINE -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -// -// WORKFLOW: Run main analysis pipeline depending on type of input -// -workflow NFCMGG_PREPROCESSING { - - take: - samplesheet // channel: samplesheet read in from --input - genomes // map: genome reference files - aligner // string: aligner to use - markdup // string: markdup method to use - roi // string: region of interest to use - genelists // file: directory containing genelist bed files for coverage analysis - main: - - // - // WORKFLOW: Run pipeline - // - PREPROCESSING ( - samplesheet, - genomes, - aligner, - markdup, - roi, - genelists - ) - - emit: - multiqc_report = PREPROCESSING.out.multiqc_report // channel: /path/to/multiqc_report.html - -} /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RUN MAIN WORKFLOW @@ -63,23 +26,21 @@ workflow NFCMGG_PREPROCESSING { workflow { - main: - // // SUBWORKFLOW: Run initialisation tasks // - PIPELINE_INITIALISATION ( + PIPELINE_INITIALISATION( params.version, params.validate_params, args, params.outdir, - params.input + params.input, ) // // WORKFLOW: Run main workflow // - NFCMGG_PREPROCESSING ( + NFCMGG_PREPROCESSING( PIPELINE_INITIALISATION.out.samplesheet, params.genomes, params.aligner, @@ -91,19 +52,49 @@ workflow { // // SUBWORKFLOW: Run completion tasks // - PIPELINE_COMPLETION ( + PIPELINE_COMPLETION( params.email, params.email_on_fail, params.plaintext_email, params.outdir, params.monochrome_logs, params.hook_url, - NFCMGG_PREPROCESSING.out.multiqc_report + NFCMGG_PREPROCESSING.out.multiqc_report, ) } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - THE END + NAMED WORKFLOWS FOR PIPELINE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +// +// WORKFLOW: Run main analysis pipeline depending on type of input +// +workflow NFCMGG_PREPROCESSING { + take: + samplesheet // channel: samplesheet read in from --input + genomes // map: genome reference files + aligner // string: aligner to use + markdup // string: markdup method to use + roi // string: region of interest to use + genelists // file: directory containing genelist bed files for coverage analysis + + main: + + // + // WORKFLOW: Run pipeline + // + PREPROCESSING( + samplesheet, + genomes, + aligner, + markdup, + roi, + genelists, + ) + + emit: + multiqc_report = PREPROCESSING.out.multiqc_report // channel: /path/to/multiqc_report.html +} diff --git a/modules/local/panelcoverage/main.nf b/modules/local/panelcoverage/main.nf index 7b38328a..a731f817 100644 --- a/modules/local/panelcoverage/main.nf +++ b/modules/local/panelcoverage/main.nf @@ -1,18 +1,18 @@ process PANELCOVERAGE { - tag "$meta.id" + tag "${meta.id}" label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bedtools:2.31.1--hf5e1c6e_1' : - 'biocontainers/bedtools:2.31.1--hf5e1c6e_1' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://depot.galaxyproject.org/singularity/bedtools:2.31.1--hf5e1c6e_1' + : 'biocontainers/bedtools:2.31.1--hf5e1c6e_1'}" input: tuple val(meta), path(perbase), path(perbase_index), path(genelists) output: tuple val(meta), path("*.mosdepth.region.dist.txt"), emit: regiondist - path "versions.yml" , emit: versions + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when @@ -20,7 +20,7 @@ process PANELCOVERAGE { script: def prefix = task.ext.prefix ?: "${meta.id}" """ - for GENELIST in $genelists + for GENELIST in ${genelists} do cmgg_genelists regiondist --samplename ${prefix} --perbase ${perbase} --genelist \$GENELIST done @@ -35,7 +35,7 @@ process PANELCOVERAGE { stub: def prefix = task.ext.prefix ?: "${meta.id}" """ - for GENELIST in $genelists + for GENELIST in ${genelists} do name=\$(basename \$GENELIST .bed) touch ${prefix}_\${name}.mosdepth.region.dist.txt diff --git a/nextflow.config b/nextflow.config index 3aeba7ac..00399037 100644 --- a/nextflow.config +++ b/nextflow.config @@ -250,7 +250,7 @@ dag { manifest { name = 'nf-cmgg/preprocessing' - author = """CMGG ICT team""" + contributors = """CMGG ICT team""" homePage = 'https://github.com/nf-cmgg/preprocessing' description = """Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.""" mainScript = 'main.nf' diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index 0cb82f0c..a87c62f6 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -1,7 +1,7 @@ // samtools modules -include { SAMTOOLS_STATS } from '../../../modules/nf-core/samtools/stats/main' -include { SAMTOOLS_IDXSTATS } from '../../../modules/nf-core/samtools/idxstats/main' -include { SAMTOOLS_FLAGSTAT } from '../../../modules/nf-core/samtools/flagstat/main' +include { SAMTOOLS_STATS } from '../../../modules/nf-core/samtools/stats/main' +include { SAMTOOLS_IDXSTATS } from '../../../modules/nf-core/samtools/idxstats/main' +include { SAMTOOLS_FLAGSTAT } from '../../../modules/nf-core/samtools/flagstat/main' // picard modules include { PICARD_COLLECTMULTIPLEMETRICS } from '../../../modules/nf-core/picard/collectmultiplemetrics/main' @@ -10,27 +10,31 @@ include { PICARD_COLLECTWGSMETRICS } from '../../../modules/nf-core/picard/ workflow BAM_QC { take: - ch_bam_bai_roi_fasta_fai_dict // channel: [ val(meta), path(bam), path(bai), path(roi), path(fasta), path(fai), path(dict)] - disable_picard // boolean + ch_bam_bai_roi_fasta_fai_dict // channel: [ val(meta), path(bam), path(bai), path(roi), path(fasta), path(fai), path(dict)] + disable_picard // boolean main: ch_versions = Channel.empty() ch_bam_bai_roi_fasta_fai_dict - .map{ meta, bam, bai, _roi, fasta, _fai, _dict -> return [meta, bam, bai, fasta]} - .set{ ch_bam_bai_fasta } + .map { meta, bam, bai, _roi, fasta, _fai, _dict -> + return [meta, bam, bai, fasta] + } + .set { ch_bam_bai_fasta } - SAMTOOLS_STATS ( ch_bam_bai_fasta ) + SAMTOOLS_STATS(ch_bam_bai_fasta) ch_versions = ch_versions.mix(SAMTOOLS_STATS.out.versions.first()) ch_bam_bai_fasta - .map{ meta, bam, bai, _fasta -> return [meta, bam, bai]} - .set{ ch_bam_bai } + .map { meta, bam, bai, _fasta -> + return [meta, bam, bai] + } + .set { ch_bam_bai } - SAMTOOLS_FLAGSTAT ( ch_bam_bai ) + SAMTOOLS_FLAGSTAT(ch_bam_bai) ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions.first()) - SAMTOOLS_IDXSTATS ( ch_bam_bai ) + SAMTOOLS_IDXSTATS(ch_bam_bai) ch_versions = ch_versions.mix(SAMTOOLS_IDXSTATS.out.versions.first()) ch_picard_hsmetrics = Channel.empty() @@ -39,37 +43,39 @@ workflow BAM_QC { if (!disable_picard) { ch_bam_bai_roi_fasta_fai_dict - .map{ meta, bam, bai, _roi, fasta, fai, _dict -> return [meta, bam, bai, fasta, fai]} - .set{ ch_bam_bai_fasta_fai } + .map { meta, bam, bai, _roi, fasta, fai, _dict -> + return [meta, bam, bai, fasta, fai] + } + .set { ch_bam_bai_fasta_fai } - PICARD_COLLECTMULTIPLEMETRICS ( ch_bam_bai_fasta_fai ) + PICARD_COLLECTMULTIPLEMETRICS(ch_bam_bai_fasta_fai) ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions.first()) ch_picard_multiplemetrics = ch_picard_multiplemetrics.mix(PICARD_COLLECTMULTIPLEMETRICS.out.metrics) ch_bam_bai_roi_fasta_fai_dict - .branch{ meta, bam, bai, roi, fasta, fai, dict -> - hsmetrics : roi != [] + .branch { meta, bam, bai, roi, fasta, fai, dict -> + hsmetrics: roi != [] return [meta, bam, bai, roi, roi, fasta, fai, dict] - wgsmetrics : roi == [] + wgsmetrics: roi == [] return [meta, bam, bai, fasta, fai] - } - .set{ch_picard} + } + .set { ch_picard } - PICARD_COLLECTWGSMETRICS ( ch_picard.wgsmetrics, [] ) + PICARD_COLLECTWGSMETRICS(ch_picard.wgsmetrics, []) ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) ch_picard_wgsmetrics = ch_picard_wgsmetrics.mix(PICARD_COLLECTWGSMETRICS.out.metrics) - PICARD_COLLECTHSMETRICS ( ch_picard.hsmetrics ) + PICARD_COLLECTHSMETRICS(ch_picard.hsmetrics) ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions.first()) ch_picard_hsmetrics = ch_picard_hsmetrics.mix(PICARD_COLLECTHSMETRICS.out.metrics) } emit: - samtools_stats = SAMTOOLS_STATS.out.stats - samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat - samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats - picard_multiplemetrics = ch_picard_multiplemetrics - picard_wgsmetrics = ch_picard_wgsmetrics - picard_hsmetrics = ch_picard_hsmetrics - versions = ch_versions + samtools_stats = SAMTOOLS_STATS.out.stats + samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat + samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats + picard_multiplemetrics = ch_picard_multiplemetrics + picard_wgsmetrics = ch_picard_wgsmetrics + picard_hsmetrics = ch_picard_hsmetrics + versions = ch_versions } diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 634ecf02..bf3b187b 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -1,69 +1,65 @@ #!/usr/bin/env nextflow // MODULES -include { MOSDEPTH } from "../../../modules/nf-core/mosdepth/main.nf" -include { SAMTOOLS_COVERAGE } from "../../../modules/nf-core/samtools/coverage/main" -include { PANELCOVERAGE } from "../../../modules/local/panelcoverage/main" +include { MOSDEPTH } from "../../../modules/nf-core/mosdepth/main.nf" +include { SAMTOOLS_COVERAGE } from "../../../modules/nf-core/samtools/coverage/main" +include { PANELCOVERAGE } from "../../../modules/local/panelcoverage/main" workflow COVERAGE { take: - ch_meta_cram_crai_fasta_fai_roi // channel: [mandatory] [meta, cram, crai, fasta, fai, roi] - ch_genelists // channel: [optional] [genelists] + ch_meta_cram_crai_fasta_fai_roi // channel: [mandatory] [meta, cram, crai, fasta, fai, roi] + ch_genelists // channel: [optional] [genelists] + main: - ch_versions = Channel.empty() - ch_coverageqc_files = Channel.empty() + ch_versions = Channel.empty() + ch_coverageqc_files = Channel.empty() - MOSDEPTH( - ch_meta_cram_crai_fasta_fai_roi.map{ - meta, cram, crai, fasta, _fai, roi -> - return [meta, cram, crai, roi, fasta] - } - ) - ch_versions = ch_versions.mix(MOSDEPTH.out.versions.first()) + MOSDEPTH( + ch_meta_cram_crai_fasta_fai_roi.map { meta, cram, crai, fasta, _fai, roi -> + return [meta, cram, crai, roi, fasta] + } + ) + ch_versions = ch_versions.mix(MOSDEPTH.out.versions.first()) - SAMTOOLS_COVERAGE( - ch_meta_cram_crai_fasta_fai_roi.map{ - meta, cram, crai, fasta, fai, _roi -> - return [meta, cram, crai, fasta, fai] - } - ) - ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) - ch_coverageqc_files = ch_coverageqc_files.merge(SAMTOOLS_COVERAGE.out.coverage) + SAMTOOLS_COVERAGE( + ch_meta_cram_crai_fasta_fai_roi.map { meta, cram, crai, fasta, fai, _roi -> + return [meta, cram, crai, fasta, fai] + } + ) + ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) + ch_coverageqc_files = ch_coverageqc_files.merge(SAMTOOLS_COVERAGE.out.coverage) - ch_genelists.view() + ch_genelists.view() - PANELCOVERAGE( - MOSDEPTH.out.per_base_bed - .join(MOSDEPTH.out.per_base_csi) - .combine(ch_genelists) - .map{meta, bed, index, genelists -> - if (genelists !instanceof List){ - // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... - genelists = [genelists] - } - def filtered_genelists = meta.tag.toLowerCase() == "seqcap" ? - genelists.findAll{it.name.toLowerCase().contains("seqcap")} : - genelists.findAll{!it.name.toLowerCase().contains("seqcap")} + PANELCOVERAGE( + MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> + if (genelists !instanceof List) { + // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... + genelists = [genelists] + } + def filtered_genelists = meta.tag.toLowerCase() == "seqcap" + ? genelists.findAll { it.name.toLowerCase().contains("seqcap") } + : genelists.findAll { !it.name.toLowerCase().contains("seqcap") } - if (filtered_genelists.size() > 0) { - return [ - meta, - bed, - index, - filtered_genelists - ] - } + if (filtered_genelists.size() > 0) { + return [ + meta, + bed, + index, + filtered_genelists, + ] } - ) - ch_versions = ch_versions.mix(PANELCOVERAGE.out.versions.first()) - ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) + } + ) + ch_versions = ch_versions.mix(PANELCOVERAGE.out.versions.first()) + ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) emit: - mosdepth_summary = MOSDEPTH.out.summary_txt - mosdepth_global = MOSDEPTH.out.global_txt - mosdepth_regions = MOSDEPTH.out.regions_txt - samtools_coverage = SAMTOOLS_COVERAGE.out.coverage - panelcoverage = PANELCOVERAGE.out.regiondist - versions = ch_versions + mosdepth_summary = MOSDEPTH.out.summary_txt + mosdepth_global = MOSDEPTH.out.global_txt + mosdepth_regions = MOSDEPTH.out.regions_txt + samtools_coverage = SAMTOOLS_COVERAGE.out.coverage + panelcoverage = PANELCOVERAGE.out.regiondist + versions = ch_versions } diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index e78ec428..859ca5a3 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -9,37 +9,39 @@ include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" workflow FASTQ_ALIGN_RNA { take: - ch_reads_aligner_index_gtf // channel: [mandatory] reads, aligner, index, gtf + ch_reads_aligner_index_gtf // channel: [mandatory] reads, aligner, index, gtf main: - ch_bam = Channel.empty() - ch_reports = Channel.empty() - ch_versions = Channel.empty() + ch_bam = Channel.empty() + ch_reports = Channel.empty() + ch_versions = Channel.empty() - ch_reads_aligner_index_gtf.branch { meta, reads, aligner, index, gtf -> + ch_reads_aligner_index_gtf + .branch { meta, reads, aligner, index, gtf -> star: aligner == 'star' - return [meta, reads, index, gtf] + return [meta, reads, index, gtf] other: true } - .set{ch_to_align} - - // Throw error for all samples with unsupported aligners - ch_to_align.other.map{ meta, _reads, aligner, _index, _fasta -> - error "Unsupported aligner ${aligner} for sample ${meta.id}" - } - - // Align fastq files to reference genome - STAR_ALIGN(ch_to_align.star, "Illumina", "CMGG") // if aligner is STAR - ch_bam = ch_bam.mix(STAR_ALIGN.out.bam) - ch_reports = ch_reports.mix( - STAR_ALIGN.out.log_final, - STAR_ALIGN.out.log_progress, - STAR_ALIGN.out.log_out - ) - ch_versions = ch_versions.mix(STAR_ALIGN.out.versions.first()) + .set { ch_to_align } + + // Throw error for all samples with unsupported aligners + ch_to_align.other.map { meta, _reads, aligner, _index, _fasta -> + error("Unsupported aligner ${aligner} for sample ${meta.id}") + } + + // Align fastq files to reference genome + STAR_ALIGN(ch_to_align.star, "Illumina", "CMGG") + // if aligner is STAR + ch_bam = ch_bam.mix(STAR_ALIGN.out.bam) + ch_reports = ch_reports.mix( + STAR_ALIGN.out.log_final, + STAR_ALIGN.out.log_progress, + STAR_ALIGN.out.log_out, + ) + ch_versions = ch_versions.mix(STAR_ALIGN.out.versions.first()) emit: - bam = ch_bam // channel: [ [meta], bam ] - reports = ch_reports // channel: [ [meta], log ] - versions = ch_versions // channel: [ versions.yml ] + bam = ch_bam // channel: [ [meta], bam ] + reports = ch_reports // channel: [ [meta], log ] + versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 2ec92389..afed2cc2 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -11,152 +11,156 @@ include { SAMTOOLS_SORMADUP } from "../../../modules/nf-core/samtools/sormad include { SAMTOOLS_SORT } from "../../../modules/nf-core/samtools/sort/main" // SUBWORKFLOWS -include { FASTQ_ALIGN_DNA } from '../../nf-core/fastq_align_dna/main' -include { FASTQ_ALIGN_RNA } from '../../local/fastq_align_rna/main' +include { FASTQ_ALIGN_DNA } from '../../nf-core/fastq_align_dna/main' +include { FASTQ_ALIGN_RNA } from '../../local/fastq_align_rna/main' // FUNCTIONS -include { getGenomeAttribute } from '../../local/utils_nfcore_preprocessing_pipeline' +include { getGenomeAttribute } from '../../local/utils_nfcore_preprocessing_pipeline' workflow FASTQ_TO_CRAM { take: - ch_meta_reads_aligner_index_fasta_gtf // channel: [mandatory] [meta, [fastq, ...], aligner [bowtie2, bwamem, bwamem2, dragmap, snap, star], aligner_index, fasta, gtf] - markdup // string: [optional ] markdup [bamsormadup, samtools, false] + ch_meta_reads_aligner_index_fasta_gtf // channel: [mandatory] [meta, [fastq, ...], aligner [bowtie2, bwamem, bwamem2, dragmap, snap, star], aligner_index, fasta, gtf] + markdup // string: [optional ] markdup [bamsormadup, samtools, false] main: - ch_versions = Channel.empty() - ch_multiqc_files = Channel.empty() + ch_versions = Channel.empty() + ch_multiqc_files = Channel.empty() - /* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: ALIGNMENT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_meta_reads_aligner_index_fasta_gtf.dump(tag: "FASTQ_TO_CRAM: reads to align",pretty: true) + ch_meta_reads_aligner_index_fasta_gtf.dump(tag: "FASTQ_TO_CRAM: reads to align", pretty: true) - ch_meta_reads_aligner_index_fasta_gtf - .branch { meta, reads, aligner, index, fasta, gtf -> - rna: meta.sample_type == "RNA" - return [meta, reads, "star", index, gtf] - dna: meta.sample_type == "DNA" || meta.sample_type == "Tissue" - return [meta, reads, aligner, index, fasta] - } - .set { ch_meta_reads_aligner_index_fasta_datatype } - - // align fastq files per sample - // ALIGNMENT([meta,fastq], index, sort) - FASTQ_ALIGN_DNA( - ch_meta_reads_aligner_index_fasta_datatype.dna, - false - ) - ch_versions = ch_versions.mix(FASTQ_ALIGN_DNA.out.versions) - - FASTQ_ALIGN_RNA( - ch_meta_reads_aligner_index_fasta_datatype.rna - ) - ch_versions = ch_versions.mix(FASTQ_ALIGN_DNA.out.versions) - - /* + ch_meta_reads_aligner_index_fasta_gtf + .branch { meta, reads, aligner, index, fasta, gtf -> + rna: meta.sample_type == "RNA" + return [meta, reads, "star", index, gtf] + dna: meta.sample_type == "DNA" || meta.sample_type == "Tissue" + return [meta, reads, aligner, index, fasta] + } + .set { ch_meta_reads_aligner_index_fasta_datatype } + + // align fastq files per sample + // ALIGNMENT([meta,fastq], index, sort) + FASTQ_ALIGN_DNA( + ch_meta_reads_aligner_index_fasta_datatype.dna, + false, + ) + ch_versions = ch_versions.mix(FASTQ_ALIGN_DNA.out.versions) + + FASTQ_ALIGN_RNA( + ch_meta_reads_aligner_index_fasta_datatype.rna + ) + ch_versions = ch_versions.mix(FASTQ_ALIGN_DNA.out.versions) + + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: MARK DUPLICATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - FASTQ_ALIGN_DNA.out.bam + FASTQ_ALIGN_DNA.out.bam .mix(FASTQ_ALIGN_RNA.out.bam) - .map { - meta, files -> + .map { meta, files -> def gk = (meta.chunks as Integer ?: 1) return [ groupKey( - // Remove the chunk prefix from the id when present, remove readgroup and chunks from meta meta - meta.subMap('readgroup', 'chunks') + [id: meta.id ==~ /^\d{4}\..*$/ ? meta.id[5..-1] : meta.id], - gk + gk, ), - files + files, ] } - .groupTuple() // Group all files in the same lane - .map { - meta, files -> + .groupTuple() + .map { meta, files -> def gk = (meta.count as Integer ?: 1) return [ groupKey( - // drop count and set id to samplename meta - meta.subMap('count') + [id: meta.samplename ?: meta.id], - gk + gk, ), - files + files, ] } - .groupTuple() // Group all files from the same sample + .groupTuple() .map { meta, files -> return [meta, files.flatten(), getGenomeAttribute(meta.genome_data, 'fasta')] } - .set{ch_bam_fasta} - ch_bam_fasta.dump(tag: "FASTQ_TO_CRAM: aligned bam per sample", pretty: true) - - ch_markdup_index = Channel.empty() - - if ( markdup == "bamsormadup") { - // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) - BIOBAMBAM_BAMSORMADUP(ch_bam_fasta) - ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch:true, failOnDuplicate:true)) - ch_multiqc_files = ch_multiqc_files.mix( BIOBAMBAM_BAMSORMADUP.out.metrics.map { _meta, metrics -> return metrics} ) - ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions.first()) - } - else if ( markdup == "samtools") { - SAMTOOLS_SORMADUP(ch_bam_fasta) - ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch:true, failOnDuplicate:true)) - ch_multiqc_files = ch_multiqc_files.mix( SAMTOOLS_SORMADUP.out.metrics.map { _meta, metrics -> return metrics} ) - ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions.first()) - } - else if ( markdup == "false" || markdup == false) { - // Merge bam files and compress - // SAMTOOLS_SORT([meta, [bam, bam], fasta]) - SAMTOOLS_SORT(ch_bam_fasta) - ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORT.out.cram.join(SAMTOOLS_SORT.out.crai, failOnMismatch:true, failOnDuplicate:true)) - ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions.first()) - } - else { - error "markdup: ${markdup} not supported" - } - ch_markdup_index.dump(tag: "FASTQ_TO_CRAM: postprocessed bam", pretty: true) - - /* + .set { ch_bam_fasta } + ch_bam_fasta.dump(tag: "FASTQ_TO_CRAM: aligned bam per sample", pretty: true) + + ch_markdup_index = Channel.empty() + + if (markdup == "bamsormadup") { + // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) + BIOBAMBAM_BAMSORMADUP(ch_bam_fasta) + ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch: true, failOnDuplicate: true)) + ch_multiqc_files = ch_multiqc_files.mix( + BIOBAMBAM_BAMSORMADUP.out.metrics.map { _meta, metrics -> + return metrics + } + ) + ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions.first()) + } + else if (markdup == "samtools") { + SAMTOOLS_SORMADUP(ch_bam_fasta) + ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch: true, failOnDuplicate: true)) + ch_multiqc_files = ch_multiqc_files.mix( + SAMTOOLS_SORMADUP.out.metrics.map { _meta, metrics -> + return metrics + } + ) + ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions.first()) + } + else if (markdup == "false" || markdup == false) { + // Merge bam files and compress + // SAMTOOLS_SORT([meta, [bam, bam], fasta]) + SAMTOOLS_SORT(ch_bam_fasta) + ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORT.out.cram.join(SAMTOOLS_SORT.out.crai, failOnMismatch: true, failOnDuplicate: true)) + ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions.first()) + } + else { + error("markdup: ${markdup} not supported") + } + ch_markdup_index.dump(tag: "FASTQ_TO_CRAM: postprocessed bam", pretty: true) + + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // COMPRESSION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_markdup_index + ch_markdup_index .branch { meta, reads, index -> bam: reads.getExtension() == "bam" - return [meta, reads, index] + return [meta, reads, index] cram: reads.getExtension() == "cram" - return [meta, reads, index] + return [meta, reads, index] } - .set {ch_markdup_index} + .set { ch_markdup_index } - ch_markdup_index.bam + ch_markdup_index.bam .map { meta, bam, bai -> bam_bai: [meta, bam, bai, getGenomeAttribute(meta.genome_data, 'fasta'), getGenomeAttribute(meta.genome_data, 'fai')] } - .set {ch_bam_bai_fasta_fai} + .set { ch_bam_bai_fasta_fai } - SAMTOOLS_CONVERT(ch_bam_bai_fasta_fai) - ch_versions = ch_versions.mix(SAMTOOLS_CONVERT.out.versions.first()) + SAMTOOLS_CONVERT(ch_bam_bai_fasta_fai) + ch_versions = ch_versions.mix(SAMTOOLS_CONVERT.out.versions.first()) - ch_markdup_index.cram + ch_markdup_index.cram .mix( - SAMTOOLS_CONVERT.out.cram.join(SAMTOOLS_CONVERT.out.crai, failOnMismatch:true, failOnDuplicate:true) + SAMTOOLS_CONVERT.out.cram.join(SAMTOOLS_CONVERT.out.crai, failOnMismatch: true, failOnDuplicate: true) ) - .set{ch_cram_crai} - ch_cram_crai.dump(tag: "FASTQ_TO_CRAM: cram and crai", pretty: true) + .set { ch_cram_crai } + ch_cram_crai.dump(tag: "FASTQ_TO_CRAM: cram and crai", pretty: true) emit: - cram_crai = ch_cram_crai - multiqc_files = ch_multiqc_files - versions = ch_versions + cram_crai = ch_cram_crai + multiqc_files = ch_multiqc_files + versions = ch_versions } diff --git a/subworkflows/local/fastq_to_unaligned_cram/main.nf b/subworkflows/local/fastq_to_unaligned_cram/main.nf index 8cb1911b..37dc0527 100644 --- a/subworkflows/local/fastq_to_unaligned_cram/main.nf +++ b/subworkflows/local/fastq_to_unaligned_cram/main.nf @@ -4,72 +4,65 @@ // Take fastq; convert to ubam and compress // MODULES -include { SAMTOOLS_CAT } from '../../../modules/nf-core/samtools/cat/main' -include { SAMTOOLS_IMPORT } from "../../../modules/nf-core/samtools/import/main" -include { MD5SUM } from "../../../modules/nf-core/md5sum/main" +include { SAMTOOLS_CAT } from '../../../modules/nf-core/samtools/cat/main' +include { SAMTOOLS_IMPORT } from "../../../modules/nf-core/samtools/import/main" +include { MD5SUM } from "../../../modules/nf-core/md5sum/main" workflow FASTQ_TO_UCRAM { take: - ch_fastq // channel: [mandatory] [meta, [fastq, ...]] + ch_fastq // channel: [mandatory] [meta, [fastq, ...]] main: - ch_versions = Channel.empty() + ch_versions = Channel.empty() - /* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: FASTQ TO BAM CONVERSION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_fastq - .dump(tag: "FASTQ_TO_UCRAM: reads to convert",pretty: true) + ch_fastq.dump(tag: "FASTQ_TO_UCRAM: reads to convert", pretty: true) - // SAMTOOLS_IMPORT([meta, fastq]) - SAMTOOLS_IMPORT(ch_fastq) - ch_versions = ch_versions.mix(SAMTOOLS_IMPORT.out.versions.first()) + // SAMTOOLS_IMPORT([meta, fastq]) + SAMTOOLS_IMPORT(ch_fastq) + ch_versions = ch_versions.mix(SAMTOOLS_IMPORT.out.versions.first()) - SAMTOOLS_IMPORT.out.cram - .map { - // set id to samplename, drop readgroup and count meta values - meta, files -> + SAMTOOLS_IMPORT.out.cram + .map { meta, files -> def gk = (meta.chunks as Integer ?: 1) return [ groupKey( - // replace id by samplename, drop readgroup meta and chunks meta - meta.subMap('id', 'readgroup', 'chunks') + [id: meta.samplename ? meta.samplename + ".unaligned" : meta.id + ".unaligned"], - gk + gk, ), - files + files, ] } - .groupTuple(by:[0]) - .dump(tag: "FASTQ_TO_UCRAM: unaligned cram per replicate",pretty: true) - .map { - meta, files -> + .groupTuple(by: [0]) + .dump(tag: "FASTQ_TO_UCRAM: unaligned cram per replicate", pretty: true) + .map { meta, files -> def gk = (meta.count as Integer ?: 1) return [ groupKey( - // drop count meta - meta.subMap('count'), - gk + gk, ), - files + files, ] } - .groupTuple(by:[0]) + .groupTuple(by: [0]) .map { meta, files -> return [meta, files.flatten()] } - .dump(tag: "FASTQ_TO_UCRAM: unaligned cram per sample",pretty: true) - .set{ch_ubam_per_sample} + .dump(tag: "FASTQ_TO_UCRAM: unaligned cram per sample", pretty: true) + .set { ch_ubam_per_sample } - // Merge bam files per sample - SAMTOOLS_CAT(ch_ubam_per_sample) - ch_versions = ch_versions.mix(SAMTOOLS_CAT.out.versions.first()) + // Merge bam files per sample + SAMTOOLS_CAT(ch_ubam_per_sample) + ch_versions = ch_versions.mix(SAMTOOLS_CAT.out.versions.first()) emit: - cram = SAMTOOLS_CAT.out.cram // [meta, cram] - versions = ch_versions // versions - + cram = SAMTOOLS_CAT.out.cram // [meta, cram] + versions = ch_versions // versions } diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf index f80a2639..d0081217 100644 --- a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -8,17 +8,17 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { samplesheetToList } from 'plugin/nf-schema' -include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' -include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' -include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { dashedLine } from '../../nf-core/utils_nfcore_pipeline' -include { nfCoreLogo } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' -include { workflowCitation } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { dashedLine } from '../../nf-core/utils_nfcore_pipeline' +include { nfCoreLogo } from '../../nf-core/utils_nfcore_pipeline' +include { imNotification } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { workflowCitation } from '../../nf-core/utils_nfcore_pipeline' /* ======================================================================================== @@ -27,7 +27,6 @@ include { workflowCitation } from '../../nf-core/utils_nfcore_pipeline' */ workflow PIPELINE_INITIALISATION { - take: version // boolean: Display version and exit validate_params // boolean: Boolean whether to validate parameters against the schema at runtime @@ -42,26 +41,26 @@ workflow PIPELINE_INITIALISATION { // // Print version and exit if required and dump pipeline parameters to JSON file // - UTILS_NEXTFLOW_PIPELINE ( + UTILS_NEXTFLOW_PIPELINE( version, true, outdir, - workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 + workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1, ) // // Validate parameters and generate parameter summary to stdout // - UTILS_NFSCHEMA_PLUGIN ( + UTILS_NFSCHEMA_PLUGIN( workflow, validate_params, - null + null, ) // // Check config provided to the pipeline // - UTILS_NFCORE_PIPELINE ( + UTILS_NFCORE_PIPELINE( nextflow_cli_args ) // @@ -72,8 +71,7 @@ workflow PIPELINE_INITIALISATION { // // Create channel from input file provided through params.input // - Channel - .fromList(samplesheetToList(input, "assets/schema_input.json")) + Channel.fromList(samplesheetToList(input, "assets/schema_input.json")) .set { ch_samplesheet } emit: @@ -88,7 +86,6 @@ workflow PIPELINE_INITIALISATION { */ workflow PIPELINE_COMPLETION { - take: email // string: email address email_on_fail // string: email address sent on pipeline failure @@ -137,12 +134,12 @@ def validateInputSamplesheet(input) { def (metas, fastqs) = input[1..2] // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end - def endedness_ok = metas.collect{ meta -> meta.single_end }.unique().size == 1 + def endedness_ok = metas.collect { meta -> meta.single_end }.unique().size == 1 if (!endedness_ok) { error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") } - return [ metas[0], fastqs ] + return [metas[0], fastqs] } // @@ -151,7 +148,8 @@ def validateInputSamplesheet(input) { def getGenomeAttribute(genome, attribute) { if (genome instanceof Map && genome.containsKey(attribute)) { return nextflow.Nextflow.file(genome[attribute], checkIfExists: true) - } else { + } + else { nextflow.Nextflow.error("Genome config does not contain attribute ${attribute}") } return null @@ -162,11 +160,7 @@ def getGenomeAttribute(genome, attribute) { // def genomeExistsError() { if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + - " Currently, the available genome keys are:\n" + - " ${params.genomes.keySet().join(", ")}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + " Currently, the available genome keys are:\n" + " ${params.genomes.keySet().join(", ")}\n" + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" error(error_string) } } @@ -179,9 +173,9 @@ def toolCitationText() { // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", // Uncomment function in methodsDescriptionText to render in MultiQC report def citation_text = [ - "Tools used in the workflow included:", - "MultiQC (Ewels et al. 2016)", - ].join(' ').trim() + "Tools used in the workflow included:", + "MultiQC (Ewels et al. 2016)", + ].join(' ').trim() return citation_text } @@ -191,8 +185,8 @@ def toolBibliographyText() { // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", // Uncomment function in methodsDescriptionText to render in MultiQC report def reference_text = [ - "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • ", - ].join(' ').trim() + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() return reference_text } @@ -214,7 +208,10 @@ def methodsDescriptionText(mqc_methods_yaml) { temp_doi_ref += "(doi: ${doi_ref.replace("https://doi.org/", "").replace(" ", "")}), " } meta["doi_text"] = temp_doi_ref.substring(0, temp_doi_ref.length() - 2) - } else meta["doi_text"] = "" + } + else { + meta["doi_text"] = "" + } meta["nodoi_text"] = meta.manifest_map.doi ? "" : "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " // Tool references @@ -228,7 +225,7 @@ def methodsDescriptionText(mqc_methods_yaml) { def methods_text = mqc_methods_yaml.text - def engine = new groovy.text.SimpleTemplateEngine() + def engine = new groovy.text.SimpleTemplateEngine() def description_html = engine.createTemplate(methods_text).make(meta) return description_html.toString() diff --git a/tests/config/igenomes_test.config b/tests/config/igenomes_test.config index 3b3e3263..80984075 100644 --- a/tests/config/igenomes_test.config +++ b/tests/config/igenomes_test.config @@ -1,20 +1,20 @@ params { genomes { GRCh38 { - bwamem = "s3://test-data/genomics/homo_sapiens/genome/bwa/" - dict = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict" - fai = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - fasta = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" - star = "s3://test-data/genomics/homo_sapiens/genome/star/" - gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + bwamem = "s3://test-data/genomics/homo_sapiens/genome/bwa/" + dict = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict" + fai = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + fasta = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + star = "s3://test-data/genomics/homo_sapiens/genome/star/" + gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" } } } aws { client { - endpoint = "https://s3.ugent.be" - protocol = "https" + endpoint = "https://s3.ugent.be" + protocol = "https" s3PathStyleAccess = true connectionTimeout = 60000 } diff --git a/tests/config/nf-test.config b/tests/config/nf-test.config index 68e597f9..c24e5c2f 100644 --- a/tests/config/nf-test.config +++ b/tests/config/nf-test.config @@ -2,14 +2,14 @@ process { resourceLimits = [ cpus: 2, memory: 6.GB, - time: 6.h + time: 6.h, ] } aws { client { - endpoint = "https://s3.ugent.be" - protocol = "https" + endpoint = "https://s3.ugent.be" + protocol = "https" s3PathStyleAccess = true connectionTimeout = 60000 } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 36f6fe4c..bf939975 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -1,4 +1,4 @@ -include { samplesheetToList } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -34,7 +34,6 @@ include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_prep */ workflow PREPROCESSING { - take: ch_samplesheet // channel: samplesheet read in from --input genomes // map: genome reference files @@ -48,151 +47,156 @@ workflow PREPROCESSING { ch_multiqc_files = Channel.empty() ch_samplesheet - .branch {meta, fastq_1, fastq_2, samplesheet, sampleinfo, flowcell -> - illumina_flowcell : (flowcell && samplesheet && sampleinfo) && !(fastq_1 || fastq_2) + .branch { meta, fastq_1, fastq_2, samplesheet, sampleinfo, flowcell -> + illumina_flowcell: (flowcell && samplesheet && sampleinfo) && !(fastq_1 || fastq_2) return [meta, samplesheet, sampleinfo, flowcell] - fastq : (fastq_1) && !(flowcell || samplesheet || sampleinfo) + fastq: (fastq_1) && !(flowcell || samplesheet || sampleinfo) return [meta, [fastq_1, fastq_2].findAll()] - other: true - error "Unable to determine input type, please check inputs" - } - .set{ch_inputs_from_samplesheet} + other: true + error("Unable to determine input type, please check inputs") + } + .set { ch_inputs_from_samplesheet } - roi = roi ? file(roi, checkIfExists:true) : null + roi = roi ? file(roi, checkIfExists: true) : null - genelists = genelists ? Channel.value(file(genelists + "/*.bed", checkIfExists:true)) : Channel.empty() + genelists = genelists ? Channel.value(file(genelists + "/*.bed", checkIfExists: true)) : Channel.empty() -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PROCESS FLOWCELL INPUTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_inputs_from_samplesheet.illumina_flowcell - .multiMap { meta, samplesheet, sampleinfo, flowcell -> - flowcell: [meta, samplesheet, flowcell] - info : samplesheetToList(sampleinfo, "assets/schema_sampleinfo.json") - } - .set{ ch_illumina_flowcell } + .multiMap { meta, samplesheet, sampleinfo, flowcell -> + flowcell: [meta, samplesheet, flowcell] + info: samplesheetToList(sampleinfo, "assets/schema_sampleinfo.json") + } + .set { ch_illumina_flowcell } // BCL_DEMULTIPLEX([meta, samplesheet, flowcell], demultiplexer) BCL_DEMULTIPLEX(ch_illumina_flowcell.flowcell, "bclconvert") - BCL_DEMULTIPLEX.out.fastq.dump(tag: "DEMULTIPLEX: fastq",pretty: true) + BCL_DEMULTIPLEX.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) ch_multiqc_files = ch_multiqc_files.mix( - BCL_DEMULTIPLEX.out.reports.map { _meta, reports -> return reports}, - BCL_DEMULTIPLEX.out.stats.map { _meta, stats -> return stats } + BCL_DEMULTIPLEX.out.reports.map { _meta, reports -> + return reports + }, + BCL_DEMULTIPLEX.out.stats.map { _meta, stats -> + return stats + }, ) ch_versions = ch_versions.mix(BCL_DEMULTIPLEX.out.versions) BCL_DEMULTIPLEX.out.fastq - .map{meta, fastq -> [meta.samplename, meta, fastq]} - .set{ch_demultiplexed_fastq} + .map { meta, fastq -> [meta.samplename, meta, fastq] } + .set { ch_demultiplexed_fastq } ch_illumina_flowcell.info - .flatten() - .transpose() - .map{sampleinfo -> [sampleinfo.samplename, sampleinfo]} - .set{ch_sampleinfo} + .flatten() + .transpose() + .map { sampleinfo -> [sampleinfo.samplename, sampleinfo] } + .set { ch_sampleinfo } // Merge fastq meta with sample info ch_demultiplexed_fastq - .combine(ch_sampleinfo, by: 0) - .map { samplename, meta, fastq, sampleinfo -> - def new_meta = meta + sampleinfo - def readgroup = readgroup_from_fastq(fastq[0]) - readgroup = readgroup + ['SM': samplename, 'LB': new_meta.library ?: ""] - new_meta = new_meta + ['readgroup' : readgroup] - return [ new_meta, fastq ] - } - .groupTuple( by: [0]) - .map { meta, fq -> - return [meta, fq.flatten().unique()] - } - .set {ch_demultiplexed_fastq_with_sampleinfo} -/* + .combine(ch_sampleinfo, by: 0) + .map { samplename, meta, fastq, sampleinfo -> + def new_meta = meta + sampleinfo + def readgroup = readgroup_from_fastq(fastq[0]) + readgroup = readgroup + ['SM': samplename, 'LB': new_meta.library ?: ""] + new_meta = new_meta + ['readgroup': readgroup] + return [new_meta, fastq] + } + .groupTuple(by: [0]) + .map { meta, fq -> + return [meta, fq.flatten().unique()] + } + .set { ch_demultiplexed_fastq_with_sampleinfo } + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PROCESS FASTQ INPUTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_inputs_from_samplesheet.fastq - .map { meta, fastq -> - // if no fastq_2, then single-end - def single_end = fastq[1] ? false : true - // add readgroup metadata - def rg = readgroup_from_fastq(fastq[0]) - // if the sample name starts with "snp_", remove it so the sampletracking works later on. - def samplename = meta.samplename.startsWith("snp_") ? meta.samplename.substring(4) : meta.samplename - rg = rg + [ 'SM': samplename, - 'LB': meta.library ?: "", - 'PL': meta.platform ?: rg.PL, - 'ID': meta.readgroup ?: rg.ID - ] - def meta_with_readgroup = meta + ['single_end': single_end, 'readgroup': rg] - return [meta_with_readgroup, fastq] - } - .set {ch_input_fastq} + .map { meta, fastq -> + // if no fastq_2, then single-end + def single_end = fastq[1] ? false : true + // add readgroup metadata + def rg = readgroup_from_fastq(fastq[0]) + // if the sample name starts with "snp_", remove it so the sampletracking works later on. + def samplename = meta.samplename.startsWith("snp_") ? meta.samplename.substring(4) : meta.samplename + rg = rg + [ + 'SM': samplename, + 'LB': meta.library ?: "", + 'PL': meta.platform ?: rg.PL, + 'ID': meta.readgroup ?: rg.ID, + ] + def meta_with_readgroup = meta + ['single_end': single_end, 'readgroup': rg] + return [meta_with_readgroup, fastq] + } + .set { ch_input_fastq } -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ASSOCIATE CORRECT GENOME AND COUNT SAMPLE REPLICATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_input_fastq - .mix(ch_demultiplexed_fastq_with_sampleinfo) - // Add the genome config to the tuple - // set genome based on organism key - .map{ meta, reads -> - if (meta.organism && !meta.genome) { - if (meta.organism ==~ /(?i)Homo[\s_]sapiens/) { - meta = meta + ["genome":"GRCh38"] - } else if (meta.organism ==~ /(?i)Mus[\s_]musculus/) { - meta = meta + ["genome":"mm10"] - } else if (meta.organism ==~/(?i)Danio[\s_]rerio/) { - meta = meta + ["genome":"GRCz11"] - } else { - meta = meta + ["genome": null ] + .mix(ch_demultiplexed_fastq_with_sampleinfo) + .map { meta, reads -> + if (meta.organism && !meta.genome) { + if (meta.organism ==~ /(?i)Homo[\s_]sapiens/) { + meta = meta + ["genome": "GRCh38"] + } + else if (meta.organism ==~ /(?i)Mus[\s_]musculus/) { + meta = meta + ["genome": "mm10"] + } + else if (meta.organism ==~ /(?i)Danio[\s_]rerio/) { + meta = meta + ["genome": "GRCz11"] + } + else { + meta = meta + ["genome": null] + } } + if (genomes && genomes[meta.genome]) { + meta = meta + ["genome_data": genomes[meta.genome]] + } + else { + meta = meta + ["genome_data": [:]] + } + // set the aligner + if (aligner && !meta.aligner) { + meta = meta + ["aligner": aligner] + } + // set the ROI + // // Special case for coPGT samples + // // if there's no global ROI AND no sample speficic ROI + // // AND the sample tag is "coPGT-M", set the sample ROI to "roi_copgt" + if (!roi && !meta.roi && meta.tag == "coPGT-M") { + meta = meta + ["roi": getGenomeAttribute(meta.genome_data, "roi_copgt")] + } + // // if there's a global ROI AND no sample specific ROI + // // set the global ROI to the sample + if (roi && !meta.roi) { + meta = meta + ["roi": roi] + } + return [meta, reads] } - if (genomes && genomes[meta.genome]){ - meta = meta + ["genome_data": genomes[meta.genome]] - } else { - meta = meta + ["genome_data": [:]] - } - // set the aligner - if (aligner && !meta.aligner) { - meta = meta + ["aligner": aligner] - } - // set the ROI - // // Special case for coPGT samples - // // if there's no global ROI AND no sample speficic ROI - // // AND the sample tag is "coPGT-M", set the sample ROI to "roi_copgt" - if (!roi && !meta.roi && meta.tag == "coPGT-M") { - meta = meta + ["roi": getGenomeAttribute(meta.genome_data, "roi_copgt")] - } - // // if there's a global ROI AND no sample specific ROI - // // set the global ROI to the sample - if (roi && !meta.roi) { - meta = meta + ["roi": roi] + .map { meta, reads -> [meta.samplename, [meta, reads]] } + .groupTuple() + .map { _samplename, meta_fastq -> [meta_fastq, meta_fastq.size()] } + .transpose() + .map { meta_fastq, count -> [meta_fastq[0] + ['count': count], meta_fastq[1]] } + .map { meta, fastq -> + return [meta - meta.subMap('fcid', 'lane', 'library'), fastq] } - return [meta, reads] - } - // Count the number of samples per samplename - .map{ meta, reads -> [meta.samplename, [meta, reads]]} - .groupTuple() - .map{ _samplename, meta_fastq -> [meta_fastq, meta_fastq.size()]} - .transpose() - .map{meta_fastq, count -> [meta_fastq[0] + ['count': count], meta_fastq[1]]} - // Clean up metadata - .map{meta, fastq -> - return [meta - meta.subMap('fcid','lane','library'), fastq] - } - .set{ch_fastq_per_sample} + .set { ch_fastq_per_sample } - ch_fastq_per_sample.dump(tag:"FASTQ per sample", pretty: true) + ch_fastq_per_sample.dump(tag: "FASTQ per sample", pretty: true) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FASTQ TRIMMING AND QC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -202,40 +206,41 @@ workflow PREPROCESSING { // Run QC, trimming and adapter removal // FASTP([meta, fastq], adapter_fasta, save_trimmed, save_merged) FASTP(ch_fastq_per_sample, [], false, false, false) - ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json.map { _meta, json -> return json} ) - ch_versions = ch_versions.mix(FASTP.out.versions.first()) + ch_multiqc_files = ch_multiqc_files.mix( + FASTP.out.json.map { _meta, json -> + return json + } + ) + ch_versions = ch_versions.mix(FASTP.out.versions.first()) // edit meta.id to match sample name FASTP.out.reads - .map { meta, reads -> - def read_files = meta.single_end.toBoolean() ? reads : reads.sort{ a,b -> a.getName().tokenize('.')[0] <=> b.getName().tokenize('.')[0] }.collate(2) - return [ - meta + [ chunks: read_files instanceof List ? read_files.size() : [read_files].size() ], - read_files - ] - } - // transpose to get read pairs - .transpose() - // set new meta.id to include split number - .map { meta, reads -> - def new_id = reads instanceof List ? reads[0].getName() - ~/_1.fastp.*/ : reads.getName() - ~/.fastp.*/ - return [ - meta - meta.subMap('id') + [ id: new_id ], - reads - ] - } - // split samples into human and non human data - .branch { meta, _reads -> - supported: meta.genome_data instanceof Map && meta.genome_data.size() > 0 - other: true - } - .set { ch_trimmed_reads } + .map { meta, reads -> + def read_files = meta.single_end.toBoolean() ? reads : reads.sort { a, b -> a.getName().tokenize('.')[0] <=> b.getName().tokenize('.')[0] }.collate(2) + return [ + meta + [chunks: read_files instanceof List ? read_files.size() : [read_files].size()], + read_files, + ] + } + .transpose() + .map { meta, reads -> + def new_id = reads instanceof List ? reads[0].getName() - ~/_1.fastp.*/ : reads.getName() - ~/.fastp.*/ + return [ + meta - meta.subMap('id') + [id: new_id], + reads, + ] + } + .branch { meta, _reads -> + supported: meta.genome_data instanceof Map && meta.genome_data.size() > 0 + other: true + } + .set { ch_trimmed_reads } - ch_trimmed_reads.supported.dump(tag:"Supported trimmed reads per sample", pretty: true) - ch_trimmed_reads.other.dump(tag:"Other trimmed reads per sample", pretty: true) + ch_trimmed_reads.supported.dump(tag: "Supported trimmed reads per sample", pretty: true) + ch_trimmed_reads.other.dump(tag: "Other trimmed reads per sample", pretty: true) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: FASTQ TO UNALIGNED CRAM CONVERSION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -244,35 +249,36 @@ workflow PREPROCESSING { FASTQ_TO_UCRAM(ch_trimmed_reads.other) ch_versions = ch_versions.mix(FASTQ_TO_UCRAM.out.versions) -/* + /* /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: FASTQ TO ALIGNED CRAM CONVERSION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_trimmed_reads.supported.map{ meta, reads -> - return [ - meta, - reads, - meta.aligner, - getGenomeAttribute(meta.genome_data, meta.aligner), - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "gtf") + ch_trimmed_reads.supported + .map { meta, reads -> + return [ + meta, + reads, + meta.aligner, + getGenomeAttribute(meta.genome_data, meta.aligner), + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "gtf"), ] - } - .set{ch_meta_reads_aligner_index_fasta_gtf} + } + .set { ch_meta_reads_aligner_index_fasta_gtf } FASTQ_TO_CRAM( ch_meta_reads_aligner_index_fasta_gtf, - markdup + markdup, ) ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.multiqc_files) ch_versions = ch_versions.mix(FASTQ_TO_CRAM.out.versions) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: FILTER SAMPLES WITH 'SNP' TAG // samples with SNP tag contain only data for sample tracking @@ -281,103 +287,130 @@ workflow PREPROCESSING { */ FASTQ_TO_CRAM.out.cram_crai - .filter{ meta, _cram, _crai -> - meta.tag != "SNP" - } - .set{ch_no_snp_samples} + .filter { meta, _cram, _crai -> + meta.tag != "SNP" + } + .set { ch_no_snp_samples } -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: COVERAGE ANALYSIS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_no_snp_samples - .map { meta, cram, crai -> - if (meta.roi) { - return [ - meta, - cram, - crai, - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - file(meta.roi, checkIfExists:true), - ] - } else { - return [ - meta, - cram, - crai, - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - [], - ] + .map { meta, cram, crai -> + if (meta.roi) { + return [ + meta, + cram, + crai, + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + file(meta.roi, checkIfExists: true), + ] + } + else { + return [ + meta, + cram, + crai, + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + [], + ] + } } - } - .set{ch_cram_crai_fasta_fai_roi} + .set { ch_cram_crai_fasta_fai_roi } if (params.run_coverage == true || params.run_coverage == "true") { COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) ch_multiqc_files = ch_multiqc_files.mix( - COVERAGE.out.mosdepth_summary .map{ _meta, txt -> return txt }, - COVERAGE.out.mosdepth_global .map{ _meta, txt -> return txt }, - COVERAGE.out.mosdepth_regions .map{ _meta, txt -> return txt }, - COVERAGE.out.samtools_coverage.map{ _meta, txt -> return txt }, + COVERAGE.out.mosdepth_summary.map { _meta, txt -> + return txt + }, + COVERAGE.out.mosdepth_global.map { _meta, txt -> + return txt + }, + COVERAGE.out.mosdepth_regions.map { _meta, txt -> + return txt + }, + COVERAGE.out.samtools_coverage.map { _meta, txt -> + return txt + }, ) ch_versions = ch_versions.mix(COVERAGE.out.versions) } -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: QC FOR ALIGNMENTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_no_snp_samples - .map { meta, cram, crai -> - if (meta.roi) { - return [ - meta, - cram, - crai, - file(meta.roi, checkIfExists:true), - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - getGenomeAttribute(meta.genome_data, "dict"), - ] - } else { - return [ - meta, - cram, - crai, - [], - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - getGenomeAttribute(meta.genome_data, "dict"), - ] + .map { meta, cram, crai -> + if (meta.roi) { + return [ + meta, + cram, + crai, + file(meta.roi, checkIfExists: true), + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + getGenomeAttribute(meta.genome_data, "dict"), + ] + } + else { + return [ + meta, + cram, + crai, + [], + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + getGenomeAttribute(meta.genome_data, "dict"), + ] + } } - } - .set{ch_cram_crai_roi_fasta_fai_dict} + .set { ch_cram_crai_roi_fasta_fai_dict } BAM_QC(ch_cram_crai_roi_fasta_fai_dict, params.disable_picard_metrics) ch_multiqc_files = ch_multiqc_files.mix( - BAM_QC.out.samtools_stats .map{ _meta, txt -> return txt }, - BAM_QC.out.samtools_flagstat .map{ _meta, txt -> return txt }, - BAM_QC.out.samtools_idxstats .map{ _meta, txt -> return txt }, - BAM_QC.out.picard_multiplemetrics .map{ _meta, txt -> return txt }, - BAM_QC.out.picard_wgsmetrics .map{ _meta, txt -> return txt }, - BAM_QC.out.picard_hsmetrics .map{ _meta, txt -> return txt }, + BAM_QC.out.samtools_stats.map { _meta, txt -> + return txt + }, + BAM_QC.out.samtools_flagstat.map { _meta, txt -> + return txt + }, + BAM_QC.out.samtools_idxstats.map { _meta, txt -> + return txt + }, + BAM_QC.out.picard_multiplemetrics.map { _meta, txt -> + return txt + }, + BAM_QC.out.picard_wgsmetrics.map { _meta, txt -> + return txt + }, + BAM_QC.out.picard_hsmetrics.map { _meta, txt -> + return txt + }, ) ch_versions = ch_versions.mix(BAM_QC.out.versions) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: CHECKSUMS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - MD5SUM(FASTQ_TO_CRAM.out.cram_crai.map{ meta, cram, _crai -> return [meta,cram] }, false) + MD5SUM( + FASTQ_TO_CRAM.out.cram_crai.map { meta, cram, _crai -> + return [meta, cram] + }, + false, + ) ch_versions = ch_versions.mix(MD5SUM.out.versions.first()) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AGGREGATE QC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -392,29 +425,29 @@ workflow PREPROCESSING { // // MODULE: MultiQC // - ch_multiqc_config = Channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) - ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config, checkIfExists: true) : Channel.empty() - ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo, checkIfExists: true) : Channel.empty() - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") - ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) - ch_methods_description = Channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) - - MULTIQC ( + ch_multiqc_config = Channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config, checkIfExists: true) : Channel.empty() + ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo, checkIfExists: true) : Channel.empty() + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) + ch_methods_description = Channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) + + MULTIQC( ch_multiqc_files.collect(), ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), [], - [] + [], ) emit: multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html - versions = ch_versions // channel: [ path(versions.yml) ] + versions = ch_versions // channel: [ path(versions.yml) ] } /* @@ -448,22 +481,17 @@ def readgroup_from_fastq(path) { // "@::::::: :::" // def sequencer_serial = fields[0] // def run_number = fields[1] - def fcid = fields[2] - def lane = fields[3] - def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" + def fcid = fields[2] + def lane = fields[3] + def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" - rg.ID = [fcid,lane].join(".") + rg.ID = [fcid, lane].join(".") rg.PU = [fcid, lane, index].findAll().join(".") rg.PL = "ILLUMINA" - } else if (fields.size() == 5) { + } + else if (fields.size() == 5) { def fcid = fields[0] rg.ID = fcid } return rg } - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - THE END -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ From 0d42714f15e9566dca316d45047c606670b81ac0 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 17 Sep 2025 17:02:08 +0200 Subject: [PATCH 013/228] bump WES ROI --- conf/igenomes.config | 2 +- conf/profiles/WES.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/igenomes.config b/conf/igenomes.config index 27ed34c8..3a6ea697 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -27,7 +27,7 @@ params { // ROI's roi_copgt = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_coPGT-M_analyses_ROI_v1.bed" - roi_wes = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v6.bed" + roi_wes = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v7.bed" } GRCm39 { // Genome reference diff --git a/conf/profiles/WES.config b/conf/profiles/WES.config index cc0a4acc..e7dd235b 100644 --- a/conf/profiles/WES.config +++ b/conf/profiles/WES.config @@ -2,6 +2,6 @@ params { aligner = "snap" run_coverage = true disable_picard_metrics = false - roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v6.bed" + roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v7.bed" genelists = "${params.igenomes_base}/Hsapiens/GRCh38/regions/genelists" } From 534d13e7470f15128ecd0ccf1434af9458690b1e Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Mon, 3 Nov 2025 17:15:04 +0100 Subject: [PATCH 014/228] small fixes before conversion --- nextflow.config | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/nextflow.config b/nextflow.config index 00399037..6022b555 100644 --- a/nextflow.config +++ b/nextflow.config @@ -250,13 +250,29 @@ dag { manifest { name = 'nf-cmgg/preprocessing' - contributors = """CMGG ICT team""" homePage = 'https://github.com/nf-cmgg/preprocessing' description = """Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.""" mainScript = 'main.nf' - nextflowVersion = '!>=25.04.0' + nextflowVersion = '!>=25.10.0' version = 'dev' doi = '' + contributors = [ + [ + name: 'Matthias De Smet', + affiliation: 'Center For Medical Genetics Ghent', + email: 'matthias.desmet@ugent.be', + github: '@matthsdsm', + contribution: ["author", "maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') + ], + [ + name: 'Nicolas Vannieuwkerke', + affiliation: 'Center For Medical Genetics Ghent', + email: 'nicolas.vannieuwkerke@ugent.be', + github: '@nvnieuwk', + contribution: ["maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '0009-0003-5619-1555' + ], + ] } validation { @@ -284,3 +300,6 @@ validation { // Load modules.config for DSL2 module specific options includeConfig 'conf/modules.config' + +workflow.output.mode = params.publish_dir_mode +outputDir = params.outdir From f8e5bb7fb002539fca83c5914144a413e2c0e2f8 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Mon, 3 Nov 2025 17:15:18 +0100 Subject: [PATCH 015/228] convert bclconvert output --- conf/modules.config | 34 ------------- main.nf | 53 +++++++------------- subworkflows/nf-core/bcl_demultiplex/main.nf | 3 ++ workflows/preprocessing.nf | 3 ++ 4 files changed, 23 insertions(+), 70 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 4860b8e9..0157c825 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -29,40 +29,6 @@ process { "--bcl-num-compression-threads ${task.cpus}", ].join(" ").trim() } - publishDir = [ - [ - path: { "${params.outdir}/InterOp" }, - mode: params.publish_dir_mode, - overwrite: true, - pattern: "**.bin", - saveAs: { filename -> filename.split("/")[-1] }, - ], - [ - path: { meta.lane ? "${params.outdir}/Reports/L00${meta.lane}" : "${params.outdir}/Reports/" }, - mode: params.publish_dir_mode, - pattern: "RunInfo.xml", - overwrite: true, - saveAs: { filename -> filename.split("/")[-1] }, - ], - [ - path: { meta.lane ? "${params.outdir}/Reports/L00${meta.lane}" : "${params.outdir}/Reports/" }, - mode: params.publish_dir_mode, - pattern: "Reports", - overwrite: true, - saveAs: { filename -> filename.split("/")[-1] }, - ], - [ - path: { meta.lane ? "${params.outdir}/Logs/L00${meta.lane}" : "${params.outdir}/Logs/" }, - mode: params.publish_dir_mode, - pattern: "Logs", - overwrite: true, - saveAs: { filename -> filename.split("/")[-1] }, - ], - [ - pattern: "**.fastq.gz", - enabled: false, - ], - ] } // FastP diff --git a/main.nf b/main.nf index 4ef95130..2122b585 100644 --- a/main.nf +++ b/main.nf @@ -26,6 +26,7 @@ include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_prep workflow { + main: // // SUBWORKFLOW: Run initialisation tasks // @@ -40,7 +41,7 @@ workflow { // // WORKFLOW: Run main workflow // - NFCMGG_PREPROCESSING( + PREPROCESSING( PIPELINE_INITIALISATION.out.samplesheet, params.genomes, params.aligner, @@ -59,42 +60,22 @@ workflow { params.outdir, params.monochrome_logs, params.hook_url, - NFCMGG_PREPROCESSING.out.multiqc_report, + PREPROCESSING.out.multiqc_report, ) -} - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - NAMED WORKFLOWS FOR PIPELINE -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ -// -// WORKFLOW: Run main analysis pipeline depending on type of input -// -workflow NFCMGG_PREPROCESSING { - take: - samplesheet // channel: samplesheet read in from --input - genomes // map: genome reference files - aligner // string: aligner to use - markdup // string: markdup method to use - roi // string: region of interest to use - genelists // file: directory containing genelist bed files for coverage analysis - - main: - - // - // WORKFLOW: Run pipeline - // - PREPROCESSING( - samplesheet, - genomes, - aligner, - markdup, - roi, - genelists, - ) + publish: + demultiplex_interop = PREPROCESSING.out.demultiplex_interop + demultiplex_reports = PREPROCESSING.out.demultiplex_reports.map { meta, reports -> [ meta, files("${reports.toUri()}/*") ] }.transpose(by:1) + demultiplex_logs = PREPROCESSING.out.demultiplex_logs.map { meta, logs -> [ meta, files("${logs.toUri()}/*") ] }.transpose(by:1) +} - emit: - multiqc_report = PREPROCESSING.out.multiqc_report // channel: /path/to/multiqc_report.html +output { + // TODO also add the RunInfo.xml file as output, needs a module update + demultiplex_interop { path "InterOp" } + demultiplex_reports { path { meta, report -> + report >> (meta.lane ? "Reports/LOO${meta.lane}/${report.name}" as String : "Reports/${report.name}") + } } + demultiplex_logs { path { meta, log -> + log >> (meta.lane ? "Logs/LOO${meta.lane}/${log.name}" as String : "Logs/${log.name}") + } } } diff --git a/subworkflows/nf-core/bcl_demultiplex/main.nf b/subworkflows/nf-core/bcl_demultiplex/main.nf index e7905cdb..48e08613 100644 --- a/subworkflows/nf-core/bcl_demultiplex/main.nf +++ b/subworkflows/nf-core/bcl_demultiplex/main.nf @@ -18,6 +18,7 @@ workflow BCL_DEMULTIPLEX { ch_reports = Channel.empty() ch_stats = Channel.empty() ch_interop = Channel.empty() + ch_logs = channel.empty() // Split flowcells into separate channels containing run as tar and run as path // https://nextflow.slack.com/archives/C02T98A23U7/p1650963988498929 @@ -49,6 +50,7 @@ workflow BCL_DEMULTIPLEX { ch_fastq = ch_fastq.mix(BCLCONVERT.out.fastq) 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_versions = ch_versions.mix(BCLCONVERT.out.versions.first()) } @@ -132,5 +134,6 @@ workflow BCL_DEMULTIPLEX { reports = ch_reports stats = ch_stats interop = ch_interop + logs = ch_logs versions = ch_versions } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index bf939975..19ee316b 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -446,6 +446,9 @@ workflow PREPROCESSING { ) emit: + demultiplex_interop = BCL_DEMULTIPLEX.out.interop + demultiplex_reports = BCL_DEMULTIPLEX.out.reports + demultiplex_logs = BCL_DEMULTIPLEX.out.logs multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html versions = ch_versions // channel: [ path(versions.yml) ] } From 2c3949f1a9ca07a571f2e7cba33884b745c00c58 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Mon, 3 Nov 2025 17:31:53 +0100 Subject: [PATCH 016/228] fix more bclconvert outputs --- main.nf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main.nf b/main.nf index 2122b585..572c11e4 100644 --- a/main.nf +++ b/main.nf @@ -64,14 +64,16 @@ workflow { ) publish: - demultiplex_interop = PREPROCESSING.out.demultiplex_interop + demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) demultiplex_reports = PREPROCESSING.out.demultiplex_reports.map { meta, reports -> [ meta, files("${reports.toUri()}/*") ] }.transpose(by:1) demultiplex_logs = PREPROCESSING.out.demultiplex_logs.map { meta, logs -> [ meta, files("${logs.toUri()}/*") ] }.transpose(by:1) } output { // TODO also add the RunInfo.xml file as output, needs a module update - demultiplex_interop { path "InterOp" } + demultiplex_interop { path { _meta, bin -> + bin >> "Interop/${bin.name}" + } } demultiplex_reports { path { meta, report -> report >> (meta.lane ? "Reports/LOO${meta.lane}/${report.name}" as String : "Reports/${report.name}") } } From 93a0496e2d798ff8aec6bb29768e3b4e087bac74 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Tue, 4 Nov 2025 13:58:53 +0100 Subject: [PATCH 017/228] finish conversion of the output handling --- conf/modules.config | 89 +- main.nf | 83 +- nf-test.config | 4 + subworkflows/local/bam_qc/main.nf | 29 +- subworkflows/local/coverage/main.nf | 21 +- .../local/fastq_to_aligned_cram/main.nf | 21 +- .../local/fastq_to_unaligned_cram/main.nf | 1 - tests/nextflow.config | 1 + tests/workflows/preprocessing.nf.test | 42 +- tests/workflows/preprocessing.nf.test.snap | 1531 ++++++++++++++++- workflows/preprocessing.nf | 62 +- 11 files changed, 1711 insertions(+), 173 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 0157c825..d7e5b2da 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -12,11 +12,11 @@ process { - publishDir = [ - path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals("versions.yml") ? null : filename }, - ] + // publishDir = [ + // path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}" }, + // mode: params.publish_dir_mode, + // saveAs: { filename -> filename.equals("versions.yml") ? null : filename }, + // ] // BCL convert withName: BCLCONVERT { @@ -45,13 +45,6 @@ process { "--compression 1", ].join(" ").trim() } - publishDir = [ - [ - path: { "${params.outdir}/${meta.samplename}" }, - mode: params.publish_dir_mode, - pattern: "*.{html,json}", - ] - ] } // FASTQ_TO_UCRAM @@ -65,7 +58,6 @@ process { "--output-fmt-option archive", ].join(" ").trim() } - publishDir = [enabled: false] } // FASTQ_TO_CRAM @@ -79,12 +71,6 @@ process { // LB : library prep // SM : samplename - - // FASTQ_ALIGN_DNA - withName: '.*:FASTQ_ALIGN_DNA:.*' { - publishDir = [enabled: false] - } - //// Bowtie2 withName: BOWTIE2_ALIGN { ext.args = { @@ -96,11 +82,6 @@ process { ].join(" ").trim() } ext.args2 = "--fast" - publishDir = [ - path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}" }, - mode: params.publish_dir_mode, - pattern: "*.log", - ] } //// BWA mem/BWA mem2 @@ -152,11 +133,6 @@ process { } } - // FASTQ_ALIGN_RNA - withName: '.*FASTQ_ALIGN_RNA:.*' { - publishDir = [enabled: false] - } - withName: STAR_ALIGN { ext.args = { [ @@ -187,20 +163,6 @@ process { "--output-fmt-option archive", ].join(" ").trim() } - publishDir = [ - [ - path: { "${params.outdir}/${meta.samplename}" }, - mode: params.publish_dir_mode, - pattern: "*metrics*", - saveAs: { filename -> filename.replace("metrics", "duplicate_metrics").replace(".merged", "") }, - ], - [ - path: { "${params.outdir}/${meta.samplename}" }, - mode: params.publish_dir_mode, - pattern: "*cram*", - saveAs: { filename -> filename.replace(".merged", "") }, - ], - ] } //// Samtools multisort @@ -213,14 +175,6 @@ process { "--output-fmt-option archive", ].join(" ").trim() } - publishDir = [ - [ - path: { "${params.outdir}/${meta.samplename}" }, - mode: params.publish_dir_mode, - pattern: "*cram*", - saveAs: { filename -> filename.replace(".merged", "") }, - ] - ] } //// BioBamBam Bamsormadup @@ -233,14 +187,6 @@ process { ].join(" ").trim() } ext.args2 = "exclude=QCFAIL" - publishDir = [ - [ - path: { "${params.outdir}/${meta.samplename}" }, - mode: params.publish_dir_mode, - pattern: "*metrics*", - saveAs: { filename -> filename.replace("metrics", "duplicate_metrics").replace(".merged", "") }, - ] - ] } //// Samtools convert @@ -254,14 +200,6 @@ process { "--output-fmt-option archive", ].join(" ").trim() } - publishDir = [ - [ - path: { "${params.outdir}/${meta.samplename}" }, - mode: params.publish_dir_mode, - pattern: "*cram*", - saveAs: { filename -> filename.replace(".merged", "") }, - ] - ] } // coverage @@ -286,18 +224,6 @@ process { // ext.args = { "--title \"Coverage ${meta.samplename ?: meta.id}\" } // } - // Checksums - withName: MD5SUM { - publishDir = [ - [ - path: { "${params.outdir}/${meta.samplename}" }, - mode: params.publish_dir_mode, - pattern: "*.md5", - saveAs: { filename -> filename.replace(".merged", "") }, - ] - ] - } - // QC withName: '.*BAM_QC.*' { @@ -314,11 +240,6 @@ process { // MultiQC withName: MULTIQC { ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } - publishDir = [ - path: { "${params.outdir}/multiqc" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename }, - ] } } diff --git a/main.nf b/main.nf index 572c11e4..9b07d959 100644 --- a/main.nf +++ b/main.nf @@ -67,17 +67,94 @@ workflow { demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) demultiplex_reports = PREPROCESSING.out.demultiplex_reports.map { meta, reports -> [ meta, files("${reports.toUri()}/*") ] }.transpose(by:1) demultiplex_logs = PREPROCESSING.out.demultiplex_logs.map { meta, logs -> [ meta, files("${logs.toUri()}/*") ] }.transpose(by:1) + fastp_json = PREPROCESSING.out.fastp_json + fastp_html = PREPROCESSING.out.fastp_html + ucrams = PREPROCESSING.out.ucrams + crams = PREPROCESSING.out.crams + align_reports = PREPROCESSING.out.align_reports + sormadup_metrics = PREPROCESSING.out.sormadup_metrics + mosdepth_global = PREPROCESSING.out.mosdepth_global + mosdepth_summary = PREPROCESSING.out.mosdepth_summary + mosdepth_regions = PREPROCESSING.out.mosdepth_regions + mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed + mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi + mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed + mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi + mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed + mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi + samtools_coverage = PREPROCESSING.out.samtools_coverage + panelcoverage = PREPROCESSING.out.panelcoverage + samtools_stats = PREPROCESSING.out.samtools_stats + samtools_flagstat = PREPROCESSING.out.samtools_flagstat + samtools_idxstats = PREPROCESSING.out.samtools_idxstats + picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics + picard_multiplemetrics_pdf = PREPROCESSING.out.picard_multiplemetrics_pdf + picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics + picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics + md5sums = PREPROCESSING.out.md5sums + multiqc_report = PREPROCESSING.out.multiqc_report + multiqc_data = PREPROCESSING.out.multiqc_data + multiqc_plots = PREPROCESSING.out.multiqc_plots + } output { - // TODO also add the RunInfo.xml file as output, needs a module update demultiplex_interop { path { _meta, bin -> bin >> "Interop/${bin.name}" } } demultiplex_reports { path { meta, report -> - report >> (meta.lane ? "Reports/LOO${meta.lane}/${report.name}" as String : "Reports/${report.name}") + def out_path = meta.lane ? "Reports/LOO${meta.lane}/${report.name}" as String : "Reports/${report.name}" + report >> out_path } } demultiplex_logs { path { meta, log -> - log >> (meta.lane ? "Logs/LOO${meta.lane}/${log.name}" as String : "Logs/${log.name}") + def out_path = meta.lane ? "Logs/LOO${meta.lane}/${log.name}" as String : "Logs/${log.name}" + log >> out_path + } } + fastp_json { path { meta, json -> + json >> "${meta.samplename}/${json.name}" + } } + fastp_html { path { meta, html -> + html >> "${meta.samplename}/${html.name}" + } } + ucrams { path { meta, cram -> + cram >> "${meta.samplename}/${meta.samplename}.unaligned.cram" + } } + crams { path { meta, cram, crai -> + cram >> "${meta.samplename}/${meta.samplename}.cram" + crai >> "${meta.samplename}/${meta.samplename}.cram.crai" + } } + align_reports { path { meta, log -> + log >> "${meta.samplename}/${log.name}" + } } + sormadup_metrics { path { meta, metrics -> + metrics >> "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" } } + mosdepth_global { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_summary { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_regions { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_per_base_d4 { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_per_base_bed { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_per_base_csi { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_regions_bed { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_regions_csi { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_quantized_bed { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_quantized_csi { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_thresholds_bed { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_thresholds_csi { path { meta, _file -> "${meta.samplename}/" } } + samtools_coverage { path { meta, _file -> "${meta.samplename}/" } } + panelcoverage { path { meta, _file -> "${meta.samplename}/" } } + samtools_stats { path { meta, _file -> "${meta.samplename}/" } } + samtools_flagstat { path { meta, _file -> "${meta.samplename}/" } } + samtools_idxstats { path { meta, _file -> "${meta.samplename}/" } } + picard_multiplemetrics { path { meta, _file -> "${meta.samplename}/" } } + picard_multiplemetrics_pdf { path { meta, _file -> "${meta.samplename}/" } } + picard_wgsmetrics { path { meta, _file -> "${meta.samplename}/" } } + picard_hsmetrics { path { meta, _file -> "${meta.samplename}/" } } + md5sums { path { meta, _file -> "${meta.samplename}/" } } + multiqc_report { path "multiqc/" } + multiqc_data { path "multiqc/" } + multiqc_plots { path "multiqc/" } } diff --git a/nf-test.config b/nf-test.config index aa727c88..f35650da 100644 --- a/nf-test.config +++ b/nf-test.config @@ -5,4 +5,8 @@ config { profile "docker" options "-dump-channels" + plugins { + load "nft-utils@0.0.7" + } + } diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index a87c62f6..f779364e 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -37,9 +37,10 @@ workflow BAM_QC { SAMTOOLS_IDXSTATS(ch_bam_bai) ch_versions = ch_versions.mix(SAMTOOLS_IDXSTATS.out.versions.first()) - ch_picard_hsmetrics = Channel.empty() - ch_picard_multiplemetrics = Channel.empty() - ch_picard_wgsmetrics = Channel.empty() + ch_picard_hsmetrics = channel.empty() + ch_picard_multiplemetrics = channel.empty() + ch_picard_multiplemetrics_pdf = channel.empty() + ch_picard_wgsmetrics = channel.empty() if (!disable_picard) { ch_bam_bai_roi_fasta_fai_dict @@ -50,7 +51,8 @@ workflow BAM_QC { PICARD_COLLECTMULTIPLEMETRICS(ch_bam_bai_fasta_fai) ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions.first()) - ch_picard_multiplemetrics = ch_picard_multiplemetrics.mix(PICARD_COLLECTMULTIPLEMETRICS.out.metrics) + ch_picard_multiplemetrics = PICARD_COLLECTMULTIPLEMETRICS.out.metrics + ch_picard_multiplemetrics_pdf = PICARD_COLLECTMULTIPLEMETRICS.out.pdf ch_bam_bai_roi_fasta_fai_dict .branch { meta, bam, bai, roi, fasta, fai, dict -> @@ -63,19 +65,20 @@ workflow BAM_QC { PICARD_COLLECTWGSMETRICS(ch_picard.wgsmetrics, []) ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) - ch_picard_wgsmetrics = ch_picard_wgsmetrics.mix(PICARD_COLLECTWGSMETRICS.out.metrics) + ch_picard_wgsmetrics = PICARD_COLLECTWGSMETRICS.out.metrics PICARD_COLLECTHSMETRICS(ch_picard.hsmetrics) ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions.first()) - ch_picard_hsmetrics = ch_picard_hsmetrics.mix(PICARD_COLLECTHSMETRICS.out.metrics) + ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics } emit: - samtools_stats = SAMTOOLS_STATS.out.stats - samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat - samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats - picard_multiplemetrics = ch_picard_multiplemetrics - picard_wgsmetrics = ch_picard_wgsmetrics - picard_hsmetrics = ch_picard_hsmetrics - versions = ch_versions + samtools_stats = SAMTOOLS_STATS.out.stats + samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat + samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats + picard_multiplemetrics = ch_picard_multiplemetrics + picard_multiplemetrics_pdf = ch_picard_multiplemetrics_pdf + picard_wgsmetrics = ch_picard_wgsmetrics + picard_hsmetrics = ch_picard_hsmetrics + versions = ch_versions } diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index bf3b187b..d59ace12 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -56,10 +56,19 @@ workflow COVERAGE { ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) emit: - mosdepth_summary = MOSDEPTH.out.summary_txt - mosdepth_global = MOSDEPTH.out.global_txt - mosdepth_regions = MOSDEPTH.out.regions_txt - samtools_coverage = SAMTOOLS_COVERAGE.out.coverage - panelcoverage = PANELCOVERAGE.out.regiondist - versions = ch_versions + mosdepth_global = MOSDEPTH.out.global_txt + mosdepth_summary = MOSDEPTH.out.summary_txt + mosdepth_regions = MOSDEPTH.out.regions_txt + mosdepth_per_base_d4 = MOSDEPTH.out.per_base_d4 + mosdepth_per_base_bed = MOSDEPTH.out.per_base_bed + mosdepth_per_base_csi = MOSDEPTH.out.per_base_csi + mosdepth_regions_bed = MOSDEPTH.out.regions_bed + mosdepth_regions_csi = MOSDEPTH.out.regions_csi + mosdepth_quantized_bed = MOSDEPTH.out.quantized_bed + mosdepth_quantized_csi = MOSDEPTH.out.quantized_csi + mosdepth_thresholds_bed = MOSDEPTH.out.thresholds_bed + mosdepth_thresholds_csi = MOSDEPTH.out.thresholds_csi + samtools_coverage = SAMTOOLS_COVERAGE.out.coverage + panelcoverage = PANELCOVERAGE.out.regiondist + versions = ch_versions } diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index afed2cc2..49199684 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -25,7 +25,7 @@ workflow FASTQ_TO_CRAM { main: ch_versions = Channel.empty() - ch_multiqc_files = Channel.empty() + ch_sormadup_metrics = Channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -99,21 +99,13 @@ workflow FASTQ_TO_CRAM { // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) BIOBAMBAM_BAMSORMADUP(ch_bam_fasta) ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch: true, failOnDuplicate: true)) - ch_multiqc_files = ch_multiqc_files.mix( - BIOBAMBAM_BAMSORMADUP.out.metrics.map { _meta, metrics -> - return metrics - } - ) + ch_sormadup_metrics = ch_sormadup_metrics.mix(BIOBAMBAM_BAMSORMADUP.out.metrics) ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions.first()) } else if (markdup == "samtools") { SAMTOOLS_SORMADUP(ch_bam_fasta) ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch: true, failOnDuplicate: true)) - ch_multiqc_files = ch_multiqc_files.mix( - SAMTOOLS_SORMADUP.out.metrics.map { _meta, metrics -> - return metrics - } - ) + ch_sormadup_metrics = ch_sormadup_metrics.mix(SAMTOOLS_SORMADUP.out.metrics) ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions.first()) } else if (markdup == "false" || markdup == false) { @@ -160,7 +152,8 @@ workflow FASTQ_TO_CRAM { ch_cram_crai.dump(tag: "FASTQ_TO_CRAM: cram and crai", pretty: true) emit: - cram_crai = ch_cram_crai - multiqc_files = ch_multiqc_files - versions = ch_versions + cram_crai = ch_cram_crai + sormadup_metrics = ch_sormadup_metrics + align_reports = FASTQ_ALIGN_DNA.out.reports + versions = ch_versions } diff --git a/subworkflows/local/fastq_to_unaligned_cram/main.nf b/subworkflows/local/fastq_to_unaligned_cram/main.nf index 37dc0527..1c458a2b 100644 --- a/subworkflows/local/fastq_to_unaligned_cram/main.nf +++ b/subworkflows/local/fastq_to_unaligned_cram/main.nf @@ -6,7 +6,6 @@ // MODULES include { SAMTOOLS_CAT } from '../../../modules/nf-core/samtools/cat/main' include { SAMTOOLS_IMPORT } from "../../../modules/nf-core/samtools/import/main" -include { MD5SUM } from "../../../modules/nf-core/md5sum/main" workflow FASTQ_TO_UCRAM { take: diff --git a/tests/nextflow.config b/tests/nextflow.config index e69de29b..548fbe63 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -0,0 +1 @@ +includeConfig "config/nf-test.config" diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index 0bb017be..2f1c5e4c 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -57,8 +57,18 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - file(workflow.out.multiqc_report[0][0]).name, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:[ + "multiqc_report", + "multiqc_plots", + "multiqc_data", + "md5sums", + "fastp_html", + "crams", + "picard_wgsmetrics", + "picard_multiplemetrics_pdf", + "picard_multiplemetrics", + "picard_hsmetrics" + ]) ).match() } } @@ -113,8 +123,18 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - file(workflow.out.multiqc_report[0][0]).name, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:[ + "multiqc_report", + "multiqc_plots", + "multiqc_data", + "md5sums", + "fastp_html", + "crams", + "picard_wgsmetrics", + "picard_multiplemetrics_pdf", + "picard_multiplemetrics", + "picard_hsmetrics" + ]) ).match() } } @@ -172,8 +192,18 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - file(workflow.out.multiqc_report[0][0]).name, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:[ + "multiqc_report", + "multiqc_plots", + "multiqc_data", + "md5sums", + "fastp_html", + "crams", + "picard_wgsmetrics", + "picard_multiplemetrics_pdf", + "picard_multiplemetrics", + "picard_hsmetrics" + ]) ).match() } } diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 80141e0d..8bd43a7e 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -1,67 +1,1510 @@ { "preprocessing - fastq - bwa - bamsormadup - roi": { "content": [ - "multiqc_report.html", - [ - "versions.yml:md5,321e55c8f19102dc87a10e981635edda", - "versions.yml:md5,3e9382a1dc62d4f405bcfb58fe6b7768", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", - "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", - "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", - "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", - "versions.yml:md5,ebdd9fe0c553612c66238375b920f178", - "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" - ] + { + "align_reports": [ + + ], + "crams": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + } + }, + "sample1.cram", + "sample1.cram.crai" + ] + ], + "demultiplex_interop": [ + + ], + "demultiplex_logs": [ + + ], + "demultiplex_reports": [ + + ], + "fastp_html": [ + [ + { + "aligner": "bwamem", + "count": 1, + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "readgroup": { + "CN": "CMGG", + "ID": "H5T2YDSX3.1", + "LB": "test", + "PL": "ILLUMINA", + "PU": "H5T2YDSX3.1", + "SM": "sample1" + }, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + }, + "sample1.fastp.html" + ] + ], + "fastp_json": [ + [ + { + "id": "sample1", + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "readgroup": { + "CN": "CMGG", + "ID": "H5T2YDSX3.1", + "PU": "H5T2YDSX3.1", + "PL": "ILLUMINA", + "SM": "sample1", + "LB": "test" + }, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "count": 1 + }, + "sample1.fastp.json:md5,543fb8fe4512975ce7dafd5287cae601" + ] + ], + "md5sums": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + } + }, + "sample1.md5" + ] + ], + "mosdepth_global": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.mosdepth.global.dist.txt:md5,4574a0f755903d7ab7aa07297cc1efee" + ] + ], + "mosdepth_per_base_bed": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.per-base.bed.gz:md5,46115d39863826ae9199340c2eb888a6" + ] + ], + "mosdepth_per_base_csi": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.per-base.bed.gz.csi:md5,12fdbaf668bda28541b869adecc15dc7" + ] + ], + "mosdepth_per_base_d4": [ + + ], + "mosdepth_quantized_bed": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.quantized.bed.gz:md5,d54d469a692c3fe4a4e1db02c08be518" + ] + ], + "mosdepth_quantized_csi": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.quantized.bed.gz.csi:md5,ac24f9c737b984091364b3c5b1f45567" + ] + ], + "mosdepth_regions": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.mosdepth.region.dist.txt:md5,388e05b0b4d7754be6fdc0b1b6eabed9" + ] + ], + "mosdepth_regions_bed": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.regions.bed.gz:md5,63a7fee57ae572a661fba2d14c6db1b4" + ] + ], + "mosdepth_regions_csi": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.regions.bed.gz.csi:md5,531956423eb6b53186ae4adc39e0e61e" + ] + ], + "mosdepth_summary": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.mosdepth.summary.txt:md5,cfd81f854b864f9630e8831b48cfc9a0" + ] + ], + "mosdepth_thresholds_bed": [ + + ], + "mosdepth_thresholds_csi": [ + + ], + "multiqc_data": [ + "multiqc_data" + ], + "multiqc_plots": [ + "multiqc_plots" + ], + "multiqc_report": [ + [ + "multiqc_report.html" + ] + ], + "panelcoverage": [ + + ], + "picard_hsmetrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + } + }, + "sample1.CollectHsMetrics.coverage_metrics" + ] + ], + "picard_multiplemetrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + } + }, + [ + "sample1.CollectMultipleMetrics.alignment_summary_metrics", + "sample1.CollectMultipleMetrics.base_distribution_by_cycle_metrics", + "sample1.CollectMultipleMetrics.quality_by_cycle_metrics", + "sample1.CollectMultipleMetrics.quality_distribution_metrics" + ] + ] + ], + "picard_multiplemetrics_pdf": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + } + }, + [ + "sample1.CollectMultipleMetrics.base_distribution_by_cycle.pdf", + "sample1.CollectMultipleMetrics.quality_by_cycle.pdf", + "sample1.CollectMultipleMetrics.quality_distribution.pdf", + "sample1.CollectMultipleMetrics.read_length_histogram.pdf" + ] + ] + ], + "picard_wgsmetrics": [ + + ], + "samtools_coverage": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.coverage.txt:md5,82e6e6b4163459aeca0b9dd40ef67d13" + ] + ], + "samtools_flagstat": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.flagstat:md5,da197e74ff53116dd9b8b1241f468aac" + ] + ], + "samtools_idxstats": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.idxstats:md5,4e1b204d3bb59e42022c5d84be705ed8" + ] + ], + "samtools_stats": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.stats:md5,0653e8f1834d58c557ad463c36ae6b61" + ] + ], + "sormadup_metrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" + ] + ], + "ucrams": [ + + ], + "versions": [ + "versions.yml:md5,321e55c8f19102dc87a10e981635edda", + "versions.yml:md5,3e9382a1dc62d4f405bcfb58fe6b7768", + "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", + "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", + "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", + "versions.yml:md5,7b30e3b870fe318aeef6b4bffc51eb87", + "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", + "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", + "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", + "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", + "versions.yml:md5,ebdd9fe0c553612c66238375b920f178", + "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" + ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.3" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-04T14:32:22.782118028" + "timestamp": "2025-11-04T13:30:49.340803877" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ - "multiqc_report.html", - [ - "versions.yml:md5,321e55c8f19102dc87a10e981635edda", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", - "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", - "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868" - ] + { + "align_reports": [ + + ], + "crams": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + } + }, + "sample1.cram", + "sample1.cram.crai" + ] + ], + "demultiplex_interop": [ + + ], + "demultiplex_logs": [ + + ], + "demultiplex_reports": [ + + ], + "fastp_html": [ + [ + { + "aligner": "bwamem", + "count": 1, + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "readgroup": { + "CN": "CMGG", + "ID": "H5T2YDSX3.1", + "LB": "test", + "PL": "ILLUMINA", + "PU": "H5T2YDSX3.1", + "SM": "sample1" + }, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + }, + "sample1.fastp.html" + ] + ], + "fastp_json": [ + [ + { + "id": "sample1", + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "readgroup": { + "CN": "CMGG", + "ID": "H5T2YDSX3.1", + "PU": "H5T2YDSX3.1", + "PL": "ILLUMINA", + "SM": "sample1", + "LB": "test" + }, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "count": 1 + }, + "sample1.fastp.json:md5,543fb8fe4512975ce7dafd5287cae601" + ] + ], + "md5sums": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" + } + }, + "sample1.md5" + ] + ], + "mosdepth_global": [ + + ], + "mosdepth_per_base_bed": [ + + ], + "mosdepth_per_base_csi": [ + + ], + "mosdepth_per_base_d4": [ + + ], + "mosdepth_quantized_bed": [ + + ], + "mosdepth_quantized_csi": [ + + ], + "mosdepth_regions": [ + + ], + "mosdepth_regions_bed": [ + + ], + "mosdepth_regions_csi": [ + + ], + "mosdepth_summary": [ + + ], + "mosdepth_thresholds_bed": [ + + ], + "mosdepth_thresholds_csi": [ + + ], + "multiqc_data": [ + "multiqc_data" + ], + "multiqc_plots": [ + "multiqc_plots" + ], + "multiqc_report": [ + [ + "multiqc_report.html" + ] + ], + "panelcoverage": [ + + ], + "picard_hsmetrics": [ + + ], + "picard_multiplemetrics": [ + + ], + "picard_multiplemetrics_pdf": [ + + ], + "picard_wgsmetrics": [ + + ], + "samtools_coverage": [ + + ], + "samtools_flagstat": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.flagstat:md5,da197e74ff53116dd9b8b1241f468aac" + ] + ], + "samtools_idxstats": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.idxstats:md5,4e1b204d3bb59e42022c5d84be705ed8" + ] + ], + "samtools_stats": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.stats:md5,0653e8f1834d58c557ad463c36ae6b61" + ] + ], + "sormadup_metrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WES", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "id": "sample1" + } + }, + "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" + ] + ], + "ucrams": [ + + ], + "versions": [ + "versions.yml:md5,321e55c8f19102dc87a10e981635edda", + "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", + "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", + "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", + "versions.yml:md5,7b30e3b870fe318aeef6b4bffc51eb87", + "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", + "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", + "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868" + ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.3" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-04T14:36:49.460737865" + "timestamp": "2025-11-04T13:36:14.450163857" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ - "multiqc_report.html", - [ - "versions.yml:md5,2dbfdf50978986550dbe621f1d49fea7", - "versions.yml:md5,321e55c8f19102dc87a10e981635edda", - "versions.yml:md5,3e9382a1dc62d4f405bcfb58fe6b7768", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", - "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", - "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", - "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", - "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" - ] + { + "align_reports": [ + + ], + "crams": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" + } + }, + "sample1.cram", + "sample1.cram.crai" + ] + ], + "demultiplex_interop": [ + + ], + "demultiplex_logs": [ + + ], + "demultiplex_reports": [ + + ], + "fastp_html": [ + [ + { + "aligner": "bwamem", + "count": 1, + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "readgroup": { + "CN": "CMGG", + "ID": "H5T2YDSX3.1", + "LB": "test", + "PL": "ILLUMINA", + "PU": "H5T2YDSX3.1", + "SM": "sample1" + }, + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" + }, + "sample1.fastp.html" + ] + ], + "fastp_json": [ + [ + { + "id": "sample1", + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "readgroup": { + "CN": "CMGG", + "ID": "H5T2YDSX3.1", + "PU": "H5T2YDSX3.1", + "PL": "ILLUMINA", + "SM": "sample1", + "LB": "test" + }, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "count": 1 + }, + "sample1.fastp.json:md5,543fb8fe4512975ce7dafd5287cae601" + ] + ], + "md5sums": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" + } + }, + "sample1.md5" + ] + ], + "mosdepth_global": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.mosdepth.global.dist.txt:md5,4574a0f755903d7ab7aa07297cc1efee" + ] + ], + "mosdepth_per_base_bed": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.per-base.bed.gz:md5,46115d39863826ae9199340c2eb888a6" + ] + ], + "mosdepth_per_base_csi": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.per-base.bed.gz.csi:md5,12fdbaf668bda28541b869adecc15dc7" + ] + ], + "mosdepth_per_base_d4": [ + + ], + "mosdepth_quantized_bed": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.quantized.bed.gz:md5,d54d469a692c3fe4a4e1db02c08be518" + ] + ], + "mosdepth_quantized_csi": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.quantized.bed.gz.csi:md5,ac24f9c737b984091364b3c5b1f45567" + ] + ], + "mosdepth_regions": [ + + ], + "mosdepth_regions_bed": [ + + ], + "mosdepth_regions_csi": [ + + ], + "mosdepth_summary": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.mosdepth.summary.txt:md5,9799b90b7db86a6eab36f33b04a67ae0" + ] + ], + "mosdepth_thresholds_bed": [ + + ], + "mosdepth_thresholds_csi": [ + + ], + "multiqc_data": [ + "multiqc_data" + ], + "multiqc_plots": [ + "multiqc_plots" + ], + "multiqc_report": [ + [ + "multiqc_report.html" + ] + ], + "panelcoverage": [ + + ], + "picard_hsmetrics": [ + + ], + "picard_multiplemetrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" + } + }, + [ + "sample1.CollectMultipleMetrics.alignment_summary_metrics", + "sample1.CollectMultipleMetrics.base_distribution_by_cycle_metrics", + "sample1.CollectMultipleMetrics.quality_by_cycle_metrics", + "sample1.CollectMultipleMetrics.quality_distribution_metrics" + ] + ] + ], + "picard_multiplemetrics_pdf": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" + } + }, + [ + "sample1.CollectMultipleMetrics.base_distribution_by_cycle.pdf", + "sample1.CollectMultipleMetrics.quality_by_cycle.pdf", + "sample1.CollectMultipleMetrics.quality_distribution.pdf", + "sample1.CollectMultipleMetrics.read_length_histogram.pdf" + ] + ] + ], + "picard_wgsmetrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "aligner": "bwamem", + "genome": "GRCh38", + "genome_data": { + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "sample1", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" + } + }, + "sample1.CollectWgsMetrics.coverage_metrics" + ] + ], + "samtools_coverage": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.coverage.txt:md5,82e6e6b4163459aeca0b9dd40ef67d13" + ] + ], + "samtools_flagstat": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.flagstat:md5,da197e74ff53116dd9b8b1241f468aac" + ] + ], + "samtools_idxstats": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.idxstats:md5,4e1b204d3bb59e42022c5d84be705ed8" + ] + ], + "samtools_stats": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.stats:md5,0653e8f1834d58c557ad463c36ae6b61" + ] + ], + "sormadup_metrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "samplename": "sample1", + "organism": "Homo sapiens", + "tag": "WGS", + "sample_type": "DNA", + "single_end": false, + "genome": "GRCh38", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "aligner": "bwamem", + "id": "sample1" + } + }, + "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" + ] + ], + "ucrams": [ + + ], + "versions": [ + "versions.yml:md5,2dbfdf50978986550dbe621f1d49fea7", + "versions.yml:md5,321e55c8f19102dc87a10e981635edda", + "versions.yml:md5,3e9382a1dc62d4f405bcfb58fe6b7768", + "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", + "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", + "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", + "versions.yml:md5,7b30e3b870fe318aeef6b4bffc51eb87", + "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", + "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", + "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", + "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", + "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" + ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.3" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-04T14:35:21.629978137" + "timestamp": "2025-11-04T13:34:27.74379172" } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 19ee316b..c3e13fd3 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -274,7 +274,7 @@ workflow PREPROCESSING { markdup, ) - ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.multiqc_files) + ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics.map { _meta, metrics -> metrics }) ch_versions = ch_versions.mix(FASTQ_TO_CRAM.out.versions) @@ -322,7 +322,21 @@ workflow PREPROCESSING { } .set { ch_cram_crai_fasta_fai_roi } - if (params.run_coverage == true || params.run_coverage == "true") { + def mosdepth_global_out = channel.empty() + def mosdepth_summary_out = channel.empty() + def mosdepth_regions_out = channel.empty() + def mosdepth_per_base_d4_out = channel.empty() + def mosdepth_per_base_bed_out = channel.empty() + def mosdepth_per_base_csi_out = channel.empty() + def mosdepth_regions_bed_out = channel.empty() + def mosdepth_regions_csi_out = channel.empty() + def mosdepth_quantized_bed_out = channel.empty() + def mosdepth_quantized_csi_out = channel.empty() + def mosdepth_thresholds_bed_out = channel.empty() + def mosdepth_thresholds_csi_out = channel.empty() + def samtools_coverage_out = channel.empty() + def panelcoverage_out = channel.empty() + if (params.run_coverage) { COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) ch_multiqc_files = ch_multiqc_files.mix( COVERAGE.out.mosdepth_summary.map { _meta, txt -> @@ -338,6 +352,20 @@ workflow PREPROCESSING { return txt }, ) + mosdepth_global_out = COVERAGE.out.mosdepth_global + mosdepth_summary_out = COVERAGE.out.mosdepth_summary + mosdepth_regions_out = COVERAGE.out.mosdepth_regions + mosdepth_per_base_d4_out = COVERAGE.out.mosdepth_per_base_d4 + mosdepth_per_base_bed_out = COVERAGE.out.mosdepth_per_base_bed + mosdepth_per_base_csi_out = COVERAGE.out.mosdepth_per_base_csi + mosdepth_regions_bed_out = COVERAGE.out.mosdepth_regions_bed + mosdepth_regions_csi_out = COVERAGE.out.mosdepth_regions_csi + mosdepth_quantized_bed_out = COVERAGE.out.mosdepth_quantized_bed + mosdepth_quantized_csi_out = COVERAGE.out.mosdepth_quantized_csi + mosdepth_thresholds_bed_out = COVERAGE.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi_out = COVERAGE.out.mosdepth_thresholds_csi + samtools_coverage_out = COVERAGE.out.samtools_coverage + panelcoverage_out = COVERAGE.out.panelcoverage ch_versions = ch_versions.mix(COVERAGE.out.versions) } @@ -449,7 +477,37 @@ workflow PREPROCESSING { demultiplex_interop = BCL_DEMULTIPLEX.out.interop demultiplex_reports = BCL_DEMULTIPLEX.out.reports demultiplex_logs = BCL_DEMULTIPLEX.out.logs + fastp_json = FASTP.out.json + fastp_html = FASTP.out.html + ucrams = FASTQ_TO_UCRAM.out.cram + crams = FASTQ_TO_CRAM.out.cram_crai + align_reports = FASTQ_TO_CRAM.out.align_reports + sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics + mosdepth_global = mosdepth_global_out + mosdepth_summary = mosdepth_summary_out + mosdepth_regions = mosdepth_regions_out + mosdepth_per_base_d4 = mosdepth_per_base_d4_out + mosdepth_per_base_bed = mosdepth_per_base_bed_out + mosdepth_per_base_csi = mosdepth_per_base_csi_out + mosdepth_regions_bed = mosdepth_regions_bed_out + mosdepth_regions_csi = mosdepth_regions_csi_out + mosdepth_quantized_bed = mosdepth_quantized_bed_out + mosdepth_quantized_csi = mosdepth_quantized_csi_out + mosdepth_thresholds_bed = mosdepth_thresholds_bed_out + mosdepth_thresholds_csi = mosdepth_thresholds_csi_out + samtools_coverage = samtools_coverage_out + panelcoverage = panelcoverage_out + samtools_stats = BAM_QC.out.samtools_stats + samtools_flagstat = BAM_QC.out.samtools_flagstat + samtools_idxstats = BAM_QC.out.samtools_idxstats + picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics + picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf + picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics + picard_hsmetrics = BAM_QC.out.picard_hsmetrics + md5sums = MD5SUM.out.checksum multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + multiqc_data = MULTIQC.out.data + multiqc_plots = MULTIQC.out.plots versions = ch_versions // channel: [ path(versions.yml) ] } From fade37ec6ba6ae0868230b26d08eebbe49e3be7a Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Tue, 4 Nov 2025 14:48:51 +0100 Subject: [PATCH 018/228] fix subwf tests --- conf/modules.config | 6 - tests/subworkflows/local/bam_qc/main.nf.test | 31 +- .../local/bam_qc/main.nf.test.snap | 293 +++++++++++----- .../local/coverage/main.nf.test.snap | 317 ++++++++++++++---- .../local/fastq_align_rna/main.nf.test | 4 +- .../local/fastq_align_rna/main.nf.test.snap | 120 +++---- .../local/fastq_to_aligned_cram/main.nf.test | 20 +- .../fastq_to_aligned_cram/main.nf.test.snap | 285 ++++++++++++---- .../fastq_to_unaligned_cram/main.nf.test | 3 +- .../fastq_to_unaligned_cram/main.nf.test.snap | 28 +- 10 files changed, 771 insertions(+), 336 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index d7e5b2da..00f0f28e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -12,12 +12,6 @@ process { - // publishDir = [ - // path: { meta.samplename ? "${params.outdir}/${meta.samplename}" : "${params.outdir}" }, - // mode: params.publish_dir_mode, - // saveAs: { filename -> filename.equals("versions.yml") ? null : filename }, - // ] - // BCL convert withName: BCLCONVERT { ext.args = { diff --git a/tests/subworkflows/local/bam_qc/main.nf.test b/tests/subworkflows/local/bam_qc/main.nf.test index 68bc3cc9..90e3c564 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test +++ b/tests/subworkflows/local/bam_qc/main.nf.test @@ -32,11 +32,12 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - workflow.out.samtools_stats, - workflow.out.samtools_flagstat, - workflow.out.samtools_idxstats, - file(workflow.out.picard_multiplemetrics[0][1][0]).name, - file(workflow.out.picard_hsmetrics[0][1]).name, + sanitizeOutput(workflow.out, unstableKeys:[ + "picard_wgsmetrics", + "picard_multiplemetrics_pdf", + "picard_multiplemetrics", + "picard_hsmetrics" + ]) ).match() } @@ -65,11 +66,12 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - workflow.out.samtools_stats, - workflow.out.samtools_flagstat, - workflow.out.samtools_idxstats, - file(workflow.out.picard_multiplemetrics[0][1][0]).name, - file(workflow.out.picard_wgsmetrics[0][1]).name, + sanitizeOutput(workflow.out, unstableKeys:[ + "picard_wgsmetrics", + "picard_multiplemetrics_pdf", + "picard_multiplemetrics", + "picard_hsmetrics" + ]) ).match() } } @@ -97,9 +99,12 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - workflow.out.samtools_stats, - workflow.out.samtools_flagstat, - workflow.out.samtools_idxstats, + sanitizeOutput(workflow.out, unstableKeys:[ + "picard_wgsmetrics", + "picard_multiplemetrics_pdf", + "picard_multiplemetrics", + "picard_hsmetrics" + ]) ).match() } } diff --git a/tests/subworkflows/local/bam_qc/main.nf.test.snap b/tests/subworkflows/local/bam_qc/main.nf.test.snap index 776c3f35..daa07dff 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test.snap +++ b/tests/subworkflows/local/bam_qc/main.nf.test.snap @@ -1,114 +1,231 @@ { "Bam QC - HSmetrics": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" + { + "picard_hsmetrics": [ + [ + { + "id": "test", + "single_end": false + }, + "test.CollectHsMetrics.coverage_metrics" + ] + ], + "picard_multiplemetrics": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.alignment_summary_metrics", + "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics", + "test.CollectMultipleMetrics.insert_size_metrics", + "test.CollectMultipleMetrics.quality_by_cycle_metrics", + "test.CollectMultipleMetrics.quality_distribution_metrics" + ] + ] + ], + "picard_multiplemetrics_pdf": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf", + "test.CollectMultipleMetrics.insert_size_histogram.pdf", + "test.CollectMultipleMetrics.quality_by_cycle.pdf", + "test.CollectMultipleMetrics.quality_distribution.pdf", + "test.CollectMultipleMetrics.read_length_histogram.pdf" + ] + ] + ], + "picard_wgsmetrics": [ + + ], + "samtools_flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" + ] + ], + "samtools_idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" + ] + ], + "samtools_stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" + ] + ], + "versions": [ + "versions.yml:md5,1e3d06d4435935cb6c01c1d94dad41c3", + "versions.yml:md5,25efd393aac661d8cb2aa8669127abac", + "versions.yml:md5,28cad528cb128dd7bdad050758f1801c", + "versions.yml:md5,ebcad29c0749995f2306fbcf31b03c8c", + "versions.yml:md5,ff0b9222ca016f9d2a7fa1d24010eccf" ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" - ] - ], - "test.CollectMultipleMetrics.alignment_summary_metrics", - "test.CollectHsMetrics.coverage_metrics" + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.1" + "nextflow": "25.10.0" }, - "timestamp": "2024-11-19T15:23:54.440455" + "timestamp": "2025-11-04T14:17:45.293786329" }, "Bam QC - Samtools": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" + { + "picard_hsmetrics": [ + + ], + "picard_multiplemetrics": [ + + ], + "picard_multiplemetrics_pdf": [ + + ], + "picard_wgsmetrics": [ + + ], + "samtools_flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" + ] + ], + "samtools_idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" + ] + ], + "samtools_stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" + ] + ], + "versions": [ + "versions.yml:md5,1e3d06d4435935cb6c01c1d94dad41c3", + "versions.yml:md5,28cad528cb128dd7bdad050758f1801c", + "versions.yml:md5,ff0b9222ca016f9d2a7fa1d24010eccf" ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" - ] - ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.1" + "nextflow": "25.10.0" }, - "timestamp": "2024-11-19T15:25:06.200354" + "timestamp": "2025-11-04T14:19:09.897986912" }, "Bam QC - WGSmetrics": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" + { + "picard_hsmetrics": [ + + ], + "picard_multiplemetrics": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.alignment_summary_metrics", + "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics", + "test.CollectMultipleMetrics.insert_size_metrics", + "test.CollectMultipleMetrics.quality_by_cycle_metrics", + "test.CollectMultipleMetrics.quality_distribution_metrics" + ] + ] + ], + "picard_multiplemetrics_pdf": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf", + "test.CollectMultipleMetrics.insert_size_histogram.pdf", + "test.CollectMultipleMetrics.quality_by_cycle.pdf", + "test.CollectMultipleMetrics.quality_distribution.pdf", + "test.CollectMultipleMetrics.read_length_histogram.pdf" + ] + ] + ], + "picard_wgsmetrics": [ + [ + { + "id": "test", + "single_end": false + }, + "test.CollectWgsMetrics.coverage_metrics" + ] + ], + "samtools_flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" + ] + ], + "samtools_idxstats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" + ] + ], + "samtools_stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" + ] + ], + "versions": [ + "versions.yml:md5,1e3d06d4435935cb6c01c1d94dad41c3", + "versions.yml:md5,25efd393aac661d8cb2aa8669127abac", + "versions.yml:md5,28cad528cb128dd7bdad050758f1801c", + "versions.yml:md5,5da695471744af2707c6864e2773aa27", + "versions.yml:md5,ff0b9222ca016f9d2a7fa1d24010eccf" ] - ], - "test.CollectMultipleMetrics.alignment_summary_metrics", - "test.CollectWgsMetrics.coverage_metrics" + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.1" + "nextflow": "25.10.0" }, - "timestamp": "2024-11-19T15:24:51.243661" + "timestamp": "2025-11-04T14:18:47.271352687" } } \ No newline at end of file diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 5e1a6c31..7c779621 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -9,7 +9,7 @@ "single_end": false, "tag": "WES" }, - "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" ] ], "1": [ @@ -19,9 +19,40 @@ "single_end": false, "tag": "WES" }, - "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + ] + ], + "10": [ + + ], + "11": [ + + ], + "12": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] ], + "13": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" + ] + ], + "14": [ + "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", + "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + ], "2": [ [ { @@ -33,29 +64,67 @@ ] ], "3": [ + + ], + "4": [ [ { "id": "test", "single_end": false, "tag": "WES" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.per-base.bed.gz:md5,c89a207273626f8415df1710bc522e8e" ] ], - "4": [ + "5": [ [ { "id": "test", "single_end": false, "tag": "WES" }, - "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" + "test.per-base.bed.gz.csi:md5,6593f9115e934350c326206088e8bc7c" ] ], - "5": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", - "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + "6": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.regions.bed.gz:md5,82848481047cda38748ec0409db8a669" + ] + ], + "7": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.regions.bed.gz.csi:md5,68d13d373b9fd8b92535f566e77ed036" + ] + ], + "8": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.quantized.bed.gz:md5,8975e3f5a62bb2ea6f349539daf8e9a4" + ] + ], + "9": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" + ] ], "mosdepth_global": [ [ @@ -67,6 +136,49 @@ "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" ] ], + "mosdepth_per_base_bed": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.per-base.bed.gz:md5,c89a207273626f8415df1710bc522e8e" + ] + ], + "mosdepth_per_base_csi": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.per-base.bed.gz.csi:md5,6593f9115e934350c326206088e8bc7c" + ] + ], + "mosdepth_per_base_d4": [ + + ], + "mosdepth_quantized_bed": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.quantized.bed.gz:md5,8975e3f5a62bb2ea6f349539daf8e9a4" + ] + ], + "mosdepth_quantized_csi": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" + ] + ], "mosdepth_regions": [ [ { @@ -77,6 +189,26 @@ "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" ] ], + "mosdepth_regions_bed": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.regions.bed.gz:md5,82848481047cda38748ec0409db8a669" + ] + ], + "mosdepth_regions_csi": [ + [ + { + "id": "test", + "single_end": false, + "tag": "WES" + }, + "test.regions.bed.gz.csi:md5,68d13d373b9fd8b92535f566e77ed036" + ] + ], "mosdepth_summary": [ [ { @@ -86,6 +218,12 @@ }, "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" ] + ], + "mosdepth_thresholds_bed": [ + + ], + "mosdepth_thresholds_csi": [ + ], "panelcoverage": [ [ @@ -116,9 +254,9 @@ ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.4" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-23T14:45:47.730036" + "timestamp": "2025-11-04T14:20:02.213734734" }, "Coverage - seqcap": { "content": [ @@ -130,7 +268,7 @@ "single_end": false, "tag": "seqcap" }, - "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" ] ], "1": [ @@ -140,9 +278,32 @@ "single_end": false, "tag": "seqcap" }, - "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + ] + ], + "10": [ + + ], + "11": [ + + ], + "12": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] ], + "13": [ + + ], + "14": [ + "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + ], "2": [ [ { @@ -154,149 +315,166 @@ ] ], "3": [ + + ], + "4": [ [ { "id": "test", "single_end": false, "tag": "seqcap" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.per-base.bed.gz:md5,c89a207273626f8415df1710bc522e8e" ] - ], - "4": [ - ], "5": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" - ], - "mosdepth_global": [ [ { "id": "test", "single_end": false, "tag": "seqcap" }, - "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + "test.per-base.bed.gz.csi:md5,6593f9115e934350c326206088e8bc7c" ] ], - "mosdepth_regions": [ + "6": [ [ { "id": "test", "single_end": false, "tag": "seqcap" }, - "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" + "test.regions.bed.gz:md5,82848481047cda38748ec0409db8a669" ] ], - "mosdepth_summary": [ + "7": [ [ { "id": "test", "single_end": false, "tag": "seqcap" }, - "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + "test.regions.bed.gz.csi:md5,68d13d373b9fd8b92535f566e77ed036" ] ], - "panelcoverage": [ - - ], - "samtools_coverage": [ + "8": [ [ { "id": "test", "single_end": false, "tag": "seqcap" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.quantized.bed.gz:md5,8975e3f5a62bb2ea6f349539daf8e9a4" ] ], - "versions": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" - ] - } - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.2" - }, - "timestamp": "2025-06-23T13:40:00.179558" - }, - "Coverage": { - "content": [ - { - "0": [ + "9": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, - "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" + "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" ] ], - "1": [ + "mosdepth_global": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" ] ], - "2": [ + "mosdepth_per_base_bed": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, - "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" + "test.per-base.bed.gz:md5,c89a207273626f8415df1710bc522e8e" ] ], - "3": [ + "mosdepth_per_base_csi": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.per-base.bed.gz.csi:md5,6593f9115e934350c326206088e8bc7c" ] ], - "4": [ + "mosdepth_per_base_d4": [ ], - "5": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + "mosdepth_quantized_bed": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.quantized.bed.gz:md5,8975e3f5a62bb2ea6f349539daf8e9a4" + ] ], - "mosdepth_global": [ + "mosdepth_quantized_csi": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, - "test.mosdepth.global.dist.txt:md5,ceec5e216dac6a4e15b961713ee8b16c" + "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" ] ], "mosdepth_regions": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, "test.mosdepth.region.dist.txt:md5,baffaa91e753347fd44c2e6e0a618d1f" ] ], + "mosdepth_regions_bed": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.regions.bed.gz:md5,82848481047cda38748ec0409db8a669" + ] + ], + "mosdepth_regions_csi": [ + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test.regions.bed.gz.csi:md5,68d13d373b9fd8b92535f566e77ed036" + ] + ], "mosdepth_summary": [ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, "test.mosdepth.summary.txt:md5,c929389c608f49ca01d800fb5cc94bb9" ] + ], + "mosdepth_thresholds_bed": [ + + ], + "mosdepth_thresholds_csi": [ + ], "panelcoverage": [ @@ -305,7 +483,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "tag": "seqcap" }, "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] @@ -318,8 +497,8 @@ ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-23T13:34:58.331928" + "timestamp": "2025-11-04T14:19:32.672589279" } } \ No newline at end of file diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test b/tests/subworkflows/local/fastq_align_rna/main.nf.test index 05f22be6..caf71651 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test @@ -39,9 +39,7 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - workflow.out.bam.collect { it.collect { it instanceof Map ? it : file(it).name } }, - workflow.out.reports.collect { it.collect { it instanceof Map ? it : file(it).name } }, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:["bam", "reports"]) ).match() } diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index cb4a1d6d..bd1553c9 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -1,71 +1,73 @@ { "fastq align rna - star": { "content": [ - [ - [ - { - "id": "test", - "samplename": "test", - "single_end": false, - "sample_type": "RNA", - "genome": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - } - }, - "test.Aligned.out.bam" - ] - ], - [ - [ - { - "id": "test", - "samplename": "test", - "single_end": false, - "sample_type": "RNA", - "genome": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - } - }, - "test.Log.final.out" + { + "bam": [ + [ + { + "genome": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "RNA", + "samplename": "test", + "single_end": false + }, + "test.Aligned.out.bam" + ] ], - [ - { - "id": "test", - "samplename": "test", - "single_end": false, - "sample_type": "RNA", - "genome": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - } - }, - "test.Log.out" + "reports": [ + [ + { + "genome": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "RNA", + "samplename": "test", + "single_end": false + }, + "test.Log.final.out" + ], + [ + { + "genome": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "RNA", + "samplename": "test", + "single_end": false + }, + "test.Log.out" + ], + [ + { + "genome": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "RNA", + "samplename": "test", + "single_end": false + }, + "test.Log.progress.out" + ] ], - [ - { - "id": "test", - "samplename": "test", - "single_end": false, - "sample_type": "RNA", - "genome": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - } - }, - "test.Log.progress.out" + "versions": [ + "versions.yml:md5,a08c174f2d393f0b39c2cfe003ffafb9" ] - ], - [ - "versions.yml:md5,a08c174f2d393f0b39c2cfe003ffafb9" - ] + } ], "meta": { - "nf-test": "0.9.1", - "nextflow": "24.10.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2025-01-14T10:45:55.903470736" + "timestamp": "2025-11-04T14:22:48.650056385" }, "fastq align rna - unknown aligner": { "content": [ diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test index bd73587b..6ee92e5e 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test @@ -44,9 +44,7 @@ nextflow_workflow { { assert workflow.success assert snapshot( - workflow.out.cram_crai.collect { it.findAll { !(it instanceof Map) }.collect { file(it).name } }, - workflow.out.multiqc_files, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:["cram_crai"]) ).match() } ) @@ -89,9 +87,7 @@ nextflow_workflow { { assert workflow.success assert snapshot( - workflow.out.cram_crai.collect { it.findAll { !(it instanceof Map) }.collect { file(it).name } }, - workflow.out.multiqc_files, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:["cram_crai"]) ).match() } ) @@ -134,9 +130,7 @@ nextflow_workflow { { assert workflow.success assert snapshot( - workflow.out.cram_crai.collect { it.findAll { !(it instanceof Map) }.collect { file(it).name } }, - workflow.out.multiqc_files, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:["cram_crai"]) ).match() } ) @@ -179,9 +173,7 @@ nextflow_workflow { { assert workflow.success assert snapshot( - workflow.out.cram_crai.collect { it.findAll { !(it instanceof Map) }.collect { file(it).name } }, - workflow.out.multiqc_files, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:["cram_crai"]) ).match() } ) @@ -225,9 +217,7 @@ nextflow_workflow { { assert workflow.success assert snapshot( - workflow.out.cram_crai.collect { it.findAll { !(it instanceof Map) }.collect { file(it).name } }, - workflow.out.multiqc_files, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:["cram_crai"]) ).match() } ) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index ad5924a6..bcaa1414 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -1,115 +1,252 @@ { "fastq to cram - stub": { "content": [ - [ - [ - "test.merged.cram", - "test.merged.cram.crai" + { + "align_reports": [ + + ], + "cram_crai": [ + [ + { + "groupSize": 1, + "groupTarget": { + "genome_data": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "DNA", + "samplename": "test", + "single_end": false + } + }, + "test.merged.cram", + "test.merged.cram.crai" + ] + ], + "sormadup_metrics": [ + + ], + "versions": [ + "versions.yml:md5,a7ccfeb53d42f57673ea59012c30e897", + "versions.yml:md5,d92f130d879deee51a23917c6e272233", + "versions.yml:md5,d92f130d879deee51a23917c6e272233" ] - ], - [ - - ], - [ - "versions.yml:md5,a7ccfeb53d42f57673ea59012c30e897", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" - ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-03T10:39:18.407178" + "timestamp": "2025-11-04T14:30:29.475396941" }, "fastq to cram - bwa - bamsormadup": { "content": [ - [ - [ - "test.cram", - "test.cram.crai" + { + "align_reports": [ + + ], + "cram_crai": [ + [ + { + "groupSize": 1, + "groupTarget": { + "genome_data": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "DNA", + "samplename": "test", + "single_end": false + } + }, + "test.cram", + "test.cram.crai" + ] + ], + "sormadup_metrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test", + "samplename": "test", + "single_end": false, + "sample_type": "DNA", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + } + } + }, + "test.merged.metrics.txt:md5,4ee20f12cb4d6077479a08310c8f6c70" + ] + ], + "versions": [ + "versions.yml:md5,7e9be834e78aaf958ee23618377d8da5", + "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d", + "versions.yml:md5,d92f130d879deee51a23917c6e272233", + "versions.yml:md5,d92f130d879deee51a23917c6e272233" ] - ], - [ - "test.merged.metrics.txt:md5,4ee20f12cb4d6077479a08310c8f6c70" - ], - [ - "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" - ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-03T10:36:05.605497" + "timestamp": "2025-11-04T14:24:09.28415088" }, "fastq to cram - bwa - samtools sormadup": { "content": [ - [ - [ - "test.merged.cram", - "test.merged.cram.crai" + { + "align_reports": [ + + ], + "cram_crai": [ + [ + { + "groupSize": 1, + "groupTarget": { + "genome_data": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "DNA", + "samplename": "test", + "single_end": false + } + }, + "test.merged.cram", + "test.merged.cram.crai" + ] + ], + "sormadup_metrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test", + "samplename": "test", + "single_end": false, + "sample_type": "DNA", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + } + } + }, + "test.merged.metrics:md5,6e4d03a56877997e0e035d267550e381" + ] + ], + "versions": [ + "versions.yml:md5,7d966b1716b0f134534741313257f0ec", + "versions.yml:md5,d92f130d879deee51a23917c6e272233", + "versions.yml:md5,d92f130d879deee51a23917c6e272233" ] - ], - [ - "test.merged.metrics:md5,6e4d03a56877997e0e035d267550e381" - ], - [ - "versions.yml:md5,7d966b1716b0f134534741313257f0ec", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" - ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-03T10:38:15.994769" + "timestamp": "2025-11-04T14:28:32.155644934" }, "fastq to cram - star - bamsormadup": { "content": [ - [ - [ - "test.cram", - "test.cram.crai" + { + "align_reports": [ + + ], + "cram_crai": [ + [ + { + "groupSize": 1, + "groupTarget": { + "genome_data": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "RNA", + "samplename": "test", + "single_end": false + } + }, + "test.cram", + "test.cram.crai" + ] + ], + "sormadup_metrics": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test", + "samplename": "test", + "single_end": false, + "sample_type": "RNA", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + } + } + }, + "test.merged.metrics.txt:md5,641527401576375d7c0b0b54fbaf63ab" + ] + ], + "versions": [ + "versions.yml:md5,7e9be834e78aaf958ee23618377d8da5", + "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d" ] - ], - [ - "test.merged.metrics.txt:md5,641527401576375d7c0b0b54fbaf63ab" - ], - [ - "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d" - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-16T08:41:12.044485" + "timestamp": "2025-11-04T14:27:31.44516813" }, "fastq to cram - bwa - samtools sort": { "content": [ - [ - [ - "test.merged.cram", - "test.merged.cram.crai" + { + "align_reports": [ + + ], + "cram_crai": [ + [ + { + "groupSize": 1, + "groupTarget": { + "genome_data": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, + "id": "test", + "sample_type": "DNA", + "samplename": "test", + "single_end": false + } + }, + "test.merged.cram", + "test.merged.cram.crai" + ] + ], + "sormadup_metrics": [ + + ], + "versions": [ + "versions.yml:md5,a7ccfeb53d42f57673ea59012c30e897", + "versions.yml:md5,d92f130d879deee51a23917c6e272233", + "versions.yml:md5,d92f130d879deee51a23917c6e272233" ] - ], - [ - - ], - [ - "versions.yml:md5,a7ccfeb53d42f57673ea59012c30e897", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" - ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-03T10:38:46.909512" + "timestamp": "2025-11-04T14:29:30.443653387" } } \ No newline at end of file diff --git a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test index c3f9d375..b3a3b185 100644 --- a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test +++ b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test @@ -27,8 +27,7 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - file(workflow.out.cram[0][1]).name, - workflow.out.versions + sanitizeOutput(workflow.out, unstableKeys:["cram"]) ).match() } diff --git a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap index be64fb72..3dfdcb8b 100644 --- a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap @@ -1,16 +1,30 @@ { "fastq to unaligned cram": { "content": [ - "test.unaligned.cram", - [ - "versions.yml:md5,422c9b3605121c3528ee755bbdb12a85", - "versions.yml:md5,f494e9f15ef064e11d31abca2f2ba51c" - ] + { + "cram": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test.unaligned", + "samplename": "test", + "single_end": false + } + }, + "test.unaligned.cram" + ] + ], + "versions": [ + "versions.yml:md5,422c9b3605121c3528ee755bbdb12a85", + "versions.yml:md5,f494e9f15ef064e11d31abca2f2ba51c" + ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.1" + "nextflow": "25.10.0" }, - "timestamp": "2024-11-19T15:29:54.134408" + "timestamp": "2025-11-04T14:30:55.301756415" } } \ No newline at end of file From 5131640f00d5b0e8538e0f8af8603b92e5646a84 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Tue, 4 Nov 2025 15:09:25 +0100 Subject: [PATCH 019/228] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11783049..e4178019 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## dev +- Update the output handling to use the new workflow output definitions. + ## v2.0.6 - Update bash options for nextflow version 25.04.2 From 4334b77660d9cf4a2cab8726e088298a086fdb73 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Tue, 4 Nov 2025 15:53:39 +0100 Subject: [PATCH 020/228] bump ci nextflow version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f45f92e..4902664d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: strategy: matrix: NXF_VER: - - "25.04.0" + - "25.10.0" tags: - "modules/local/panelcoverage" - "subworkflows/local/bam_qc" From 5b2ee8acaed8241b634591f162f81e547f78d37c Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Tue, 4 Nov 2025 16:30:20 +0100 Subject: [PATCH 021/228] bump bcl_demultiplex --- modules.json | 2 +- subworkflows/nf-core/bcl_demultiplex/main.nf | 16 +- subworkflows/nf-core/bcl_demultiplex/meta.yml | 4 + .../bcl_demultiplex/tests/main.nf.test | 47 +- .../bcl_demultiplex/tests/main.nf.test.snap | 438 ++++++++++-------- 5 files changed, 294 insertions(+), 213 deletions(-) diff --git a/modules.json b/modules.json index d860bfc6..9b8eb350 100644 --- a/modules.json +++ b/modules.json @@ -154,7 +154,7 @@ "nf-core": { "bcl_demultiplex": { "branch": "master", - "git_sha": "27cceb2eb8aa959d4a8819caab886386a59a3789", + "git_sha": "1a0770da1cf5c5cd388bf888ba8798bc4d1fba56", "installed_by": ["subworkflows"] }, "fastq_align_dna": { diff --git a/subworkflows/nf-core/bcl_demultiplex/main.nf b/subworkflows/nf-core/bcl_demultiplex/main.nf index 48e08613..bfe1ae83 100644 --- a/subworkflows/nf-core/bcl_demultiplex/main.nf +++ b/subworkflows/nf-core/bcl_demultiplex/main.nf @@ -13,11 +13,11 @@ workflow BCL_DEMULTIPLEX { demultiplexer // bclconvert or bcl2fastq main: - ch_versions = Channel.empty() - ch_fastq = Channel.empty() - ch_reports = Channel.empty() - ch_stats = Channel.empty() - ch_interop = Channel.empty() + ch_versions = channel.empty() + ch_fastq = channel.empty() + ch_reports = channel.empty() + ch_stats = channel.empty() + ch_interop = channel.empty() ch_logs = channel.empty() // Split flowcells into separate channels containing run as tar and run as path @@ -122,9 +122,9 @@ workflow BCL_DEMULTIPLEX { meta.single_end = fastq.size() == 1 return [meta, fastq.flatten()] } - .branch { - fastq : it[0].empty == false - empty_fastq : it[0].empty == true + .branch { meta, _fastq -> + fastq : meta.empty == false + empty_fastq : meta.empty == true } .set{ch_fastq_with_meta} diff --git a/subworkflows/nf-core/bcl_demultiplex/meta.yml b/subworkflows/nf-core/bcl_demultiplex/meta.yml index 2fc8f7aa..856f5204 100644 --- a/subworkflows/nf-core/bcl_demultiplex/meta.yml +++ b/subworkflows/nf-core/bcl_demultiplex/meta.yml @@ -48,6 +48,10 @@ output: type: file description: Demultiplexing statistics (bcl2fastq only) pattern: "Stats/*" + - logs: + type: file + description: Demultiplexing logs (bclconvert only) + pattern: "Logs/*" - 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 838a56cf..e1fb00ab 100644 --- a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test +++ b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test @@ -32,15 +32,25 @@ nextflow_workflow { assertAll( { assert workflow.success }, { assert snapshot( - workflow.out.reports, - workflow.out.versions, - workflow.out.fastq, - workflow.out.stats, - workflow.out.interop.get(0).get(1).findAll { file(it).name != "IndexMetricsOut.bin" }, + sanitizeOutput(workflow.out, unstableKeys: ["empty_fastq", "logs"]).collectEntries { key, val -> + if (key == "interop") { + return [ key, val.collect { meta, files -> + [ + meta, + files.collect { interop_file -> + if (interop_file.endsWith("IndexMetricsOut.bin")) { + file(interop_file).name + } else { + interop_file + } + } + ] + } ] + } + return [ key, val ] + }, ).match() }, - { assert file(workflow.out.interop.get(0).get(1).find { file(it).name == "IndexMetricsOut.bin" }).exists() }, - { assert file(workflow.out.empty_fastq.get(0).get(1).find { file(it).name == "SampleZ_S5_L001_R1_001.fastq.gz" }).exists() } ) } } @@ -65,14 +75,25 @@ nextflow_workflow { assertAll( { assert workflow.success }, { assert snapshot( - workflow.out.reports, - workflow.out.versions, - workflow.out.fastq, - workflow.out.stats, - workflow.out.interop.get(0).get(1).findAll { file(it).name != "IndexMetricsOut.bin" }, + sanitizeOutput(workflow.out).collectEntries { key, val -> + if (key == "interop") { + return [ key, val.collect { meta, files -> + [ + meta, + files.collect { interop_file -> + if (interop_file.endsWith("IndexMetricsOut.bin")) { + file(interop_file).name + } else { + interop_file + } + } + ] + } ] + } + return [ key, val ] + }, ).match() }, - { assert file(workflow.out.interop.get(0).get(1).find { file(it).name == "IndexMetricsOut.bin" }).exists() } ) } } 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 88cc0e93..537c7efe 100644 --- a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap +++ b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap @@ -1,240 +1,296 @@ { "bclconvert": { "content": [ - [ - [ - { - "id": "HMTFYDRXX", - "lane": 1 - }, + { + "empty_fastq": [ [ - "Adapter_Cycle_Metrics.csv:md5,05fbe7b2b0acdd557d355b448aa88ace", - "Adapter_Metrics.csv:md5,0fa4ac708955417af9d18cec4955552f", - "Demultiplex_Stats.csv:md5,4a3f451faa098156623b55b0f2ff27ee", - "Demultiplex_Tile_Stats.csv:md5,8f6fb58990572c4aa19c0100d8351484", - "IndexMetricsOut.bin:md5,fb16c8a9873e5b5950ae5949126af76c", - "Index_Hopping_Counts.csv:md5,f59474d96afe8218c7590bb240b19690", - "Quality_Metrics.csv:md5,c4622066f85d93b1661c928a46cfc508", - "Quality_Tile_Metrics.csv:md5,e22bc5e2f147695150b02afcccb38c4f", - "RunInfo.xml:md5,f283cb4600235db9261ee1e319b1407e", - "SampleSheet.csv:md5,4113eabae23136cc819c7f15ac5b6aad", - "Top_Unknown_Barcodes.csv:md5,37dbc2860c640fc721820b0217ea0504", - "fastq_list.csv:md5,482cf7fe9b304a900e4ede3bb25b4912" - ] - ] - ], - [ - "versions.yml:md5,d5d640ea998880b16202e0989b6e3926" - ], - [ - [ - { - "id": "Sample1_S1_L001", - "samplename": "Sample1", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "Sample1", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.GAACTGAGCG+TCGTGGAGCG" + { + "empty": true, + "fcid": "HMTFYDRXX", + "id": "SampleZ_S5_L001", + "lane": 1, + "readgroup": { + + }, + "samplename": "SampleZ", + "single_end": true }, - "empty": false, - "single_end": true - }, - [ - "Sample1_S1_L001_R1_001.fastq.gz:md5,b5489d1964db8db5502eb742cc3ef3ec" + [ + "SampleZ_S5_L001_R1_001.fastq.gz" + ] ] ], - [ - { - "id": "Sample23_S3_L001", - "samplename": "Sample23", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "Sample23", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.CGTCTCATAT+TATAGTAGCT" + "fastq": [ + [ + { + "id": "Sample1_S1_L001", + "samplename": "Sample1", + "fcid": "HMTFYDRXX", + "lane": 1, + "readgroup": { + "ID": "HMTFYDRXX.1", + "SM": "Sample1", + "PL": "ILLUMINA", + "PU": "HMTFYDRXX.1.GAACTGAGCG+TCGTGGAGCG" + }, + "empty": false, + "single_end": true }, - "empty": false, - "single_end": true - }, + [ + "Sample1_S1_L001_R1_001.fastq.gz:md5,b5489d1964db8db5502eb742cc3ef3ec" + ] + ], [ - "Sample23_S3_L001_R1_001.fastq.gz:md5,767a1091320320b140288066e29bccc5" + { + "id": "Sample23_S3_L001", + "samplename": "Sample23", + "fcid": "HMTFYDRXX", + "lane": 1, + "readgroup": { + "ID": "HMTFYDRXX.1", + "SM": "Sample23", + "PL": "ILLUMINA", + "PU": "HMTFYDRXX.1.CGTCTCATAT+TATAGTAGCT" + }, + "empty": false, + "single_end": true + }, + [ + "Sample23_S3_L001_R1_001.fastq.gz:md5,767a1091320320b140288066e29bccc5" + ] + ], + [ + { + "id": "SampleA_S2_L001", + "samplename": "SampleA", + "fcid": "HMTFYDRXX", + "lane": 1, + "readgroup": { + "ID": "HMTFYDRXX.1", + "SM": "SampleA", + "PL": "ILLUMINA", + "PU": "HMTFYDRXX.1.AGGTCAGATA+CTACAAGATA" + }, + "empty": false, + "single_end": true + }, + [ + "SampleA_S2_L001_R1_001.fastq.gz:md5,7de2ea88133409f34563f40a0d8c9e55" + ] + ], + [ + { + "id": "sampletest_S4_L001", + "samplename": "sampletest", + "fcid": "HMTFYDRXX", + "lane": 1, + "readgroup": { + "ID": "HMTFYDRXX.1", + "SM": "sampletest", + "PL": "ILLUMINA", + "PU": "HMTFYDRXX.1.ATTCCATAAG+TGCCTGGTGG" + }, + "empty": false, + "single_end": true + }, + [ + "sampletest_S4_L001_R1_001.fastq.gz:md5,c16c7de1b7bffb5e4503f4d94c40f881" + ] ] ], - [ - { - "id": "SampleA_S2_L001", - "samplename": "SampleA", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "SampleA", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.AGGTCAGATA+CTACAAGATA" - }, - "empty": false, - "single_end": true - }, + "interop": [ [ - "SampleA_S2_L001_R1_001.fastq.gz:md5,7de2ea88133409f34563f40a0d8c9e55" + { + "id": "HMTFYDRXX", + "lane": 1 + }, + [ + "BasecallingMetricsOut.bin:md5,7fb651325cba614d497d376eaf43fef4", + "CorrectedIntMetricsOut.bin:md5,dc8d57282ba9ece9e5fc58a92aa2ac52", + "EmpiricalPhasingMetricsOut.bin:md5,1ef4631faf0a3a3beb31b10fc38a734d", + "EventMetricsOut.bin:md5,dee320ce29bdadde44589aa9439f53ab", + "ExtendedTileMetricsOut.bin:md5,f01d1a9cf8445adf719e652ad7304cf2", + "ExtractionMetricsOut.bin:md5,972f4082ad950baaf42a6d28517d28a8", + "FWHMGridMetricsOut.bin:md5,6e297bafcd845bfd0440d08e1bb27685", + "ImageMetricsOut.bin:md5,ac5d1f0a1f611c0c7c9dd8e6b9e701b1", + "IndexMetricsOut.bin", + "OpticalModelMetricsOut.bin:md5,3eaea5fcf2d353950b1e720c73695ccb", + "PFGridMetricsOut.bin:md5,ae469858ee96ffafbcaf3afb814bdab2", + "QMetrics2030Out.bin:md5,438248760db58917b32f4eccc6c64c39", + "QMetricsByLaneOut.bin:md5,e8254cb4a27846710a2a143296be2d8f", + "QMetricsOut.bin:md5,8f6b83028a42be721200a598161ac5c6", + "RegistrationMetricsOut.bin:md5,b5ebd957aed067b6403d851ba2ce0139", + "TileMetricsOut.bin:md5,21388348d81fa9be326d30ef6d348464" + ] ] ], - [ - { - "id": "sampletest_S4_L001", - "samplename": "sampletest", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "sampletest", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.ATTCCATAAG+TGCCTGGTGG" + "logs": [ + [ + { + "id": "HMTFYDRXX", + "lane": 1 }, - "empty": false, - "single_end": true - }, + "Logs" + ] + ], + "reports": [ [ - "sampletest_S4_L001_R1_001.fastq.gz:md5,c16c7de1b7bffb5e4503f4d94c40f881" + { + "id": "HMTFYDRXX", + "lane": 1 + }, + [ + "Adapter_Cycle_Metrics.csv:md5,05fbe7b2b0acdd557d355b448aa88ace", + "Adapter_Metrics.csv:md5,0fa4ac708955417af9d18cec4955552f", + "Demultiplex_Detailed_Stats.csv:md5,5a6a4d66a96256ff71e4f649927fb112", + "Demultiplex_Stats.csv:md5,4a3f451faa098156623b55b0f2ff27ee", + "Demultiplex_Tile_Stats.csv:md5,f91fb0c7a2c5588ed43c7f9145d004ee", + "IndexMetricsOut.bin:md5,fb16c8a9873e5b5950ae5949126af76c", + "Index_Hopping_Counts.csv:md5,f59474d96afe8218c7590bb240b19690", + "Quality_Metrics.csv:md5,c4622066f85d93b1661c928a46cfc508", + "Quality_Tile_Metrics.csv:md5,e22bc5e2f147695150b02afcccb38c4f", + "RunInfo.xml:md5,f283cb4600235db9261ee1e319b1407e", + "SampleSheet.csv:md5,4113eabae23136cc819c7f15ac5b6aad", + "Top_Unknown_Barcodes.csv:md5,37dbc2860c640fc721820b0217ea0504", + "fastq_list.csv:md5,482cf7fe9b304a900e4ede3bb25b4912" + ] ] + ], + "stats": [ + + ], + "versions": [ + "versions.yml:md5,b1427a2b3abad63b04f1dd62c8f40e2e" ] - ], - [ - - ], - [ - "BasecallingMetricsOut.bin:md5,7fb651325cba614d497d376eaf43fef4", - "CorrectedIntMetricsOut.bin:md5,dc8d57282ba9ece9e5fc58a92aa2ac52", - "EmpiricalPhasingMetricsOut.bin:md5,1ef4631faf0a3a3beb31b10fc38a734d", - "EventMetricsOut.bin:md5,dee320ce29bdadde44589aa9439f53ab", - "ExtendedTileMetricsOut.bin:md5,f01d1a9cf8445adf719e652ad7304cf2", - "ExtractionMetricsOut.bin:md5,972f4082ad950baaf42a6d28517d28a8", - "FWHMGridMetricsOut.bin:md5,6e297bafcd845bfd0440d08e1bb27685", - "ImageMetricsOut.bin:md5,ac5d1f0a1f611c0c7c9dd8e6b9e701b1", - "OpticalModelMetricsOut.bin:md5,3eaea5fcf2d353950b1e720c73695ccb", - "PFGridMetricsOut.bin:md5,ae469858ee96ffafbcaf3afb814bdab2", - "QMetrics2030Out.bin:md5,438248760db58917b32f4eccc6c64c39", - "QMetricsByLaneOut.bin:md5,e8254cb4a27846710a2a143296be2d8f", - "QMetricsOut.bin:md5,8f6b83028a42be721200a598161ac5c6", - "RegistrationMetricsOut.bin:md5,b5ebd957aed067b6403d851ba2ce0139", - "TileMetricsOut.bin:md5,21388348d81fa9be326d30ef6d348464" - ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.10.0" }, - "timestamp": "2025-06-02T12:35:59.918717" + "timestamp": "2025-11-04T16:13:41.469897018" }, "bcl2fastq": { "content": [ - [ - [ - { - "id": "test", - "lane": 1 - }, + { + "empty_fastq": [ + + ], + "fastq": [ + [ + { + "id": "Sample1_S1_L001", + "samplename": "Sample1", + "fcid": "test", + "lane": 1, + "readgroup": { + "ID": "000000000-K9H97.1", + "SM": "Sample1", + "PL": "ILLUMINA", + "PU": "000000000-K9H97.1" + }, + "empty": false, + "single_end": true + }, + [ + "Sample1_S1_L001_R1_001.fastq.gz:md5,0675fb6365322eaafb33c0f8e862b54b" + ] + ] + ], + "interop": [ [ + { + "id": "test", + "lane": 1 + }, + [ + "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", + "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", + "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", + "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", + "IndexMetricsOut.bin", + "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", + "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" + ] + ] + ], + "logs": [ + + ], + "reports": [ + [ + { + "id": "test", + "lane": 1 + }, [ [ [ [ [ - "lane.html:md5,794e48287f47a9f22dcb6b6d0c22c3eb", - "laneBarcode.html:md5,2bbdae3ee57151eab520c966597d7438" - ], - [ - - ] - ] - ], - [ - [ - [ - "lane.html:md5,f741870307050dcea79a838f5971770f", - "laneBarcode.html:md5,ffe2e863811c76cb9da27d5d124e0611" - ], - [ - "lane.html:md5,cca97e771d3491dbc8cd3fe389595b09", - "laneBarcode.html:md5,cca97e771d3491dbc8cd3fe389595b09" + [ + "lane.html:md5,794e48287f47a9f22dcb6b6d0c22c3eb", + "laneBarcode.html:md5,2bbdae3ee57151eab520c966597d7438" + ], + [ + + ] ] ], [ [ - "lane.html:md5,c383b0768d9978733d3f5d3b91c15af0", - "laneBarcode.html:md5,48842c23b9a2816aec540177df870968" + [ + "lane.html:md5,f741870307050dcea79a838f5971770f", + "laneBarcode.html:md5,ffe2e863811c76cb9da27d5d124e0611" + ], + [ + "lane.html:md5,cca97e771d3491dbc8cd3fe389595b09", + "laneBarcode.html:md5,cca97e771d3491dbc8cd3fe389595b09" + ] ], [ - + [ + "lane.html:md5,c383b0768d9978733d3f5d3b91c15af0", + "laneBarcode.html:md5,48842c23b9a2816aec540177df870968" + ], + [ + + ] ] ] - ] - ], - "Report.css:md5,eb7d3eb68fc1539f411404987246b59b", - "index.html:md5,5747c407854ae2c358d0ec201ce622d8", - "tree.html:md5,a1b9bf592973ca829ec69ddf888b7e34" + ], + "Report.css:md5,eb7d3eb68fc1539f411404987246b59b", + "index.html:md5,5747c407854ae2c358d0ec201ce622d8", + "tree.html:md5,a1b9bf592973ca829ec69ddf888b7e34" + ] ] ] - ] - ], - [ - "versions.yml:md5,513271615cb02dbe541a6202d713ef81" - ], - [ - [ - { - "id": "Sample1_S1_L001", - "samplename": "Sample1", - "fcid": "test", - "lane": 1, - "readgroup": { - "ID": "000000000-K9H97.1", - "SM": "Sample1", - "PL": "ILLUMINA", - "PU": "000000000-K9H97.1" - }, - "empty": false, - "single_end": true - }, - [ - "Sample1_S1_L001_R1_001.fastq.gz:md5,0675fb6365322eaafb33c0f8e862b54b" - ] - ] - ], - [ - [ - { - "id": "test", - "lane": 1 - }, + ], + "stats": [ [ - "AdapterTrimming.txt:md5,48ed2b914b1246c0b5d8667525550946", - "ConversionStats.xml:md5,8fe0f57f3f5d256a0762dba75ac62d05", - "DemultiplexingStats.xml:md5,2047ff18f5b9107c084de06e9ff943ad", - "DemuxSummaryF1L1.txt:md5,03e5fd0c1e3079c5f8c7b4d0501b37ff", - "FastqSummaryF1L1.txt:md5,0c6f2d87ee183b84d1051cde9a5643d1", - "Stats.json:md5,8e5f038b8aa9e465599d3575f930e604" + { + "id": "test", + "lane": 1 + }, + [ + "AdapterTrimming.txt:md5,48ed2b914b1246c0b5d8667525550946", + "ConversionStats.xml:md5,8fe0f57f3f5d256a0762dba75ac62d05", + "DemultiplexingStats.xml:md5,2047ff18f5b9107c084de06e9ff943ad", + "DemuxSummaryF1L1.txt:md5,03e5fd0c1e3079c5f8c7b4d0501b37ff", + "FastqSummaryF1L1.txt:md5,0c6f2d87ee183b84d1051cde9a5643d1", + "Stats.json:md5,8e5f038b8aa9e465599d3575f930e604" + ] ] + ], + "versions": [ + "versions.yml:md5,513271615cb02dbe541a6202d713ef81" ] - ], - [ - "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", - "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", - "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", - "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", - "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", - "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" - ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-08-05T13:35:57.172636143" + "timestamp": "2025-11-04T15:08:58.666466636" } } \ No newline at end of file From 1af5c002c539bd2c830f6057b7dae00f84ce8996 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 12 Nov 2025 14:37:29 +0100 Subject: [PATCH 022/228] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0964e70c..f23ca715 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/ci.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/ci.yml) [![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A525.04.0-23aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A525.10.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) From caf4700c285a38e0778b64709e6ee7e9976f26c7 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 13 Nov 2025 15:45:21 +0100 Subject: [PATCH 023/228] fix version in config --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 6022b555..61af1dd1 100644 --- a/nextflow.config +++ b/nextflow.config @@ -254,7 +254,7 @@ manifest { description = """Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.""" mainScript = 'main.nf' nextflowVersion = '!>=25.10.0' - version = 'dev' + version = '2.1.0dev' doi = '' contributors = [ [ From c8888bec9ddb7ae96b3ba877a85989fb79f785f9 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 13 Nov 2025 15:52:33 +0100 Subject: [PATCH 024/228] bump changelog version --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4178019..5bf9c031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## dev +## 2.1.0dev - Update the output handling to use the new workflow output definitions. From 907ef2e3b52a21b1325c8b38724cad68c70622c4 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 13 Nov 2025 16:11:23 +0100 Subject: [PATCH 025/228] Template update for nf-core/tools version 3.4.1 --- .devcontainer/devcontainer.json | 20 + .devcontainer/setup.sh | 13 + .gitattributes | 4 + .github/.dockstore.yml | 6 + .github/CONTRIBUTING.md | 118 +++++ .github/ISSUE_TEMPLATE/bug_report.yml | 42 ++ .github/ISSUE_TEMPLATE/feature_request.yml | 11 + .github/PULL_REQUEST_TEMPLATE.md | 25 + .github/actions/get-shards/action.yml | 69 +++ .github/actions/nf-test/action.yml | 111 +++++ .github/workflows/branch.yml | 46 ++ .github/workflows/clean-up.yml | 24 + .github/workflows/download_pipeline.yml | 134 ++++++ .github/workflows/fix_linting.yml | 89 ++++ .github/workflows/linting.yml | 80 ++++ .github/workflows/linting_comment.yml | 28 ++ .github/workflows/nf-test.yml | 141 ++++++ .../workflows/template-version-comment.yml | 46 ++ .gitignore | 9 + .nf-core.yml | 40 ++ .pre-commit-config.yaml | 27 ++ .prettierignore | 14 + .prettierrc.yml | 6 + .vscode/settings.json | 3 + CHANGELOG.md | 16 + CITATIONS.md | 41 ++ LICENSE | 2 +- README.md | 91 ++++ assets/adaptivecard.json | 67 +++ assets/email_template.html | 53 +++ assets/email_template.txt | 31 ++ assets/methods_description_template.yml | 29 ++ assets/multiqc_config.yml | 14 + assets/samplesheet.csv | 3 + assets/schema_input.json | 33 ++ assets/sendmail_template.txt | 53 +++ assets/slackreport.json | 34 ++ conf/base.config | 66 +++ conf/igenomes.config | 440 ++++++++++++++++++ conf/igenomes_ignored.config | 9 + conf/modules.config | 34 ++ conf/test.config | 30 ++ conf/test_full.config | 24 + docs/README.md | 8 + docs/output.md | 61 +++ docs/usage.md | 212 +++++++++ main.nf | 105 +++++ modules.json | 41 ++ modules/nf-core/fastqc/environment.yml | 7 + modules/nf-core/fastqc/main.nf | 64 +++ modules/nf-core/fastqc/meta.yml | 72 +++ modules/nf-core/fastqc/tests/main.nf.test | 309 ++++++++++++ .../nf-core/fastqc/tests/main.nf.test.snap | 392 ++++++++++++++++ modules/nf-core/multiqc/environment.yml | 7 + modules/nf-core/multiqc/main.nf | 63 +++ modules/nf-core/multiqc/meta.yml | 92 ++++ modules/nf-core/multiqc/tests/main.nf.test | 92 ++++ .../nf-core/multiqc/tests/main.nf.test.snap | 41 ++ modules/nf-core/multiqc/tests/nextflow.config | 5 + nextflow.config | 280 +++++++++++ nextflow_schema.json | 257 ++++++++++ nf-test.config | 24 + ro-crate-metadata.json | 295 ++++++++++++ .../main.nf | 275 +++++++++++ .../nf-core/utils_nextflow_pipeline/main.nf | 126 +++++ .../nf-core/utils_nextflow_pipeline/meta.yml | 38 ++ .../tests/main.function.nf.test | 54 +++ .../tests/main.function.nf.test.snap | 20 + .../tests/main.workflow.nf.test | 113 +++++ .../tests/nextflow.config | 9 + .../nf-core/utils_nfcore_pipeline/main.nf | 419 +++++++++++++++++ .../nf-core/utils_nfcore_pipeline/meta.yml | 24 + .../tests/main.function.nf.test | 126 +++++ .../tests/main.function.nf.test.snap | 136 ++++++ .../tests/main.workflow.nf.test | 29 ++ .../tests/main.workflow.nf.test.snap | 19 + .../tests/nextflow.config | 9 + .../nf-core/utils_nfschema_plugin/main.nf | 74 +++ .../nf-core/utils_nfschema_plugin/meta.yml | 35 ++ .../utils_nfschema_plugin/tests/main.nf.test | 173 +++++++ .../tests/nextflow.config | 8 + .../tests/nextflow_schema.json | 96 ++++ tests/.nftignore | 12 + tests/default.nf.test | 33 ++ tests/nextflow.config | 14 + tower.yml | 5 + workflows/preprocessing.nf | 97 ++++ 87 files changed, 6546 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.json create mode 100755 .devcontainer/setup.sh create mode 100644 .gitattributes create mode 100644 .github/.dockstore.yml create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/actions/get-shards/action.yml create mode 100644 .github/actions/nf-test/action.yml create mode 100644 .github/workflows/branch.yml create mode 100644 .github/workflows/clean-up.yml create mode 100644 .github/workflows/download_pipeline.yml create mode 100644 .github/workflows/fix_linting.yml create mode 100644 .github/workflows/linting.yml create mode 100644 .github/workflows/linting_comment.yml create mode 100644 .github/workflows/nf-test.yml create mode 100644 .github/workflows/template-version-comment.yml create mode 100644 .gitignore create mode 100644 .nf-core.yml create mode 100644 .pre-commit-config.yaml create mode 100644 .prettierignore create mode 100644 .prettierrc.yml create mode 100644 .vscode/settings.json create mode 100644 CHANGELOG.md create mode 100644 CITATIONS.md create mode 100644 README.md create mode 100644 assets/adaptivecard.json create mode 100644 assets/email_template.html create mode 100644 assets/email_template.txt create mode 100644 assets/methods_description_template.yml create mode 100644 assets/multiqc_config.yml create mode 100644 assets/samplesheet.csv create mode 100644 assets/schema_input.json create mode 100644 assets/sendmail_template.txt create mode 100644 assets/slackreport.json create mode 100644 conf/base.config create mode 100644 conf/igenomes.config create mode 100644 conf/igenomes_ignored.config create mode 100644 conf/modules.config create mode 100644 conf/test.config create mode 100644 conf/test_full.config create mode 100644 docs/README.md create mode 100644 docs/output.md create mode 100644 docs/usage.md create mode 100644 main.nf create mode 100644 modules.json create mode 100644 modules/nf-core/fastqc/environment.yml create mode 100644 modules/nf-core/fastqc/main.nf create mode 100644 modules/nf-core/fastqc/meta.yml create mode 100644 modules/nf-core/fastqc/tests/main.nf.test create mode 100644 modules/nf-core/fastqc/tests/main.nf.test.snap create mode 100644 modules/nf-core/multiqc/environment.yml create mode 100644 modules/nf-core/multiqc/main.nf create mode 100644 modules/nf-core/multiqc/meta.yml create mode 100644 modules/nf-core/multiqc/tests/main.nf.test create mode 100644 modules/nf-core/multiqc/tests/main.nf.test.snap create mode 100644 modules/nf-core/multiqc/tests/nextflow.config create mode 100644 nextflow.config create mode 100644 nextflow_schema.json create mode 100644 nf-test.config create mode 100644 ro-crate-metadata.json create mode 100644 subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/meta.yml create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test create mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/main.nf create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/meta.yml create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/main.nf create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/meta.yml create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json create mode 100644 tests/.nftignore create mode 100644 tests/default.nf.test create mode 100644 tests/nextflow.config create mode 100644 tower.yml create mode 100644 workflows/preprocessing.nf diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..97c8c97f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +{ + "name": "nfcore", + "image": "nfcore/devcontainer:latest", + + "remoteUser": "root", + "privileged": true, + + "remoteEnv": { + // Workspace path on the host for mounting with docker-outside-of-docker + "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" + }, + + "onCreateCommand": "./.devcontainer/setup.sh", + + "hostRequirements": { + "cpus": 4, + "memory": "16gb", + "storage": "32gb" + } +} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 00000000..3ad5e2ac --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Customise the terminal command prompt +echo "export PROMPT_DIRTRIM=2" >> $HOME/.bashrc +echo "export PS1='\[\e[3;36m\]\w ->\[\e[0m\\] '" >> $HOME/.bashrc +export PROMPT_DIRTRIM=2 +export PS1='\[\e[3;36m\]\w ->\[\e[0m\\] ' + +# Update Nextflow +nextflow self-update + +# Update welcome message +echo "Welcome to the nf-cmgg/preprocessing devcontainer!" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7a2dabc2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +*.config linguist-language=nextflow +*.nf.test linguist-language=nextflow +modules/nf-core/** linguist-generated +subworkflows/nf-core/** linguist-generated diff --git a/.github/.dockstore.yml b/.github/.dockstore.yml new file mode 100644 index 00000000..191fabd2 --- /dev/null +++ b/.github/.dockstore.yml @@ -0,0 +1,6 @@ +# Dockstore config version, not pipeline version +version: 1.2 +workflows: + - subclass: nfl + primaryDescriptorPath: /nextflow.config + publish: True diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..47f18382 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,118 @@ +# `nf-cmgg/preprocessing`: Contributing Guidelines + +Hi there! +Many thanks for taking an interest in improving nf-cmgg/preprocessing. + +We try to manage the required tasks for nf-cmgg/preprocessing using GitHub issues, you probably came to this page when creating one. +Please use the pre-filled template to save time. + +However, don't be put off by this template - other more general issues and suggestions are welcome! +Contributions to the code are even more welcome ;) + +## Contribution workflow + +If you'd like to write some code for nf-cmgg/preprocessing, the standard workflow is as follows: + +1. Check that there isn't already an issue about your idea in the [nf-cmgg/preprocessing issues](https://github.com/nf-cmgg/preprocessing/issues) to avoid duplicating work. If there isn't one already, please create one so that others know you're working on this +2. [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the [nf-cmgg/preprocessing repository](https://github.com/nf-cmgg/preprocessing) to your GitHub account +3. Make the necessary changes / additions within your forked repository following [Pipeline conventions](#pipeline-contribution-conventions) +4. Use `nf-core pipelines schema build` and add any new parameters to the pipeline JSON schema (requires [nf-core tools](https://github.com/nf-core/tools) >= 1.10). +5. Submit a Pull Request against the `dev` branch and wait for the code to be reviewed and merged + +If you're not used to this workflow with git, you can start with some [docs from GitHub](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests) or even their [excellent `git` resources](https://try.github.io/). + +## Tests + +You have the option to test your changes locally by running the pipeline. For receiving warnings about process selectors and other `debug` information, it is recommended to use the debug profile. Execute all the tests with the following command: + +```bash +nf-test test --profile debug,test,docker --verbose +``` + +When you create a pull request with changes, [GitHub Actions](https://github.com/features/actions) will run automatic tests. +Typically, pull-requests are only fully reviewed when these tests are passing, though of course we can help out before then. + +There are typically two types of tests that run: + +### Lint tests + +`nf-core` has a [set of guidelines](https://nf-co.re/developers/guidelines) which all pipelines must adhere to. +To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core pipelines lint ` command. + +If any failures or warnings are encountered, please follow the listed URL for more documentation. + +### Pipeline tests + +Each `nf-core` pipeline should be set up with a minimal set of test-data. +`GitHub Actions` then runs the pipeline on this data to ensure that it exits successfully. +If there are any failures then the automated tests fail. +These tests are run both with the latest available version of `Nextflow` and also the minimum required version that is stated in the pipeline code. + +## Patch + +:warning: Only in the unlikely and regretful event of a release happening with a bug. + +- On your own fork, make a new branch `patch` based on `upstream/main` or `upstream/master`. +- Fix the bug, and bump version (X.Y.Z+1). +- Open a pull-request from `patch` to `main`/`master` with the changes. + +## Pipeline contribution conventions + +To make the `nf-cmgg/preprocessing` code and processing logic more understandable for new contributors and to ensure quality, we semi-standardise the way the code and other contributions are written. + +### Adding a new step + +If you wish to contribute a new step, please use the following coding standards: + +1. Define the corresponding input channel into your new process from the expected previous process channel. +2. Write the process block (see below). +3. Define the output channel if needed (see below). +4. Add any new parameters to `nextflow.config` with a default (see below). +5. Add any new parameters to `nextflow_schema.json` with help text (via the `nf-core pipelines schema build` tool). +6. Add sanity checks and validation for all relevant parameters. +7. Perform local tests to validate that the new code works as expected. +8. If applicable, add a new test in the `tests` directory. +9. Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. +10. Add a description of the output files and if relevant any appropriate images from the MultiQC report to `docs/output.md`. + +### Default values + +Parameters should be initialised / defined with default values within the `params` scope in `nextflow.config`. + +Once there, use `nf-core pipelines schema build` to add to `nextflow_schema.json`. + +### Default processes resource requirements + +Sensible defaults for process resource requirements (CPUs / memory / time) for a process should be defined in `conf/base.config`. These should generally be specified generic with `withLabel:` selectors so they can be shared across multiple processes/steps of the pipeline. A nf-core standard set of labels that should be followed where possible can be seen in the [nf-core pipeline template](https://github.com/nf-core/tools/blob/main/nf_core/pipeline-template/conf/base.config), which has the default process as a single core-process, and then different levels of multi-core configurations for increasingly large memory requirements defined with standardised labels. + +The process resources can be passed on to the tool dynamically within the process with the `${task.cpus}` and `${task.memory}` variables in the `script:` block. + +### Naming schemes + +Please use the following naming schemes, to make it easy to understand what is going where. + +- initial process channel: `ch_output_from_` +- intermediate and terminal channels: `ch__for_` + +### Nextflow version bumping + +If you are using a new feature from core Nextflow, you may bump the minimum required version of nextflow in the pipeline with: `nf-core pipelines bump-version --nextflow . [min-nf-version]` + +### Images and figures + +For overview images and other documents we follow the nf-core [style guidelines and examples](https://nf-co.re/developers/design_guidelines). + +## GitHub Codespaces + +This repo includes a devcontainer configuration which will create a GitHub Codespaces for Nextflow development! This is an online developer environment that runs in your browser, complete with VSCode and a terminal. + +To get started: + +- Open the repo in [Codespaces](https://github.com/nf-cmgg/preprocessing/codespaces) +- Tools installed + - nf-core + - Nextflow + +Devcontainer specs: + +- [DevContainer config](.devcontainer/devcontainer.json) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..da749353 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,42 @@ +name: Bug report +description: Report something that is broken or incorrect +labels: bug +body: + - type: textarea + id: description + attributes: + label: Description of the bug + description: A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + id: command_used + attributes: + label: Command used and terminal output + description: Steps to reproduce the behaviour. Please paste the command you used to launch the pipeline and the output from your terminal. + render: console + placeholder: | + $ nextflow run ... + + Some output where something broke + + - type: textarea + id: files + attributes: + label: Relevant files + description: | + Please drag and drop the relevant files here. Create a `.zip` archive if the extension is not allowed. + Your verbose log file `.nextflow.log` is often useful _(this is a hidden file in the directory where you launched the pipeline)_ as well as custom Nextflow configuration files. + + - type: textarea + id: system + attributes: + label: System information + description: | + * Nextflow version _(eg. 23.04.0)_ + * Hardware _(eg. HPC, Desktop, Cloud)_ + * Executor _(eg. slurm, local, awsbatch)_ + * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ + * OS _(eg. CentOS Linux, macOS, Linux Mint)_ + * Version of nf-cmgg/preprocessing _(eg. 1.1, 1.5, 1.8.2)_ diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..268e4c2f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,11 @@ +name: Feature request +description: Suggest an idea for the nf-cmgg/preprocessing pipeline +labels: enhancement +body: + - type: textarea + id: description + attributes: + label: Description of feature + description: Please describe your suggestion for a new feature. It might help to describe a problem or use case, plus any alternatives that you have considered. + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..8e00290d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ + + +## PR checklist + +- [ ] This comment contains a description of changes (with reason). +- [ ] If you've fixed a bug or added code that should be tested, add tests! +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-cmgg/preprocessing/tree/main/.github/CONTRIBUTING.md) +- [ ] Make sure your code lints (`nf-core pipelines lint`). +- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). +- [ ] Check for unexpected warnings in debug mode (`nextflow run . -profile debug,test,docker --outdir `). +- [ ] Usage Documentation in `docs/usage.md` is updated. +- [ ] Output Documentation in `docs/output.md` is updated. +- [ ] `CHANGELOG.md` is updated. +- [ ] `README.md` is updated (including new tool citations and authors/contributors). diff --git a/.github/actions/get-shards/action.yml b/.github/actions/get-shards/action.yml new file mode 100644 index 00000000..34085279 --- /dev/null +++ b/.github/actions/get-shards/action.yml @@ -0,0 +1,69 @@ +name: "Get number of shards" +description: "Get the number of nf-test shards for the current CI job" +inputs: + max_shards: + description: "Maximum number of shards allowed" + required: true + paths: + description: "Component paths to test" + required: false + tags: + description: "Tags to pass as argument for nf-test --tag parameter" + required: false +outputs: + shard: + description: "Array of shard numbers" + value: ${{ steps.shards.outputs.shard }} + total_shards: + description: "Total number of shards" + value: ${{ steps.shards.outputs.total_shards }} +runs: + using: "composite" + steps: + - name: Install nf-test + uses: nf-core/setup-nf-test@v1 + with: + version: ${{ env.NFT_VER }} + - name: Get number of shards + id: shards + shell: bash + run: | + # Run nf-test with dynamic parameter + nftest_output=$(nf-test test \ + --profile +docker \ + $(if [ -n "${{ inputs.tags }}" ]; then echo "--tag ${{ inputs.tags }}"; fi) \ + --dry-run \ + --ci \ + --changed-since HEAD^) || { + echo "nf-test command failed with exit code $?" + echo "Full output: $nftest_output" + exit 1 + } + echo "nf-test dry-run output: $nftest_output" + + # Default values for shard and total_shards + shard="[]" + total_shards=0 + + # Check if there are related tests + if echo "$nftest_output" | grep -q 'No tests to execute'; then + echo "No related tests found." + else + # Extract the number of related tests + number_of_shards=$(echo "$nftest_output" | sed -n 's|.*Executed \([0-9]*\) tests.*|\1|p') + if [[ -n "$number_of_shards" && "$number_of_shards" -gt 0 ]]; then + shards_to_run=$(( $number_of_shards < ${{ inputs.max_shards }} ? $number_of_shards : ${{ inputs.max_shards }} )) + shard=$(seq 1 "$shards_to_run" | jq -R . | jq -c -s .) + total_shards="$shards_to_run" + else + echo "Unexpected output format. Falling back to default values." + fi + fi + + # Write to GitHub Actions outputs + echo "shard=$shard" >> $GITHUB_OUTPUT + echo "total_shards=$total_shards" >> $GITHUB_OUTPUT + + # Debugging output + echo "Final shard array: $shard" + echo "Total number of shards: $total_shards" diff --git a/.github/actions/nf-test/action.yml b/.github/actions/nf-test/action.yml new file mode 100644 index 00000000..3b9724c7 --- /dev/null +++ b/.github/actions/nf-test/action.yml @@ -0,0 +1,111 @@ +name: "nf-test Action" +description: "Runs nf-test with common setup steps" +inputs: + profile: + description: "Profile to use" + required: true + shard: + description: "Shard number for this CI job" + required: true + total_shards: + description: "Total number of test shards(NOT the total number of matrix jobs)" + required: true + paths: + description: "Test paths" + required: true + tags: + description: "Tags to pass as argument for nf-test --tag parameter" + required: false +runs: + using: "composite" + steps: + - name: Setup Nextflow + uses: nf-core/setup-nextflow@v2 + with: + version: "${{ env.NXF_VERSION }}" + + - name: Set up Python + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + with: + python-version: "3.14" + + - name: Install nf-test + uses: nf-core/setup-nf-test@v1 + with: + version: "${{ env.NFT_VER }}" + install-pdiff: true + + - name: Setup apptainer + if: contains(inputs.profile, 'singularity') + uses: eWaterCycle/setup-apptainer@main + + - name: Set up Singularity + if: contains(inputs.profile, 'singularity') + shell: bash + run: | + mkdir -p $NXF_SINGULARITY_CACHEDIR + mkdir -p $NXF_SINGULARITY_LIBRARYDIR + + - name: Conda setup + if: contains(inputs.profile, 'conda') + uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3 + with: + auto-update-conda: true + conda-solver: libmamba + channels: conda-forge + channel-priority: strict + conda-remove-defaults: true + + - name: Run nf-test + shell: bash + env: + NFT_WORKDIR: ${{ env.NFT_WORKDIR }} + run: | + nf-test test \ + --profile=+${{ inputs.profile }} \ + $(if [ -n "${{ inputs.tags }}" ]; then echo "--tag ${{ inputs.tags }}"; fi) \ + --ci \ + --changed-since HEAD^ \ + --verbose \ + --tap=test.tap \ + --shard ${{ inputs.shard }}/${{ inputs.total_shards }} + + # Save the absolute path of the test.tap file to the output + echo "tap_file_path=$(realpath test.tap)" >> $GITHUB_OUTPUT + + - name: Generate test summary + if: always() + shell: bash + run: | + # Add header if it doesn't exist (using a token file to track this) + if [ ! -f ".summary_header" ]; then + echo "# 🚀 nf-test results" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Status | Test Name | Profile | Shard |" >> $GITHUB_STEP_SUMMARY + echo "|:------:|-----------|---------|-------|" >> $GITHUB_STEP_SUMMARY + touch .summary_header + fi + + if [ -f test.tap ]; then + while IFS= read -r line; do + if [[ $line =~ ^ok ]]; then + test_name="${line#ok }" + # Remove the test number from the beginning + test_name="${test_name#* }" + echo "| ✅ | ${test_name} | ${{ inputs.profile }} | ${{ inputs.shard }}/${{ inputs.total_shards }} |" >> $GITHUB_STEP_SUMMARY + elif [[ $line =~ ^not\ ok ]]; then + test_name="${line#not ok }" + # Remove the test number from the beginning + test_name="${test_name#* }" + echo "| ❌ | ${test_name} | ${{ inputs.profile }} | ${{ inputs.shard }}/${{ inputs.total_shards }} |" >> $GITHUB_STEP_SUMMARY + fi + done < test.tap + else + echo "| ⚠️ | No test results found | ${{ inputs.profile }} | ${{ inputs.shard }}/${{ inputs.total_shards }} |" >> $GITHUB_STEP_SUMMARY + fi + + - name: Clean up + if: always() + shell: bash + run: | + sudo rm -rf /home/ubuntu/tests/ diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml new file mode 100644 index 00000000..f7aa27a5 --- /dev/null +++ b/.github/workflows/branch.yml @@ -0,0 +1,46 @@ +name: nf-core branch protection +# This workflow is triggered on PRs to `main`/`master` branch on the repository +# It fails when someone tries to make a PR against the nf-core `main`/`master` branch instead of `dev` +on: + pull_request_target: + branches: + - main + - master + +jobs: + test: + runs-on: ubuntu-latest + steps: + # PRs to the nf-core repo main/master branch are only ok if coming from the nf-core repo `dev` or any `patch` branches + - name: Check PRs + if: github.repository == 'nf-cmgg/preprocessing' + run: | + { [[ ${{github.event.pull_request.head.repo.full_name }} == nf-cmgg/preprocessing ]] && [[ $GITHUB_HEAD_REF == "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] + + # If the above check failed, post a comment on the PR explaining the failure + # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets + - name: Post PR comment + if: failure() + uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 + with: + message: | + ## This PR is against the `${{github.event.pull_request.base.ref}}` branch :x: + + * Do not close this PR + * Click _Edit_ and change the `base` to `dev` + * This CI test will remain failed until you push a new commit + + --- + + Hi @${{ github.event.pull_request.user.login }}, + + It looks like this pull-request is has been made against the [${{github.event.pull_request.head.repo.full_name }}](https://github.com/${{github.event.pull_request.head.repo.full_name }}) ${{github.event.pull_request.base.ref}} branch. + The ${{github.event.pull_request.base.ref}} branch on nf-core repositories should always contain code from the latest release. + Because of this, PRs to ${{github.event.pull_request.base.ref}} are only allowed if they come from the [${{github.event.pull_request.head.repo.full_name }}](https://github.com/${{github.event.pull_request.head.repo.full_name }}) `dev` branch. + + You do not need to close this PR, you can change the target branch to `dev` by clicking the _"Edit"_ button at the top of this page. + Note that even after this, the test will continue to show as failing until you push a new commit. + + Thanks again for your contribution! + repo-token: ${{ secrets.GITHUB_TOKEN }} + allow-repeats: false diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml new file mode 100644 index 00000000..6adb0fff --- /dev/null +++ b/.github/workflows/clean-up.yml @@ -0,0 +1,24 @@ +name: "Close user-tagged issues and PRs" +on: + schedule: + - cron: "0 0 * * 0" # Once a week + +jobs: + clean-up: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10 + with: + stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." + stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment if it is still useful." + close-issue-message: "This issue was closed because it has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor and then staled for 20 days with no activity." + days-before-stale: 30 + days-before-close: 20 + days-before-pr-close: -1 + any-of-labels: "awaiting-changes,awaiting-feedback" + exempt-issue-labels: "WIP" + exempt-pr-labels: "WIP" + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml new file mode 100644 index 00000000..6d94bcbf --- /dev/null +++ b/.github/workflows/download_pipeline.yml @@ -0,0 +1,134 @@ +name: Test successful pipeline download with 'nf-core pipelines download' + +# Run the workflow when: +# - dispatched manually +# - when a PR is opened or reopened to main/master branch +# - the head branch of the pull request is updated, i.e. if fixes for a release are pushed last minute to dev. +on: + workflow_dispatch: + inputs: + testbranch: + description: "The specific branch you wish to utilize for the test execution of nf-core pipelines download." + required: true + default: "dev" + pull_request: + branches: + - main + - master + +env: + NXF_ANSI_LOG: false + +jobs: + configure: + runs-on: ubuntu-latest + outputs: + REPO_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPO_LOWERCASE }} + REPOTITLE_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPOTITLE_LOWERCASE }} + REPO_BRANCH: ${{ steps.get_repo_properties.outputs.REPO_BRANCH }} + steps: + - name: Get the repository name and current branch + id: get_repo_properties + run: | + echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" + echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> "$GITHUB_OUTPUT" + echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> "$GITHUB_OUTPUT" + + download: + runs-on: ubuntu-latest + needs: configure + steps: + - name: Install Nextflow + uses: nf-core/setup-nextflow@v2 + + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + with: + python-version: "3.14" + architecture: "x64" + + - name: Setup Apptainer + uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0 + with: + apptainer-version: 1.3.4 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install git+https://github.com/nf-core/tools.git + + - name: Make a cache directory for the container images + run: | + mkdir -p ./singularity_container_images + + - name: Download the pipeline + env: + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images + run: | + nf-core pipelines download ${{ needs.configure.outputs.REPO_LOWERCASE }} \ + --revision ${{ needs.configure.outputs.REPO_BRANCH }} \ + --outdir ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} \ + --compress "none" \ + --container-system 'singularity' \ + --container-library "quay.io" -l "docker.io" -l "community.wave.seqera.io/library/" \ + --container-cache-utilisation 'amend' \ + --download-configuration 'yes' + + - name: Inspect download + run: tree ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} + + - name: Inspect container images + run: tree ./singularity_container_images | tee ./container_initial + + - name: Count the downloaded number of container images + id: count_initial + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Initial container image count: $image_count" + echo "IMAGE_COUNT_INITIAL=$image_count" >> "$GITHUB_OUTPUT" + + - name: Run the downloaded pipeline (stub) + id: stub_run_pipeline + continue-on-error: true + env: + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images + NXF_SINGULARITY_HOME_MOUNT: true + run: nextflow run ./${{needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results + - name: Run the downloaded pipeline (stub run not supported) + id: run_pipeline + if: ${{ steps.stub_run_pipeline.outcome == 'failure' }} + env: + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images + NXF_SINGULARITY_HOME_MOUNT: true + run: nextflow run ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -profile test,singularity --outdir ./results + + - name: Count the downloaded number of container images + id: count_afterwards + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Post-pipeline run container image count: $image_count" + echo "IMAGE_COUNT_AFTER=$image_count" >> "$GITHUB_OUTPUT" + + - name: Compare container image counts + id: count_comparison + run: | + if [ "${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }}" -ne "${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }}" ]; then + initial_count=${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }} + final_count=${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }} + difference=$((final_count - initial_count)) + echo "$difference additional container images were \n downloaded at runtime . The pipeline has no support for offline runs!" + tree ./singularity_container_images > ./container_afterwards + diff ./container_initial ./container_afterwards + exit 1 + else + echo "The pipeline can be downloaded successfully!" + fi + + - name: Upload Nextflow logfile for debugging purposes + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: nextflow_logfile.txt + path: .nextflow.log* + include-hidden-files: true diff --git a/.github/workflows/fix_linting.yml b/.github/workflows/fix_linting.yml new file mode 100644 index 00000000..63b82243 --- /dev/null +++ b/.github/workflows/fix_linting.yml @@ -0,0 +1,89 @@ +name: Fix linting from a comment +on: + issue_comment: + types: [created] + +jobs: + fix-linting: + # Only run if comment is on a PR with the main repo, and if it contains the magic keywords + if: > + contains(github.event.comment.html_url, '/pull/') && + contains(github.event.comment.body, '@nf-core-bot fix linting') && + github.repository == 'nf-cmgg/preprocessing' + runs-on: ubuntu-latest + steps: + # Use the @nf-core-bot token to check out so we can push later + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + token: ${{ secrets.nf_core_bot_auth_token }} + + # indication that the linting is being fixed + - name: React on comment + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 + with: + comment-id: ${{ github.event.comment.id }} + reactions: eyes + + # Action runs on the issue comment, so we don't get the PR by default + # Use the gh cli to check out the PR + - name: Checkout Pull Request + run: gh pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} + + # Install and run pre-commit + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + with: + python-version: "3.14" + + - name: Install pre-commit + run: pip install pre-commit + + - name: Run pre-commit + id: pre-commit + run: pre-commit run --all-files + continue-on-error: true + + # indication that the linting has finished + - name: react if linting finished succesfully + if: steps.pre-commit.outcome == 'success' + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 + with: + comment-id: ${{ github.event.comment.id }} + reactions: "+1" + + - name: Commit & push changes + id: commit-and-push + if: steps.pre-commit.outcome == 'failure' + run: | + git config user.email "core@nf-co.re" + git config user.name "nf-core-bot" + git config push.default upstream + git add . + git status + git commit -m "[automated] Fix code linting" + git push + + - name: react if linting errors were fixed + id: react-if-fixed + if: steps.commit-and-push.outcome == 'success' + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 + with: + comment-id: ${{ github.event.comment.id }} + reactions: hooray + + - name: react if linting errors were not fixed + if: steps.commit-and-push.outcome == 'failure' + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 + with: + comment-id: ${{ github.event.comment.id }} + reactions: confused + + - name: react if linting errors were not fixed + if: steps.commit-and-push.outcome == 'failure' + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 + with: + issue-number: ${{ github.event.issue.number }} + body: | + @${{ github.actor }} I tried to fix the linting errors, but it didn't work. Please fix them manually. + See [CI log](https://github.com/nf-cmgg/preprocessing/actions/runs/${{ github.run_id }}) for more details. diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 00000000..30e66026 --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,80 @@ +name: nf-core linting +# This workflow is triggered on pushes and PRs to the repository. +# It runs the `nf-core pipelines lint` and markdown lint tests to ensure +# that the code meets the nf-core guidelines. +on: + pull_request: + release: + types: [published] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Set up Python 3.14 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + with: + python-version: "3.14" + + - name: Install pre-commit + run: pip install pre-commit + + - name: Run pre-commit + run: pre-commit run --all-files + + nf-core: + runs-on: ubuntu-latest + steps: + - name: Check out pipeline code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Install Nextflow + uses: nf-core/setup-nextflow@v2 + + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + with: + python-version: "3.14" + architecture: "x64" + + - name: read .nf-core.yml + uses: pietrobolcato/action-read-yaml@9f13718d61111b69f30ab4ac683e67a56d254e1d # 1.1.0 + id: read_yml + with: + config: ${{ github.workspace }}/.nf-core.yml + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Run nf-core pipelines lint + if: ${{ github.base_ref != 'master' }} + env: + GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} + run: nf-core -l lint_log.txt pipelines lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md + + - name: Run nf-core pipelines lint --release + if: ${{ github.base_ref == 'master' }} + env: + GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} + run: nf-core -l lint_log.txt pipelines lint --release --dir ${GITHUB_WORKSPACE} --markdown lint_results.md + + - name: Save PR number + if: ${{ always() }} + run: echo ${{ github.event.pull_request.number }} > PR_number.txt + + - name: Upload linting log file artifact + if: ${{ always() }} + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: linting-logs + path: | + lint_log.txt + lint_results.md + PR_number.txt diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml new file mode 100644 index 00000000..e6e9bc26 --- /dev/null +++ b/.github/workflows/linting_comment.yml @@ -0,0 +1,28 @@ +name: nf-core linting comment +# This workflow is triggered after the linting action is complete +# It posts an automated comment to the PR, even if the PR is coming from a fork + +on: + workflow_run: + workflows: ["nf-core linting"] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Download lint results + uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 + with: + workflow: linting.yml + workflow_conclusion: completed + + - name: Get PR number + id: pr_number + run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT + + - name: Post PR comment + uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + number: ${{ steps.pr_number.outputs.pr_number }} + path: linting-logs/lint_results.md diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml new file mode 100644 index 00000000..c7448f3e --- /dev/null +++ b/.github/workflows/nf-test.yml @@ -0,0 +1,141 @@ +name: Run nf-test +on: + pull_request: + paths-ignore: + - "docs/**" + - "**/meta.yml" + - "**/*.md" + - "**/*.png" + - "**/*.svg" + release: + types: [published] + workflow_dispatch: + +# Cancel if a newer run is started +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NFT_VER: "0.9.3" + NFT_WORKDIR: "~" + NXF_ANSI_LOG: false + NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity + NXF_SINGULARITY_LIBRARYDIR: ${{ github.workspace }}/.singularity + +jobs: + nf-test-changes: + name: nf-test-changes + runs-on: # use GitHub runners + - "ubuntu-latest" + outputs: + shard: ${{ steps.set-shards.outputs.shard }} + total_shards: ${{ steps.set-shards.outputs.total_shards }} + steps: + - name: Clean Workspace # Purge the workspace in case it's running on a self-hosted runner + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + fetch-depth: 0 + + - name: get number of shards + id: set-shards + uses: ./.github/actions/get-shards + env: + NFT_VER: ${{ env.NFT_VER }} + with: + max_shards: 7 + + - name: debug + run: | + echo ${{ steps.set-shards.outputs.shard }} + echo ${{ steps.set-shards.outputs.total_shards }} + + nf-test: + name: "${{ matrix.profile }} | ${{ matrix.NXF_VER }} | ${{ matrix.shard }}/${{ needs.nf-test-changes.outputs.total_shards }}" + needs: [nf-test-changes] + if: ${{ needs.nf-test-changes.outputs.total_shards != '0' }} + runs-on: # use GitHub runners + - "ubuntu-latest" + strategy: + fail-fast: false + matrix: + shard: ${{ fromJson(needs.nf-test-changes.outputs.shard) }} + profile: [conda, docker, singularity] + isMain: + - ${{ github.base_ref == 'master' || github.base_ref == 'main' }} + # Exclude conda and singularity on dev + exclude: + - isMain: false + profile: "conda" + - isMain: false + profile: "singularity" + NXF_VER: + - "25.04.0" + - "latest-everything" + env: + NXF_ANSI_LOG: false + TOTAL_SHARDS: ${{ needs.nf-test-changes.outputs.total_shards }} + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + fetch-depth: 0 + + - name: Run nf-test + id: run_nf_test + uses: ./.github/actions/nf-test + continue-on-error: ${{ matrix.NXF_VER == 'latest-everything' }} + env: + NFT_WORKDIR: ${{ env.NFT_WORKDIR }} + NXF_VERSION: ${{ matrix.NXF_VER }} + with: + profile: ${{ matrix.profile }} + shard: ${{ matrix.shard }} + total_shards: ${{ env.TOTAL_SHARDS }} + + - name: Report test status + if: ${{ always() }} + run: | + if [[ "${{ steps.run_nf_test.outcome }}" == "failure" ]]; then + echo "::error::Test with ${{ matrix.NXF_VER }} failed" + # Add to workflow summary + echo "## ❌ Test failed: ${{ matrix.profile }} | ${{ matrix.NXF_VER }} | Shard ${{ matrix.shard }}/${{ env.TOTAL_SHARDS }}" >> $GITHUB_STEP_SUMMARY + if [[ "${{ matrix.NXF_VER }}" == "latest-everything" ]]; then + echo "::warning::Test with latest-everything failed but will not cause workflow failure. Please check if the error is expected or if it needs fixing." + fi + if [[ "${{ matrix.NXF_VER }}" != "latest-everything" ]]; then + exit 1 + fi + fi + + confirm-pass: + needs: [nf-test] + if: always() + runs-on: # use GitHub runners + - "ubuntu-latest" + steps: + - name: One or more tests failed (excluding latest-everything) + if: ${{ contains(needs.*.result, 'failure') }} + run: exit 1 + + - name: One or more tests cancelled + if: ${{ contains(needs.*.result, 'cancelled') }} + run: exit 1 + + - name: All tests ok + if: ${{ contains(needs.*.result, 'success') }} + run: exit 0 + + - name: debug-print + if: always() + run: | + echo "::group::DEBUG: `needs` Contents" + echo "DEBUG: toJSON(needs) = ${{ toJSON(needs) }}" + echo "DEBUG: toJSON(needs.*.result) = ${{ toJSON(needs.*.result) }}" + echo "::endgroup::" diff --git a/.github/workflows/template-version-comment.yml b/.github/workflows/template-version-comment.yml new file mode 100644 index 00000000..c5988af9 --- /dev/null +++ b/.github/workflows/template-version-comment.yml @@ -0,0 +1,46 @@ +name: nf-core template version comment +# This workflow is triggered on PRs to check if the pipeline template version matches the latest nf-core version. +# It posts a comment to the PR, even if it comes from a fork. + +on: pull_request_target + +jobs: + template_version: + runs-on: ubuntu-latest + steps: + - name: Check out pipeline code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Read template version from .nf-core.yml + uses: nichmor/minimal-read-yaml@1f7205277e25e156e1f63815781db80a6d490b8f # v0.0.2 + id: read_yml + with: + config: ${{ github.workspace }}/.nf-core.yml + + - name: Install nf-core + run: | + python -m pip install --upgrade pip + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Check nf-core outdated + id: nf_core_outdated + run: echo "OUTPUT=$(pip list --outdated | grep nf-core)" >> ${GITHUB_ENV} + + - name: Post nf-core template version comment + uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 + if: | + contains(env.OUTPUT, 'nf-core') + with: + repo-token: ${{ secrets.NF_CORE_BOT_AUTH_TOKEN }} + allow-repeats: false + message: | + > [!WARNING] + > Newer version of the nf-core template is available. + > + > Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. + > Please update your pipeline to the latest version. + > + > For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). + # diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a42ce016 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.nextflow* +work/ +data/ +results/ +.DS_Store +testing/ +testing* +*.pyc +null/ diff --git a/.nf-core.yml b/.nf-core.yml new file mode 100644 index 00000000..d565b189 --- /dev/null +++ b/.nf-core.yml @@ -0,0 +1,40 @@ +lint: + files_exist: + - CODE_OF_CONDUCT.md + - CITATIONS.md + - assets/nf-core-preprocessing_logo_light.png + - docs/images/nf-core-preprocessing_logo_light.png + - docs/images/nf-core-preprocessing_logo_dark.png + - .github/ISSUE_TEMPLATE/config.yml + - .github/workflows/awstest.yml + - .github/workflows/awsfulltest.yml + files_unchanged: + - CODE_OF_CONDUCT.md + - assets/nf-core-preprocessing_logo_light.png + - docs/images/nf-core-preprocessing_logo_light.png + - docs/images/nf-core-preprocessing_logo_dark.png + - .github/ISSUE_TEMPLATE/bug_report.yml + - docs/README.md + - LICENSE + merge_markers: + - bin/cmgg_genelists + multiqc_config: + - report_comment + nextflow_config: + - manifest.name + - manifest.homePage + template_strings: + - bin/cmgg_genelists +nf_core_version: 3.4.1 +repository_type: pipeline +template: + author: Matthias De Smet, Nicolas Vannieuwkerke + description: Demultiplexing, adapter trimming, alignment, and coverage calculation + for NGS data. + force: false + is_nfcore: false + name: preprocessing + org: nf-cmgg + outdir: . + skip_features: [] + version: 2.1.0dev diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..d06777a8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +repos: + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v3.1.0" + hooks: + - id: prettier + additional_dependencies: + - prettier@3.6.2 + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + exclude: | + (?x)^( + .*ro-crate-metadata.json$| + modules/nf-core/.*| + subworkflows/nf-core/.*| + .*\.snap$ + )$ + - id: end-of-file-fixer + exclude: | + (?x)^( + .*ro-crate-metadata.json$| + modules/nf-core/.*| + subworkflows/nf-core/.*| + .*\.snap$ + )$ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..2255e3e3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,14 @@ +email_template.html +adaptivecard.json +slackreport.json +.nextflow* +work/ +data/ +results/ +.DS_Store +testing/ +testing* +*.pyc +bin/ +.nf-test/ +ro-crate-metadata.json diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 00000000..07dbd8bb --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,6 @@ +printWidth: 120 +tabWidth: 4 +overrides: + - files: "*.{md,yml,yaml,html,css,scss,js,cff}" + options: + tabWidth: 2 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..a33b527c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "markdown.styles": ["public/vscode_markdown.css"] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..d19f9d42 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# nf-cmgg/preprocessing: Changelog + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## v2.1.0dev - [date] + +Initial release of nf-cmgg/preprocessing, created with the [nf-core](https://nf-co.re/) template. + +### `Added` + +### `Fixed` + +### `Dependencies` + +### `Deprecated` diff --git a/CITATIONS.md b/CITATIONS.md new file mode 100644 index 00000000..2a5a3059 --- /dev/null +++ b/CITATIONS.md @@ -0,0 +1,41 @@ +# nf-cmgg/preprocessing: Citations + +## [nf-core](https://pubmed.ncbi.nlm.nih.gov/32055031/) + +> Ewels PA, Peltzer A, Fillinger S, Patel H, Alneberg J, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. The nf-core framework for community-curated bioinformatics pipelines. Nat Biotechnol. 2020 Mar;38(3):276-278. doi: 10.1038/s41587-020-0439-x. PubMed PMID: 32055031. + +## [Nextflow](https://pubmed.ncbi.nlm.nih.gov/28398311/) + +> Di Tommaso P, Chatzou M, Floden EW, Barja PP, Palumbo E, Notredame C. Nextflow enables reproducible computational workflows. Nat Biotechnol. 2017 Apr 11;35(4):316-319. doi: 10.1038/nbt.3820. PubMed PMID: 28398311. + +## Pipeline tools + +- [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) + +> Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. + +- [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) + +> Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. + +## Software packaging/containerisation tools + +- [Anaconda](https://anaconda.com) + + > Anaconda Software Distribution. Computer software. Vers. 2-2.4.0. Anaconda, Nov. 2016. Web. + +- [Bioconda](https://pubmed.ncbi.nlm.nih.gov/29967506/) + + > Grüning B, Dale R, Sjödin A, Chapman BA, Rowe J, Tomkins-Tinch CH, Valieris R, Köster J; Bioconda Team. Bioconda: sustainable and comprehensive software distribution for the life sciences. Nat Methods. 2018 Jul;15(7):475-476. doi: 10.1038/s41592-018-0046-7. PubMed PMID: 29967506. + +- [BioContainers](https://pubmed.ncbi.nlm.nih.gov/28379341/) + + > da Veiga Leprevost F, Grüning B, Aflitos SA, Röst HL, Uszkoreit J, Barsnes H, Vaudel M, Moreno P, Gatto L, Weber J, Bai M, Jimenez RC, Sachsenberg T, Pfeuffer J, Alvarez RV, Griss J, Nesvizhskii AI, Perez-Riverol Y. BioContainers: an open-source and community-driven framework for software standardization. Bioinformatics. 2017 Aug 15;33(16):2580-2582. doi: 10.1093/bioinformatics/btx192. PubMed PMID: 28379341; PubMed Central PMCID: PMC5870671. + +- [Docker](https://dl.acm.org/doi/10.5555/2600239.2600241) + + > Merkel, D. (2014). Docker: lightweight linux containers for consistent development and deployment. Linux Journal, 2014(239), 2. doi: 10.5555/2600239.2600241. + +- [Singularity](https://pubmed.ncbi.nlm.nih.gov/28494014/) + + > Kurtzer GM, Sochat V, Bauer MW. Singularity: Scientific containers for mobility of compute. PLoS One. 2017 May 11;12(5):e0177459. doi: 10.1371/journal.pone.0177459. eCollection 2017. PubMed PMID: 28494014; PubMed Central PMCID: PMC5426675. diff --git a/LICENSE b/LICENSE index 28e1f563..d52aa1a9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Center For Medical Genetics Ghent +Copyright (c) The nf-cmgg/preprocessing team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 00000000..a96a6e68 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +# nf-cmgg/preprocessing + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing) +[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml) +[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) +[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) + +[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) +[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1) +[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) +[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) +[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) +[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing) + +## Introduction + +**nf-cmgg/preprocessing** is a bioinformatics pipeline that ... + + + + +1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/)) + +## Usage + +> [!NOTE] +> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data. + + + +Now, you can run the pipeline using: + + + +```bash +nextflow run nf-cmgg/preprocessing \ + -profile \ + --input samplesheet.csv \ + --outdir +``` + +> [!WARNING] +> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files). + +## Credits + +nf-cmgg/preprocessing was originally written by Matthias De Smet, Nicolas Vannieuwkerke. + +We thank the following people for their extensive assistance in the development of this pipeline: + + + +## Contributions and Support + +If you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md). + +## Citations + + + + + + +An extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file. + +This pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/main/LICENSE). + +> **The nf-core framework for community-curated bioinformatics pipelines.** +> +> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen. +> +> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x). diff --git a/assets/adaptivecard.json b/assets/adaptivecard.json new file mode 100644 index 00000000..92ed5f06 --- /dev/null +++ b/assets/adaptivecard.json @@ -0,0 +1,67 @@ +{ + "type": "message", + "attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "contentUrl": null, + "content": { + "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "msteams": { + "width": "Full" + }, + "type": "AdaptiveCard", + "version": "1.2", + "body": [ + { + "type": "TextBlock", + "size": "Large", + "weight": "Bolder", + "color": "<% if (success) { %>Good<% } else { %>Attention<%} %>", + "text": "nf-cmgg/preprocessing v${version} - ${runName}", + "wrap": true + }, + { + "type": "TextBlock", + "spacing": "None", + "text": "Completed at ${dateComplete} (duration: ${duration})", + "isSubtle": true, + "wrap": true + }, + { + "type": "TextBlock", + "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors. The full error message was: ${errorReport}.<% } %>", + "wrap": true + }, + { + "type": "TextBlock", + "text": "The command used to launch the workflow was as follows:", + "wrap": true + }, + { + "type": "TextBlock", + "text": "${commandLine}", + "isSubtle": true, + "wrap": true + } + ], + "actions": [ + { + "type": "Action.ShowCard", + "title": "Pipeline Configuration", + "card": { + "type": "AdaptiveCard", + "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "body": [ + { + "type": "FactSet", + "facts": [<% out << summary.collect{ k,v -> "{\"title\": \"$k\", \"value\" : \"$v\"}"}.join(",\n") %> + ] + } + ] + } + } + ] + } + } + ] +} diff --git a/assets/email_template.html b/assets/email_template.html new file mode 100644 index 00000000..8ebf727d --- /dev/null +++ b/assets/email_template.html @@ -0,0 +1,53 @@ + + + + + + + + nf-cmgg/preprocessing Pipeline Report + + +
    + + + +

    nf-cmgg/preprocessing ${version}

    +

    Run Name: $runName

    + +<% if (!success){ + out << """ +
    +

    nf-cmgg/preprocessing execution completed unsuccessfully!

    +

    The exit status of the task that caused the workflow execution to fail was: $exitStatus.

    +

    The full error message was:

    +
    ${errorReport}
    +
    + """ +} else { + out << """ +
    + nf-cmgg/preprocessing execution completed successfully! +
    + """ +} +%> + +

    The workflow was completed at $dateComplete (duration: $duration)

    +

    The command used to launch the workflow was as follows:

    +
    $commandLine
    + +

    Pipeline Configuration:

    + + + <% out << summary.collect{ k,v -> "" }.join("\n") %> + +
    $k
    $v
    + +

    nf-cmgg/preprocessing

    +

    https://github.com/nf-cmgg/preprocessing

    + +
    + + + diff --git a/assets/email_template.txt b/assets/email_template.txt new file mode 100644 index 00000000..578f35b6 --- /dev/null +++ b/assets/email_template.txt @@ -0,0 +1,31 @@ +Run Name: $runName + +<% if (success){ + out << "## nf-cmgg/preprocessing execution completed successfully! ##" +} else { + out << """#################################################### +## nf-cmgg/preprocessing execution completed unsuccessfully! ## +#################################################### +The exit status of the task that caused the workflow execution to fail was: $exitStatus. +The full error message was: + +${errorReport} +""" +} %> + + +The workflow was completed at $dateComplete (duration: $duration) + +The command used to launch the workflow was as follows: + + $commandLine + + + +Pipeline Configuration: +----------------------- +<% out << summary.collect{ k,v -> " - $k: $v" }.join("\n") %> + +-- +nf-cmgg/preprocessing +https://github.com/nf-cmgg/preprocessing diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml new file mode 100644 index 00000000..8902b62a --- /dev/null +++ b/assets/methods_description_template.yml @@ -0,0 +1,29 @@ +id: "nf-cmgg-preprocessing-methods-description" +description: "Suggested text and references to use when describing pipeline usage within the methods section of a publication." +section_name: "nf-cmgg/preprocessing Methods Description" +section_href: "https://github.com/nf-cmgg/preprocessing" +plot_type: "html" +## TODO nf-core: Update the HTML below to your preferred methods description, e.g. add publication citation for this pipeline +## You inject any metadata in the Nextflow '${workflow}' object +data: | +

    Methods

    +

    Data was processed using nf-cmgg/preprocessing v${workflow.manifest.version} ${doi_text} of the nf-core collection of workflows (Ewels et al., 2020), utilising reproducible software environments from the Bioconda (Grüning et al., 2018) and Biocontainers (da Veiga Leprevost et al., 2017) projects.

    +

    The pipeline was executed with Nextflow v${workflow.nextflow.version} (Di Tommaso et al., 2017) with the following command:

    +
    ${workflow.commandLine}
    +

    ${tool_citations}

    +

    References

    +
      +
    • Di Tommaso, P., Chatzou, M., Floden, E. W., Barja, P. P., Palumbo, E., & Notredame, C. (2017). Nextflow enables reproducible computational workflows. Nature Biotechnology, 35(4), 316-319. doi: 10.1038/nbt.3820
    • +
    • Ewels, P. A., Peltzer, A., Fillinger, S., Patel, H., Alneberg, J., Wilm, A., Garcia, M. U., Di Tommaso, P., & Nahnsen, S. (2020). The nf-core framework for community-curated bioinformatics pipelines. Nature Biotechnology, 38(3), 276-278. doi: 10.1038/s41587-020-0439-x
    • +
    • Grüning, B., Dale, R., Sjödin, A., Chapman, B. A., Rowe, J., Tomkins-Tinch, C. H., Valieris, R., Köster, J., & Bioconda Team. (2018). Bioconda: sustainable and comprehensive software distribution for the life sciences. Nature Methods, 15(7), 475–476. doi: 10.1038/s41592-018-0046-7
    • +
    • da Veiga Leprevost, F., Grüning, B. A., Alves Aflitos, S., Röst, H. L., Uszkoreit, J., Barsnes, H., Vaudel, M., Moreno, P., Gatto, L., Weber, J., Bai, M., Jimenez, R. C., Sachsenberg, T., Pfeuffer, J., Vera Alvarez, R., Griss, J., Nesvizhskii, A. I., & Perez-Riverol, Y. (2017). BioContainers: an open-source and community-driven framework for software standardization. Bioinformatics (Oxford, England), 33(16), 2580–2582. doi: 10.1093/bioinformatics/btx192
    • + ${tool_bibliography} +
    +
    +
    Notes:
    +
      + ${nodoi_text} +
    • The command above does not include parameters contained in any configs or profiles that may have been used. Ensure the config file is also uploaded with your publication!
    • +
    • You should also cite all software used within this run. Check the "Software Versions" of this report to get version information.
    • +
    +
    diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml new file mode 100644 index 00000000..fe5c11d1 --- /dev/null +++ b/assets/multiqc_config.yml @@ -0,0 +1,14 @@ +report_comment: > + This report has been generated by the nf-cmgg/preprocessing + analysis pipeline. +report_section_order: + "nf-cmgg-preprocessing-methods-description": + order: -1000 + software_versions: + order: -1001 + "nf-cmgg-preprocessing-summary": + order: -1002 + +export_plots: true + +disable_version_detection: true diff --git a/assets/samplesheet.csv b/assets/samplesheet.csv new file mode 100644 index 00000000..5f653ab7 --- /dev/null +++ b/assets/samplesheet.csv @@ -0,0 +1,3 @@ +sample,fastq_1,fastq_2 +SAMPLE_PAIRED_END,/path/to/fastq/files/AEG588A1_S1_L002_R1_001.fastq.gz,/path/to/fastq/files/AEG588A1_S1_L002_R2_001.fastq.gz +SAMPLE_SINGLE_END,/path/to/fastq/files/AEG588A4_S4_L003_R1_001.fastq.gz, diff --git a/assets/schema_input.json b/assets/schema_input.json new file mode 100644 index 00000000..2605e47c --- /dev/null +++ b/assets/schema_input.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/nf-cmgg/preprocessing/main/assets/schema_input.json", + "title": "nf-cmgg/preprocessing pipeline - params.input schema", + "description": "Schema for the file provided with params.input", + "type": "array", + "items": { + "type": "object", + "properties": { + "sample": { + "type": "string", + "pattern": "^\\S+$", + "errorMessage": "Sample name must be provided and cannot contain spaces", + "meta": ["id"] + }, + "fastq_1": { + "type": "string", + "format": "file-path", + "exists": true, + "pattern": "^([\\S\\s]*\\/)?[^\\s\\/]+\\.f(ast)?q\\.gz$", + "errorMessage": "FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" + }, + "fastq_2": { + "type": "string", + "format": "file-path", + "exists": true, + "pattern": "^([\\S\\s]*\\/)?[^\\s\\/]+\\.f(ast)?q\\.gz$", + "errorMessage": "FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" + } + }, + "required": ["sample", "fastq_1"] + } +} diff --git a/assets/sendmail_template.txt b/assets/sendmail_template.txt new file mode 100644 index 00000000..d904231a --- /dev/null +++ b/assets/sendmail_template.txt @@ -0,0 +1,53 @@ +To: $email +Subject: $subject +Mime-Version: 1.0 +Content-Type: multipart/related;boundary="nfcoremimeboundary" + +--nfcoremimeboundary +Content-Type: text/html; charset=utf-8 + +$email_html + +--nfcoremimeboundary +Content-Type: image/png;name="nf-cmgg-preprocessing_logo.png" +Content-Transfer-Encoding: base64 +Content-ID: +Content-Disposition: inline; filename="nf-cmgg-preprocessing_logo_light.png" + +<% out << new File("$projectDir/assets/nf-cmgg-preprocessing_logo_light.png"). + bytes. + encodeBase64(). + toString(). + tokenize( '\n' )*. + toList()*. + collate( 76 )*. + collect { it.join() }. + flatten(). + join( '\n' ) %> + +<% +if (mqcFile){ +def mqcFileObj = new File("$mqcFile") +if (mqcFileObj.length() < mqcMaxSize){ +out << """ +--nfcoremimeboundary +Content-Type: text/html; name=\"multiqc_report\" +Content-Transfer-Encoding: base64 +Content-ID: +Content-Disposition: attachment; filename=\"${mqcFileObj.getName()}\" + +${mqcFileObj. + bytes. + encodeBase64(). + toString(). + tokenize( '\n' )*. + toList()*. + collate( 76 )*. + collect { it.join() }. + flatten(). + join( '\n' )} +""" +}} +%> + +--nfcoremimeboundary-- diff --git a/assets/slackreport.json b/assets/slackreport.json new file mode 100644 index 00000000..84fc115a --- /dev/null +++ b/assets/slackreport.json @@ -0,0 +1,34 @@ +{ + "attachments": [ + { + "fallback": "Plain-text summary of the attachment.", + "color": "<% if (success) { %>good<% } else { %>danger<%} %>", + "author_name": "nf-cmgg/preprocessing ${version} - ${runName}", + "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", + "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", + "fields": [ + { + "title": "Command used to launch the workflow", + "value": "```${commandLine}```", + "short": false + } + <% + if (!success) { %> + , + { + "title": "Full error message", + "value": "```${errorReport}```", + "short": false + }, + { + "title": "Pipeline configuration", + "value": "<% out << summary.collect{ k,v -> k == "hook_url" ? "_${k}_: (_hidden_)" : ( ( v.class.toString().contains('Path') || ( v.class.toString().contains('String') && v.contains('/') ) ) ? "_${k}_: `${v}`" : (v.class.toString().contains('DateTime') ? ("_${k}_: " + v.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM))) : "_${k}_: ${v}") ) }.join(",\n") %>", + "short": false + } + <% } + %> + ], + "footer": "Completed at <% out << dateComplete.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM)) %> (duration: ${duration})" + } + ] +} diff --git a/conf/base.config b/conf/base.config new file mode 100644 index 00000000..4f3a0d41 --- /dev/null +++ b/conf/base.config @@ -0,0 +1,66 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + nf-cmgg/preprocessing Nextflow base config file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + A 'blank slate' config file, appropriate for general use on most high performance + compute environments. Assumes that all software is installed and available on + the PATH. Runs in `local` mode - all jobs will be run on the logged in environment. +---------------------------------------------------------------------------------------- +*/ + +process { + + // TODO nf-core: Check the defaults for all processes + cpus = { 1 * task.attempt } + memory = { 6.GB * task.attempt } + time = { 4.h * task.attempt } + + errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } + maxRetries = 1 + maxErrors = '-1' + + // Process-specific resource requirements + // NOTE - Please try and reuse the labels below as much as possible. + // These labels are used and recognised by default in DSL2 files hosted on nf-core/modules. + // If possible, it would be nice to keep the same label naming convention when + // adding in your local modules too. + // TODO nf-core: Customise requirements for specific processes. + // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors + withLabel:process_single { + cpus = { 1 } + memory = { 6.GB * task.attempt } + time = { 4.h * task.attempt } + } + withLabel:process_low { + cpus = { 2 * task.attempt } + memory = { 12.GB * task.attempt } + time = { 4.h * task.attempt } + } + withLabel:process_medium { + cpus = { 6 * task.attempt } + memory = { 36.GB * task.attempt } + time = { 8.h * task.attempt } + } + withLabel:process_high { + cpus = { 12 * task.attempt } + memory = { 72.GB * task.attempt } + time = { 16.h * task.attempt } + } + withLabel:process_long { + time = { 20.h * task.attempt } + } + withLabel:process_high_memory { + memory = { 200.GB * task.attempt } + } + withLabel:error_ignore { + errorStrategy = 'ignore' + } + withLabel:error_retry { + errorStrategy = 'retry' + maxRetries = 2 + } + withLabel: process_gpu { + ext.use_gpu = { workflow.profile.contains('gpu') } + accelerator = { workflow.profile.contains('gpu') ? 1 : null } + } +} diff --git a/conf/igenomes.config b/conf/igenomes.config new file mode 100644 index 00000000..3f114377 --- /dev/null +++ b/conf/igenomes.config @@ -0,0 +1,440 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for iGenomes paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines reference genomes using iGenome paths. + Can be used by any config that customises the base path using: + $params.igenomes_base / --igenomes_base +---------------------------------------------------------------------------------------- +*/ + +params { + // illumina iGenomes reference file paths + genomes { + 'GRCh37' { + fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/README.txt" + mito_name = "MT" + macs_gsize = "2.7e9" + blacklist = "${projectDir}/assets/blacklists/GRCh37-blacklist.bed" + } + 'GRCh38' { + fasta = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.bed" + mito_name = "chrM" + macs_gsize = "2.7e9" + blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" + } + 'CHM13' { + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAIndex/" + bwamem2 = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAmem2Index/" + gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/CHM13/Annotation/Genes/genes.gtf" + gff = "ftp://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz" + mito_name = "chrM" + } + 'GRCm38' { + fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/README.txt" + mito_name = "MT" + macs_gsize = "1.87e9" + blacklist = "${projectDir}/assets/blacklists/GRCm38-blacklist.bed" + } + 'TAIR10' { + fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/README.txt" + mito_name = "Mt" + } + 'EB2' { + fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/README.txt" + } + 'UMD3.1' { + fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/README.txt" + mito_name = "MT" + } + 'WBcel235' { + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed" + mito_name = "MtDNA" + macs_gsize = "9e7" + } + 'CanFam3.1' { + fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/README.txt" + mito_name = "MT" + } + 'GRCz10' { + fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'BDGP6' { + fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed" + mito_name = "M" + macs_gsize = "1.2e8" + } + 'EquCab2' { + fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/README.txt" + mito_name = "MT" + } + 'EB1' { + fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/README.txt" + } + 'Galgal4' { + fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'Gm01' { + fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/README.txt" + } + 'Mmul_1' { + fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/README.txt" + mito_name = "MT" + } + 'IRGSP-1.0' { + fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed" + mito_name = "Mt" + } + 'CHIMP2.1.4' { + fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/README.txt" + mito_name = "MT" + } + 'Rnor_5.0' { + fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'Rnor_6.0' { + fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed" + mito_name = "MT" + } + 'R64-1-1' { + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed" + mito_name = "MT" + macs_gsize = "1.2e7" + } + 'EF2' { + fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/README.txt" + mito_name = "MT" + macs_gsize = "1.21e7" + } + 'Sbi1' { + fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/README.txt" + } + 'Sscrofa10.2' { + fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/README.txt" + mito_name = "MT" + } + 'AGPv3' { + fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed" + mito_name = "Mt" + } + 'hg38' { + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.bed" + mito_name = "chrM" + macs_gsize = "2.7e9" + blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" + } + 'hg19' { + fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "2.7e9" + blacklist = "${projectDir}/assets/blacklists/hg19-blacklist.bed" + } + 'mm10' { + fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "1.87e9" + blacklist = "${projectDir}/assets/blacklists/mm10-blacklist.bed" + } + 'bosTau8' { + fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.bed" + mito_name = "chrM" + } + 'ce10' { + fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "9e7" + } + 'canFam3' { + fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/README.txt" + mito_name = "chrM" + } + 'danRer10' { + fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.bed" + mito_name = "chrM" + macs_gsize = "1.37e9" + } + 'dm6' { + fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.bed" + mito_name = "chrM" + macs_gsize = "1.2e8" + } + 'equCab2' { + fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/README.txt" + mito_name = "chrM" + } + 'galGal4' { + fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/README.txt" + mito_name = "chrM" + } + 'panTro4' { + fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/README.txt" + mito_name = "chrM" + } + 'rn6' { + fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.bed" + mito_name = "chrM" + } + 'sacCer3' { + fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BismarkIndex/" + readme = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Annotation/README.txt" + mito_name = "chrM" + macs_gsize = "1.2e7" + } + 'susScr3' { + fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" + bwa = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/version0.6.0/" + bowtie2 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/Bowtie2Index/" + star = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/STARIndex/" + bismark = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BismarkIndex/" + gtf = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.gtf" + bed12 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.bed" + readme = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/README.txt" + mito_name = "chrM" + } + } +} diff --git a/conf/igenomes_ignored.config b/conf/igenomes_ignored.config new file mode 100644 index 00000000..b4034d82 --- /dev/null +++ b/conf/igenomes_ignored.config @@ -0,0 +1,9 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for iGenomes paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Empty genomes dictionary to use when igenomes is ignored. +---------------------------------------------------------------------------------------- +*/ + +params.genomes = [:] diff --git a/conf/modules.config b/conf/modules.config new file mode 100644 index 00000000..d203d2b6 --- /dev/null +++ b/conf/modules.config @@ -0,0 +1,34 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Config file for defining DSL2 per module options and publishing paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Available keys to override module options: + ext.args = Additional arguments appended to command in module. + ext.args2 = Second set of arguments appended to command in module (multi-tool modules). + ext.args3 = Third set of arguments appended to command in module (multi-tool modules). + ext.prefix = File name prefix for output files. +---------------------------------------------------------------------------------------- +*/ + +process { + + publishDir = [ + path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + + withName: FASTQC { + ext.args = '--quiet' + } + + withName: 'MULTIQC' { + ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } + publishDir = [ + path: { "${params.outdir}/multiqc" }, + mode: params.publish_dir_mode, + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + +} diff --git a/conf/test.config b/conf/test.config new file mode 100644 index 00000000..99e207ff --- /dev/null +++ b/conf/test.config @@ -0,0 +1,30 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running minimal tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a fast and simple pipeline test. + + Use as follows: + nextflow run nf-cmgg/preprocessing -profile test, --outdir + +---------------------------------------------------------------------------------------- +*/ + +process { + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '1.h' + ] +} + +params { + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + + // Input data + // TODO nf-core: Specify the paths to your test data on nf-core/test-datasets + // TODO nf-core: Give any required params for the test so that command line flags are not needed + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv'// Genome references + genome = 'R64-1-1' +} diff --git a/conf/test_full.config b/conf/test_full.config new file mode 100644 index 00000000..6225119a --- /dev/null +++ b/conf/test_full.config @@ -0,0 +1,24 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for running full-size tests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Defines input files and everything required to run a full size pipeline test. + + Use as follows: + nextflow run nf-cmgg/preprocessing -profile test_full, --outdir + +---------------------------------------------------------------------------------------- +*/ + +params { + config_profile_name = 'Full test profile' + config_profile_description = 'Full test dataset to check pipeline function' + + // Input data for full size test + // TODO nf-core: Specify the paths to your full test data ( on nf-core/test-datasets or directly in repositories, e.g. SRA) + // TODO nf-core: Give any required params for the test so that command line flags are not needed + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' + + // Genome references + genome = 'R64-1-1' +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..18efa6bf --- /dev/null +++ b/docs/README.md @@ -0,0 +1,8 @@ +# nf-cmgg/preprocessing: Documentation + +The nf-cmgg/preprocessing documentation is split into the following pages: + +- [Usage](usage.md) + - An overview of how the pipeline works, how to run it and a description of all of the different command-line flags. +- [Output](output.md) + - An overview of the different results produced by the pipeline and how to interpret them. diff --git a/docs/output.md b/docs/output.md new file mode 100644 index 00000000..43f03a89 --- /dev/null +++ b/docs/output.md @@ -0,0 +1,61 @@ +# nf-cmgg/preprocessing: Output + +## Introduction + +This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. + +The directories listed below will be created in the results directory after the pipeline has finished. All paths are relative to the top-level results directory. + + + +## Pipeline overview + +The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: + +- [FastQC](#fastqc) - Raw read QC +- [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline +- [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution + +### FastQC + +
    +Output files + +- `fastqc/` + - `*_fastqc.html`: FastQC report containing quality metrics. + - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. + +
    + +[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your sequenced reads. It provides information about the quality score distribution across your reads, per base sequence content (%A/T/G/C), adapter contamination and overrepresented sequences. For further reading and documentation see the [FastQC help pages](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/). + +### MultiQC + +
    +Output files + +- `multiqc/` + - `multiqc_report.html`: a standalone HTML file that can be viewed in your web browser. + - `multiqc_data/`: directory containing parsed statistics from the different tools used in the pipeline. + - `multiqc_plots/`: directory containing static images from the report in various formats. + +
    + +[MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. + +Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQC. The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. For more information about how to use MultiQC reports, see . + +### Pipeline information + +
    +Output files + +- `pipeline_info/` + - Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. + - Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. + - Reformatted samplesheet files used as input to the pipeline: `samplesheet.valid.csv`. + - Parameters used by the pipeline run: `params.json`. + +
    + +[Nextflow](https://www.nextflow.io/docs/latest/tracing.html) provides excellent functionality for generating various reports relevant to the running and execution of the pipeline. This will allow you to troubleshoot errors with the running of the pipeline, and also provide you with other information such as launch commands, run times and resource usage. diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..3f528f39 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,212 @@ +# nf-cmgg/preprocessing: Usage + +> _Documentation of pipeline parameters is generated automatically from the pipeline schema and can no longer be found in markdown files._ + +## Introduction + + + +## Samplesheet input + +You will need to create a samplesheet with information about the samples you would like to analyse before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row as shown in the examples below. + +```bash +--input '[path to samplesheet file]' +``` + +### Multiple runs of the same sample + +The `sample` identifiers have to be the same when you have re-sequenced the same sample more than once e.g. to increase sequencing depth. The pipeline will concatenate the raw reads before performing any downstream analysis. Below is an example for the same sample sequenced across 3 lanes: + +```csv title="samplesheet.csv" +sample,fastq_1,fastq_2 +CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz +CONTROL_REP1,AEG588A1_S1_L003_R1_001.fastq.gz,AEG588A1_S1_L003_R2_001.fastq.gz +CONTROL_REP1,AEG588A1_S1_L004_R1_001.fastq.gz,AEG588A1_S1_L004_R2_001.fastq.gz +``` + +### Full samplesheet + +The pipeline will auto-detect whether a sample is single- or paired-end using the information provided in the samplesheet. The samplesheet can have as many columns as you desire, however, there is a strict requirement for the first 3 columns to match those defined in the table below. + +A final samplesheet file consisting of both single- and paired-end data may look something like the one below. This is for 6 samples, where `TREATMENT_REP3` has been sequenced twice. + +```csv title="samplesheet.csv" +sample,fastq_1,fastq_2 +CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz +CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz +CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz +TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz, +TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz, +TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz, +TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz, +``` + +| Column | Description | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | +| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | + +An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. + +## Running the pipeline + +The typical command for running the pipeline is as follows: + +```bash +nextflow run nf-cmgg/preprocessing --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker +``` + +This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. + +Note that the pipeline will create the following files in your working directory: + +```bash +work # Directory containing the nextflow working files + # Finished results in specified location (defined with --outdir) +.nextflow_log # Log file from Nextflow +# Other nextflow hidden files, eg. history of pipeline runs and old logs. +``` + +If you wish to repeatedly use the same parameters for multiple runs, rather than specifying each flag in the command, you can specify these in a params file. + +Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. + +> [!WARNING] +> Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). + +The above pipeline run specified with a params file in yaml format: + +```bash +nextflow run nf-cmgg/preprocessing -profile docker -params-file params.yaml +``` + +with: + +```yaml title="params.yaml" +input: './samplesheet.csv' +outdir: './results/' +genome: 'GRCh37' +<...> +``` + +You can also generate such `YAML`/`JSON` files via [nf-core/launch](https://nf-co.re/launch). + +### Updating the pipeline + +When you run the above command, Nextflow automatically pulls the pipeline code from GitHub and stores it as a cached version. When running the pipeline after this, it will always use the cached version if available - even if the pipeline has been updated since. To make sure that you're running the latest version of the pipeline, make sure that you regularly update the cached version of the pipeline: + +```bash +nextflow pull nf-cmgg/preprocessing +``` + +### Reproducibility + +It is a good idea to specify the pipeline version when running the pipeline on your data. This ensures that a specific version of the pipeline code and software are used when you run your pipeline. If you keep using the same tag, you'll be running the same version of the pipeline, even if there have been changes to the code since. + +First, go to the [nf-cmgg/preprocessing releases page](https://github.com/nf-cmgg/preprocessing/releases) and find the latest pipeline version - numeric only (eg. `1.3.1`). Then specify this when running the pipeline with `-r` (one hyphen) - eg. `-r 1.3.1`. Of course, you can switch to another version by changing the number after the `-r` flag. + +This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. For example, at the bottom of the MultiQC reports. + +To further assist in reproducibility, you can use share and reuse [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. + +> [!TIP] +> If you wish to share such profile (such as upload as supplementary material for academic publications), make sure to NOT include cluster specific paths to files, nor institutional specific profiles. + +## Core Nextflow arguments + +> [!NOTE] +> These options are part of Nextflow and use a _single_ hyphen (pipeline parameters use a double-hyphen) + +### `-profile` + +Use this parameter to choose a configuration profile. Profiles can give configuration presets for different compute environments. + +Several generic profiles are bundled with the pipeline which instruct the pipeline to use software packaged using different methods (Docker, Singularity, Podman, Shifter, Charliecloud, Apptainer, Conda) - see below. + +> [!IMPORTANT] +> We highly recommend the use of Docker or Singularity containers for full pipeline reproducibility, however when this is not possible, Conda is also supported. + +The pipeline also dynamically loads configurations from [https://github.com/nf-core/configs](https://github.com/nf-core/configs) when it runs, making multiple config profiles for various institutional clusters available at run time. For more information and to check if your system is supported, please see the [nf-core/configs documentation](https://github.com/nf-core/configs#documentation). + +Note that multiple profiles can be loaded, for example: `-profile test,docker` - the order of arguments is important! +They are loaded in sequence, so later profiles can overwrite earlier profiles. + +If `-profile` is not specified, the pipeline will run locally and expect all software to be installed and available on the `PATH`. This is _not_ recommended, since it can lead to different results on different machines dependent on the computer environment. + +- `test` + - A profile with a complete configuration for automated testing + - Includes links to test data so needs no other parameters +- `docker` + - A generic configuration profile to be used with [Docker](https://docker.com/) +- `singularity` + - A generic configuration profile to be used with [Singularity](https://sylabs.io/docs/) +- `podman` + - A generic configuration profile to be used with [Podman](https://podman.io/) +- `shifter` + - A generic configuration profile to be used with [Shifter](https://nersc.gitlab.io/development/shifter/how-to-use/) +- `charliecloud` + - A generic configuration profile to be used with [Charliecloud](https://charliecloud.io/) +- `apptainer` + - A generic configuration profile to be used with [Apptainer](https://apptainer.org/) +- `wave` + - A generic configuration profile to enable [Wave](https://seqera.io/wave/) containers. Use together with one of the above (requires Nextflow ` 24.03.0-edge` or later). +- `conda` + - A generic configuration profile to be used with [Conda](https://conda.io/docs/). Please only use Conda as a last resort i.e. when it's not possible to run the pipeline with Docker, Singularity, Podman, Shifter, Charliecloud, or Apptainer. + +### `-resume` + +Specify this when restarting a pipeline. Nextflow will use cached results from any pipeline steps where the inputs are the same, continuing from where it got to previously. For input to be considered the same, not only the names must be identical but the files' contents as well. For more info about this parameter, see [this blog post](https://www.nextflow.io/blog/2019/demystifying-nextflow-resume.html). + +You can also supply a run name to resume a specific run: `-resume [run-name]`. Use the `nextflow log` command to show previous run names. + +### `-c` + +Specify the path to a specific config file (this is a core Nextflow command). See the [nf-core website documentation](https://nf-co.re/usage/configuration) for more information. + +## Custom configuration + +### Resource requests + +Whilst the default requirements set within the pipeline will hopefully work for most people and with most input data, you may find that you want to customise the compute resources that the pipeline requests. Each step in the pipeline has a default set of requirements for number of CPUs, memory and time. For most of the pipeline steps, if the job exits with any of the error codes specified [here](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L18) it will automatically be resubmitted with higher resources request (2 x original, then 3 x original). If it still fails after the third attempt then the pipeline execution is stopped. + +To change the resource requests, please see the [max resources](https://nf-co.re/docs/usage/configuration#max-resources) and [tuning workflow resources](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources) section of the nf-core website. + +### Custom Containers + +In some cases, you may wish to change the container or conda environment used by a pipeline steps for a particular tool. By default, nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However, in some cases the pipeline specified version maybe out of date. + +To use a different container from the default container or conda environment specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/usage/configuration#updating-tool-versions) section of the nf-core website. + +### Custom Tool Arguments + +A pipeline might not always support every possible argument or option of a particular tool used in pipeline. Fortunately, nf-core pipelines provide some freedom to users to insert additional parameters that the pipeline does not include by default. + +To learn how to provide additional arguments to a particular tool of the pipeline, please see the [customising tool arguments](https://nf-co.re/docs/usage/configuration#customising-tool-arguments) section of the nf-core website. + +### nf-core/configs + +In most cases, you will only need to create a custom config as a one-off but if you and others within your organisation are likely to be running nf-core pipelines regularly and need to use the same settings regularly it may be a good idea to request that your custom config file is uploaded to the `nf-core/configs` git repository. Before you do this please can you test that the config file works with your pipeline of choice using the `-c` parameter. You can then create a pull request to the `nf-core/configs` repository with the addition of your config file, associated documentation file (see examples in [`nf-core/configs/docs`](https://github.com/nf-core/configs/tree/master/docs)), and amending [`nfcore_custom.config`](https://github.com/nf-core/configs/blob/master/nfcore_custom.config) to include your custom profile. + +See the main [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for more information about creating your own configuration files. + +If you have any questions or issues please send us a message on [Slack](https://nf-co.re/join/slack) on the [`#configs` channel](https://nfcore.slack.com/channels/configs). + +## Running in the background + +Nextflow handles job submissions and supervises the running jobs. The Nextflow process must run until the pipeline is finished. + +The Nextflow `-bg` flag launches Nextflow in the background, detached from your terminal so that the workflow does not stop if you log out of your session. The logs are saved to a file. + +Alternatively, you can use `screen` / `tmux` or similar tool to create a detached session which you can log back into at a later time. +Some HPC setups also allow you to run nextflow within a cluster job submitted your job scheduler (from where it submits more jobs). + +## Nextflow memory requirements + +In some cases, the Nextflow Java virtual machines can start to request a large amount of memory. +We recommend adding the following line to your environment to limit this (typically in `~/.bashrc` or `~./bash_profile`): + +```bash +NXF_OPTS='-Xms1g -Xmx4g' +``` diff --git a/main.nf b/main.nf new file mode 100644 index 00000000..8d9c8186 --- /dev/null +++ b/main.nf @@ -0,0 +1,105 @@ +#!/usr/bin/env nextflow +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + nf-cmgg/preprocessing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Github : https://github.com/nf-cmgg/preprocessing +---------------------------------------------------------------------------------------- +*/ + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS / WORKFLOWS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +include { PREPROCESSING } from './workflows/preprocessing' +include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_preprocessing_pipeline' + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GENOME PARAMETER VALUES +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// TODO nf-core: Remove this line if you don't need a FASTA file +// This is an example of how to use getGenomeAttribute() to fetch parameters +// from igenomes.config using `--genome` +params.fasta = getGenomeAttribute('fasta') + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + NAMED WORKFLOWS FOR PIPELINE +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// +// WORKFLOW: Run main analysis pipeline depending on type of input +// +workflow NFCMGG_PREPROCESSING { + + take: + samplesheet // channel: samplesheet read in from --input + + main: + + // + // WORKFLOW: Run pipeline + // + PREPROCESSING ( + samplesheet + ) + emit: + multiqc_report = PREPROCESSING.out.multiqc_report // channel: /path/to/multiqc_report.html +} +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + RUN MAIN WORKFLOW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +workflow { + + main: + // + // SUBWORKFLOW: Run initialisation tasks + // + PIPELINE_INITIALISATION ( + params.version, + params.validate_params, + params.monochrome_logs, + args, + params.outdir, + params.input, + params.help, + params.help_full, + params.show_hidden + ) + + // + // WORKFLOW: Run main workflow + // + NFCMGG_PREPROCESSING ( + PIPELINE_INITIALISATION.out.samplesheet + ) + // + // SUBWORKFLOW: Run completion tasks + // + PIPELINE_COMPLETION ( + params.email, + params.email_on_fail, + params.plaintext_email, + params.outdir, + params.monochrome_logs, + params.hook_url, + NFCMGG_PREPROCESSING.out.multiqc_report + ) +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + THE END +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ diff --git a/modules.json b/modules.json new file mode 100644 index 00000000..91d4b13b --- /dev/null +++ b/modules.json @@ -0,0 +1,41 @@ +{ + "name": "nf-cmgg/preprocessing", + "homePage": "https://github.com/nf-cmgg/preprocessing", + "repos": { + "https://github.com/nf-core/modules.git": { + "modules": { + "nf-core": { + "fastqc": { + "branch": "master", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "installed_by": ["modules"] + }, + "multiqc": { + "branch": "master", + "git_sha": "e10b76ca0c66213581bec2833e30d31f239dec0b", + "installed_by": ["modules"] + } + } + }, + "subworkflows": { + "nf-core": { + "utils_nextflow_pipeline": { + "branch": "master", + "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", + "installed_by": ["subworkflows"] + }, + "utils_nfcore_pipeline": { + "branch": "master", + "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", + "installed_by": ["subworkflows"] + }, + "utils_nfschema_plugin": { + "branch": "master", + "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", + "installed_by": ["subworkflows"] + } + } + } + } + } +} diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml new file mode 100644 index 00000000..f9f54ee9 --- /dev/null +++ b/modules/nf-core/fastqc/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::fastqc=0.12.1 diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf new file mode 100644 index 00000000..23e16634 --- /dev/null +++ b/modules/nf-core/fastqc/main.nf @@ -0,0 +1,64 @@ +process FASTQC { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/fastqc:0.12.1--hdfd78af_0' : + 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" + + input: + tuple val(meta), path(reads) + + output: + tuple val(meta), path("*.html"), emit: html + tuple val(meta), path("*.zip") , emit: zip + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + // Make list of old name and new name pairs to use for renaming in the bash while loop + def old_new_pairs = reads instanceof Path || reads.size() == 1 ? [[ reads, "${prefix}.${reads.extension}" ]] : reads.withIndex().collect { entry, index -> [ entry, "${prefix}_${index + 1}.${entry.extension}" ] } + def rename_to = old_new_pairs*.join(' ').join(' ') + def renamed_files = old_new_pairs.collect{ _old_name, new_name -> new_name }.join(' ') + + // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) + // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 + // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label + def memory_in_mb = task.memory ? task.memory.toUnit('MB') / task.cpus : null + // FastQC memory value allowed range (100 - 10000) + def fastqc_memory = memory_in_mb > 10000 ? 10000 : (memory_in_mb < 100 ? 100 : memory_in_mb) + + """ + printf "%s %s\\n" ${rename_to} | while read old_name new_name; do + [ -f "\${new_name}" ] || ln -s \$old_name \$new_name + done + + fastqc \\ + ${args} \\ + --threads ${task.cpus} \\ + --memory ${fastqc_memory} \\ + ${renamed_files} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.html + touch ${prefix}.zip + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml new file mode 100644 index 00000000..c8d9d025 --- /dev/null +++ b/modules/nf-core/fastqc/meta.yml @@ -0,0 +1,72 @@ +name: fastqc +description: Run FastQC on sequenced reads +keywords: + - quality control + - qc + - adapters + - fastq +tools: + - fastqc: + description: | + FastQC gives general quality metrics about your reads. + It provides information about the quality score distribution + across your reads, the per base sequence content (%A/C/G/T). + + You get information about adapter contamination and other + overrepresented sequences. + homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ + documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ + licence: ["GPL-2.0-only"] + identifier: biotools:fastqc +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files of size 1 and 2 for single-end and paired-end data, + respectively. + ontologies: [] +output: + html: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.html": + type: file + description: FastQC report + pattern: "*_{fastqc.html}" + ontologies: [] + zip: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.zip": + type: file + description: FastQC report archive + pattern: "*_{fastqc.zip}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@drpatelh" + - "@grst" + - "@ewels" + - "@FelixKrueger" +maintainers: + - "@drpatelh" + - "@grst" + - "@ewels" + - "@FelixKrueger" diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test new file mode 100644 index 00000000..e9d79a07 --- /dev/null +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -0,0 +1,309 @@ +nextflow_process { + + name "Test Process FASTQC" + script "../main.nf" + process "FASTQC" + + tag "modules" + tag "modules_nfcore" + tag "fastqc" + + test("sarscov2 single-end [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [ id: 'test', single_end:true ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. + // looks like this:
    Mon 2 Oct 2023
    test.gz
    + // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + test("sarscov2 paired-end [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [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 process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + test("sarscov2 interleaved [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + test("sarscov2 paired-end [bam]") { + + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + test("sarscov2 multiple [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [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), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, + { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, + { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + test("sarscov2 custom_prefix") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'mysample', single_end:true ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } + ) + } + } + + test("sarscov2 single-end [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id: 'test', single_end:true ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 paired-end [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [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(process.out).match() } + ) + } + } + + test("sarscov2 interleaved [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 paired-end [bam] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 multiple [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [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), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 custom_prefix - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'mysample', single_end:true ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap new file mode 100644 index 00000000..d5db3092 --- /dev/null +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -0,0 +1,392 @@ +{ + "sarscov2 custom_prefix": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:16.374038" + }, + "sarscov2 single-end [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": true + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": true + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:24.993809" + }, + "sarscov2 custom_prefix - stub": { + "content": [ + { + "0": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:03:10.93942" + }, + "sarscov2 interleaved [fastq]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:42.355718" + }, + "sarscov2 paired-end [bam]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:53.276274" + }, + "sarscov2 multiple [fastq]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:05.527626" + }, + "sarscov2 paired-end [fastq]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:31.188871" + }, + "sarscov2 paired-end [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:34.273566" + }, + "sarscov2 multiple [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:03:02.304411" + }, + "sarscov2 single-end [fastq]": { + "content": [ + [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:19.095607" + }, + "sarscov2 interleaved [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:44.640184" + }, + "sarscov2 paired-end [bam] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:53.550742" + } +} \ No newline at end of file diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml new file mode 100644 index 00000000..dd513cbd --- /dev/null +++ b/modules/nf-core/multiqc/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::multiqc=1.31 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf new file mode 100644 index 00000000..5288f5cc --- /dev/null +++ b/modules/nf-core/multiqc/main.nf @@ -0,0 +1,63 @@ +process MULTIQC { + 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/ef/eff0eafe78d5f3b65a6639265a16b89fdca88d06d18894f90fcdb50142004329/data' : + 'community.wave.seqera.io/library/multiqc:1.31--1efbafd542a23882' }" + + input: + path multiqc_files, stageAs: "?/*" + path(multiqc_config) + path(extra_multiqc_config) + path(multiqc_logo) + path(replace_names) + path(sample_names) + + output: + path "*multiqc_report.html", emit: report + path "*_data" , emit: data + path "*_plots" , optional:true, emit: plots + path "versions.yml" , emit: versions + + 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 \\ + . + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) + END_VERSIONS + """ + + stub: + """ + mkdir multiqc_data + mkdir multiqc_plots + touch multiqc_report.html + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml new file mode 100644 index 00000000..ce30eb73 --- /dev/null +++ b/modules/nf-core/multiqc/meta.yml @@ -0,0 +1,92 @@ +name: multiqc +description: Aggregate results from bioinformatics analyses across many samples into + a single report +keywords: + - QC + - bioinformatics tools + - Beautiful stand-alone HTML report +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: + - multiqc_files: + type: file + description: | + List of reports / files recognised 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: + - "*multiqc_report.html": + type: file + description: MultiQC report file + pattern: "multiqc_report.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: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@abhi18av" + - "@bunop" + - "@drpatelh" + - "@jfy133" +maintainers: + - "@abhi18av" + - "@bunop" + - "@drpatelh" + - "@jfy133" diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test new file mode 100644 index 00000000..33316a7d --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -0,0 +1,92 @@ +nextflow_process { + + name "Test Process MULTIQC" + script "../main.nf" + process "MULTIQC" + + tag "modules" + tag "modules_nfcore" + tag "multiqc" + + config "./nextflow.config" + + test("sarscov2 single-end [fastqc]") { + + when { + process { + """ + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) + input[1] = [] + input[2] = [] + input[3] = [] + input[4] = [] + input[5] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("multiqc_versions_single") } + ) + } + + } + + test("sarscov2 single-end [fastqc] [config]") { + + when { + process { + """ + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) + input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) + input[2] = [] + input[3] = [] + input[4] = [] + input[5] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, + { assert process.out.data[0] ==~ ".*/multiqc_data" }, + { assert snapshot(process.out.versions).match("multiqc_versions_config") } + ) + } + } + + test("sarscov2 single-end [fastqc] - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) + input[1] = [] + input[2] = [] + input[3] = [] + input[4] = [] + input[5] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.report.collect { file(it).getName() } + + process.out.data.collect { file(it).getName() } + + process.out.plots.collect { file(it).getName() } + + process.out.versions ).match("multiqc_stub") } + ) + } + + } +} diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap new file mode 100644 index 00000000..17881d15 --- /dev/null +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -0,0 +1,41 @@ +{ + "multiqc_versions_single": { + "content": [ + [ + "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-08T20:57:36.139055243" + }, + "multiqc_stub": { + "content": [ + [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-08T20:59:15.142230631" + }, + "multiqc_versions_config": { + "content": [ + [ + "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-08T20:58:29.629087066" + } +} \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config new file mode 100644 index 00000000..c537a6a3 --- /dev/null +++ b/modules/nf-core/multiqc/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'MULTIQC' { + ext.prefix = null + } +} diff --git a/nextflow.config b/nextflow.config new file mode 100644 index 00000000..dd7bef4d --- /dev/null +++ b/nextflow.config @@ -0,0 +1,280 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + nf-cmgg/preprocessing Nextflow config file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Default config options for all compute environments +---------------------------------------------------------------------------------------- +*/ + +// Global default params, used in configs +params { + + // TODO nf-core: Specify your pipeline's command line flags + // Input options + input = null + + // References + genome = null + igenomes_base = 's3://ngi-igenomes/igenomes/' + igenomes_ignore = false + + // MultiQC options + multiqc_config = null + multiqc_title = null + multiqc_logo = null + max_multiqc_email_size = '25.MB' + multiqc_methods_description = null + + // Boilerplate options + outdir = null + publish_dir_mode = 'copy' + email = null + email_on_fail = null + plaintext_email = false + monochrome_logs = false + hook_url = System.getenv('HOOK_URL') + help = false + help_full = false + show_hidden = false + version = false + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' + trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') + + // Config options + config_profile_name = null + config_profile_description = null + + custom_config_version = 'master' + custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + config_profile_contact = null + config_profile_url = null + + // Schema validation default options + validate_params = true +} + +// Load base.config by default for all pipelines +includeConfig 'conf/base.config' + +profiles { + debug { + dumpHashes = true + process.beforeScript = 'echo $HOSTNAME' + cleanup = false + nextflow.enable.configProcessNamesValidation = true + } + conda { + conda.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + conda.channels = ['conda-forge', 'bioconda'] + apptainer.enabled = false + } + mamba { + conda.enabled = true + conda.useMamba = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + } + docker { + docker.enabled = true + conda.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + docker.runOptions = '-u $(id -u):$(id -g)' + } + arm64 { + process.arch = 'arm64' + // TODO https://github.com/nf-core/modules/issues/6694 + // For now if you're using arm64 you have to use wave for the sake of the maintainers + // wave profile + apptainer.ociAutoPull = true + singularity.ociAutoPull = true + wave.enabled = true + wave.freeze = true + wave.strategy = 'conda,container' + } + emulate_amd64 { + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + } + singularity { + singularity.enabled = true + singularity.autoMounts = true + conda.enabled = false + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + } + podman { + podman.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + } + shifter { + shifter.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + } + charliecloud { + charliecloud.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + apptainer.enabled = false + } + apptainer { + apptainer.enabled = true + apptainer.autoMounts = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + wave { + apptainer.ociAutoPull = true + singularity.ociAutoPull = true + wave.enabled = true + wave.freeze = true + wave.strategy = 'conda,container' + } + gpu { + docker.runOptions = '-u $(id -u):$(id -g) --gpus all' + apptainer.runOptions = '--nv' + singularity.runOptions = '--nv' + } + test { includeConfig 'conf/test.config' } + test_full { includeConfig 'conf/test_full.config' } +} + +// Set AWS client to anonymous when using the default igenomes_base +aws.client.anonymous = !params.igenomes_ignore && params.igenomes_base?.startsWith('s3://ngi-igenomes/igenomes/') ?: false +// Load nf-core custom profiles from different institutions + +// If params.custom_config_base is set AND either the NXF_OFFLINE environment variable is not set or params.custom_config_base is a local path, the nfcore_custom.config file from the specified base path is included. +// Load nf-cmgg/preprocessing custom profiles from different institutions. +includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" + + +// Load nf-cmgg/preprocessing custom profiles from different institutions. +// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs +// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" + +// Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile +// Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled +// Set to your registry if you have a mirror of containers +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' +charliecloud.registry = 'quay.io' + +// Load igenomes.config if required +includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' + +// Export these variables to prevent local Python/R libraries from conflicting with those in the container +// The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. +// See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. + +env { + PYTHONNOUSERSITE = 1 + R_PROFILE_USER = "/.Rprofile" + R_ENVIRON_USER = "/.Renviron" + JULIA_DEPOT_PATH = "/usr/local/share/julia" +} + +// Set bash options +process.shell = [ + "bash", + "-C", // No clobber - prevent output redirection from overwriting files. + "-e", // Exit if a tool returns a non-zero status/exit code + "-u", // Treat unset variables and parameters as an error + "-o", // Returns the status of the last command to exit.. + "pipefail" // ..with a non-zero status or zero if all successfully execute +] + +// Disable process selector warnings by default. Use debug profile to enable warnings. +nextflow.enable.configProcessNamesValidation = false + +timeline { + enabled = true + file = "${params.outdir}/pipeline_info/execution_timeline_${params.trace_report_suffix}.html" +} +report { + enabled = true + file = "${params.outdir}/pipeline_info/execution_report_${params.trace_report_suffix}.html" +} +trace { + enabled = true + file = "${params.outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt" +} +dag { + enabled = true + file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" +} + +manifest { + name = 'nf-cmgg/preprocessing' + contributors = [ + // TODO nf-core: Update the field with the details of the contributors to your pipeline. New with Nextflow version 24.10.0 + [ + name: 'Matthias De Smet', + affiliation: '', + email: '', + github: '', + contribution: [], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '' + ], + [ + name: ' Nicolas Vannieuwkerke', + affiliation: '', + email: '', + github: '', + contribution: [], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '' + ], + ] + homePage = 'https://github.com/nf-cmgg/preprocessing' + description = """Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.""" + mainScript = 'main.nf' + defaultBranch = 'main' + nextflowVersion = '!>=25.04.0' + version = '2.1.0dev' + doi = '' +} + +// Nextflow plugins +plugins { + id 'nf-schema@2.5.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet +} + +validation { + defaultIgnoreParams = ["genomes"] + monochromeLogs = params.monochrome_logs +} + +// Load modules.config for DSL2 module specific options +includeConfig 'conf/modules.config' diff --git a/nextflow_schema.json b/nextflow_schema.json new file mode 100644 index 00000000..858f55b9 --- /dev/null +++ b/nextflow_schema.json @@ -0,0 +1,257 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/nf-cmgg/preprocessing/main/nextflow_schema.json", + "title": "nf-cmgg/preprocessing pipeline parameters", + "description": "Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.", + "type": "object", + "$defs": { + "input_output_options": { + "title": "Input/output options", + "type": "object", + "fa_icon": "fas fa-terminal", + "description": "Define where the pipeline should find input data and save output data.", + "required": ["input", "outdir"], + "properties": { + "input": { + "type": "string", + "format": "file-path", + "exists": true, + "schema": "assets/schema_input.json", + "mimetype": "text/csv", + "pattern": "^\\S+\\.csv$", + "description": "Path to comma-separated file containing information about the samples in the experiment.", + "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row.", + "fa_icon": "fas fa-file-csv" + }, + "outdir": { + "type": "string", + "format": "directory-path", + "description": "The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure.", + "fa_icon": "fas fa-folder-open" + }, + "email": { + "type": "string", + "description": "Email address for completion summary.", + "fa_icon": "fas fa-envelope", + "help_text": "Set this parameter to your e-mail address to get a summary e-mail with details of the run sent to you when the workflow exits. If set in your user config file (`~/.nextflow/config`) then you don't need to specify this on the command line for every run.", + "pattern": "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$" + }, + "multiqc_title": { + "type": "string", + "description": "MultiQC report title. Printed as page header, used for filename if not otherwise specified.", + "fa_icon": "fas fa-file-signature" + } + } + }, + "reference_genome_options": { + "title": "Reference genome options", + "type": "object", + "fa_icon": "fas fa-dna", + "description": "Reference genome related files and options required for the workflow.", + "properties": { + "genome": { + "type": "string", + "description": "Name of iGenomes reference.", + "fa_icon": "fas fa-book", + "help_text": "If using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`. \n\nSee the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details." + }, + "fasta": { + "type": "string", + "format": "file-path", + "exists": true, + "mimetype": "text/plain", + "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", + "description": "Path to FASTA genome file.", + "help_text": "This parameter is *mandatory* if `--genome` is not specified. If you don't have a BWA index available this will be generated for you automatically. Combine with `--save_reference` to save BWA index for future runs.", + "fa_icon": "far fa-file-code" + }, + "igenomes_ignore": { + "type": "boolean", + "description": "Do not load the iGenomes reference config.", + "fa_icon": "fas fa-ban", + "hidden": true, + "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." + }, + "igenomes_base": { + "type": "string", + "format": "directory-path", + "description": "The base path to the igenomes reference files", + "fa_icon": "fas fa-ban", + "hidden": true, + "default": "s3://ngi-igenomes/igenomes/" + } + } + }, + "institutional_config_options": { + "title": "Institutional config options", + "type": "object", + "fa_icon": "fas fa-university", + "description": "Parameters used to describe centralised config profiles. These should not be edited.", + "help_text": "The centralised nf-core configuration profiles use a handful of pipeline parameters to describe themselves. This information is then printed to the Nextflow log when you run a pipeline. You should not need to change these values when you run a pipeline.", + "properties": { + "custom_config_version": { + "type": "string", + "description": "Git commit id for Institutional configs.", + "default": "master", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "custom_config_base": { + "type": "string", + "description": "Base directory for Institutional configs.", + "default": "https://raw.githubusercontent.com/nf-core/configs/master", + "hidden": true, + "help_text": "If you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.", + "fa_icon": "fas fa-users-cog" + }, + "config_profile_name": { + "type": "string", + "description": "Institutional config name.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "config_profile_description": { + "type": "string", + "description": "Institutional config description.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "config_profile_contact": { + "type": "string", + "description": "Institutional config contact information.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "config_profile_url": { + "type": "string", + "description": "Institutional config URL link.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + } + } + }, + "generic_options": { + "title": "Generic options", + "type": "object", + "fa_icon": "fas fa-file-import", + "description": "Less common options for the pipeline, typically set in a config file.", + "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", + "properties": { + "version": { + "type": "boolean", + "description": "Display version and exit.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "publish_dir_mode": { + "type": "string", + "default": "copy", + "description": "Method used to save pipeline results to output directory.", + "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", + "fa_icon": "fas fa-copy", + "enum": ["symlink", "rellink", "link", "copy", "copyNoFollow", "move"], + "hidden": true + }, + "email_on_fail": { + "type": "string", + "description": "Email address for completion summary, only when pipeline fails.", + "fa_icon": "fas fa-exclamation-triangle", + "pattern": "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$", + "help_text": "An email address to send a summary email to when the pipeline is completed - ONLY sent if the pipeline does not exit successfully.", + "hidden": true + }, + "plaintext_email": { + "type": "boolean", + "description": "Send plain-text email instead of HTML.", + "fa_icon": "fas fa-remove-format", + "hidden": true + }, + "max_multiqc_email_size": { + "type": "string", + "description": "File size limit when attaching MultiQC reports to summary emails.", + "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", + "default": "25.MB", + "fa_icon": "fas fa-file-upload", + "hidden": true + }, + "monochrome_logs": { + "type": "boolean", + "description": "Do not use coloured log outputs.", + "fa_icon": "fas fa-palette", + "hidden": true + }, + "hook_url": { + "type": "string", + "description": "Incoming hook URL for messaging service", + "fa_icon": "fas fa-people-group", + "help_text": "Incoming hook URL for messaging service. Currently, MS Teams and Slack are supported.", + "hidden": true + }, + "multiqc_config": { + "type": "string", + "format": "file-path", + "description": "Custom config file to supply to MultiQC.", + "fa_icon": "fas fa-cog", + "hidden": true + }, + "multiqc_logo": { + "type": "string", + "description": "Custom logo file to supply to MultiQC. File name must also be set in the MultiQC config file", + "fa_icon": "fas fa-image", + "hidden": true + }, + "multiqc_methods_description": { + "type": "string", + "description": "Custom MultiQC yaml file containing HTML including a methods description.", + "fa_icon": "fas fa-cog" + }, + "validate_params": { + "type": "boolean", + "description": "Boolean whether to validate parameters against the schema at runtime", + "default": true, + "fa_icon": "fas fa-check-square", + "hidden": true + }, + "pipelines_testdata_base_path": { + "type": "string", + "fa_icon": "far fa-check-circle", + "description": "Base URL or local path to location of pipeline test dataset files", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/", + "hidden": true + }, + "trace_report_suffix": { + "type": "string", + "fa_icon": "far calendar", + "description": "Suffix to add to the trace report filename. Default is the date and time in the format yyyy-MM-dd_HH-mm-ss.", + "hidden": true + }, + "help": { + "type": ["boolean", "string"], + "description": "Display the help message." + }, + "help_full": { + "type": "boolean", + "description": "Display the full detailed help message." + }, + "show_hidden": { + "type": "boolean", + "description": "Display hidden parameters in the help message (only works when --help or --help_full are provided)." + } + } + } + }, + "allOf": [ + { + "$ref": "#/$defs/input_output_options" + }, + { + "$ref": "#/$defs/reference_genome_options" + }, + { + "$ref": "#/$defs/institutional_config_options" + }, + { + "$ref": "#/$defs/generic_options" + } + ] +} diff --git a/nf-test.config b/nf-test.config new file mode 100644 index 00000000..3a1fff59 --- /dev/null +++ b/nf-test.config @@ -0,0 +1,24 @@ +config { + // location for all nf-test tests + testsDir "." + + // nf-test directory including temporary files for each test + workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + + // location of an optional nextflow.config file specific for executing tests + configFile "tests/nextflow.config" + + // ignore tests coming from the nf-core/modules repo + ignore 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*' + + // run all test with defined profile(s) from the main nextflow.config + profile "test" + + // list of filenames or patterns that should be trigger a full test run + triggers 'nextflow.config', 'nf-test.config', 'conf/test.config', 'tests/nextflow.config', 'tests/.nftignore' + + // load the necessary plugins + plugins { + load "nft-utils@0.0.3" + } +} diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json new file mode 100644 index 00000000..35a2f1d3 --- /dev/null +++ b/ro-crate-metadata.json @@ -0,0 +1,295 @@ +{ + "@context": [ + "https://w3id.org/ro/crate/1.1/context", + { + "GithubService": "https://w3id.org/ro/terms/test#GithubService", + "JenkinsService": "https://w3id.org/ro/terms/test#JenkinsService", + "PlanemoEngine": "https://w3id.org/ro/terms/test#PlanemoEngine", + "TestDefinition": "https://w3id.org/ro/terms/test#TestDefinition", + "TestInstance": "https://w3id.org/ro/terms/test#TestInstance", + "TestService": "https://w3id.org/ro/terms/test#TestService", + "TestSuite": "https://w3id.org/ro/terms/test#TestSuite", + "TravisService": "https://w3id.org/ro/terms/test#TravisService", + "definition": "https://w3id.org/ro/terms/test#definition", + "engineVersion": "https://w3id.org/ro/terms/test#engineVersion", + "instance": "https://w3id.org/ro/terms/test#instance", + "resource": "https://w3id.org/ro/terms/test#resource", + "runsOn": "https://w3id.org/ro/terms/test#runsOn" + } + ], + "@graph": [ + { + "@id": "./", + "@type": "Dataset", + "creativeWorkStatus": "InProgress", + "datePublished": "2025-11-13T15:11:21+00:00", + "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that ...\n\n\n\n\n1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/))\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by Matthias De Smet, Nicolas Vannieuwkerke.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\n## Citations\n\n\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/main/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "hasPart": [ + { + "@id": "main.nf" + }, + { + "@id": "assets/" + }, + { + "@id": "conf/" + }, + { + "@id": "docs/" + }, + { + "@id": "modules/" + }, + { + "@id": "modules/nf-core/" + }, + { + "@id": "workflows/" + }, + { + "@id": "subworkflows/" + }, + { + "@id": "nextflow.config" + }, + { + "@id": "README.md" + }, + { + "@id": "nextflow_schema.json" + }, + { + "@id": "CHANGELOG.md" + }, + { + "@id": "LICENSE" + }, + { + "@id": "CITATIONS.md" + }, + { + "@id": "modules.json" + }, + { + "@id": "docs/usage.md" + }, + { + "@id": "docs/output.md" + }, + { + "@id": ".nf-core.yml" + }, + { + "@id": ".pre-commit-config.yaml" + }, + { + "@id": ".prettierignore" + } + ], + "isBasedOn": "https://github.com/nf-cmgg/preprocessing", + "license": "MIT", + "mainEntity": { + "@id": "main.nf" + }, + "mentions": [ + { + "@id": "#3be06551-eaa0-4c8e-8ad8-cf70f05fb90c" + } + ], + "name": "nf-cmgg/preprocessing" + }, + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "about": { + "@id": "./" + }, + "conformsTo": [ + { + "@id": "https://w3id.org/ro/crate/1.1" + }, + { + "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" + } + ] + }, + { + "@id": "main.nf", + "@type": [ + "File", + "SoftwareSourceCode", + "ComputationalWorkflow" + ], + "dateCreated": "", + "dateModified": "2025-11-13T16:11:21Z", + "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", + "keywords": [ + "nf-core", + "nextflow" + ], + "license": [ + "MIT" + ], + "name": [ + "nf-cmgg/preprocessing" + ], + "programmingLanguage": { + "@id": "https://w3id.org/workflowhub/workflow-ro-crate#nextflow" + }, + "sdPublisher": { + "@id": "https://nf-co.re/" + }, + "url": [ + "https://github.com/nf-cmgg/preprocessing", + "https://nf-co.re/nf-cmgg/preprocessing/dev/" + ], + "version": [ + "2.1.0dev" + ] + }, + { + "@id": "https://w3id.org/workflowhub/workflow-ro-crate#nextflow", + "@type": "ComputerLanguage", + "identifier": { + "@id": "https://www.nextflow.io/" + }, + "name": "Nextflow", + "url": { + "@id": "https://www.nextflow.io/" + }, + "version": "!>=25.04.0" + }, + { + "@id": "#3be06551-eaa0-4c8e-8ad8-cf70f05fb90c", + "@type": "TestSuite", + "instance": [ + { + "@id": "#4d67a865-3114-4fc8-94e4-c36091fb7276" + } + ], + "mainEntity": { + "@id": "main.nf" + }, + "name": "Test suite for nf-cmgg/preprocessing" + }, + { + "@id": "#4d67a865-3114-4fc8-94e4-c36091fb7276", + "@type": "TestInstance", + "name": "GitHub Actions workflow for testing nf-cmgg/preprocessing", + "resource": "repos/nf-cmgg/preprocessing/actions/workflows/nf-test.yml", + "runsOn": { + "@id": "https://w3id.org/ro/terms/test#GithubService" + }, + "url": "https://api.github.com" + }, + { + "@id": "https://w3id.org/ro/terms/test#GithubService", + "@type": "TestService", + "name": "Github Actions", + "url": { + "@id": "https://github.com" + } + }, + { + "@id": "assets/", + "@type": "Dataset", + "description": "Additional files" + }, + { + "@id": "conf/", + "@type": "Dataset", + "description": "Configuration files" + }, + { + "@id": "docs/", + "@type": "Dataset", + "description": "Markdown files for documenting the pipeline" + }, + { + "@id": "modules/", + "@type": "Dataset", + "description": "Modules used by the pipeline" + }, + { + "@id": "modules/nf-core/", + "@type": "Dataset", + "description": "nf-core modules" + }, + { + "@id": "workflows/", + "@type": "Dataset", + "description": "Main pipeline workflows to be executed in main.nf" + }, + { + "@id": "subworkflows/", + "@type": "Dataset", + "description": "Smaller subworkflows" + }, + { + "@id": "nextflow.config", + "@type": "File", + "description": "Main Nextflow configuration file" + }, + { + "@id": "README.md", + "@type": "File", + "description": "Basic pipeline usage information" + }, + { + "@id": "nextflow_schema.json", + "@type": "File", + "description": "JSON schema for pipeline parameter specification" + }, + { + "@id": "CHANGELOG.md", + "@type": "File", + "description": "Information on changes made to the pipeline" + }, + { + "@id": "LICENSE", + "@type": "File", + "description": "The license - should be MIT" + }, + { + "@id": "CITATIONS.md", + "@type": "File", + "description": "Citations needed when using the pipeline" + }, + { + "@id": "modules.json", + "@type": "File", + "description": "Version information for modules from nf-core/modules" + }, + { + "@id": "docs/usage.md", + "@type": "File", + "description": "Usage documentation" + }, + { + "@id": "docs/output.md", + "@type": "File", + "description": "Output documentation" + }, + { + "@id": ".nf-core.yml", + "@type": "File", + "description": "nf-core configuration file, configuring template features and linting rules" + }, + { + "@id": ".pre-commit-config.yaml", + "@type": "File", + "description": "Configuration file for pre-commit hooks" + }, + { + "@id": ".prettierignore", + "@type": "File", + "description": "Ignore file for prettier" + }, + { + "@id": "https://nf-co.re/", + "@type": "Organization", + "name": "nf-core", + "url": "https://nf-co.re/" + } + ] +} \ No newline at end of file diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf new file mode 100644 index 00000000..8e821b6f --- /dev/null +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -0,0 +1,275 @@ +// +// Subworkflow with functionality specific to the nf-cmgg/preprocessing pipeline +// + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { imNotification } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBWORKFLOW TO INITIALISE PIPELINE +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +workflow PIPELINE_INITIALISATION { + + take: + version // boolean: Display version and exit + validate_params // boolean: Boolean whether to validate parameters against the schema at runtime + monochrome_logs // boolean: Do not use coloured log outputs + nextflow_cli_args // array: List of positional nextflow CLI args + outdir // string: The output directory where the results will be saved + input // string: Path to input samplesheet + help // boolean: Display help message and exit + help_full // boolean: Show the full help message + show_hidden // boolean: Show hidden parameters in the help message + + main: + + ch_versions = Channel.empty() + + // + // Print version and exit if required and dump pipeline parameters to JSON file + // + UTILS_NEXTFLOW_PIPELINE ( + version, + true, + outdir, + workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 + ) + + // + // Validate parameters and generate parameter summary to stdout + // + command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir " + + UTILS_NFSCHEMA_PLUGIN ( + workflow, + validate_params, + null, + help, + help_full, + show_hidden, + "", + "", + command + ) + + // + // Check config provided to the pipeline + // + UTILS_NFCORE_PIPELINE ( + nextflow_cli_args + ) + + // + // Custom validation for pipeline parameters + // + validateInputParameters() + + // + // Create channel from input file provided through params.input + // + + Channel + .fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json")) + .map { + meta, fastq_1, fastq_2 -> + if (!fastq_2) { + return [ meta.id, meta + [ single_end:true ], [ fastq_1 ] ] + } else { + return [ meta.id, meta + [ single_end:false ], [ fastq_1, fastq_2 ] ] + } + } + .groupTuple() + .map { samplesheet -> + validateInputSamplesheet(samplesheet) + } + .map { + meta, fastqs -> + return [ meta, fastqs.flatten() ] + } + .set { ch_samplesheet } + + emit: + samplesheet = ch_samplesheet + versions = ch_versions +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBWORKFLOW FOR PIPELINE COMPLETION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +workflow PIPELINE_COMPLETION { + + take: + email // string: email address + email_on_fail // string: email address sent on pipeline failure + plaintext_email // boolean: Send plain-text email instead of HTML + outdir // path: Path to output directory where results will be published + monochrome_logs // boolean: Disable ANSI colour codes in log output + hook_url // string: hook URL for notifications + multiqc_report // string: Path to MultiQC report + + main: + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + def multiqc_reports = multiqc_report.toList() + + // + // Completion email and summary + // + workflow.onComplete { + if (email || email_on_fail) { + completionEmail( + summary_params, + email, + email_on_fail, + plaintext_email, + outdir, + monochrome_logs, + multiqc_reports.getVal(), + ) + } + + completionSummary(monochrome_logs) + if (hook_url) { + imNotification(summary_params, hook_url) + } + } + + workflow.onError { + log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + } +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + FUNCTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +// +// Check and validate pipeline parameters +// +def validateInputParameters() { + genomeExistsError() +} + +// +// Validate channels from input samplesheet +// +def validateInputSamplesheet(input) { + def (metas, fastqs) = input[1..2] + + // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end + def endedness_ok = metas.collect{ meta -> meta.single_end }.unique().size == 1 + if (!endedness_ok) { + error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") + } + + return [ metas[0], fastqs ] +} +// +// Get attribute from genome config file e.g. fasta +// +def getGenomeAttribute(attribute) { + if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { + if (params.genomes[ params.genome ].containsKey(attribute)) { + return params.genomes[ params.genome ][ attribute ] + } + } + return null +} + +// +// Exit pipeline if incorrect --genome key provided +// +def genomeExistsError() { + if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + + " Currently, the available genome keys are:\n" + + " ${params.genomes.keySet().join(", ")}\n" + + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + error(error_string) + } +} +// +// Generate methods description for MultiQC +// +def toolCitationText() { + // TODO nf-core: Optionally add in-text citation tools to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def citation_text = [ + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + "." + ].join(' ').trim() + + return citation_text +} + +def toolBibliographyText() { + // TODO nf-core: Optionally add bibliographic entries to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def reference_text = [ + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() + + return reference_text +} + +def methodsDescriptionText(mqc_methods_yaml) { + // Convert to a named map so can be used as with familiar NXF ${workflow} variable syntax in the MultiQC YML file + def meta = [:] + meta.workflow = workflow.toMap() + meta["manifest_map"] = workflow.manifest.toMap() + + // Pipeline DOI + if (meta.manifest_map.doi) { + // Using a loop to handle multiple DOIs + // Removing `https://doi.org/` to handle pipelines using DOIs vs DOI resolvers + // Removing ` ` since the manifest.doi is a string and not a proper list + def temp_doi_ref = "" + def manifest_doi = meta.manifest_map.doi.tokenize(",") + manifest_doi.each { doi_ref -> + temp_doi_ref += "(doi: ${doi_ref.replace("https://doi.org/", "").replace(" ", "")}), " + } + meta["doi_text"] = temp_doi_ref.substring(0, temp_doi_ref.length() - 2) + } else meta["doi_text"] = "" + meta["nodoi_text"] = meta.manifest_map.doi ? "" : "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " + + // Tool references + meta["tool_citations"] = "" + meta["tool_bibliography"] = "" + + // TODO nf-core: Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! + // meta["tool_citations"] = toolCitationText().replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") + // meta["tool_bibliography"] = toolBibliographyText() + + + def methods_text = mqc_methods_yaml.text + + def engine = new groovy.text.SimpleTemplateEngine() + def description_html = engine.createTemplate(methods_text).make(meta) + + return description_html.toString() +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf new file mode 100644 index 00000000..d6e593e8 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -0,0 +1,126 @@ +// +// Subworkflow with functionality that may be useful for any Nextflow pipeline +// + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBWORKFLOW DEFINITION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +workflow UTILS_NEXTFLOW_PIPELINE { + take: + print_version // boolean: print version + dump_parameters // boolean: dump parameters + outdir // path: base directory used to publish pipeline results + check_conda_channels // boolean: check conda channels + + main: + + // + // Print workflow version and exit on --version + // + if (print_version) { + log.info("${workflow.manifest.name} ${getWorkflowVersion()}") + System.exit(0) + } + + // + // Dump pipeline parameters to a JSON file + // + if (dump_parameters && outdir) { + dumpParametersToJSON(outdir) + } + + // + // When running with Conda, warn if channels have not been set-up appropriately + // + if (check_conda_channels) { + checkCondaChannels() + } + + emit: + dummy_emit = true +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + FUNCTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// +// Generate version string +// +def getWorkflowVersion() { + def version_string = "" as String + if (workflow.manifest.version) { + def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' + version_string += "${prefix_v}${workflow.manifest.version}" + } + + if (workflow.commitId) { + def git_shortsha = workflow.commitId.substring(0, 7) + version_string += "-g${git_shortsha}" + } + + return version_string +} + +// +// Dump pipeline parameters to a JSON file +// +def dumpParametersToJSON(outdir) { + def timestamp = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") + def jsonStr = groovy.json.JsonOutput.toJson(params) + temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) + + nextflow.extension.FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") + temp_pf.delete() +} + +// +// When running with -profile conda, warn if channels have not been set-up appropriately +// +def checkCondaChannels() { + def parser = new org.yaml.snakeyaml.Yaml() + def channels = [] + try { + def config = parser.load("conda config --show channels".execute().text) + channels = config.channels + } + catch (NullPointerException e) { + log.debug(e) + log.warn("Could not verify conda channel configuration.") + return null + } + catch (IOException e) { + log.debug(e) + log.warn("Could not verify conda channel configuration.") + return null + } + + // Check that all channels are present + // This channel list is ordered by required channel priority. + def required_channels_in_order = ['conda-forge', 'bioconda'] + def channels_missing = ((required_channels_in_order as Set) - (channels as Set)) as Boolean + + // Check that they are in the right order + def channel_priority_violation = required_channels_in_order != channels.findAll { ch -> ch in required_channels_in_order } + + if (channels_missing | channel_priority_violation) { + log.warn """\ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + There is a problem with your Conda configuration! + You will need to set-up the conda-forge and bioconda channels correctly. + Please refer to https://bioconda.github.io/ + The observed channel order is + ${channels} + but the following channel order is required: + ${required_channels_in_order} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + """.stripIndent(true) + } +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml new file mode 100644 index 00000000..e5c3a0a8 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NEXTFLOW_PIPELINE" +description: Subworkflow with functionality that may be useful for any Nextflow pipeline +keywords: + - utility + - pipeline + - initialise + - version +components: [] +input: + - print_version: + type: boolean + description: | + Print the version of the pipeline and exit + - dump_parameters: + type: boolean + description: | + Dump the parameters of the pipeline to a JSON file + - output_directory: + type: directory + description: Path to output dir to write JSON file to. + pattern: "results/" + - check_conda_channel: + type: boolean + description: | + Check if the conda channel priority is correct. +output: + - dummy_emit: + type: boolean + description: | + Dummy emit to make nf-core subworkflows lint happy +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test new file mode 100644 index 00000000..68718e4f --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test @@ -0,0 +1,54 @@ + +nextflow_function { + + name "Test Functions" + script "subworkflows/nf-core/utils_nextflow_pipeline/main.nf" + config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config" + tag 'subworkflows' + tag 'utils_nextflow_pipeline' + tag 'subworkflows/utils_nextflow_pipeline' + + test("Test Function getWorkflowVersion") { + + function "getWorkflowVersion" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function dumpParametersToJSON") { + + function "dumpParametersToJSON" + + when { + function { + """ + // define inputs of the function here. Example: + input[0] = "$outputDir" + """.stripIndent() + } + } + + then { + assertAll( + { assert function.success } + ) + } + } + + test("Test Function checkCondaChannels") { + + function "checkCondaChannels" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap new file mode 100644 index 00000000..e3f0baf4 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap @@ -0,0 +1,20 @@ +{ + "Test Function getWorkflowVersion": { + "content": [ + "v9.9.9" + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:02:05.308243" + }, + "Test Function checkCondaChannels": { + "content": null, + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:02:12.425833" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test new file mode 100644 index 00000000..02dbf094 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test @@ -0,0 +1,113 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NEXTFLOW_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config" + workflow "UTILS_NEXTFLOW_PIPELINE" + tag 'subworkflows' + tag 'utils_nextflow_pipeline' + tag 'subworkflows/utils_nextflow_pipeline' + + test("Should run no inputs") { + + when { + workflow { + """ + print_version = false + dump_parameters = false + outdir = null + check_conda_channels = false + + input[0] = print_version + input[1] = dump_parameters + input[2] = outdir + input[3] = check_conda_channels + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should print version") { + + when { + workflow { + """ + print_version = true + dump_parameters = false + outdir = null + check_conda_channels = false + + input[0] = print_version + input[1] = dump_parameters + input[2] = outdir + input[3] = check_conda_channels + """ + } + } + + then { + expect { + with(workflow) { + assert success + assert "nextflow_workflow v9.9.9" in stdout + } + } + } + } + + test("Should dump params") { + + when { + workflow { + """ + print_version = false + dump_parameters = true + outdir = 'results' + check_conda_channels = false + + input[0] = false + input[1] = true + input[2] = outdir + input[3] = false + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should not create params JSON if no output directory") { + + when { + workflow { + """ + print_version = false + dump_parameters = true + outdir = null + check_conda_channels = false + + input[0] = false + input[1] = true + input[2] = outdir + input[3] = false + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config new file mode 100644 index 00000000..a09572e5 --- /dev/null +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config @@ -0,0 +1,9 @@ +manifest { + name = 'nextflow_workflow' + author = """nf-core""" + homePage = 'https://127.0.0.1' + description = """Dummy pipeline""" + nextflowVersion = '!>=23.04.0' + version = '9.9.9' + doi = 'https://doi.org/10.5281/zenodo.5070524' +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf new file mode 100644 index 00000000..bfd25876 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -0,0 +1,419 @@ +// +// Subworkflow with utility functions specific to the nf-core pipeline template +// + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBWORKFLOW DEFINITION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +workflow UTILS_NFCORE_PIPELINE { + take: + nextflow_cli_args + + main: + valid_config = checkConfigProvided() + checkProfileProvided(nextflow_cli_args) + + emit: + valid_config +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + FUNCTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// +// Warn if a -profile or Nextflow config has not been provided to run the pipeline +// +def checkConfigProvided() { + def valid_config = true as Boolean + if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) { + log.warn( + "[${workflow.manifest.name}] You are attempting to run the pipeline without any custom configuration!\n\n" + "This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" + " (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" + " (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" + " (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" + "Please refer to the quick start section and usage docs for the pipeline.\n " + ) + valid_config = false + } + return valid_config +} + +// +// Exit pipeline if --profile contains spaces +// +def checkProfileProvided(nextflow_cli_args) { + if (workflow.profile.endsWith(',')) { + error( + "The `-profile` option cannot end with a trailing comma, please remove it and re-run the pipeline!\n" + "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n" + ) + } + if (nextflow_cli_args[0]) { + log.warn( + "nf-core pipelines do not accept positional arguments. The positional argument `${nextflow_cli_args[0]}` has been detected.\n" + "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n" + ) + } +} + +// +// Generate workflow version string +// +def getWorkflowVersion() { + def version_string = "" as String + if (workflow.manifest.version) { + def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' + version_string += "${prefix_v}${workflow.manifest.version}" + } + + if (workflow.commitId) { + def git_shortsha = workflow.commitId.substring(0, 7) + version_string += "-g${git_shortsha}" + } + + return version_string +} + +// +// Get software versions for pipeline +// +def processVersionsFromYAML(yaml_file) { + def yaml = new org.yaml.snakeyaml.Yaml() + def versions = yaml.load(yaml_file).collectEntries { k, v -> [k.tokenize(':')[-1], v] } + return yaml.dumpAsMap(versions).trim() +} + +// +// Get workflow version for pipeline +// +def workflowVersionToYAML() { + return """ + Workflow: + ${workflow.manifest.name}: ${getWorkflowVersion()} + Nextflow: ${workflow.nextflow.version} + """.stripIndent().trim() +} + +// +// Get channel of software versions used in pipeline in YAML format +// +def softwareVersionsToYAML(ch_versions) { + return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) +} + +// +// Get workflow summary for MultiQC +// +def paramsSummaryMultiqc(summary_params) { + def summary_section = '' + summary_params + .keySet() + .each { group -> + def group_params = summary_params.get(group) + // This gets the parameters of that particular group + if (group_params) { + summary_section += "

    ${group}

    \n" + summary_section += "
    \n" + group_params + .keySet() + .sort() + .each { param -> + summary_section += "
    ${param}
    ${group_params.get(param) ?: 'N/A'}
    \n" + } + summary_section += "
    \n" + } + } + + def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String + yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" + yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" + yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" + yaml_file_text += "plot_type: 'html'\n" + yaml_file_text += "data: |\n" + yaml_file_text += "${summary_section}" + + return yaml_file_text +} + +// +// ANSII colours used for terminal logging +// +def logColours(monochrome_logs=true) { + def colorcodes = [:] as Map + + // Reset / Meta + colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" + colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" + colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" + colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m" + colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" + colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" + colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" + + // Regular Colors + colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" + colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" + colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" + colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" + colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" + colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" + colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" + colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" + + // Bold + colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" + colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" + colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" + colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" + colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" + colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" + colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" + colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" + + // Underline + colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" + colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" + colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" + colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" + colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" + colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" + colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" + colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" + + // High Intensity + colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" + colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" + colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" + colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" + colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" + colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" + colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" + colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" + + // Bold High Intensity + colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" + colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" + colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" + colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" + colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" + colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" + colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" + colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" + + return colorcodes +} + +// Return a single report from an object that may be a Path or List +// +def getSingleReport(multiqc_reports) { + if (multiqc_reports instanceof Path) { + return multiqc_reports + } else if (multiqc_reports instanceof List) { + if (multiqc_reports.size() == 0) { + log.warn("[${workflow.manifest.name}] No reports found from process 'MULTIQC'") + return null + } else if (multiqc_reports.size() == 1) { + return multiqc_reports.first() + } else { + log.warn("[${workflow.manifest.name}] Found multiple reports from process 'MULTIQC', will use only one") + return multiqc_reports.first() + } + } else { + return null + } +} + +// +// Construct and send completion email +// +def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs=true, multiqc_report=null) { + + // Set up the e-mail variables + def subject = "[${workflow.manifest.name}] Successful: ${workflow.runName}" + if (!workflow.success) { + subject = "[${workflow.manifest.name}] FAILED: ${workflow.runName}" + } + + def summary = [:] + summary_params + .keySet() + .sort() + .each { group -> + summary << summary_params[group] + } + + def misc_fields = [:] + misc_fields['Date Started'] = workflow.start + misc_fields['Date Completed'] = workflow.complete + misc_fields['Pipeline script file path'] = workflow.scriptFile + misc_fields['Pipeline script hash ID'] = workflow.scriptId + if (workflow.repository) { + misc_fields['Pipeline repository Git URL'] = workflow.repository + } + if (workflow.commitId) { + misc_fields['Pipeline repository Git Commit'] = workflow.commitId + } + if (workflow.revision) { + misc_fields['Pipeline Git branch/tag'] = workflow.revision + } + misc_fields['Nextflow Version'] = workflow.nextflow.version + misc_fields['Nextflow Build'] = workflow.nextflow.build + misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp + + def email_fields = [:] + email_fields['version'] = getWorkflowVersion() + email_fields['runName'] = workflow.runName + email_fields['success'] = workflow.success + email_fields['dateComplete'] = workflow.complete + email_fields['duration'] = workflow.duration + email_fields['exitStatus'] = workflow.exitStatus + email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + email_fields['errorReport'] = (workflow.errorReport ?: 'None') + email_fields['commandLine'] = workflow.commandLine + email_fields['projectDir'] = workflow.projectDir + email_fields['summary'] = summary << misc_fields + + // On success try attach the multiqc report + def mqc_report = getSingleReport(multiqc_report) + + // Check if we are only sending emails on failure + def email_address = email + if (!email && email_on_fail && !workflow.success) { + email_address = email_on_fail + } + + // Render the TXT template + def engine = new groovy.text.GStringTemplateEngine() + def tf = new File("${workflow.projectDir}/assets/email_template.txt") + def txt_template = engine.createTemplate(tf).make(email_fields) + def email_txt = txt_template.toString() + + // Render the HTML template + def hf = new File("${workflow.projectDir}/assets/email_template.html") + def html_template = engine.createTemplate(hf).make(email_fields) + def email_html = html_template.toString() + + // Render the sendmail template + def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as MemoryUnit + def smail_fields = [email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes()] + def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") + def sendmail_template = engine.createTemplate(sf).make(smail_fields) + def sendmail_html = sendmail_template.toString() + + // Send the HTML e-mail + def colors = logColours(monochrome_logs) as Map + if (email_address) { + try { + if (plaintext_email) { + new org.codehaus.groovy.GroovyException('Send plaintext e-mail, not HTML') + } + // Try to send HTML e-mail using sendmail + def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") + sendmail_tf.withWriter { w -> w << sendmail_html } + ['sendmail', '-t'].execute() << sendmail_html + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Sent summary e-mail to ${email_address} (sendmail)-") + } + catch (Exception msg) { + log.debug(msg.toString()) + log.debug("Trying with mail instead of sendmail") + // Catch failures and try with plaintext + def mail_cmd = ['mail', '-s', subject, '--content-type=text/html', email_address] + mail_cmd.execute() << email_html + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Sent summary e-mail to ${email_address} (mail)-") + } + } + + // Write summary e-mail HTML to a file + def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") + output_hf.withWriter { w -> w << email_html } + nextflow.extension.FilesEx.copyTo(output_hf.toPath(), "${outdir}/pipeline_info/pipeline_report.html") + output_hf.delete() + + // Write summary e-mail TXT to a file + def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") + output_tf.withWriter { w -> w << email_txt } + nextflow.extension.FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt") + output_tf.delete() +} + +// +// Print pipeline summary on completion +// +def completionSummary(monochrome_logs=true) { + def colors = logColours(monochrome_logs) as Map + if (workflow.success) { + if (workflow.stats.ignoredCount == 0) { + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Pipeline completed successfully${colors.reset}-") + } + else { + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-") + } + } + else { + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") + } +} + +// +// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack +// +def imNotification(summary_params, hook_url) { + def summary = [:] + summary_params + .keySet() + .sort() + .each { group -> + summary << summary_params[group] + } + + def misc_fields = [:] + misc_fields['start'] = workflow.start + misc_fields['complete'] = workflow.complete + misc_fields['scriptfile'] = workflow.scriptFile + misc_fields['scriptid'] = workflow.scriptId + if (workflow.repository) { + misc_fields['repository'] = workflow.repository + } + if (workflow.commitId) { + misc_fields['commitid'] = workflow.commitId + } + if (workflow.revision) { + misc_fields['revision'] = workflow.revision + } + misc_fields['nxf_version'] = workflow.nextflow.version + misc_fields['nxf_build'] = workflow.nextflow.build + misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp + + def msg_fields = [:] + msg_fields['version'] = getWorkflowVersion() + msg_fields['runName'] = workflow.runName + msg_fields['success'] = workflow.success + msg_fields['dateComplete'] = workflow.complete + msg_fields['duration'] = workflow.duration + msg_fields['exitStatus'] = workflow.exitStatus + msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') + msg_fields['errorReport'] = (workflow.errorReport ?: 'None') + msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") + msg_fields['projectDir'] = workflow.projectDir + msg_fields['summary'] = summary << misc_fields + + // Render the JSON template + def engine = new groovy.text.GStringTemplateEngine() + // Different JSON depending on the service provider + // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format + def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" + def hf = new File("${workflow.projectDir}/assets/${json_path}") + def json_template = engine.createTemplate(hf).make(msg_fields) + def json_message = json_template.toString() + + // POST + def post = new URL(hook_url).openConnection() + post.setRequestMethod("POST") + post.setDoOutput(true) + post.setRequestProperty("Content-Type", "application/json") + post.getOutputStream().write(json_message.getBytes("UTF-8")) + def postRC = post.getResponseCode() + if (!postRC.equals(200)) { + log.warn(post.getErrorStream().getText()) + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml b/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml new file mode 100644 index 00000000..d08d2434 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/meta.yml @@ -0,0 +1,24 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "UTILS_NFCORE_PIPELINE" +description: Subworkflow with utility functions specific to the nf-core pipeline template +keywords: + - utility + - pipeline + - initialise + - version +components: [] +input: + - nextflow_cli_args: + type: list + description: | + Nextflow CLI positional arguments +output: + - success: + type: boolean + description: | + Dummy output to indicate success +authors: + - "@adamrtalbot" +maintainers: + - "@adamrtalbot" + - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test new file mode 100644 index 00000000..f117040c --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test @@ -0,0 +1,126 @@ + +nextflow_function { + + name "Test Functions" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Test Function checkConfigProvided") { + + function "checkConfigProvided" + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function checkProfileProvided") { + + function "checkProfileProvided" + + when { + function { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function without logColours") { + + function "logColours" + + when { + function { + """ + input[0] = true + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function with logColours") { + function "logColours" + + when { + function { + """ + input[0] = false + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert snapshot(function.result).match() } + ) + } + } + + test("Test Function getSingleReport with a single file") { + function "getSingleReport" + + when { + function { + """ + input[0] = file(params.modules_testdata_base_path + '/generic/tsv/test.tsv', checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert function.result.contains("test.tsv") } + ) + } + } + + test("Test Function getSingleReport with multiple files") { + function "getSingleReport" + + when { + function { + """ + input[0] = [ + file(params.modules_testdata_base_path + '/generic/tsv/test.tsv', checkIfExists: true), + file(params.modules_testdata_base_path + '/generic/tsv/network.tsv', checkIfExists: true), + file(params.modules_testdata_base_path + '/generic/tsv/expression.tsv', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert function.success }, + { assert function.result.contains("test.tsv") }, + { assert !function.result.contains("network.tsv") }, + { assert !function.result.contains("expression.tsv") } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap new file mode 100644 index 00000000..02c67014 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap @@ -0,0 +1,136 @@ +{ + "Test Function checkProfileProvided": { + "content": null, + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:03.360873" + }, + "Test Function checkConfigProvided": { + "content": [ + true + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:02:59.729647" + }, + "Test Function without logColours": { + "content": [ + { + "reset": "", + "bold": "", + "dim": "", + "underlined": "", + "blink": "", + "reverse": "", + "hidden": "", + "black": "", + "red": "", + "green": "", + "yellow": "", + "blue": "", + "purple": "", + "cyan": "", + "white": "", + "bblack": "", + "bred": "", + "bgreen": "", + "byellow": "", + "bblue": "", + "bpurple": "", + "bcyan": "", + "bwhite": "", + "ublack": "", + "ured": "", + "ugreen": "", + "uyellow": "", + "ublue": "", + "upurple": "", + "ucyan": "", + "uwhite": "", + "iblack": "", + "ired": "", + "igreen": "", + "iyellow": "", + "iblue": "", + "ipurple": "", + "icyan": "", + "iwhite": "", + "biblack": "", + "bired": "", + "bigreen": "", + "biyellow": "", + "biblue": "", + "bipurple": "", + "bicyan": "", + "biwhite": "" + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:17.969323" + }, + "Test Function with logColours": { + "content": [ + { + "reset": "\u001b[0m", + "bold": "\u001b[1m", + "dim": "\u001b[2m", + "underlined": "\u001b[4m", + "blink": "\u001b[5m", + "reverse": "\u001b[7m", + "hidden": "\u001b[8m", + "black": "\u001b[0;30m", + "red": "\u001b[0;31m", + "green": "\u001b[0;32m", + "yellow": "\u001b[0;33m", + "blue": "\u001b[0;34m", + "purple": "\u001b[0;35m", + "cyan": "\u001b[0;36m", + "white": "\u001b[0;37m", + "bblack": "\u001b[1;30m", + "bred": "\u001b[1;31m", + "bgreen": "\u001b[1;32m", + "byellow": "\u001b[1;33m", + "bblue": "\u001b[1;34m", + "bpurple": "\u001b[1;35m", + "bcyan": "\u001b[1;36m", + "bwhite": "\u001b[1;37m", + "ublack": "\u001b[4;30m", + "ured": "\u001b[4;31m", + "ugreen": "\u001b[4;32m", + "uyellow": "\u001b[4;33m", + "ublue": "\u001b[4;34m", + "upurple": "\u001b[4;35m", + "ucyan": "\u001b[4;36m", + "uwhite": "\u001b[4;37m", + "iblack": "\u001b[0;90m", + "ired": "\u001b[0;91m", + "igreen": "\u001b[0;92m", + "iyellow": "\u001b[0;93m", + "iblue": "\u001b[0;94m", + "ipurple": "\u001b[0;95m", + "icyan": "\u001b[0;96m", + "iwhite": "\u001b[0;97m", + "biblack": "\u001b[1;90m", + "bired": "\u001b[1;91m", + "bigreen": "\u001b[1;92m", + "biyellow": "\u001b[1;93m", + "biblue": "\u001b[1;94m", + "bipurple": "\u001b[1;95m", + "bicyan": "\u001b[1;96m", + "biwhite": "\u001b[1;97m" + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:21.714424" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test new file mode 100644 index 00000000..8940d32d --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test @@ -0,0 +1,29 @@ +nextflow_workflow { + + name "Test Workflow UTILS_NFCORE_PIPELINE" + script "../main.nf" + config "subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config" + workflow "UTILS_NFCORE_PIPELINE" + tag "subworkflows" + tag "subworkflows_nfcore" + tag "utils_nfcore_pipeline" + tag "subworkflows/utils_nfcore_pipeline" + + test("Should run without failures") { + + when { + workflow { + """ + input[0] = [] + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap new file mode 100644 index 00000000..859d1030 --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap @@ -0,0 +1,19 @@ +{ + "Should run without failures": { + "content": [ + { + "0": [ + true + ], + "valid_config": [ + true + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-02-28T12:03:25.726491" + } +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config new file mode 100644 index 00000000..d0a926bf --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config @@ -0,0 +1,9 @@ +manifest { + name = 'nextflow_workflow' + author = """nf-core""" + homePage = 'https://127.0.0.1' + description = """Dummy pipeline""" + nextflowVersion = '!>=23.04.0' + version = '9.9.9' + doi = 'https://doi.org/10.5281/zenodo.5070524' +} diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf new file mode 100644 index 00000000..ee4738c8 --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -0,0 +1,74 @@ +// +// Subworkflow that uses the nf-schema plugin to validate parameters and render the parameter summary +// + +include { paramsSummaryLog } from 'plugin/nf-schema' +include { validateParameters } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' + +workflow UTILS_NFSCHEMA_PLUGIN { + + take: + input_workflow // workflow: the workflow object used by nf-schema to get metadata from the workflow + validate_params // boolean: validate the parameters + parameters_schema // string: path to the parameters JSON schema. + // this has to be the same as the schema given to `validation.parametersSchema` + // when this input is empty it will automatically use the configured schema or + // "${projectDir}/nextflow_schema.json" as default. This input should not be empty + // for meta pipelines + help // boolean: show help message + help_full // boolean: show full help message + show_hidden // boolean: show hidden parameters in help message + before_text // string: text to show before the help message and parameters summary + after_text // string: text to show after the help message and parameters summary + command // string: an example command of the pipeline + + main: + + if(help || help_full) { + help_options = [ + beforeText: before_text, + afterText: after_text, + command: command, + showHidden: show_hidden, + fullHelp: help_full, + ] + if(parameters_schema) { + help_options << [parametersSchema: parameters_schema] + } + log.info paramsHelp( + help_options, + params.help instanceof String ? params.help : "", + ) + exit 0 + } + + // + // Print parameter summary to stdout. This will display the parameters + // that differ from the default given in the JSON schema + // + + summary_options = [:] + if(parameters_schema) { + summary_options << [parametersSchema: parameters_schema] + } + log.info before_text + log.info paramsSummaryLog(summary_options, input_workflow) + log.info after_text + + // + // Validate the parameters using nextflow_schema.json or the schema + // given via the validation.parametersSchema configuration option + // + if(validate_params) { + validateOptions = [:] + if(parameters_schema) { + validateOptions << [parametersSchema: parameters_schema] + } + validateParameters(validateOptions) + } + + emit: + dummy_emit = true +} + diff --git a/subworkflows/nf-core/utils_nfschema_plugin/meta.yml b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml new file mode 100644 index 00000000..f7d9f028 --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "utils_nfschema_plugin" +description: Run nf-schema to validate parameters and create a summary of changed parameters +keywords: + - validation + - JSON schema + - plugin + - parameters + - summary +components: [] +input: + - input_workflow: + type: object + description: | + The workflow object of the used pipeline. + This object contains meta data used to create the params summary log + - validate_params: + type: boolean + description: Validate the parameters and error if invalid. + - parameters_schema: + type: string + description: | + Path to the parameters JSON schema. + This has to be the same as the schema given to the `validation.parametersSchema` config + option. When this input is empty it will automatically use the configured schema or + "${projectDir}/nextflow_schema.json" as default. The schema should not be given in this way + for meta pipelines. +output: + - dummy_emit: + type: boolean + description: Dummy emit to make nf-core subworkflows lint happy +authors: + - "@nvnieuwk" +maintainers: + - "@nvnieuwk" diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test new file mode 100644 index 00000000..c977917a --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test @@ -0,0 +1,173 @@ +nextflow_workflow { + + name "Test Subworkflow UTILS_NFSCHEMA_PLUGIN" + script "../main.nf" + workflow "UTILS_NFSCHEMA_PLUGIN" + + tag "subworkflows" + tag "subworkflows_nfcore" + tag "subworkflows/utils_nfschema_plugin" + tag "plugin/nf-schema" + + config "./nextflow.config" + + test("Should run nothing") { + + when { + + params { + test_data = '' + } + + workflow { + """ + validate_params = false + input[0] = workflow + input[1] = validate_params + input[2] = "" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should validate params") { + + when { + + params { + test_data = '' + outdir = null + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ Validation of pipeline parameters failed!') } } + ) + } + } + + test("Should run nothing - custom schema") { + + when { + + params { + test_data = '' + } + + workflow { + """ + validate_params = false + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should validate params - custom schema") { + + when { + + params { + test_data = '' + outdir = null + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ Validation of pipeline parameters failed!') } } + ) + } + } + + test("Should create a help message") { + + when { + + params { + test_data = '' + outdir = null + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + input[3] = true + input[4] = false + input[5] = false + input[6] = "Before" + input[7] = "After" + input[8] = "nextflow run test/test" + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config new file mode 100644 index 00000000..8d8c7371 --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -0,0 +1,8 @@ +plugins { + id "nf-schema@2.5.1" +} + +validation { + parametersSchema = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + monochromeLogs = true +} diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json new file mode 100644 index 00000000..331e0d2f --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/./master/nextflow_schema.json", + "title": ". pipeline parameters", + "description": "", + "type": "object", + "$defs": { + "input_output_options": { + "title": "Input/output options", + "type": "object", + "fa_icon": "fas fa-terminal", + "description": "Define where the pipeline should find input data and save output data.", + "required": ["outdir"], + "properties": { + "validate_params": { + "type": "boolean", + "description": "Validate parameters?", + "default": true, + "hidden": true + }, + "outdir": { + "type": "string", + "format": "directory-path", + "description": "The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure.", + "fa_icon": "fas fa-folder-open" + }, + "test_data_base": { + "type": "string", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/modules", + "description": "Base for test data directory", + "hidden": true + }, + "test_data": { + "type": "string", + "description": "Fake test data param", + "hidden": true + } + } + }, + "generic_options": { + "title": "Generic options", + "type": "object", + "fa_icon": "fas fa-file-import", + "description": "Less common options for the pipeline, typically set in a config file.", + "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", + "properties": { + "help": { + "type": "boolean", + "description": "Display help text.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "version": { + "type": "boolean", + "description": "Display version and exit.", + "fa_icon": "fas fa-question-circle", + "hidden": true + }, + "logo": { + "type": "boolean", + "default": true, + "description": "Display nf-core logo in console output.", + "fa_icon": "fas fa-image", + "hidden": true + }, + "singularity_pull_docker_container": { + "type": "boolean", + "description": "Pull Singularity container from Docker?", + "hidden": true + }, + "publish_dir_mode": { + "type": "string", + "default": "copy", + "description": "Method used to save pipeline results to output directory.", + "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", + "fa_icon": "fas fa-copy", + "enum": ["symlink", "rellink", "link", "copy", "copyNoFollow", "move"], + "hidden": true + }, + "monochrome_logs": { + "type": "boolean", + "description": "Use monochrome_logs", + "hidden": true + } + } + } + }, + "allOf": [ + { + "$ref": "#/$defs/input_output_options" + }, + { + "$ref": "#/$defs/generic_options" + } + ] +} diff --git a/tests/.nftignore b/tests/.nftignore new file mode 100644 index 00000000..e128a128 --- /dev/null +++ b/tests/.nftignore @@ -0,0 +1,12 @@ +.DS_Store +multiqc/multiqc_data/fastqc_top_overrepresented_sequences_table.txt +multiqc/multiqc_data/multiqc.parquet +multiqc/multiqc_data/multiqc.log +multiqc/multiqc_data/multiqc_data.json +multiqc/multiqc_data/multiqc_sources.txt +multiqc/multiqc_data/multiqc_software_versions.txt +multiqc/multiqc_data/llms-full.txt +multiqc/multiqc_plots/{svg,pdf,png}/*.{svg,pdf,png} +multiqc/multiqc_report.html +fastqc/*_fastqc.{html,zip} +pipeline_info/*.{html,json,txt,yml} diff --git a/tests/default.nf.test b/tests/default.nf.test new file mode 100644 index 00000000..ea895f17 --- /dev/null +++ b/tests/default.nf.test @@ -0,0 +1,33 @@ +nextflow_pipeline { + + name "Test pipeline" + script "../main.nf" + tag "pipeline" + + test("-profile test") { + + when { + params { + outdir = "$outputDir" + } + } + + then { + // stable_name: All files + folders in ${params.outdir}/ with a stable name + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assertAll( + { assert workflow.success}, + { assert snapshot( + // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions + removeNextflowVersion("$outputDir/pipeline_info/preprocessing_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() } + ) + } + } +} diff --git a/tests/nextflow.config b/tests/nextflow.config new file mode 100644 index 00000000..5fa4a9fa --- /dev/null +++ b/tests/nextflow.config @@ -0,0 +1,14 @@ +/* +======================================================================================== + Nextflow config file for running nf-test tests +======================================================================================== +*/ + +// TODO nf-core: Specify any additional parameters here +// Or any resources requirements +params { + modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/' + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/preprocessing' +} + +aws.client.anonymous = true // fixes S3 access issues on self-hosted runners diff --git a/tower.yml b/tower.yml new file mode 100644 index 00000000..787aedfe --- /dev/null +++ b/tower.yml @@ -0,0 +1,5 @@ +reports: + multiqc_report.html: + display: "MultiQC HTML report" + samplesheet.csv: + display: "Auto-created samplesheet with collated metadata and FASTQ paths" diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf new file mode 100644 index 00000000..6a060472 --- /dev/null +++ b/workflows/preprocessing.nf @@ -0,0 +1,97 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +include { FASTQC } from '../modules/nf-core/fastqc/main' +include { MULTIQC } from '../modules/nf-core/multiqc/main' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + RUN MAIN WORKFLOW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +workflow PREPROCESSING { + + take: + ch_samplesheet // channel: samplesheet read in from --input + main: + + ch_versions = Channel.empty() + ch_multiqc_files = Channel.empty() + // + // MODULE: Run FastQC + // + FASTQC ( + ch_samplesheet + ) + ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) + ch_versions = ch_versions.mix(FASTQC.out.versions.first()) + + // + // Collate and save software versions + // + softwareVersionsToYAML(ch_versions) + .collectFile( + storeDir: "${params.outdir}/pipeline_info", + name: 'preprocessing_software_' + 'mqc_' + 'versions.yml', + sort: true, + newLine: true + ).set { ch_collated_versions } + + + // + // MODULE: MultiQC + // + ch_multiqc_config = Channel.fromPath( + "$projectDir/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_custom_config = params.multiqc_config ? + Channel.fromPath(params.multiqc_config, checkIfExists: true) : + Channel.empty() + ch_multiqc_logo = params.multiqc_logo ? + Channel.fromPath(params.multiqc_logo, checkIfExists: true) : + Channel.empty() + + summary_params = paramsSummaryMap( + workflow, parameters_schema: "nextflow_schema.json") + ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) + ch_multiqc_files = ch_multiqc_files.mix( + ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? + file(params.multiqc_methods_description, checkIfExists: true) : + file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) + ch_methods_description = Channel.value( + methodsDescriptionText(ch_multiqc_custom_methods_description)) + + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + ch_multiqc_files = ch_multiqc_files.mix( + ch_methods_description.collectFile( + name: 'methods_description_mqc.yaml', + sort: true + ) + ) + + MULTIQC ( + ch_multiqc_files.collect(), + ch_multiqc_config.toList(), + ch_multiqc_custom_config.toList(), + ch_multiqc_logo.toList(), + [], + [] + ) + + emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + versions = ch_versions // channel: [ path(versions.yml) ] + +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + THE END +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ From 86c028ff63fa62df231facc838607f7738fa59f6 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 13 Nov 2025 16:58:02 +0100 Subject: [PATCH 026/228] fix issues introduced with the template sync --- main.nf | 3 ++ nextflow.config | 10 ++--- nextflow_schema.json | 39 ++++++++++++++++--- .../main.nf | 9 ++--- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/main.nf b/main.nf index 72c1d99a..ee3fa058 100644 --- a/main.nf +++ b/main.nf @@ -34,6 +34,9 @@ workflow { args, params.outdir, params.input, + params.help, + params.help_full, + params.show_hidden, ) // diff --git a/nextflow.config b/nextflow.config index 998a8d09..d8a643ce 100644 --- a/nextflow.config +++ b/nextflow.config @@ -15,7 +15,7 @@ params { // References genome = null - igenomes_base = 's3://ngi-igenomes/igenomes/' + igenomes_base = '/references/' igenomes_ignore = false // Analysis options @@ -70,6 +70,9 @@ params { // Load base.config by default for all pipelines includeConfig 'conf/base.config' +// Load igenomes.config if required +includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' + profiles { debug { dumpHashes = true @@ -184,8 +187,6 @@ profiles { test_full { includeConfig 'conf/test_full.config' } } -// Set AWS client to anonymous when using the default igenomes_base -aws.client.anonymous = !params.igenomes_ignore && params.igenomes_base?.startsWith('s3://ngi-igenomes/igenomes/') ?: false // Load nf-core custom profiles from different institutions // If params.custom_config_base is set AND either the NXF_OFFLINE environment variable is not set or params.custom_config_base is a local path, the nfcore_custom.config file from the specified base path is included. @@ -206,9 +207,6 @@ podman.registry = 'quay.io' singularity.registry = 'quay.io' charliecloud.registry = 'quay.io' -// Load igenomes.config if required -includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' - // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. diff --git a/nextflow_schema.json b/nextflow_schema.json index 266484fe..f1f0fe72 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -173,12 +173,6 @@ "description": "Less common options for the pipeline, typically set in a config file.", "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", "properties": { - "help": { - "type": "boolean", - "description": "Display help text.", - "fa_icon": "fas fa-question-circle", - "hidden": true - }, "version": { "type": "boolean", "description": "Display version and exit.", @@ -253,6 +247,39 @@ "default": true, "fa_icon": "fas fa-check-square", "hidden": true + }, + "pipelines_testdata_base_path": { + "type": "string", + "fa_icon": "far fa-check-circle", + "description": "Base URL or local path to location of pipeline test dataset files", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/", + "hidden": true + }, + "trace_report_suffix": { + "type": "string", + "fa_icon": "far calendar", + "description": "Suffix to add to the trace report filename. Default is the date and time in the format yyyy-MM-dd_HH-mm-ss.", + "hidden": true + }, + "help": { + "type": ["boolean", "string"], + "description": "Display the help message." + }, + "help_full": { + "type": "boolean", + "description": "Display the full detailed help message." + }, + "show_hidden": { + "type": "boolean", + "description": "Display hidden parameters in the help message (only works when --help or --help_full are provided)." + }, + "igenomes_base": { + "type": "string", + "format": "directory-path", + "description": "Directory / URL base for iGenomes references.", + "fa_icon": "fas fa-cloud-download-alt", + "default": "/references/", + "hidden": true } } } diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf index fb156013..5d8dfa37 100644 --- a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -29,7 +29,6 @@ workflow PIPELINE_INITIALISATION { take: version // boolean: Display version and exit validate_params // boolean: Boolean whether to validate parameters against the schema at runtime - monochrome_logs // boolean: Do not use coloured log outputs nextflow_cli_args // array: List of positional nextflow CLI args outdir // string: The output directory where the results will be saved input // string: Path to input samplesheet @@ -168,11 +167,9 @@ def validateInputSamplesheet(input) { // // Get attribute from genome config file e.g. fasta // -def getGenomeAttribute(attribute) { - if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { - if (params.genomes[ params.genome ].containsKey(attribute)) { - return params.genomes[ params.genome ][ attribute ] - } +def getGenomeAttribute(genomes, attribute) { + if (genomes && genomes.containsKey(attribute)) { + return genomes[ attribute ] } return null } From 9e66e71ce2060774bcf668218eea41d947735b4c Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 13 Nov 2025 17:00:27 +0100 Subject: [PATCH 027/228] Channel -> channel --- subworkflows/local/bam_qc/main.nf | 2 +- subworkflows/local/coverage/main.nf | 4 ++-- subworkflows/local/fastq_align_rna/main.nf | 6 +++--- subworkflows/local/fastq_to_aligned_cram/main.nf | 6 +++--- .../local/fastq_to_unaligned_cram/main.nf | 2 +- .../utils_nfcore_preprocessing_pipeline/main.nf | 4 ++-- subworkflows/nf-core/fastq_align_dna/main.nf | 8 ++++---- .../nf-core/utils_nextflow_pipeline/main.nf | 4 ++-- .../nf-core/utils_nfcore_pipeline/main.nf | 2 +- workflows/preprocessing.nf | 16 ++++++++-------- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index f779364e..bd2cc469 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -14,7 +14,7 @@ workflow BAM_QC { disable_picard // boolean main: - ch_versions = Channel.empty() + ch_versions = channel.empty() ch_bam_bai_roi_fasta_fai_dict .map { meta, bam, bai, _roi, fasta, _fai, _dict -> diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index d59ace12..7ff19c7f 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -12,8 +12,8 @@ workflow COVERAGE { main: - ch_versions = Channel.empty() - ch_coverageqc_files = Channel.empty() + ch_versions = channel.empty() + ch_coverageqc_files = channel.empty() MOSDEPTH( ch_meta_cram_crai_fasta_fai_roi.map { meta, cram, crai, fasta, _fai, roi -> diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index 859ca5a3..03b9c585 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -12,9 +12,9 @@ workflow FASTQ_ALIGN_RNA { ch_reads_aligner_index_gtf // channel: [mandatory] reads, aligner, index, gtf main: - ch_bam = Channel.empty() - ch_reports = Channel.empty() - ch_versions = Channel.empty() + ch_bam = channel.empty() + ch_reports = channel.empty() + ch_versions = channel.empty() ch_reads_aligner_index_gtf .branch { meta, reads, aligner, index, gtf -> diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 49199684..76ea8b63 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -24,8 +24,8 @@ workflow FASTQ_TO_CRAM { main: - ch_versions = Channel.empty() - ch_sormadup_metrics = Channel.empty() + ch_versions = channel.empty() + ch_sormadup_metrics = channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -93,7 +93,7 @@ workflow FASTQ_TO_CRAM { .set { ch_bam_fasta } ch_bam_fasta.dump(tag: "FASTQ_TO_CRAM: aligned bam per sample", pretty: true) - ch_markdup_index = Channel.empty() + ch_markdup_index = channel.empty() if (markdup == "bamsormadup") { // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) diff --git a/subworkflows/local/fastq_to_unaligned_cram/main.nf b/subworkflows/local/fastq_to_unaligned_cram/main.nf index 1c458a2b..f1137f26 100644 --- a/subworkflows/local/fastq_to_unaligned_cram/main.nf +++ b/subworkflows/local/fastq_to_unaligned_cram/main.nf @@ -13,7 +13,7 @@ workflow FASTQ_TO_UCRAM { main: - ch_versions = Channel.empty() + ch_versions = channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf index 5d8dfa37..c66aaf01 100644 --- a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -38,7 +38,7 @@ workflow PIPELINE_INITIALISATION { main: - ch_versions = Channel.empty() + ch_versions = channel.empty() // // Print version and exit if required and dump pipeline parameters to JSON file @@ -82,7 +82,7 @@ workflow PIPELINE_INITIALISATION { // // Create channel from input file provided through params.input // - Channel.fromList(samplesheetToList(input, "assets/schema_input.json")) + channel.fromList(samplesheetToList(input, "assets/schema_input.json")) .set { ch_samplesheet } emit: diff --git a/subworkflows/nf-core/fastq_align_dna/main.nf b/subworkflows/nf-core/fastq_align_dna/main.nf index e6636ae8..6239522f 100644 --- a/subworkflows/nf-core/fastq_align_dna/main.nf +++ b/subworkflows/nf-core/fastq_align_dna/main.nf @@ -20,10 +20,10 @@ workflow FASTQ_ALIGN_DNA { main: - ch_bam_index = Channel.empty() - ch_bam = Channel.empty() - ch_reports = Channel.empty() - ch_versions = Channel.empty() + ch_bam_index = channel.empty() + ch_bam = channel.empty() + ch_reports = channel.empty() + ch_versions = channel.empty() ch_reads_aligner_index_fasta.branch { meta, reads, aligner, index, fasta -> bowtie2 : aligner == 'bowtie2' diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index d6e593e8..0b4a6b60 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -36,7 +36,7 @@ workflow UTILS_NEXTFLOW_PIPELINE { // When running with Conda, warn if channels have not been set-up appropriately // if (check_conda_channels) { - checkCondaChannels() + checkCondachannels() } emit: @@ -84,7 +84,7 @@ def dumpParametersToJSON(outdir) { // // When running with -profile conda, warn if channels have not been set-up appropriately // -def checkCondaChannels() { +def checkCondachannels() { def parser = new org.yaml.snakeyaml.Yaml() def channels = [] try { diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index bfd25876..2f30e9a4 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -98,7 +98,7 @@ def workflowVersionToYAML() { // Get channel of software versions used in pipeline in YAML format // def softwareVersionsToYAML(ch_versions) { - return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) + return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(channel.of(workflowVersionToYAML())) } // diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index c3e13fd3..0753d6b5 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -43,8 +43,8 @@ workflow PREPROCESSING { genelists // file: directory containing genelist bed files for coverage analysis main: - ch_versions = Channel.empty() - ch_multiqc_files = Channel.empty() + ch_versions = channel.empty() + ch_multiqc_files = channel.empty() ch_samplesheet .branch { meta, fastq_1, fastq_2, samplesheet, sampleinfo, flowcell -> @@ -59,7 +59,7 @@ workflow PREPROCESSING { roi = roi ? file(roi, checkIfExists: true) : null - genelists = genelists ? Channel.value(file(genelists + "/*.bed", checkIfExists: true)) : Channel.empty() + genelists = genelists ? channel.value(file(genelists + "/*.bed", checkIfExists: true)) : channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -453,13 +453,13 @@ workflow PREPROCESSING { // // MODULE: MultiQC // - ch_multiqc_config = Channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) - ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config, checkIfExists: true) : Channel.empty() - ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo, checkIfExists: true) : Channel.empty() + ch_multiqc_config = channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_custom_config = params.multiqc_config ? channel.fromPath(params.multiqc_config, checkIfExists: true) : channel.empty() + ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") - ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) + ch_workflow_summary = channel.value(paramsSummaryMultiqc(summary_params)) ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) - ch_methods_description = Channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) From 24166c03d3234c86ba8b8f636c81cf64cb626fbe Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 13 Nov 2025 17:17:35 +0100 Subject: [PATCH 028/228] lint issues + module updates --- conf/modules.config | 12 +- modules.json | 9 +- modules/nf-core/md5sum/environment.yml | 9 +- modules/nf-core/md5sum/main.nf | 29 ++--- modules/nf-core/md5sum/meta.yml | 28 +++-- .../nf-core/md5sum/tests/main.nf.test.snap | 70 +++++------ modules/nf-core/md5sum/tests/tags.yml | 2 - modules/nf-core/star/align/environment.yml | 2 + modules/nf-core/star/align/meta.yml | 117 +++++++++++------- modules/nf-core/star/align/star-align.diff | 1 - modules/nf-core/star/align/tests/tags.yml | 2 - subworkflows/local/coverage/main.nf | 4 +- 12 files changed, 161 insertions(+), 124 deletions(-) delete mode 100644 modules/nf-core/md5sum/tests/tags.yml delete mode 100644 modules/nf-core/star/align/tests/tags.yml diff --git a/conf/modules.config b/conf/modules.config index 00f0f28e..512adf84 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -47,7 +47,7 @@ process { label = "process_medium" ext.args = { [ - meta.readgroup ? "--rg-line \"@RG\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\t") + "\"" : "", + meta.readgroup ? "--rg-line \"@RG\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\t") + "\"" : "", "--output-fmt cram", "--output-fmt-option archive", ].join(" ").trim() @@ -72,7 +72,7 @@ process { "--local", "--fast-local", meta.readgroup ? "--rg-id ${meta.readgroup.ID}" : "", - meta.readgroup ? "--rg " + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join(" --rg ") : "", + meta.readgroup ? "--rg " + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join(" --rg ") : "", ].join(" ").trim() } ext.args2 = "--fast" @@ -87,7 +87,7 @@ process { "-v 3", "-Y", "-c 250", - meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\\t") + "\"" : "", + meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : "", ].join(" ").trim() } ext.args2 = "--fast" @@ -97,7 +97,7 @@ process { withName: DRAGMAP_ALIGN { ext.args = { [ - meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\\t") + "\"" : "" + meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : "" ].join(" ").trim() } ext.args2 = "--fast" @@ -122,7 +122,7 @@ process { "-S id", "-sa", "-xf 2", - meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults { it.value?.trim() ? "${it.key}:${it.value}" : null }.join("\\t") + "\"" : "", + meta.readgroup ? "-R \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : "", ].join(" ").trim() } } @@ -137,7 +137,7 @@ process { "--outSAMattributes All", "--chimSegmentMin 20", "--outFilterMismatchNmax 4", - meta.readgroup ? "--outSAMattrRGline \"ID:${meta.readgroup.ID}" + meta.readgroup.findResults { it.value?.trim() && it.key != "ID" ? "${it.key}:${it.value}" : null }.join(" ") + "\"" : "", + meta.readgroup ? "--outSAMattrRGline \"ID:${meta.readgroup.ID}" + meta.readgroup.findResults { rg -> rg.value?.trim() && rg.key != "ID" ? "${rg.key}:${rg.value}" : null }.join(" ") + "\"" : "", ].join(" ").trim() } } diff --git a/modules.json b/modules.json index 9b8eb350..3deb83d8 100644 --- a/modules.json +++ b/modules.json @@ -51,9 +51,14 @@ "installed_by": ["modules"], "patch": "modules/nf-core/fastp/fastp.diff" }, + "fastqc": { + "branch": "master", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "installed_by": ["modules"] + }, "md5sum": { "branch": "master", - "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "mosdepth": { @@ -144,7 +149,7 @@ }, "star/align": { "branch": "master", - "git_sha": "3c259f0ac1ed9ae3f6b835461d054edffc60120e", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" } diff --git a/modules/nf-core/md5sum/environment.yml b/modules/nf-core/md5sum/environment.yml index c7eb9bd1..9b926b1f 100644 --- a/modules/nf-core/md5sum/environment.yml +++ b/modules/nf-core/md5sum/environment.yml @@ -1,5 +1,12 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda dependencies: - - conda-forge::coreutils=8.30 + - conda-forge::coreutils=9.5 + - conda-forge::grep=3.11 + - conda-forge::gzip=1.13 + - conda-forge::lbzip2=2.5 + - conda-forge::sed=4.8 + - conda-forge::tar=1.34 diff --git a/modules/nf-core/md5sum/main.nf b/modules/nf-core/md5sum/main.nf index d77bb8ce..ea8cffed 100644 --- a/modules/nf-core/md5sum/main.nf +++ b/modules/nf-core/md5sum/main.nf @@ -1,11 +1,11 @@ process MD5SUM { - tag "$meta.id" + tag "${meta.id}" label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : - 'nf-core/ubuntu:20.04' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data' + : 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}" input: tuple val(meta), path(files) @@ -13,30 +13,32 @@ process MD5SUM { output: tuple val(meta), path("*.md5"), emit: checksum - path "versions.yml" , emit: versions + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" // will only use when as_separate_files = false - if ( as_separate_files ) { + def prefix = task.ext.prefix ?: "${meta.id}" + // will only use when as_separate_files = false + if (as_separate_files) { """ find -L * -maxdepth 0 -type f \\ ! -name '*.md5' \\ - -exec sh -c 'md5sum $args "\$1" > "\$1.md5"' _ "{}" \\; + -exec sh -c 'md5sum ${args} "\$1" > "\$1.md5"' _ "{}" \\; cat <<-END_VERSIONS > versions.yml "${task.process}": md5sum: \$( md5sum --version | sed '1!d; s/.* //' ) END_VERSIONS """ - } else { + } + else { """ find -L * -type f \\ ! -name '*.md5' \\ - -exec md5sum $args "{}" + \\ + -exec md5sum ${args} "{}" + \\ > ${prefix}.md5 cat <<-END_VERSIONS > versions.yml @@ -47,9 +49,8 @@ process MD5SUM { } stub: - def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - if ( as_separate_files ) { + if (as_separate_files) { """ find -L * -type f \\ ! -name '*.md5' \\ @@ -60,7 +61,8 @@ process MD5SUM { md5sum: \$( md5sum --version | sed '1!d; s/.* //' ) END_VERSIONS """ - } else { + } + else { """ touch ${prefix}.md5 @@ -70,5 +72,4 @@ process MD5SUM { END_VERSIONS """ } - } diff --git a/modules/nf-core/md5sum/meta.yml b/modules/nf-core/md5sum/meta.yml index 363d763f..c1f7e36d 100644 --- a/modules/nf-core/md5sum/meta.yml +++ b/modules/nf-core/md5sum/meta.yml @@ -21,14 +21,15 @@ input: type: file description: Any number of files. One md5sum file will be generated for each. pattern: "*.*" - - - as_separate_files: - type: boolean - description: | - If true, each file will have its own md5sum file. If false, all files will be - checksummed into a single md5sum file. + ontologies: [] + - as_separate_files: + type: boolean + description: | + If true, each file will have its own md5sum file. If false, all files will be + checksummed into a single md5sum file. output: - - checksum: - - meta: + checksum: + - - meta: type: map description: | Groovy Map containing sample information @@ -37,11 +38,14 @@ output: type: file description: File containing checksum pattern: "*.md5" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/md5sum/tests/main.nf.test.snap b/modules/nf-core/md5sum/tests/main.nf.test.snap index cd7593b4..20b59b0b 100644 --- a/modules/nf-core/md5sum/tests/main.nf.test.snap +++ b/modules/nf-core/md5sum/tests/main.nf.test.snap @@ -14,7 +14,7 @@ ] ], "1": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ], "checksum": [ [ @@ -28,15 +28,15 @@ ] ], "versions": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "24.10.2" }, - "timestamp": "2024-07-01T11:05:22.111018419" + "timestamp": "2024-12-13T11:49:35.159607272" }, "md5sum on paired fastq, separate": { "content": [ @@ -53,7 +53,7 @@ ] ], "1": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ], "checksum": [ [ @@ -67,15 +67,15 @@ ] ], "versions": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "24.10.2" }, - "timestamp": "2024-07-01T11:05:12.083864677" + "timestamp": "2024-12-13T11:49:27.200164144" }, "md5sum on hello.txt - stub": { "content": [ @@ -89,7 +89,7 @@ ] ], "1": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ], "checksum": [ [ @@ -100,15 +100,15 @@ ] ], "versions": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "24.10.2" }, - "timestamp": "2024-07-01T11:04:42.230073228" + "timestamp": "2024-12-13T11:49:01.643624698" }, "md5sum on hello.txt": { "content": [ @@ -122,7 +122,7 @@ ] ], "1": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ], "checksum": [ [ @@ -133,15 +133,15 @@ ] ], "versions": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "24.10.2" }, - "timestamp": "2024-07-01T11:04:22.089948509" + "timestamp": "2024-12-13T11:48:47.201714961" }, "md5sum on paired fastq, combined": { "content": [ @@ -155,7 +155,7 @@ ] ], "1": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ], "checksum": [ [ @@ -166,15 +166,15 @@ ] ], "versions": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "24.10.2" }, - "timestamp": "2024-07-01T11:04:52.085480359" + "timestamp": "2024-12-13T11:49:10.207550973" }, "md5sum on paired fastq, combined - stub": { "content": [ @@ -188,7 +188,7 @@ ] ], "1": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ], "checksum": [ [ @@ -199,15 +199,15 @@ ] ], "versions": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "24.10.2" }, - "timestamp": "2024-07-01T11:05:01.935454952" + "timestamp": "2024-12-13T11:49:18.36682418" }, "md5sum on hello.txt (BSD-style)": { "content": [ @@ -221,7 +221,7 @@ ] ], "1": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ], "checksum": [ [ @@ -232,14 +232,14 @@ ] ], "versions": [ - "versions.yml:md5,5745fe6b917070b6158ade64fcb4aa91" + "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "24.10.2" }, - "timestamp": "2024-07-01T11:04:32.078323542" + "timestamp": "2024-12-13T11:48:54.672060206" } } \ No newline at end of file diff --git a/modules/nf-core/md5sum/tests/tags.yml b/modules/nf-core/md5sum/tests/tags.yml deleted file mode 100644 index bb45d190..00000000 --- a/modules/nf-core/md5sum/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -md5sum: - - "modules/nf-core/md5sum/**" diff --git a/modules/nf-core/star/align/environment.yml b/modules/nf-core/star/align/environment.yml index 9ed1940f..91e37ae1 100644 --- a/modules/nf-core/star/align/environment.yml +++ b/modules/nf-core/star/align/environment.yml @@ -1,3 +1,5 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda diff --git a/modules/nf-core/star/align/meta.yml b/modules/nf-core/star/align/meta.yml index 5cfe763e..1ee46905 100644 --- a/modules/nf-core/star/align/meta.yml +++ b/modules/nf-core/star/align/meta.yml @@ -26,6 +26,7 @@ input: description: | List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. + ontologies: [] - - meta2: type: map description: | @@ -44,18 +45,19 @@ input: type: file description: Annotation GTF file pattern: "*.{gtf}" - - - star_ignore_sjdbgtf: - type: boolean - description: Ignore annotation GTF file - - - seq_platform: - type: string - description: Sequencing platform - - - seq_center: - type: string - description: Sequencing center + ontologies: [] + - star_ignore_sjdbgtf: + type: boolean + description: Ignore annotation GTF file + - seq_platform: + type: string + description: Sequencing platform + - seq_center: + type: string + description: Sequencing center output: - - log_final: - - meta: + log_final: + - - meta: type: map description: | Groovy Map containing sample information @@ -64,8 +66,9 @@ output: type: file description: STAR final log file pattern: "*Log.final.out" - - log_out: - - meta: + ontologies: [] + log_out: + - - meta: type: map description: | Groovy Map containing sample information @@ -74,8 +77,9 @@ output: type: file description: STAR lot out file pattern: "*Log.out" - - log_progress: - - meta: + ontologies: [] + log_progress: + - - meta: type: map description: | Groovy Map containing sample information @@ -84,13 +88,16 @@ output: type: file description: STAR log progress file pattern: "*Log.progress.out" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - - bam: - - meta: + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -99,8 +106,9 @@ output: type: file description: Output BAM file containing read alignments pattern: "*.{bam}" - - bam_sorted: - - meta: + ontologies: [] + bam_sorted: + - - meta: type: map description: | Groovy Map containing sample information @@ -109,8 +117,9 @@ output: type: file description: Sorted BAM file of read alignments (optional) pattern: "*sortedByCoord.out.bam" - - bam_sorted_aligned: - - meta: + ontologies: [] + bam_sorted_aligned: + - - meta: type: map description: | Groovy Map containing sample information @@ -119,8 +128,9 @@ output: type: file description: Sorted BAM file of read alignments (optional) pattern: "*.Aligned.sortedByCoord.out.bam" - - bam_transcript: - - meta: + ontologies: [] + bam_transcript: + - - meta: type: map description: | Groovy Map containing sample information @@ -129,8 +139,9 @@ output: type: file description: Output BAM file of transcriptome alignment (optional) pattern: "*toTranscriptome.out.bam" - - bam_unsorted: - - meta: + ontologies: [] + bam_unsorted: + - - meta: type: map description: | Groovy Map containing sample information @@ -139,8 +150,9 @@ output: type: file description: Unsorted BAM file of read alignments (optional) pattern: "*Aligned.unsort.out.bam" - - fastq: - - meta: + ontologies: [] + fastq: + - - meta: type: map description: | Groovy Map containing sample information @@ -149,8 +161,10 @@ output: type: file description: Unmapped FastQ files (optional) pattern: "*fastq.gz" - - tab: - - meta: + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + tab: + - - meta: type: map description: | Groovy Map containing sample information @@ -159,8 +173,10 @@ output: type: file description: STAR output tab file(s) (optional) pattern: "*.tab" - - spl_junc_tab: - - meta: + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + spl_junc_tab: + - - meta: type: map description: | Groovy Map containing sample information @@ -169,8 +185,10 @@ output: type: file description: STAR output splice junction tab file pattern: "*.SJ.out.tab" - - read_per_gene_tab: - - meta: + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + read_per_gene_tab: + - - meta: type: map description: | Groovy Map containing sample information @@ -179,8 +197,10 @@ output: type: file description: STAR output read per gene tab file pattern: "*.ReadsPerGene.out.tab" - - junction: - - meta: + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + junction: + - - meta: type: map description: | Groovy Map containing sample information @@ -189,19 +209,20 @@ output: type: file description: STAR chimeric junction output file (optional) pattern: "*.out.junction" - - sam: - - meta: + ontologies: [] + sam: + - - meta: type: map description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - pattern: "*.out.sam" - "*.out.sam": type: file description: STAR output SAM file(s) (optional) pattern: "*.out.sam" - - wig: - - meta: + ontologies: [] + wig: + - - meta: type: map description: | Groovy Map containing sample information @@ -210,8 +231,9 @@ output: type: file description: STAR output wiggle format file(s) (optional) pattern: "*.wig" - - bedgraph: - - meta: + ontologies: [] + bedgraph: + - - meta: type: map description: | Groovy Map containing sample information @@ -220,6 +242,7 @@ output: type: file description: STAR output bedGraph format file(s) (optional) pattern: "*.bg" + ontologies: [] authors: - "@kevinmenden" - "@drpatelh" diff --git a/modules/nf-core/star/align/star-align.diff b/modules/nf-core/star/align/star-align.diff index 93befc80..3502ee3b 100644 --- a/modules/nf-core/star/align/star-align.diff +++ b/modules/nf-core/star/align/star-align.diff @@ -26,7 +26,6 @@ Changes in 'star/align/main.nf': 'modules/nf-core/star/align/environment.yml' is unchanged 'modules/nf-core/star/align/meta.yml' is unchanged -'modules/nf-core/star/align/tests/tags.yml' is unchanged 'modules/nf-core/star/align/tests/nextflow.starfusion.config' is unchanged 'modules/nf-core/star/align/tests/main.nf.test' is unchanged 'modules/nf-core/star/align/tests/nextflow.arriba.config' is unchanged diff --git a/modules/nf-core/star/align/tests/tags.yml b/modules/nf-core/star/align/tests/tags.yml deleted file mode 100644 index 8beace16..00000000 --- a/modules/nf-core/star/align/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -star/align: - - modules/nf-core/star/align/** diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 7ff19c7f..27a19c43 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -39,8 +39,8 @@ workflow COVERAGE { genelists = [genelists] } def filtered_genelists = meta.tag.toLowerCase() == "seqcap" - ? genelists.findAll { it.name.toLowerCase().contains("seqcap") } - : genelists.findAll { !it.name.toLowerCase().contains("seqcap") } + ? genelists.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } + : genelists.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } if (filtered_genelists.size() > 0) { return [ From c0444d0be0196a4dfe182e833807482bc44b9d4f Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 19 Nov 2025 17:16:47 +0100 Subject: [PATCH 029/228] update star/align --- modules.json | 2 +- modules/nf-core/star/align/main.nf | 4 ++-- modules/nf-core/star/align/star-align.diff | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules.json b/modules.json index 3deb83d8..3ef41a0c 100644 --- a/modules.json +++ b/modules.json @@ -149,7 +149,7 @@ }, "star/align": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" } diff --git a/modules/nf-core/star/align/main.nf b/modules/nf-core/star/align/main.nf index d61ffdfa..034f91df 100644 --- a/modules/nf-core/star/align/main.nf +++ b/modules/nf-core/star/align/main.nf @@ -40,8 +40,8 @@ process STAR_ALIGN { prefix = task.ext.prefix ?: "${meta.id}" def reads1 = [] def reads2 = [] - meta.single_end ? [reads].flatten().each{reads1 << it} : reads.eachWithIndex{ v, ix -> ( ix & 1 ? reads2 : reads1) << v } - def ignore_gtf = gtf ? "--sjdbGTFfile $gtf" : "" + meta.single_end ? [reads].flatten().each{ read -> reads1 << read} : reads.eachWithIndex{ v, ix -> ( ix & 1 ? reads2 : reads1) << v } + def ignore_gtf = gtf ? "--sjdbGTFfile $gtf" : '' def seq_platform_arg = seq_platform ? "'PL:$seq_platform'" : "" def seq_center_arg = seq_center ? "'CN:$seq_center'" : "" attrRG = args.contains("--outSAMattrRGline") ? "" : "--outSAMattrRGline 'ID:$prefix' $seq_center_arg 'SM:$prefix' $seq_platform_arg" diff --git a/modules/nf-core/star/align/star-align.diff b/modules/nf-core/star/align/star-align.diff index 3502ee3b..019f65d6 100644 --- a/modules/nf-core/star/align/star-align.diff +++ b/modules/nf-core/star/align/star-align.diff @@ -17,9 +17,9 @@ Changes in 'star/align/main.nf': @@ -44,7 +41,7 @@ def reads1 = [] def reads2 = [] - meta.single_end ? [reads].flatten().each{reads1 << it} : reads.eachWithIndex{ v, ix -> ( ix & 1 ? reads2 : reads1) << v } + meta.single_end ? [reads].flatten().each{ read -> reads1 << read} : reads.eachWithIndex{ v, ix -> ( ix & 1 ? reads2 : reads1) << v } - def ignore_gtf = star_ignore_sjdbgtf ? '' : "--sjdbGTFfile $gtf" -+ def ignore_gtf = gtf ? "--sjdbGTFfile $gtf" : "" ++ def ignore_gtf = gtf ? "--sjdbGTFfile $gtf" : '' def seq_platform_arg = seq_platform ? "'PL:$seq_platform'" : "" def seq_center_arg = seq_center ? "'CN:$seq_center'" : "" attrRG = args.contains("--outSAMattrRGline") ? "" : "--outSAMattrRGline 'ID:$prefix' $seq_center_arg 'SM:$prefix' $seq_platform_arg" From 28c2be3fc2d581af2f19c4597c7a1a9adce3be7f Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 20 Nov 2025 16:47:00 +0100 Subject: [PATCH 030/228] fix as much linting as possible --- .nf-core.yml | 3 +++ .prettierignore | 1 + modules.json | 6 +++--- nextflow_schema.json | 13 +++++++++++++ ro-crate-metadata.json | 2 +- .../nf-core/utils_nextflow_pipeline/main.nf | 4 ++-- .../nf-core/utils_nextflow_pipeline/tests/tags.yml | 2 -- .../nf-core/utils_nfcore_pipeline/tests/tags.yml | 2 -- subworkflows/nf-core/utils_nfschema_plugin/main.nf | 1 - 9 files changed, 23 insertions(+), 11 deletions(-) delete mode 100644 subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml delete mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml diff --git a/.nf-core.yml b/.nf-core.yml index d565b189..d4ae7ba5 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -25,6 +25,9 @@ lint: - manifest.homePage template_strings: - bin/cmgg_genelists + nf_test_content: false + subworkflow_changes: + - fastq_align_dna nf_core_version: 3.4.1 repository_type: pipeline template: diff --git a/.prettierignore b/.prettierignore index edd29f01..2255e3e3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,4 +10,5 @@ testing/ testing* *.pyc bin/ +.nf-test/ ro-crate-metadata.json diff --git a/modules.json b/modules.json index 3ef41a0c..8474373b 100644 --- a/modules.json +++ b/modules.json @@ -169,17 +169,17 @@ }, "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "56372688d8979092cafbe0c5c3895b491166ca1c", + "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "1b6b9a3338d011367137808b49b923515080e3ba", + "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "2fd2cd6d0e7b273747f32e465fdc6bcc3ae0814e", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["subworkflows"] } } diff --git a/nextflow_schema.json b/nextflow_schema.json index f1f0fe72..d6a4828f 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -280,6 +280,19 @@ "fa_icon": "fas fa-cloud-download-alt", "default": "/references/", "hidden": true + }, + "igenomes_ignore": { + "type": "boolean", + "description": "Do not load the iGenomes reference config.", + "fa_icon": "fas fa-ban", + "hidden": true, + "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." + }, + "genome": { + "type": "string", + "description": "Name of iGenomes reference.", + "fa_icon": "fas fa-book", + "help_text": "If using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`. \n\nSee the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details." } } } diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 35a2f1d3..d3e36bec 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -23,7 +23,7 @@ "@type": "Dataset", "creativeWorkStatus": "InProgress", "datePublished": "2025-11-13T15:11:21+00:00", - "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that ...\n\n\n\n\n1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/))\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by Matthias De Smet, Nicolas Vannieuwkerke.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\n## Citations\n\n\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/main/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP) or [`snap`](https://github.com/amplab/snap) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag\nfc_sample1,test,Homo sapiens,WES\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index 0b4a6b60..d6e593e8 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -36,7 +36,7 @@ workflow UTILS_NEXTFLOW_PIPELINE { // When running with Conda, warn if channels have not been set-up appropriately // if (check_conda_channels) { - checkCondachannels() + checkCondaChannels() } emit: @@ -84,7 +84,7 @@ def dumpParametersToJSON(outdir) { // // When running with -profile conda, warn if channels have not been set-up appropriately // -def checkCondachannels() { +def checkCondaChannels() { def parser = new org.yaml.snakeyaml.Yaml() def channels = [] try { diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml deleted file mode 100644 index f8476112..00000000 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -subworkflows/utils_nextflow_pipeline: - - subworkflows/nf-core/utils_nextflow_pipeline/** diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml deleted file mode 100644 index ac8523c9..00000000 --- a/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -subworkflows/utils_nfcore_pipeline: - - subworkflows/nf-core/utils_nfcore_pipeline/** diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf index ee4738c8..acb39724 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -71,4 +71,3 @@ workflow UTILS_NFSCHEMA_PLUGIN { emit: dummy_emit = true } - From 0efef0872d2ae75371ec5839c88be02f307a7c32 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 20 Nov 2025 17:11:44 +0100 Subject: [PATCH 031/228] bump nextflow to 25.10.0 --- .github/workflows/nf-test.yml | 6 +++--- README.md | 2 +- nextflow.config | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index c7448f3e..96b4ae4b 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -9,7 +9,7 @@ on: - "**/*.svg" release: types: [published] - workflow_dispatch: + workflow_dispatch: null # Cancel if a newer run is started concurrency: @@ -76,8 +76,8 @@ jobs: - isMain: false profile: "singularity" NXF_VER: - - "25.04.0" - - "latest-everything" + - 25.10.0 + - latest-everything env: NXF_ANSI_LOG: false TOTAL_SHARDS: ${{ needs.nf-test-changes.outputs.total_shards }} diff --git a/README.md b/README.md index c0293e61..7a23f1d2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) [![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) -[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) [![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) diff --git a/nextflow.config b/nextflow.config index d8a643ce..d9645896 100644 --- a/nextflow.config +++ b/nextflow.config @@ -273,7 +273,7 @@ manifest { description = """Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.""" mainScript = 'main.nf' defaultBranch = 'main' - nextflowVersion = '!>=25.04.0' + nextflowVersion = '!>=25.10.0' version = '2.1.0dev' doi = '' } From c5b84484e7ed7693966b419b0a4dc1beceea088c Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 20 Nov 2025 17:17:45 +0100 Subject: [PATCH 032/228] patch subwf --- modules.json | 130 +++++++++++++----- .../fastq_align_dna/fastq_align_dna.diff | 110 +++++++++++++++ 2 files changed, 208 insertions(+), 32 deletions(-) create mode 100644 subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff diff --git a/modules.json b/modules.json index 8474373b..2d50f2d3 100644 --- a/modules.json +++ b/modules.json @@ -8,149 +8,204 @@ "bcl2fastq": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": ["bcl_demultiplex"] + "installed_by": [ + "bcl_demultiplex" + ] }, "bclconvert": { "branch": "master", "git_sha": "27cceb2eb8aa959d4a8819caab886386a59a3789", - "installed_by": ["bcl_demultiplex", "modules"] + "installed_by": [ + "bcl_demultiplex", + "modules" + ] }, "biobambam/bamsormadup": { "branch": "master", "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, "bowtie2/align": { "branch": "master", "git_sha": "8864afe586537bf562eac7b83349c26207f3cb4d", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, "dragmap/align": { "branch": "master", "git_sha": "8864afe586537bf562eac7b83349c26207f3cb4d", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, "fastp": { "branch": "master", "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/fastp/fastp.diff" }, "fastqc": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "md5sum": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "mosdepth": { "branch": "master", "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, "multiqc": { "branch": "master", "git_sha": "471cf3ca1617271b9b6fea09ea2ebdee78b874de", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "picard/collecthsmetrics": { "branch": "master", "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, "samtools/cat": { "branch": "master", "git_sha": "b13f07be4c508d6ff6312d354d09f2493243e208", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/cat/samtools-cat.diff" }, "samtools/convert": { "branch": "master", "git_sha": "b13f07be4c508d6ff6312d354d09f2493243e208", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, "samtools/flagstat": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/idxstats": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/import": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/sormadup": { "branch": "master", "git_sha": "38f3b0200093498b70ac2d63a83eac5642e3c873", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, "samtools/sort": { "branch": "master", "git_sha": "b7800db9b069ed505db3f9d91b8c72faea9be17b", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "samtools/stats": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, "snapaligner/align": { "branch": "master", "git_sha": "77bdd7e1047d2abe21ae8d89acc295ea553ecbae", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, "star/align": { "branch": "master", "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/star/align/star-align.diff" } } @@ -160,30 +215,41 @@ "bcl_demultiplex": { "branch": "master", "git_sha": "1a0770da1cf5c5cd388bf888ba8798bc4d1fba56", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "fastq_align_dna": { "branch": "master", "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ], + "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfschema_plugin": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] } } } } } -} +} \ No newline at end of file diff --git a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff new file mode 100644 index 00000000..44d24df2 --- /dev/null +++ b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff @@ -0,0 +1,110 @@ +Changes in component 'nf-core/fastq_align_dna' +Changes in 'fastq_align_dna/main.nf': +--- subworkflows/nf-core/fastq_align_dna/main.nf ++++ subworkflows/nf-core/fastq_align_dna/main.nf +@@ -15,51 +15,59 @@ + + workflow FASTQ_ALIGN_DNA { + take: +- ch_reads // channel: [mandatory] meta, reads +- ch_aligner_index // channel: [mandatory] aligner index +- ch_fasta // channel: [mandatory] fasta file +- aligner // string: [mandatory] aligner [bowtie2, bwamem, bwamem2, dragmap, snap] +- sort // boolean: [mandatory] true -> sort, false -> don't sort ++ ch_reads_aligner_index_fasta // channel: [mandatory] reads, aligner, index, fasta ++ sort // boolean: [mandatory] true -> sort, false -> don't sort + + main: + +- ch_bam_index = Channel.empty() +- ch_bam = Channel.empty() +- ch_reports = Channel.empty() +- ch_versions = Channel.empty() ++ ch_bam_index = channel.empty() ++ ch_bam = channel.empty() ++ ch_reports = channel.empty() ++ ch_versions = channel.empty() ++ ++ ch_reads_aligner_index_fasta.branch { meta, reads, aligner, index, fasta -> ++ bowtie2 : aligner == 'bowtie2' ++ return [meta, reads, index, fasta] ++ bwamem : aligner == 'bwamem' ++ return [meta, reads, index, fasta] ++ bwamem2 : aligner == 'bwamem2' ++ return [meta, reads, index, fasta] ++ dragmap : aligner == 'dragmap' ++ return [meta, reads, index, fasta] ++ snap : aligner == 'snap' ++ return [meta, reads, index] ++ other : true ++ } ++ .set{ch_to_align} ++ ++ // Throw error for all samples with unsupported aligners ++ ch_to_align.other.map{ meta, _reads, aligner, _index, _fasta -> ++ error "Unsupported aligner ${aligner} for sample ${meta.id}" ++ } + + // Align fastq files to reference genome and (optionally) sort +- if (aligner == 'bowtie2') { +- BOWTIE2_ALIGN(ch_reads, ch_aligner_index, ch_fasta, false, sort) // if aligner is bowtie2 +- ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) +- ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions) +- } +- else if (aligner == 'bwamem'){ +- BWAMEM1_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem +- ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) +- ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) +- ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions) +- } +- else if (aligner == 'bwamem2'){ +- BWAMEM2_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem2 +- ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) +- ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions) +- } +- else if (aligner == 'dragmap'){ +- DRAGMAP_ALIGN(ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is dragmap +- ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) +- ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) +- ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions) +- } +- else if (aligner == 'snap'){ +- SNAP_ALIGN (ch_reads, ch_aligner_index) // If aligner is snap +- ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) +- ch_bam_index.mix(SNAP_ALIGN.out.bai) +- ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions) +- } +- else { +- error "Unknown aligner: ${aligner}" +- } ++ BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 ++ ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) ++ ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions.first()) ++ ++ BWAMEM1_MEM (ch_to_align.bwamem, sort) // If aligner is bwa-mem ++ ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) ++ ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) ++ ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions.first()) ++ ++ BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 ++ ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) ++ ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions.first()) ++ ++ DRAGMAP_ALIGN(ch_to_align.dragmap, sort) // If aligner is dragmap ++ ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) ++ ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) ++ ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) ++ ++ SNAP_ALIGN(ch_to_align.snap) // If aligner is snap ++ ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) ++ ch_bam_index.mix(SNAP_ALIGN.out.bai) ++ ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions.first()) + + emit: + bam = ch_bam // channel: [ [meta], bam ] + +'subworkflows/nf-core/fastq_align_dna/meta.yml' is unchanged +'subworkflows/nf-core/fastq_align_dna/tests/main.nf.test' is unchanged +'subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap' is unchanged +'subworkflows/nf-core/fastq_align_dna/tests/nextflow.config' is unchanged +************************************************************ From a721f8b32159b854414742390609791668f95ade Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 13:26:43 +0100 Subject: [PATCH 033/228] remove old ci flow and add credentials to new one --- .github/workflows/ci.yml | 101 ---------------------------------- .github/workflows/nf-test.yml | 2 + 2 files changed, 2 insertions(+), 101 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 4902664d..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,101 +0,0 @@ -name: nf-core CI -# This workflow runs the pipeline with the minimal test dataset to check that it completes without any syntax errors -on: - push: - branches: - - dev - pull_request: - release: - types: [published] - -env: - NXF_ANSI_LOG: false - NFT_VER: "0.9.2" - NFT_WORKDIR: "~" - NFT_DIFF: "pdiff" - NFT_DIFF_ARGS: "--line-numbers --expand-tabs=2" - AWS_ACCESS_KEY_ID: ${{ secrets.UGENT_S3_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.UGENT_S3_SECRET_KEY }} - -concurrency: - group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" - cancel-in-progress: true - -jobs: - test: - name: ${{ matrix.tags }} ${{ matrix.profile }} NF-${{ matrix.NXF_VER }} - # Only run on push if this is the nf-core dev branch (merged PRs) - if: "${{ github.event_name != 'push' || (github.event_name == 'push' && github.repository == 'nf-cmgg/preprocessing') }}" - runs-on: ubuntu-latest - strategy: - matrix: - NXF_VER: - - "25.10.0" - tags: - - "modules/local/panelcoverage" - - "subworkflows/local/bam_qc" - - "subworkflows/local/coverage" - - "subworkflows/local/fastq_to_aligned_cram" - - "subworkflows/local/fastq_align_rna" - - "subworkflows/local/fastq_to_unaligned_cram" - - "workflows/preprocessing" - - "pipeline" - profile: - - "test,docker" - steps: - - name: Check out pipeline code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - - - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 - with: - version: "${{ matrix.NXF_VER }}" - - - name: Disk space cleanup - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 - - - uses: actions/setup-python@v4 - with: - python-version: "3.11" - architecture: "x64" - - - name: Install pdiff to see diff between nf-test snapshots - run: | - python -m pip install --upgrade pip - pip install pdiff - - - name: Cache nf-test installation - id: cache-software - uses: actions/cache@v3 - with: - path: | - /usr/local/bin/nf-test - /home/runner/.nf-test/nf-test.jar - key: ${{ runner.os }}-${{ env.NFT_VER }}-nftest - - - name: Install nf-test - if: steps.cache-software.outputs.cache-hit != 'true' - run: | - wget -qO- https://code.askimed.com/install/nf-test | bash - sudo mv nf-test /usr/local/bin/ - - - name: Run nf-test - run: | - nf-test test --verbose --tag "${{ matrix.tags }}" --profile "+${{ matrix.profile }}" --junitxml=test.xml --tap=test.tap - - - uses: pcolby/tap-summary@v1 - with: - path: >- - test.tap - - - name: Output log on failure - if: failure() - run: | - sudo apt install bat > /dev/null - batcat --decorations=always --color=always ${{ github.workspace }}/.nf-test/tests/*/meta/nextflow.log - - - name: Publish Test Report - uses: mikepenz/action-junit-report@v3 - if: always() # always run even if the previous step fails - with: - report_paths: test.xml diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index 96b4ae4b..2288a9b9 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -23,6 +23,8 @@ env: NXF_ANSI_LOG: false NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity NXF_SINGULARITY_LIBRARYDIR: ${{ github.workspace }}/.singularity + AWS_ACCESS_KEY_ID: ${{ secrets.UGENT_S3_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.UGENT_S3_SECRET_KEY }} jobs: nf-test-changes: From 2accfb1abadfd20c77a611cf44ea78e3d2d9fa49 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 13:29:10 +0100 Subject: [PATCH 034/228] pre commit --- modules.json | 129 +++++++++++++-------------------------------------- 1 file changed, 32 insertions(+), 97 deletions(-) diff --git a/modules.json b/modules.json index 2d50f2d3..99e26ff2 100644 --- a/modules.json +++ b/modules.json @@ -8,204 +8,149 @@ "bcl2fastq": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": [ - "bcl_demultiplex" - ] + "installed_by": ["bcl_demultiplex"] }, "bclconvert": { "branch": "master", "git_sha": "27cceb2eb8aa959d4a8819caab886386a59a3789", - "installed_by": [ - "bcl_demultiplex", - "modules" - ] + "installed_by": ["bcl_demultiplex", "modules"] }, "biobambam/bamsormadup": { "branch": "master", "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, "bowtie2/align": { "branch": "master", "git_sha": "8864afe586537bf562eac7b83349c26207f3cb4d", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, "dragmap/align": { "branch": "master", "git_sha": "8864afe586537bf562eac7b83349c26207f3cb4d", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, "fastp": { "branch": "master", "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/fastp/fastp.diff" }, "fastqc": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "md5sum": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "mosdepth": { "branch": "master", "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, "multiqc": { "branch": "master", "git_sha": "471cf3ca1617271b9b6fea09ea2ebdee78b874de", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "picard/collecthsmetrics": { "branch": "master", "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, "samtools/cat": { "branch": "master", "git_sha": "b13f07be4c508d6ff6312d354d09f2493243e208", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/cat/samtools-cat.diff" }, "samtools/convert": { "branch": "master", "git_sha": "b13f07be4c508d6ff6312d354d09f2493243e208", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, "samtools/flagstat": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/idxstats": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/import": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/sormadup": { "branch": "master", "git_sha": "38f3b0200093498b70ac2d63a83eac5642e3c873", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, "samtools/sort": { "branch": "master", "git_sha": "b7800db9b069ed505db3f9d91b8c72faea9be17b", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "samtools/stats": { "branch": "master", "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, "snapaligner/align": { "branch": "master", "git_sha": "77bdd7e1047d2abe21ae8d89acc295ea553ecbae", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, "star/align": { "branch": "master", "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" } } @@ -215,41 +160,31 @@ "bcl_demultiplex": { "branch": "master", "git_sha": "1a0770da1cf5c5cd388bf888ba8798bc4d1fba56", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "fastq_align_dna": { "branch": "master", "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", - "installed_by": [ - "subworkflows" - ], + "installed_by": ["subworkflows"], "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] } } } } } -} \ No newline at end of file +} From c23343b6e07966d61cf1e8fee5877b8780133307 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 14:00:24 +0100 Subject: [PATCH 035/228] fix rocrate --- ro-crate-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index d3e36bec..1bcdab89 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -23,7 +23,7 @@ "@type": "Dataset", "creativeWorkStatus": "InProgress", "datePublished": "2025-11-13T15:11:21+00:00", - "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP) or [`snap`](https://github.com/amplab/snap) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag\nfc_sample1,test,Homo sapiens,WES\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP) or [`snap`](https://github.com/amplab/snap) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag\nfc_sample1,test,Homo sapiens,WES\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" From 9ed2cfa68605ae6e79840390a6cae36ab11acdb5 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 14:03:33 +0100 Subject: [PATCH 036/228] fix versions yaml name --- workflows/preprocessing.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 0753d6b5..68e017b1 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -447,7 +447,7 @@ workflow PREPROCESSING { // Collate and save software versions // softwareVersionsToYAML(ch_versions) - .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_pipeline_software_mqc_versions.yml', sort: true, newLine: true) + .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'preprocessing_software_mqc_versions.yml', sort: true, newLine: true) .set { ch_collated_versions } // From 52beab73c7a20dd3b1cfc01fc4c47c6737c330db Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 14:09:42 +0100 Subject: [PATCH 037/228] remove template tests and add outdir to existing pipeline tests --- tests/default.nf.test | 33 --------------------------------- tests/main.nf.test | 2 ++ 2 files changed, 2 insertions(+), 33 deletions(-) delete mode 100644 tests/default.nf.test diff --git a/tests/default.nf.test b/tests/default.nf.test deleted file mode 100644 index ea895f17..00000000 --- a/tests/default.nf.test +++ /dev/null @@ -1,33 +0,0 @@ -nextflow_pipeline { - - name "Test pipeline" - script "../main.nf" - tag "pipeline" - - test("-profile test") { - - when { - params { - outdir = "$outputDir" - } - } - - then { - // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) - // stable_path: All files in ${params.outdir}/ with stable content - def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') - assertAll( - { assert workflow.success}, - { assert snapshot( - // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions - removeNextflowVersion("$outputDir/pipeline_info/preprocessing_software_mqc_versions.yml"), - // All stable path name, with a relative path - stable_name, - // All files with stable contents - stable_path - ).match() } - ) - } - } -} diff --git a/tests/main.nf.test b/tests/main.nf.test index 14b7f084..6eb6875a 100644 --- a/tests/main.nf.test +++ b/tests/main.nf.test @@ -14,6 +14,7 @@ nextflow_pipeline { input = "${projectDir}/tests/inputs/fastq.yml" aligner = "bwamem" igenomes_base = "s3://reference-data/genomes" + outdir = "$outputDir" } } @@ -30,6 +31,7 @@ nextflow_pipeline { input = "${projectDir}/tests/inputs/flowcell.yml" aligner = "bwamem" igenomes_base = "s3://reference-data/genomes" + outdir = "$outputDir" } } From 605fb67032f5a9cbbe69a1ad9cc2c70c2e57e383 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 14:14:03 +0100 Subject: [PATCH 038/228] nft-utils -> 0.0.7 --- nf-test.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nf-test.config b/nf-test.config index 3a1fff59..fa368ccb 100644 --- a/nf-test.config +++ b/nf-test.config @@ -19,6 +19,6 @@ config { // load the necessary plugins plugins { - load "nft-utils@0.0.3" + load "nft-utils@0.0.7" } } From 7a9272b5300bddd70f615241d8019fcff64f9736 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 14:42:17 +0100 Subject: [PATCH 039/228] fix snapshot --- tests/workflows/preprocessing.nf.test.snap | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 8bd43a7e..36fadad2 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -618,11 +618,11 @@ "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,7b30e3b870fe318aeef6b4bffc51eb87", "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", "versions.yml:md5,ebdd9fe0c553612c66238375b920f178", "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" @@ -633,7 +633,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.0" }, - "timestamp": "2025-11-04T13:30:49.340803877" + "timestamp": "2025-11-21T14:24:42.558578431" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -944,10 +944,10 @@ "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,7b30e3b870fe318aeef6b4bffc51eb87", "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868" ] } @@ -956,7 +956,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.0" }, - "timestamp": "2025-11-04T13:36:14.450163857" + "timestamp": "2025-11-21T14:29:48.196853611" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1491,11 +1491,11 @@ "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,7b30e3b870fe318aeef6b4bffc51eb87", "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" ] @@ -1505,6 +1505,6 @@ "nf-test": "0.9.2", "nextflow": "25.10.0" }, - "timestamp": "2025-11-04T13:34:27.74379172" + "timestamp": "2025-11-21T14:28:06.35129428" } } \ No newline at end of file From ecc43058201400ce957b605763a08ab2e60eda2c Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 14:49:56 +0100 Subject: [PATCH 040/228] rename main test file --- tests/{main.nf.test => default.nf.test} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{main.nf.test => default.nf.test} (100%) diff --git a/tests/main.nf.test b/tests/default.nf.test similarity index 100% rename from tests/main.nf.test rename to tests/default.nf.test From cf529ea671d8ba3887babc9cf67628833d9d41ee Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 21 Nov 2025 15:02:16 +0100 Subject: [PATCH 041/228] final linting fix --- .nf-core.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.nf-core.yml b/.nf-core.yml index d4ae7ba5..dc7ee414 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -14,6 +14,7 @@ lint: - docs/images/nf-core-preprocessing_logo_light.png - docs/images/nf-core-preprocessing_logo_dark.png - .github/ISSUE_TEMPLATE/bug_report.yml + - .github/PULL_REQUEST_TEMPLATE.md - docs/README.md - LICENSE merge_markers: @@ -26,8 +27,6 @@ lint: template_strings: - bin/cmgg_genelists nf_test_content: false - subworkflow_changes: - - fastq_align_dna nf_core_version: 3.4.1 repository_type: pipeline template: From 37d3c30d46ff1cafc3c85456c3d3a702680f1908 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:34:38 +0100 Subject: [PATCH 042/228] update bcl-convert config for gcp --- conf/modules.config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 512adf84..750415bc 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -14,13 +14,13 @@ process { // BCL convert withName: BCLCONVERT { + cpus = 32 + memory = 64.GB ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", "--force", - "--bcl-num-parallel-tiles ${task.cpus}", - "--bcl-num-conversion-threads ${task.cpus}", - "--bcl-num-compression-threads ${task.cpus}", + "--strict", ].join(" ").trim() } } From 9c49fb1e8fafc5cf2623a1287076486699bffbac Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:48:05 +0100 Subject: [PATCH 043/228] add dynamic disk allocation --- conf/modules.config | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/modules.config b/conf/modules.config index 750415bc..97089065 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -16,6 +16,7 @@ process { withName: BCLCONVERT { cpus = 32 memory = 64.GB + disk = { 500.GB * task.attempt } ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", From 2d51974a2fbec03cd3ff97a89ebe09d85f3844b8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:17:19 +0100 Subject: [PATCH 044/228] increase mem --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 97089065..8a8a5c50 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -15,7 +15,7 @@ process { // BCL convert withName: BCLCONVERT { cpus = 32 - memory = 64.GB + memory = 128.GB disk = { 500.GB * task.attempt } ext.args = { [ From 8d95252a81f599f223a163a38e1b296936307af8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:20:12 +0100 Subject: [PATCH 045/228] fix linting --- .github/workflows/linting.yml | 6 +++--- .nf-core.yml | 2 +- .prettierignore | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 30e66026..7a527a34 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -11,7 +11,7 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Python 3.14 uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Install Nextflow uses: nf-core/setup-nextflow@v2 @@ -71,7 +71,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 with: name: linting-logs path: | diff --git a/.nf-core.yml b/.nf-core.yml index dc7ee414..ea3d4a79 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -27,7 +27,7 @@ lint: template_strings: - bin/cmgg_genelists nf_test_content: false -nf_core_version: 3.4.1 +nf_core_version: 3.5.1 repository_type: pipeline template: author: Matthias De Smet, Nicolas Vannieuwkerke diff --git a/.prettierignore b/.prettierignore index 2255e3e3..dd749d43 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,3 +12,5 @@ testing* bin/ .nf-test/ ro-crate-metadata.json +modules/nf-core/ +subworkflows/nf-core/ From c21d91a6be0247d7accb125ada1bef20a1b79c8c Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:39:00 +0100 Subject: [PATCH 046/228] bump bcl2fastq/bclconvert and subworkflow --- modules.json | 6 +- modules/nf-core/bcl2fastq/meta.yml | 89 +++-- modules/nf-core/bclconvert/Dockerfile | 4 +- modules/nf-core/bclconvert/main.nf | 59 ++- modules/nf-core/bclconvert/meta.yml | 92 ++--- modules/nf-core/bclconvert/tests/main.nf.test | 95 ++++- .../bclconvert/tests/main.nf.test.snap | 344 ++++++++++++++++-- .../nf-core/bclconvert/tests/nextflow.config | 11 +- .../bcl_demultiplex/tests/main.nf.test | 16 +- 9 files changed, 557 insertions(+), 159 deletions(-) diff --git a/modules.json b/modules.json index 99e26ff2..49345c50 100644 --- a/modules.json +++ b/modules.json @@ -7,12 +7,12 @@ "nf-core": { "bcl2fastq": { "branch": "master", - "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["bcl_demultiplex"] }, "bclconvert": { "branch": "master", - "git_sha": "27cceb2eb8aa959d4a8819caab886386a59a3789", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["bcl_demultiplex", "modules"] }, "biobambam/bamsormadup": { @@ -159,7 +159,7 @@ "nf-core": { "bcl_demultiplex": { "branch": "master", - "git_sha": "1a0770da1cf5c5cd388bf888ba8798bc4d1fba56", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["subworkflows"] }, "fastq_align_dna": { diff --git a/modules/nf-core/bcl2fastq/meta.yml b/modules/nf-core/bcl2fastq/meta.yml index a30a33ef..af17d591 100644 --- a/modules/nf-core/bcl2fastq/meta.yml +++ b/modules/nf-core/bcl2fastq/meta.yml @@ -21,80 +21,89 @@ input: type: file description: "Input samplesheet" pattern: "*.{csv}" + ontologies: + - edam: http://edamontology.org/format_3752 # CSV - run_dir: type: file description: | Input run directory containing RunInfo.xml and BCL data Could be a directory or a tar of the directory + ontologies: [] output: - - fastq: - - meta: - type: file - description: Demultiplexed sample FASTQ files - pattern: "**_S*_L00?_R?_00?.fastq.gz" + fastq: + - - meta: + type: map + description: Groovy Map containing sample information - output/**_S[1-9]*_R?_00?.fastq.gz: type: file description: Demultiplexed sample FASTQ files pattern: "**_S*_L00?_R?_00?.fastq.gz" - - fastq_idx: - - meta: - type: file - description: Optional demultiplexed index FASTQ files - pattern: "**_S*_L00?_I?_00?.fastq.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + fastq_idx: + - - meta: + type: map + description: Groovy Map containing sample information - output/**_S[1-9]*_I?_00?.fastq.gz: type: file description: Optional demultiplexed index FASTQ files pattern: "**_S*_L00?_I?_00?.fastq.gz" - - undetermined: - - meta: - type: file - description: Optional undetermined sample FASTQ files - pattern: "Undetermined_S0_L00?_R?_00?.fastq.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + undetermined: + - - meta: + type: map + description: Groovy Map containing sample information - output/**Undetermined_S0*_R?_00?.fastq.gz: type: file description: Optional undetermined sample FASTQ files pattern: "Undetermined_S0_L00?_R?_00?.fastq.gz" - - undetermined_idx: - - meta: - type: file - description: Optional undetermined index FASTQ files - pattern: "Undetermined_S0_L00?_I?_00?.fastq.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + undetermined_idx: + - - meta: + type: map + description: Groovy Map containing sample information - output/**Undetermined_S0*_I?_00?.fastq.gz: type: file description: Optional undetermined index FASTQ files pattern: "Undetermined_S0_L00?_I?_00?.fastq.gz" - - reports: - - meta: - type: file - description: Demultiplexing Reports - pattern: "Reports/*" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + reports: + - - meta: + type: map + description: Groovy Map containing sample information - output/Reports: type: file description: Demultiplexing Reports pattern: "Reports/*" - - stats: - - meta: - type: file - description: Statistics files - pattern: "Stats/*" + ontologies: [] + stats: + - - meta: + type: map + description: Groovy Map containing sample information - output/Stats: type: file description: Statistics files pattern: "Stats/*" - - interop: - - meta: - type: file - description: Interop files - pattern: "*.{bin}" + ontologies: [] + interop: + - - meta: + type: map + description: Groovy Map containing sample information - InterOp/*.bin: type: file description: Interop files pattern: "*.{bin}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/bclconvert/Dockerfile b/modules/nf-core/bclconvert/Dockerfile index 441ebc2f..eda84168 100644 --- a/modules/nf-core/bclconvert/Dockerfile +++ b/modules/nf-core/bclconvert/Dockerfile @@ -3,7 +3,7 @@ # Push to nfcore/bclconvert: FROM debian:bullseye-slim -ARG BCLCONVERT_VERSION="4.3.13" +ARG BCLCONVERT_VERSION="4.4.6" LABEL org.opencontainers.image.description="Docker image containing bcl-convert" LABEL org.opencontainers.image.version="$BCLCONVERT_VERSION" LABEL org.opencontainers.image.documentation="https://github.com/nf-core/modules/blob/master/modules/nf-core/bclconvert/README.md" @@ -24,7 +24,7 @@ RUN apt-get update \ # Link hostname cmd to fix hardcoded path RUN ln -s /bin/hostname /usr/bin/hostname # Install bcl-convert -ADD bcl-convert-4.3.13-2.el7.x86_64.rpm bcl-convert.rpm +COPY bcl-convert-4.4.6-2.el8.x86_64.rpm bcl-convert.rpm SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN rpm2cpio bcl-convert.rpm | cpio -idmv \ && rm bcl-convert.rpm diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index a9bc0197..82ad6b19 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -2,20 +2,20 @@ process BCLCONVERT { tag {"$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } label 'process_high' - container "nf-core/bclconvert:4.3.13" + container "nf-core/bclconvert:4.4.6" input: tuple val(meta), path(samplesheet), path(run_dir) output: - tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq - tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , optional:true, emit: fastq_idx - tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz") , optional:true, emit: undetermined - tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz") , optional:true, emit: undetermined_idx - tuple val(meta), path("output/Reports") , emit: reports - tuple val(meta), path("output/Logs") , emit: logs - tuple val(meta), path("**/InterOp/*.bin", includeInputs: true), emit: interop - path("versions.yml") , emit: versions + tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq + tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true + tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true + tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true + tuple val(meta), path("output/Reports") , emit: reports + tuple val(meta), path("output/Logs") , emit: logs + tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true + path("versions.yml") , emit: versions when: task.ext.when == null || task.ext.when @@ -62,9 +62,50 @@ process BCLCONVERT { --bcl-input-directory ${input_dir} \\ --sample-sheet ${samplesheet} + # copy the InterOp folder contents to ensure it gets picked up when using fusion + mkdir -p output/InterOp/ + cp -n **/InterOp/*.bin output/InterOp/ + cat <<-END_VERSIONS > versions.yml "${task.process}": bclconvert: \$(bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //') END_VERSIONS """ + + stub: + """ + mkdir -p output/Reports + mkdir -p output/Logs + echo "" | gzip > output/Sample1_S1_L001_R1_001.fastq.gz + echo "" | gzip > output/Undetermined_S0_L001_R1_001.fastq.gz + touch output/Reports/Adapter_Cycle_Metrics.csv + touch output/Reports/Adapter_Metrics.csv + touch output/Reports/Demultiplex_Stats.csv + touch output/Reports/Demultiplex_Tile_Stats.csv + touch output/Reports/fastq_list.csv + touch output/Reports/Index_Hopping_Counts.csv + touch output/Reports/IndexMetricsOut.bin + touch output/Reports/Quality_Metrics.csv + touch output/Reports/Quality_Tile_Metrics.csv + touch output/Reports/RunInfo.xml + touch output/Reports/SampleSheet.csv + touch output/Reports/Top_Unknown_Barcodes.csv + touch output/Logs/Errors.log + touch output/Logs/FastqComplete.log + touch output/Logs/Info.log + touch output/Logs/Warnings.log + mkdir -p output/InterOp + touch output/InterOp/ControlMetricsOut.bin + touch output/InterOp/CorrectedIntMetricsOut.bin + touch output/InterOp/ErrorMetricsOut.bin + touch output/InterOp/ExtractionMetricsOut.bin + touch output/InterOp/IndexMetricsOut.bin + touch output/InterOp/QMetricsOut.bin + touch output/InterOp/TileMetricsOut.bin + cat <<-END_VERSIONS > versions.yml + "${task.process}": + bclconvert: \$(bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //') + END_VERSIONS + """ + } diff --git a/modules/nf-core/bclconvert/meta.yml b/modules/nf-core/bclconvert/meta.yml index f40c8768..e1cd3e01 100644 --- a/modules/nf-core/bclconvert/meta.yml +++ b/modules/nf-core/bclconvert/meta.yml @@ -30,66 +30,50 @@ input: Could be a directory or a tar of the directory ontologies: [] output: - - fastq: - - meta: - type: file - description: Demultiplexed sample FASTQ files - pattern: "**_S*_L00?_R?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + fastq: + - - meta: + type: map + description: Groovy Map containing sample information - output/**_S[1-9]*_R?_00?.fastq.gz: type: file description: Demultiplexed sample FASTQ files pattern: "**_S*_L00?_R?_00?.fastq.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format - - fastq_idx: - - meta: - type: file - description: Optional demultiplexed index FASTQ files - pattern: "**_S*_L00?_I?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + fastq_idx: + - - meta: + type: map + description: Groovy Map containing sample information - output/**_S[1-9]*_I?_00?.fastq.gz: type: file description: Optional demultiplexed index FASTQ files pattern: "**_S*_L00?_I?_00?.fastq.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format - - undetermined: - - meta: - type: file - description: Optional undetermined sample FASTQ files - pattern: "Undetermined_S0_L00?_R?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + undetermined: + - - meta: + type: map + description: Groovy Map containing sample information - output/**Undetermined_S0*_R?_00?.fastq.gz: type: file description: Optional undetermined sample FASTQ files pattern: "Undetermined_S0_L00?_R?_00?.fastq.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format - - undetermined_idx: - - meta: - type: file - description: Optional undetermined index FASTQ files - pattern: "Undetermined_S0_L00?_I?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + undetermined_idx: + - - meta: + type: map + description: Groovy Map containing sample information - output/**Undetermined_S0*_I?_00?.fastq.gz: type: file description: Optional undetermined index FASTQ files pattern: "Undetermined_S0_L00?_I?_00?.fastq.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format - - reports: - - meta: - type: file - description: Demultiplexing Reports - pattern: "Reports/*.{csv,xml}" - ontologies: - - edam: http://edamontology.org/format_3752 # CSV - - edam: http://edamontology.org/format_2332 # XML + reports: + - - meta: + type: map + description: Groovy Map containing sample information - output/Reports: type: file description: Demultiplexing Reports @@ -97,35 +81,31 @@ output: ontologies: - edam: http://edamontology.org/format_3752 # CSV - edam: http://edamontology.org/format_2332 # XML - - logs: - - meta: - type: file - description: Log files - pattern: "Logs/*.{log,txt}" - ontologies: [] + logs: + - - meta: + type: map + description: Groovy Map containing sample information - output/Logs: type: file description: Log files pattern: "Logs/*.{log,txt}" ontologies: [] - - interop: - - meta: - type: file - description: Interop files - pattern: "*.{bin}" - ontologies: [] - - "**/InterOp/*.bin": + interop: + - - meta: + type: map + description: Groovy Map containing sample information + - "output/InterOp/*.bin": type: file description: Interop files pattern: "*.{bin}" ontologies: [] - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/bclconvert/tests/main.nf.test b/modules/nf-core/bclconvert/tests/main.nf.test index b246be20..b2971c02 100644 --- a/modules/nf-core/bclconvert/tests/main.nf.test +++ b/modules/nf-core/bclconvert/tests/main.nf.test @@ -4,14 +4,17 @@ nextflow_process { script "../main.nf" process "BCLCONVERT" config "./nextflow.config" + tag "bclconvert" tag "modules" tag "modules_nfcore" - test("homo sapiens illumina [bcl]") { + test("homo_sapiens illumina [bcl]") { when { + params { + module_args = "--force --first-tile-only true" + } process { - //TODO use new test dataset when available, see https://github.com/nf-core/test-datasets/issues/996 """ input[0] = [ [ id: 'test', lane:1 ], @@ -26,16 +29,88 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( + process.out.fastq, + process.out.fastq_idx, + process.out.undetermined.collect { meta, fastq -> file(fastq).name }, + process.out.undetermined_idx, process.out.reports, + process.out.logs.collect { meta, logs -> file(logs).list().sort() }, + process.out.interop.collect { meta, interop -> + interop.findAll { interopfile -> + file(interopfile).name != "IndexMetricsOut.bin" } }, process.out.versions, - process.out.fastq, - file(process.out.logs.get(0).get(1)).list().sort(), - process.out.interop.get(0).get(1).findAll { file(it).name != "IndexMetricsOut.bin" }, - ).match() - }, - { assert process.out.undetermined.get(0).get(1) ==~ ".*/Undetermined_S0_L001_R1_001.fastq.gz"}, - { assert file(process.out.interop.get(0).get(1).find { file(it).name == "IndexMetricsOut.bin" }).exists() } + path(process.out.versions[0]).yaml + ).match() } + ) + } + } + + test("sars_cov2 illumina [bcl]") { + when { + params { + module_args = "--force --tiles s_1_2101" + } + process { + """ + input[0] = [ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bcl/SampleSheet.csv', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bcl/200624_A00834_0183_BHMTFYDRXX.tar.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.fastq.collect { + meta, fastqs -> + fastqs.findAll { + fastqfile -> + file(fastqfile).name != "SampleZ_S5_L001_R1_001.fastq.gz" + } + }, + process.out.fastq_idx, + process.out.undetermined.collect { meta, fastq -> file(fastq).name }, + process.out.undetermined_idx, + process.out.reports, + process.out.logs.collect { meta, logs -> file(logs).list().sort() }, + process.out.interop, + process.out.interop.collect { meta, interop -> + interop.findAll { interopfile -> + file(interopfile).name != "IndexMetricsOut.bin" } }, + process.out.versions, + path(process.out.versions[0]).yaml + ).match() } + ) + } + } + + test("homo_sapiens illumina [bcl] - stub") { + options "-stub" + + when { + params { + module_args = "--force --first-tile-only true" + } + process { + """ + input[0] = [ + [ id: 'test', lane:1 ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bcl/flowcell_samplesheet.csv', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bcl/flowcell.tar.gz', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } ) } } -} \ No newline at end of file +} diff --git a/modules/nf-core/bclconvert/tests/main.nf.test.snap b/modules/nf-core/bclconvert/tests/main.nf.test.snap index 0c366a2d..b7838a5e 100644 --- a/modules/nf-core/bclconvert/tests/main.nf.test.snap +++ b/modules/nf-core/bclconvert/tests/main.nf.test.snap @@ -1,6 +1,303 @@ { - "homo sapiens illumina [bcl]": { + "sars_cov2 illumina [bcl]": { + "content": [ + [ + [ + "Sample1_S1_L001_R1_001.fastq.gz:md5,b5489d1964db8db5502eb742cc3ef3ec", + "Sample23_S3_L001_R1_001.fastq.gz:md5,767a1091320320b140288066e29bccc5", + "SampleA_S2_L001_R1_001.fastq.gz:md5,7de2ea88133409f34563f40a0d8c9e55", + "sampletest_S4_L001_R1_001.fastq.gz:md5,c16c7de1b7bffb5e4503f4d94c40f881" + ] + ], + [ + + ], + [ + "Undetermined_S0_L001_R1_001.fastq.gz" + ], + [ + + ], + [ + [ + { + "id": "test" + }, + [ + "Adapter_Cycle_Metrics.csv:md5,05fbe7b2b0acdd557d355b448aa88ace", + "Adapter_Metrics.csv:md5,0fa4ac708955417af9d18cec4955552f", + "Demultiplex_Detailed_Stats.csv:md5,5a6a4d66a96256ff71e4f649927fb112", + "Demultiplex_Stats.csv:md5,4a3f451faa098156623b55b0f2ff27ee", + "Demultiplex_Tile_Stats.csv:md5,f91fb0c7a2c5588ed43c7f9145d004ee", + "IndexMetricsOut.bin:md5,fb16c8a9873e5b5950ae5949126af76c", + "Index_Hopping_Counts.csv:md5,f59474d96afe8218c7590bb240b19690", + "Quality_Metrics.csv:md5,c4622066f85d93b1661c928a46cfc508", + "Quality_Tile_Metrics.csv:md5,e22bc5e2f147695150b02afcccb38c4f", + "RunInfo.xml:md5,f283cb4600235db9261ee1e319b1407e", + "SampleSheet.csv:md5,4113eabae23136cc819c7f15ac5b6aad", + "Top_Unknown_Barcodes.csv:md5,37dbc2860c640fc721820b0217ea0504", + "fastq_list.csv:md5,482cf7fe9b304a900e4ede3bb25b4912" + ] + ] + ], + [ + [ + "Errors.log", + "FastqComplete.txt", + "Info.log", + "Warnings.log" + ] + ], + [ + [ + { + "id": "test" + }, + [ + "BasecallingMetricsOut.bin:md5,7fb651325cba614d497d376eaf43fef4", + "CorrectedIntMetricsOut.bin:md5,dc8d57282ba9ece9e5fc58a92aa2ac52", + "EmpiricalPhasingMetricsOut.bin:md5,1ef4631faf0a3a3beb31b10fc38a734d", + "EventMetricsOut.bin:md5,dee320ce29bdadde44589aa9439f53ab", + "ExtendedTileMetricsOut.bin:md5,f01d1a9cf8445adf719e652ad7304cf2", + "ExtractionMetricsOut.bin:md5,972f4082ad950baaf42a6d28517d28a8", + "FWHMGridMetricsOut.bin:md5,6e297bafcd845bfd0440d08e1bb27685", + "ImageMetricsOut.bin:md5,ac5d1f0a1f611c0c7c9dd8e6b9e701b1", + "IndexMetricsOut.bin:md5,6d95975d5909eb88f824e6dc8066457d", + "OpticalModelMetricsOut.bin:md5,3eaea5fcf2d353950b1e720c73695ccb", + "PFGridMetricsOut.bin:md5,ae469858ee96ffafbcaf3afb814bdab2", + "QMetrics2030Out.bin:md5,438248760db58917b32f4eccc6c64c39", + "QMetricsByLaneOut.bin:md5,e8254cb4a27846710a2a143296be2d8f", + "QMetricsOut.bin:md5,8f6b83028a42be721200a598161ac5c6", + "RegistrationMetricsOut.bin:md5,b5ebd957aed067b6403d851ba2ce0139", + "TileMetricsOut.bin:md5,21388348d81fa9be326d30ef6d348464" + ] + ] + ], + [ + [ + "BasecallingMetricsOut.bin:md5,7fb651325cba614d497d376eaf43fef4", + "CorrectedIntMetricsOut.bin:md5,dc8d57282ba9ece9e5fc58a92aa2ac52", + "EmpiricalPhasingMetricsOut.bin:md5,1ef4631faf0a3a3beb31b10fc38a734d", + "EventMetricsOut.bin:md5,dee320ce29bdadde44589aa9439f53ab", + "ExtendedTileMetricsOut.bin:md5,f01d1a9cf8445adf719e652ad7304cf2", + "ExtractionMetricsOut.bin:md5,972f4082ad950baaf42a6d28517d28a8", + "FWHMGridMetricsOut.bin:md5,6e297bafcd845bfd0440d08e1bb27685", + "ImageMetricsOut.bin:md5,ac5d1f0a1f611c0c7c9dd8e6b9e701b1", + "OpticalModelMetricsOut.bin:md5,3eaea5fcf2d353950b1e720c73695ccb", + "PFGridMetricsOut.bin:md5,ae469858ee96ffafbcaf3afb814bdab2", + "QMetrics2030Out.bin:md5,438248760db58917b32f4eccc6c64c39", + "QMetricsByLaneOut.bin:md5,e8254cb4a27846710a2a143296be2d8f", + "QMetricsOut.bin:md5,8f6b83028a42be721200a598161ac5c6", + "RegistrationMetricsOut.bin:md5,b5ebd957aed067b6403d851ba2ce0139", + "TileMetricsOut.bin:md5,21388348d81fa9be326d30ef6d348464" + ] + ], + [ + "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" + ], + { + "BCLCONVERT": { + "bclconvert": "4.4.6" + } + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-23T10:12:42.943671245" + }, + "homo_sapiens illumina [bcl] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "lane": 1 + }, + "Sample1_S1_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "lane": 1 + }, + "Undetermined_S0_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "3": [ + + ], + "4": [ + [ + { + "id": "test", + "lane": 1 + }, + [ + "Adapter_Cycle_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Adapter_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Demultiplex_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Demultiplex_Tile_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "Index_Hopping_Counts.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Quality_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Quality_Tile_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "RunInfo.xml:md5,d41d8cd98f00b204e9800998ecf8427e", + "SampleSheet.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Top_Unknown_Barcodes.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "fastq_list.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "5": [ + [ + { + "id": "test", + "lane": 1 + }, + [ + "Errors.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "FastqComplete.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "Info.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "Warnings.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "lane": 1 + }, + [ + "ControlMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "CorrectedIntMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "ErrorMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "ExtractionMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "QMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "TileMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "7": [ + "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" + ], + "fastq": [ + [ + { + "id": "test", + "lane": 1 + }, + "Sample1_S1_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "fastq_idx": [ + + ], + "interop": [ + [ + { + "id": "test", + "lane": 1 + }, + [ + "ControlMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "CorrectedIntMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "ErrorMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "ExtractionMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "QMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "TileMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "logs": [ + [ + { + "id": "test", + "lane": 1 + }, + [ + "Errors.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "FastqComplete.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "Info.log:md5,d41d8cd98f00b204e9800998ecf8427e", + "Warnings.log:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "reports": [ + [ + { + "id": "test", + "lane": 1 + }, + [ + "Adapter_Cycle_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Adapter_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Demultiplex_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Demultiplex_Tile_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", + "Index_Hopping_Counts.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Quality_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Quality_Tile_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "RunInfo.xml:md5,d41d8cd98f00b204e9800998ecf8427e", + "SampleSheet.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "Top_Unknown_Barcodes.csv:md5,d41d8cd98f00b204e9800998ecf8427e", + "fastq_list.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "undetermined": [ + [ + { + "id": "test", + "lane": 1 + }, + "Undetermined_S0_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "undetermined_idx": [ + + ], + "versions": [ + "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-23T10:12:55.362214653" + }, + "homo_sapiens illumina [bcl]": { "content": [ + [ + [ + { + "id": "test", + "lane": 1 + }, + "Sample1_S1_L001_R1_001.fastq.gz:md5,0675fb6365322eaafb33c0f8e862b54b" + ] + ], + [ + + ], + [ + "Undetermined_S0_L001_R1_001.fastq.gz" + ], + [ + + ], [ [ { @@ -10,8 +307,9 @@ [ "Adapter_Cycle_Metrics.csv:md5,5a0c88793b4a0885fe3dda16609b576e", "Adapter_Metrics.csv:md5,989240b8840b2169ac1061f952c90f6c", + "Demultiplex_Detailed_Stats.csv:md5,fda7961f2958545daa94b55b84c99eb1", "Demultiplex_Stats.csv:md5,93949a8cd96f907d83e0808c1ec2a04b", - "Demultiplex_Tile_Stats.csv:md5,83120160b0f22a1303fa1db31c19f6e9", + "Demultiplex_Tile_Stats.csv:md5,d966f774c438485907ae22ac34b85722", "IndexMetricsOut.bin:md5,9e688c58a5487b8eaf69c9e1005ad0bf", "Index_Hopping_Counts.csv:md5,1059369e375fd8f8423c0f6c934be978", "Quality_Metrics.csv:md5,6614accb1bb414fe312b17b81f5521f7", @@ -24,36 +322,36 @@ ] ], [ - "versions.yml:md5,3a54ec728e3eb67bfd5af57ebd36ccab" + [ + "Errors.log", + "FastqComplete.txt", + "Info.log", + "Warnings.log" + ] ], [ [ - { - "id": "test", - "lane": 1 - }, - "Sample1_S1_L001_R1_001.fastq.gz:md5,0675fb6365322eaafb33c0f8e862b54b" + "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", + "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", + "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", + "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", + "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", + "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" ] ], [ - "Errors.log", - "FastqComplete.txt", - "Info.log", - "Warnings.log" + "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" ], - [ - "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", - "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", - "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", - "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", - "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", - "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" - ] + { + "BCLCONVERT": { + "bclconvert": "4.4.6" + } + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-06-02T12:35:36.967547" + "timestamp": "2025-09-23T10:12:18.369689549" } -} +} \ No newline at end of file diff --git a/modules/nf-core/bclconvert/tests/nextflow.config b/modules/nf-core/bclconvert/tests/nextflow.config index 344f4720..848581b5 100644 --- a/modules/nf-core/bclconvert/tests/nextflow.config +++ b/modules/nf-core/bclconvert/tests/nextflow.config @@ -1,10 +1,5 @@ process { - - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - - ext.args = {[ - meta.lane ? "--bcl-only-lane ${meta.lane}" : "", - "--force", - "--first-tile-only true" - ].join(" ").trim()} + withName: "BCLCONVERT" { + ext.args = params.module_args + } } diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test index e1fb00ab..65a158e9 100644 --- a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test +++ b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test @@ -34,13 +34,13 @@ nextflow_workflow { { assert snapshot( sanitizeOutput(workflow.out, unstableKeys: ["empty_fastq", "logs"]).collectEntries { key, val -> if (key == "interop") { - return [ key, val.collect { meta, files -> - [ + return [ key, val.collect { meta, files -> + [ meta, - files.collect { interop_file -> + files.collect { interop_file -> if (interop_file.endsWith("IndexMetricsOut.bin")) { file(interop_file).name - } else { + } else { interop_file } } @@ -77,13 +77,13 @@ nextflow_workflow { { assert snapshot( sanitizeOutput(workflow.out).collectEntries { key, val -> if (key == "interop") { - return [ key, val.collect { meta, files -> - [ + return [ key, val.collect { meta, files -> + [ meta, - files.collect { interop_file -> + files.collect { interop_file -> if (interop_file.endsWith("IndexMetricsOut.bin")) { file(interop_file).name - } else { + } else { interop_file } } From 2676acf537a09a925a30871596bf998f2f5f6e0e Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:39:53 +0100 Subject: [PATCH 047/228] bump bamsormadup --- modules.json | 2 +- .../bamsormadup/biobambam-bamsormadup.diff | 2 +- .../biobambam/bamsormadup/environment.yml | 2 ++ .../nf-core/biobambam/bamsormadup/meta.yml | 34 ++++++++++++------- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/modules.json b/modules.json index 49345c50..5ba03302 100644 --- a/modules.json +++ b/modules.json @@ -17,7 +17,7 @@ }, "biobambam/bamsormadup": { "branch": "master", - "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, diff --git a/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff b/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff index 749067c4..9c5a8c3e 100644 --- a/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff +++ b/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff @@ -1,4 +1,4 @@ -Changes in module 'nf-core/biobambam/bamsormadup' +Changes in component 'nf-core/biobambam/bamsormadup' 'modules/nf-core/biobambam/bamsormadup/environment.yml' is unchanged 'modules/nf-core/biobambam/bamsormadup/meta.yml' is unchanged Changes in 'biobambam/bamsormadup/main.nf': diff --git a/modules/nf-core/biobambam/bamsormadup/environment.yml b/modules/nf-core/biobambam/bamsormadup/environment.yml index eb19895a..8c8c3166 100644 --- a/modules/nf-core/biobambam/bamsormadup/environment.yml +++ b/modules/nf-core/biobambam/bamsormadup/environment.yml @@ -1,3 +1,5 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda diff --git a/modules/nf-core/biobambam/bamsormadup/meta.yml b/modules/nf-core/biobambam/bamsormadup/meta.yml index cfd09d87..a863c54a 100644 --- a/modules/nf-core/biobambam/bamsormadup/meta.yml +++ b/modules/nf-core/biobambam/bamsormadup/meta.yml @@ -23,6 +23,7 @@ input: - bams: type: file description: List containing 1 or more bam files + ontologies: [] - - meta2: type: map description: | @@ -32,9 +33,10 @@ input: type: file description: Reference genome in FASTA format (optional) pattern: "*.{fa,fasta,fna}" + ontologies: [] output: - - bam: - - meta: + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -43,8 +45,9 @@ output: type: file description: BAM file with duplicate reads marked/removed pattern: "*.bam" - - bam_index: - - meta: + ontologies: [] + bam_index: + - - meta: type: map description: | Groovy Map containing sample information @@ -53,8 +56,9 @@ output: type: file description: BAM index file pattern: "*.bai" - - cram: - - meta: + ontologies: [] + cram: + - - meta: type: map description: | Groovy Map containing sample information @@ -63,8 +67,9 @@ output: type: file description: CRAM file with duplicate reads marked/removed pattern: "*.cram" - - metrics: - - meta: + ontologies: [] + metrics: + - - meta: type: map description: | Groovy Map containing sample information @@ -73,11 +78,14 @@ output: type: file description: Duplicate metrics file generated by biobambam pattern: "*.{metrics.txt}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: From a9d31ad3016aabddace60f3d600d34f8924cc3e2 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:07:04 +0100 Subject: [PATCH 048/228] bump aligners, add strobealign --- README.md | 2 +- assets/schema_input.json | 2 +- assets/schema_sampleinfo.json | 2 +- modules.json | 17 +- modules/nf-core/bowtie2/align/meta.yml | 106 +++--- .../bowtie2/align/tests/large_index.config | 2 +- .../nf-core/bowtie2/align/tests/sam.config | 2 +- .../nf-core/bowtie2/align/tests/sam2.config | 2 +- modules/nf-core/bwa/mem/environment.yml | 6 +- modules/nf-core/bwa/mem/main.nf | 4 +- modules/nf-core/bwa/mem/meta.yml | 53 +-- .../nf-core/bwa/mem/tests/main.nf.test.snap | 56 ++-- modules/nf-core/bwamem2/mem/environment.yml | 6 +- modules/nf-core/bwamem2/mem/main.nf | 4 +- modules/nf-core/bwamem2/mem/meta.yml | 42 +-- .../bwamem2/mem/tests/main.nf.test.snap | 40 +-- modules/nf-core/dragmap/align/meta.yml | 58 ++-- .../nf-core/snapaligner/align/environment.yml | 3 +- modules/nf-core/snapaligner/align/main.nf | 4 +- modules/nf-core/snapaligner/align/meta.yml | 25 +- .../snapaligner/align/tests/main.nf.test | 4 +- .../snapaligner/align/tests/main.nf.test.snap | 32 +- modules/nf-core/strobealign/environment.yml | 9 + modules/nf-core/strobealign/main.nf | 108 +++++++ modules/nf-core/strobealign/meta.yml | 142 ++++++++ .../nf-core/strobealign/tests/main.nf.test | 303 ++++++++++++++++++ .../strobealign/tests/main.nf.test.snap | 274 ++++++++++++++++ .../nf-core/strobealign/tests/nextflow.config | 6 + nextflow_schema.json | 2 +- subworkflows/nf-core/fastq_align_dna/main.nf | 24 +- subworkflows/nf-core/fastq_align_dna/meta.yml | 3 + .../fastq_align_dna/tests/main.nf.test | 41 +++ .../fastq_align_dna/tests/main.nf.test.snap | 144 +++++++-- .../fastq_align_dna/tests/nextflow.config | 12 - 34 files changed, 1278 insertions(+), 262 deletions(-) create mode 100644 modules/nf-core/strobealign/environment.yml create mode 100644 modules/nf-core/strobealign/main.nf create mode 100644 modules/nf-core/strobealign/meta.yml create mode 100644 modules/nf-core/strobealign/tests/main.nf.test create mode 100644 modules/nf-core/strobealign/tests/main.nf.test.snap create mode 100644 modules/nf-core/strobealign/tests/nextflow.config delete mode 100644 subworkflows/nf-core/fastq_align_dna/tests/nextflow.config diff --git a/README.md b/README.md index 7a23f1d2..5bbc40e9 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Steps inlcude: 1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html) 2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp) -3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP) or [`snap`](https://github.com/amplab/snap) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq +3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq 4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html) 5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html) 6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics) diff --git a/assets/schema_input.json b/assets/schema_input.json index e0ba1632..deb42ab7 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -37,7 +37,7 @@ "meta": ["aligner"], "type": "string", "description": "Aligner to use to align sample to the reference genome", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "star"] + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star"] }, "tag": { "meta": ["tag"], diff --git a/assets/schema_sampleinfo.json b/assets/schema_sampleinfo.json index b9c8aaf3..c5443971 100644 --- a/assets/schema_sampleinfo.json +++ b/assets/schema_sampleinfo.json @@ -85,7 +85,7 @@ "meta": ["aligner"], "type": "string", "description": "Aligner to use to align sample to the reference genome", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "star"] + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star"] } } }, diff --git a/modules.json b/modules.json index 5ba03302..cd0c8667 100644 --- a/modules.json +++ b/modules.json @@ -23,25 +23,25 @@ }, "bowtie2/align": { "branch": "master", - "git_sha": "8864afe586537bf562eac7b83349c26207f3cb4d", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", - "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", + "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", - "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", + "git_sha": "d86336f3e7ae0d5f76c67b0859409769cfeb2af2", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, "dragmap/align": { "branch": "master", - "git_sha": "8864afe586537bf562eac7b83349c26207f3cb4d", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, @@ -143,7 +143,7 @@ }, "snapaligner/align": { "branch": "master", - "git_sha": "77bdd7e1047d2abe21ae8d89acc295ea553ecbae", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, @@ -152,6 +152,11 @@ "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" + }, + "strobealign": { + "branch": "master", + "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", + "installed_by": ["_", "a", "d", "f", "g", "i", "l", "n", "q", "s", "t"] } } }, @@ -164,7 +169,7 @@ }, "fastq_align_dna": { "branch": "master", - "git_sha": "a29f18660f5e3748d44d6f716241e70c942c065d", + "git_sha": "070ddae7fb59384d3d85bf69eb9a1d71ab33ada9", "installed_by": ["subworkflows"], "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" }, diff --git a/modules/nf-core/bowtie2/align/meta.yml b/modules/nf-core/bowtie2/align/meta.yml index 7436097b..0c12b28a 100644 --- a/modules/nf-core/bowtie2/align/meta.yml +++ b/modules/nf-core/bowtie2/align/meta.yml @@ -14,7 +14,7 @@ tools: sequencing reads to long reference sequences. homepage: http://bowtie-bio.sourceforge.net/bowtie2/index.shtml documentation: http://bowtie-bio.sourceforge.net/bowtie2/manual.shtml - doi: 10.1038/nmeth.1923 + doi: 10.1186/gb-2009-10-3-r25 licence: ["GPL-3.0-or-later"] identifier: "" input: @@ -28,6 +28,7 @@ input: description: | List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. + ontologies: [] - - meta2: type: map description: | @@ -37,6 +38,7 @@ input: type: file description: Bowtie2 genome index files pattern: "*.ebwt" + ontologies: [] - - meta3: type: map description: | @@ -46,84 +48,88 @@ input: type: file description: Bowtie2 genome fasta file pattern: "*.fasta" - - - save_unaligned: - type: boolean - description: | - Save reads that do not map to the reference (true) or discard them (false) - (default: false) - - - sort_bam: - type: boolean - description: use samtools sort (true) or samtools view (false) - pattern: "true or false" + ontologies: [] + - save_unaligned: + type: boolean + description: | + Save reads that do not map to the reference (true) or discard them (false) + (default: false) + - sort_bam: + type: boolean + description: use samtools sort (true) or samtools view (false) + pattern: "true or false" output: - - sam: - - meta: - type: file - description: Output SAM file containing read alignments - pattern: "*.sam" + sam: + - - meta: + type: map + description: Groovy Map containing sample information - "*.sam": type: file description: Output SAM file containing read alignments pattern: "*.sam" - - bam: - - meta: - type: file - description: Output BAM file containing read alignments - pattern: "*.bam" + ontologies: [] + bam: + - - meta: + type: map + description: Groovy Map containing sample information - "*.bam": type: file description: Output BAM file containing read alignments pattern: "*.bam" - - cram: - - meta: - type: file - description: Output CRAM file containing read alignments - pattern: "*.cram" + ontologies: [] + cram: + - - meta: + type: map + description: Groovy Map containing sample information - "*.cram": type: file description: Output CRAM file containing read alignments pattern: "*.cram" - - csi: - - meta: - type: file - description: Output SAM/BAM index for large inputs - pattern: "*.csi" + ontologies: [] + csi: + - - meta: + type: map + description: Groovy Map containing sample information - "*.csi": type: file description: Output SAM/BAM index for large inputs pattern: "*.csi" - - crai: - - meta: - type: file - description: Output CRAM index - pattern: "*.crai" + ontologies: [] + crai: + - - meta: + type: map + description: Groovy Map containing sample information - "*.crai": type: file description: Output CRAM index pattern: "*.crai" - - log: - - meta: - type: file - description: Alignment log - pattern: "*.log" + ontologies: [] + log: + - - meta: + type: map + description: Groovy Map containing sample information - "*.log": type: file description: Alignment log pattern: "*.log" - - fastq: - - meta: - type: file - description: Unaligned FastQ files - pattern: "*.fastq.gz" + ontologies: [] + fastq: + - - meta: + type: map + description: Groovy Map containing sample information - "*fastq.gz": type: file description: Unaligned FastQ files pattern: "*.fastq.gz" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@joseespinosa" - "@drpatelh" diff --git a/modules/nf-core/bowtie2/align/tests/large_index.config b/modules/nf-core/bowtie2/align/tests/large_index.config index fdc1c59d..b2f0c405 100644 --- a/modules/nf-core/bowtie2/align/tests/large_index.config +++ b/modules/nf-core/bowtie2/align/tests/large_index.config @@ -2,4 +2,4 @@ process { withName: BOWTIE2_BUILD { ext.args = '--large-index' } -} \ No newline at end of file +} diff --git a/modules/nf-core/bowtie2/align/tests/sam.config b/modules/nf-core/bowtie2/align/tests/sam.config index c1d8c358..14d94e9a 100644 --- a/modules/nf-core/bowtie2/align/tests/sam.config +++ b/modules/nf-core/bowtie2/align/tests/sam.config @@ -2,4 +2,4 @@ process { withName: BOWTIE2_ALIGN { ext.args2 = '--output-fmt SAM' } -} \ No newline at end of file +} diff --git a/modules/nf-core/bowtie2/align/tests/sam2.config b/modules/nf-core/bowtie2/align/tests/sam2.config index 4e85ff0e..c39156f9 100644 --- a/modules/nf-core/bowtie2/align/tests/sam2.config +++ b/modules/nf-core/bowtie2/align/tests/sam2.config @@ -2,4 +2,4 @@ process { withName: BOWTIE2_ALIGN { ext.args2 = '-O SAM' } -} \ No newline at end of file +} diff --git a/modules/nf-core/bwa/mem/environment.yml b/modules/nf-core/bwa/mem/environment.yml index ed5448a1..54e67949 100644 --- a/modules/nf-core/bwa/mem/environment.yml +++ b/modules/nf-core/bwa/mem/environment.yml @@ -6,8 +6,8 @@ channels: dependencies: # renovate: datasource=conda depName=bioconda/bwa - - bioconda::bwa=0.7.18 + - bioconda::bwa=0.7.19 # renovate: datasource=conda depName=bioconda/htslib - - bioconda::htslib=1.21 + - bioconda::htslib=1.22.1 # renovate: datasource=conda depName=bioconda/samtools - - bioconda::samtools=1.21 + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/bwa/mem/main.nf b/modules/nf-core/bwa/mem/main.nf index da6ea4a2..a646e9e7 100644 --- a/modules/nf-core/bwa/mem/main.nf +++ b/modules/nf-core/bwa/mem/main.nf @@ -4,8 +4,8 @@ process BWA_MEM { 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/bf/bf7890f8d4e38a7586581cb7fa13401b7af1582f21d94eef969df4cea852b6da/data' : - 'community.wave.seqera.io/library/bwa_htslib_samtools:56c9f8d5201889a4' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/d7/d7e24dc1e4d93ca4d3a76a78d4c834a7be3985b0e1e56fddd61662e047863a8a/data' : + 'community.wave.seqera.io/library/bwa_htslib_samtools:83b50ff84ead50d0' }" input: tuple val(meta) , path(reads), path(index), path(fasta) diff --git a/modules/nf-core/bwa/mem/meta.yml b/modules/nf-core/bwa/mem/meta.yml index b6f696c0..e1265ab7 100644 --- a/modules/nf-core/bwa/mem/meta.yml +++ b/modules/nf-core/bwa/mem/meta.yml @@ -55,52 +55,57 @@ input: ontologies: - edam: "http://edamontology.org/data_2044" # Sequence - edam: "http://edamontology.org/format_1929" # FASTA - - - sort_bam: - type: boolean - description: use samtools sort (true) or samtools view (false) - pattern: "true or false" + - sort_bam: + type: boolean + description: use samtools sort (true) or samtools view (false) + pattern: "true or false" output: - - bam: - - meta: - type: file - description: Output BAM file containing read alignments + bam: + - - meta: + type: map + description: Groovy Map containing sample information - "*.bam": type: file description: Output BAM file containing read alignments pattern: "*.{bam}" ontologies: - edam: "http://edamontology.org/format_2572" # BAM - - cram: - - meta: + cram: + - - meta: type: file - description: Output CRAM file containing read alignments + description: Output BAM file containing read alignments + ontologies: [] - "*.cram": type: file description: Output CRAM file containing read alignments pattern: "*.{cram}" ontologies: - edam: "http://edamontology.org/format_3462" # CRAM - - csi: - - meta: - type: file - description: Optional index file for BAM file + csi: + - - meta: + type: map + description: Groovy Map containing sample information - "*.csi": type: file description: Optional index file for BAM file pattern: "*.{csi}" - - crai: - - meta: - type: file - description: Optional index file for CRAM file + ontologies: [] + crai: + - - meta: + type: map + description: Groovy Map containing sample information - "*.crai": type: file description: Optional index file for CRAM file pattern: "*.{crai}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" - "@jeremy1805" diff --git a/modules/nf-core/bwa/mem/tests/main.nf.test.snap b/modules/nf-core/bwa/mem/tests/main.nf.test.snap index 3aaefdda..51496a3c 100644 --- a/modules/nf-core/bwa/mem/tests/main.nf.test.snap +++ b/modules/nf-core/bwa/mem/tests/main.nf.test.snap @@ -11,16 +11,16 @@ ], [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "53df0e7b72f1f85fb28af5fec435246", + "37b4ee1649480bd1ff98666447f64fa5", "798439cbd7fd81cbcc5078022dc5479d" ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:36:00.831642964" + "timestamp": "2025-09-23T11:05:11.396076472" }, "Single-End Sort": { "content": [ @@ -34,16 +34,16 @@ ], [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "5eca502b75fefc26e8000908bf0bb3a3", + "57106634fcaf3bf503d5487a7717c5d3", "94fcf617f5b994584c4e8d4044e16b4f" ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:36:16.025706238" + "timestamp": "2025-09-23T11:05:19.529514701" }, "Paired-End": { "content": [ @@ -57,16 +57,16 @@ ], [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "fec2aafbba4637767bc4e202c71aee58", + "57770ff7c7186ed40c42f3d71c16ce3c", "57aeef88ed701a8ebc8e2f0a381b2a6" ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:36:27.309924644" + "timestamp": "2025-09-23T11:05:27.433790935" }, "Paired-End Sort": { "content": [ @@ -80,16 +80,16 @@ ], [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "d5ad8844218280969c1f9349bd62d057", + "8f5d8f83b485dcfa1f47a73ae645e3a7", "af8628d9df18b2d3d4f6fd47ef2bb872" ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:36:45.448624985" + "timestamp": "2025-09-23T11:05:35.775774487" }, "Single-end - stub": { "content": [ @@ -125,7 +125,7 @@ ] ], "4": [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], "bam": [ [ @@ -158,15 +158,15 @@ ] ], "versions": [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:37:16.211123969" + "timestamp": "2025-09-23T11:05:51.638917351" }, "Paired-End - no fasta": { "content": [ @@ -180,16 +180,16 @@ ], [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "fec2aafbba4637767bc4e202c71aee58", + "57770ff7c7186ed40c42f3d71c16ce3c", "57aeef88ed701a8ebc8e2f0a381b2a6" ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:36:56.592159657" + "timestamp": "2025-09-23T11:05:43.764589371" }, "Paired-end - stub": { "content": [ @@ -225,7 +225,7 @@ ] ], "4": [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], "bam": [ [ @@ -258,14 +258,14 @@ ] ], "versions": [ - "versions.yml:md5,c60680eba0f00e791c0d5a0a6e9d665f" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:37:32.177177506" + "timestamp": "2025-09-23T11:05:59.642014144" } } \ No newline at end of file diff --git a/modules/nf-core/bwamem2/mem/environment.yml b/modules/nf-core/bwamem2/mem/environment.yml index c069e281..f3637444 100644 --- a/modules/nf-core/bwamem2/mem/environment.yml +++ b/modules/nf-core/bwamem2/mem/environment.yml @@ -6,8 +6,8 @@ channels: dependencies: # renovate: datasource=conda depName=bioconda/bwa-mem2 - - bwa-mem2=2.2.1 + - bwa-mem2=2.3 # renovate: datasource=conda depName=bioconda/htslib - - htslib=1.21 + - htslib=1.22.1 # renovate: datasource=conda depName=bioconda/samtools - - samtools=1.21 + - samtools=1.22.1 diff --git a/modules/nf-core/bwamem2/mem/main.nf b/modules/nf-core/bwamem2/mem/main.nf index 41e2252a..830c1710 100644 --- a/modules/nf-core/bwamem2/mem/main.nf +++ b/modules/nf-core/bwamem2/mem/main.nf @@ -4,8 +4,8 @@ process BWAMEM2_MEM { 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/9a/9ac054213e67b3c9308e409b459080bbe438f8fd6c646c351bc42887f35a42e7/data' : - 'community.wave.seqera.io/library/bwa-mem2_htslib_samtools:e1f420694f8e42bd' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e0/e05ce34b46ad42810eb29f74e4e304c0cb592b2ca15572929ed8bbaee58faf01/data' : + 'community.wave.seqera.io/library/bwa-mem2_htslib_samtools:db98f81f55b64113' }" input: tuple val(meta), path(reads), path(index), path(fasta) diff --git a/modules/nf-core/bwamem2/mem/meta.yml b/modules/nf-core/bwamem2/mem/meta.yml index d17e0dbd..6c7d1728 100644 --- a/modules/nf-core/bwamem2/mem/meta.yml +++ b/modules/nf-core/bwamem2/mem/meta.yml @@ -55,13 +55,13 @@ input: ontologies: - edam: "http://edamontology.org/data_2044" # Sequence - edam: "http://edamontology.org/format_1929" # FASTA - - - sort_bam: - type: boolean - description: use samtools sort (true) or samtools view (false) - pattern: "true or false" + - sort_bam: + type: boolean + description: use samtools sort (true) or samtools view (false) + pattern: "true or false" output: - - sam: - - meta: + sam: + - - meta: type: map description: | Groovy Map containing sample information @@ -72,8 +72,8 @@ output: pattern: "*.{sam}" ontologies: - edam: "http://edamontology.org/format_2573" # SAM - - bam: - - meta: + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -84,8 +84,8 @@ output: pattern: "*.{bam}" ontologies: - edam: "http://edamontology.org/format_2572" # BAM - - cram: - - meta: + cram: + - - meta: type: map description: | Groovy Map containing sample information @@ -96,8 +96,8 @@ output: pattern: "*.{cram}" ontologies: - edam: "http://edamontology.org/format_3462" # CRAM - - crai: - - meta: + crai: + - - meta: type: map description: | Groovy Map containing sample information @@ -106,8 +106,9 @@ output: type: file description: Index file for CRAM file pattern: "*.{crai}" - - csi: - - meta: + ontologies: [] + csi: + - - meta: type: map description: | Groovy Map containing sample information @@ -116,11 +117,14 @@ output: type: file description: Index file for BAM file pattern: "*.{csi}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@maxulysse" - "@matthdsm" diff --git a/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap b/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap index ec90701f..b7d40a68 100644 --- a/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap +++ b/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap @@ -1,17 +1,17 @@ { "sarscov2 - [fastq1, fastq2], index, fasta, false": { "content": [ - "9505760d66e1d5a5d34ab79a98228c6", + "e414c2d48e2e44c2c52c20ecd88e8bd8", "57aeef88ed701a8ebc8e2f0a381b2a6", [ - "versions.yml:md5,ca1b1dcf82b92fb0751816fca16a477a" + "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T10:57:52.782442426" + "timestamp": "2025-09-23T11:44:52.73673293" }, "sarscov2 - [fastq1, fastq2], index, fasta, true - stub": { "content": [ @@ -44,7 +44,7 @@ ] ], "5": [ - "versions.yml:md5,ca1b1dcf82b92fb0751816fca16a477a" + "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" ], "bam": [ [ @@ -74,56 +74,56 @@ ], "versions": [ - "versions.yml:md5,ca1b1dcf82b92fb0751816fca16a477a" + "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T10:58:37.140104324" + "timestamp": "2025-09-23T11:45:14.834888709" }, "sarscov2 - [fastq1, fastq2], index, fasta, true": { "content": [ - "e0c38d5772ca5f4d5d9999f4477e933c", + "716ed1ef39deaad346ca7cf86e08f959", "af8628d9df18b2d3d4f6fd47ef2bb872", [ - "versions.yml:md5,ca1b1dcf82b92fb0751816fca16a477a" + "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T10:58:19.047052261" + "timestamp": "2025-09-23T11:45:04.750057645" }, "sarscov2 - fastq, index, fasta, false": { "content": [ - "58d05395bbb819e929885bde415947ae", + "283a83f604f3f5338acedfee349dccf4", "798439cbd7fd81cbcc5078022dc5479d", [ - "versions.yml:md5,ca1b1dcf82b92fb0751816fca16a477a" + "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T10:56:53.456559296" + "timestamp": "2025-09-23T11:44:28.57550711" }, "sarscov2 - fastq, index, fasta, true": { "content": [ - "276189f6f003f99a87664e74fad2893d", + "ed99048bb552cac58e39923b550b6d5b", "94fcf617f5b994584c4e8d4044e16b4f", [ - "versions.yml:md5,ca1b1dcf82b92fb0751816fca16a477a" + "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T10:57:21.949711746" + "timestamp": "2025-09-23T11:44:40.437183765" } } \ No newline at end of file diff --git a/modules/nf-core/dragmap/align/meta.yml b/modules/nf-core/dragmap/align/meta.yml index 80f020f5..ba3ab484 100644 --- a/modules/nf-core/dragmap/align/meta.yml +++ b/modules/nf-core/dragmap/align/meta.yml @@ -25,6 +25,7 @@ input: description: | List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. + ontologies: [] - - meta2: type: map description: | @@ -34,6 +35,7 @@ input: type: file description: DRAGMAP hash table pattern: "Directory containing DRAGMAP hash table *.{cmp,.bin,.txt}" + ontologies: [] - - meta3: type: map description: | @@ -43,12 +45,13 @@ input: type: file description: Genome fasta reference files pattern: "*.{fa,fasta,fna}" - - - sort_bam: - type: boolean - description: Sort the BAM file + ontologies: [] + - sort_bam: + type: boolean + description: Sort the BAM file output: - - sam: - - meta: + sam: + - - meta: type: map description: | Groovy Map containing sample information @@ -57,17 +60,20 @@ output: type: file description: Output SAM file containing read alignments pattern: "*.{sam}" - - bam: - - meta: - type: file - description: Output BAM file containing read alignments - pattern: "*.{bam}" + ontologies: [] + bam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] - "*.bam": type: file description: Output BAM file containing read alignments pattern: "*.{bam}" - - cram: - - meta: + ontologies: [] + cram: + - - meta: type: map description: | Groovy Map containing sample information @@ -76,8 +82,9 @@ output: type: file description: Output CRAM file containing read alignments pattern: "*.{cram}" - - crai: - - meta: + ontologies: [] + crai: + - - meta: type: map description: | Groovy Map containing sample information @@ -86,8 +93,9 @@ output: type: file description: Index file for CRAM file pattern: "*.{crai}" - - csi: - - meta: + ontologies: [] + csi: + - - meta: type: map description: | Groovy Map containing sample information @@ -96,8 +104,9 @@ output: type: file description: Index file for CRAM file pattern: "*.{csi}" - - log: - - meta: + ontologies: [] + log: + - - meta: type: map description: | Groovy Map containing sample information @@ -106,11 +115,14 @@ output: type: file description: Log file pattern: "*.{log}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@edmundmiller" maintainers: diff --git a/modules/nf-core/snapaligner/align/environment.yml b/modules/nf-core/snapaligner/align/environment.yml index c2bd7a6a..5dc75127 100644 --- a/modules/nf-core/snapaligner/align/environment.yml +++ b/modules/nf-core/snapaligner/align/environment.yml @@ -4,4 +4,5 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::snap-aligner=2.0.3 + # renovate: datasource=conda depName=bioconda/snap-aligner + - bioconda::snap-aligner=2.0.5 diff --git a/modules/nf-core/snapaligner/align/main.nf b/modules/nf-core/snapaligner/align/main.nf index 5cf6d6bc..eacf4644 100644 --- a/modules/nf-core/snapaligner/align/main.nf +++ b/modules/nf-core/snapaligner/align/main.nf @@ -4,8 +4,8 @@ process SNAPALIGNER_ALIGN { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/snap-aligner:2.0.3--hd03093a_0': - 'biocontainers/snap-aligner:2.0.3--hd03093a_0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/21/21f75cd3d97dfe58e62bea51751b04d33a03a16eae3e9947335d569e22962143/data': + 'community.wave.seqera.io/library/snap-aligner:2.0.5--23601d3a3a2ae452' }" input: tuple val(meta) , path(reads, stageAs: "?/*"), path(index) diff --git a/modules/nf-core/snapaligner/align/meta.yml b/modules/nf-core/snapaligner/align/meta.yml index e0a71c04..66f2fca4 100644 --- a/modules/nf-core/snapaligner/align/meta.yml +++ b/modules/nf-core/snapaligner/align/meta.yml @@ -27,6 +27,8 @@ input: description: List of input fastq files of size 2 for paired fastq or 1 for bam or single fastq pattern: "*.{fastq.gz,fq.gz,fastq,fq,bam}" + ontologies: + - edam: http://edamontology.org/format_1930 # FASTQ - - meta2: type: map description: | @@ -36,9 +38,10 @@ input: type: file description: List of SNAP genome index files pattern: "{Genome,GenomeIndex,GenomeIndexHash,OverflowTable}" + ontologies: [] output: - - bam: - - meta: + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -47,8 +50,9 @@ output: type: file description: Aligned BAM file pattern: "*.{bam}" - - bai: - - meta: + ontologies: [] + bai: + - - meta: type: map description: | Groovy Map containing sample information @@ -57,11 +61,14 @@ output: type: file description: Optional aligned BAM file index pattern: "*.{bai}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/snapaligner/align/tests/main.nf.test b/modules/nf-core/snapaligner/align/tests/main.nf.test index 43a6d935..254ea40d 100644 --- a/modules/nf-core/snapaligner/align/tests/main.nf.test +++ b/modules/nf-core/snapaligner/align/tests/main.nf.test @@ -112,7 +112,7 @@ nextflow_process { } } } - + when { params { module_args = "-so" @@ -136,4 +136,4 @@ nextflow_process { ) } } -} \ No newline at end of file +} diff --git a/modules/nf-core/snapaligner/align/tests/main.nf.test.snap b/modules/nf-core/snapaligner/align/tests/main.nf.test.snap index 9b03ecd9..f660cd39 100644 --- a/modules/nf-core/snapaligner/align/tests/main.nf.test.snap +++ b/modules/nf-core/snapaligner/align/tests/main.nf.test.snap @@ -8,7 +8,7 @@ "id": "test", "single_end": true }, - "test.bam:md5,ca1c2472d7fd405edd7d8edebc7a2373" + "test.bam:md5,fc98a93036a3c5f7c674d470f7c5515a" ] ], "1": [ @@ -21,7 +21,7 @@ ] ], "2": [ - "versions.yml:md5,991ee6a1ff9cb59542426a1ecf063188" + "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" ], "bai": [ [ @@ -38,19 +38,19 @@ "id": "test", "single_end": true }, - "test.bam:md5,ca1c2472d7fd405edd7d8edebc7a2373" + "test.bam:md5,fc98a93036a3c5f7c674d470f7c5515a" ] ], "versions": [ - "versions.yml:md5,991ee6a1ff9cb59542426a1ecf063188" + "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-26T14:27:48.935351249" + "timestamp": "2025-09-23T12:01:44.085165306" }, "test_snapaligner_stub": { "content": [ @@ -74,7 +74,7 @@ ] ], "2": [ - "versions.yml:md5,991ee6a1ff9cb59542426a1ecf063188" + "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" ], "bai": [ [ @@ -95,15 +95,15 @@ ] ], "versions": [ - "versions.yml:md5,991ee6a1ff9cb59542426a1ecf063188" + "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-26T14:41:41.497793191" + "timestamp": "2025-09-23T12:01:58.930050472" }, "test_snapaligner_paired": { "content": [ @@ -114,7 +114,7 @@ "id": "test", "single_end": false }, - "test.bam:md5,7fef4ace398a5e5060ae54d4466c1503" + "test.bam:md5,d4e6df5e063034da268fa4b97db369d3" ] ], "1": [ @@ -127,7 +127,7 @@ ] ], "2": [ - "versions.yml:md5,991ee6a1ff9cb59542426a1ecf063188" + "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" ], "bai": [ [ @@ -144,18 +144,18 @@ "id": "test", "single_end": false }, - "test.bam:md5,7fef4ace398a5e5060ae54d4466c1503" + "test.bam:md5,d4e6df5e063034da268fa4b97db369d3" ] ], "versions": [ - "versions.yml:md5,991ee6a1ff9cb59542426a1ecf063188" + "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-26T14:27:59.945692303" + "timestamp": "2025-09-23T12:01:51.606664577" } } \ No newline at end of file diff --git a/modules/nf-core/strobealign/environment.yml b/modules/nf-core/strobealign/environment.yml new file mode 100644 index 00000000..fc1f89b8 --- /dev/null +++ b/modules/nf-core/strobealign/environment.yml @@ -0,0 +1,9 @@ +channels: + - conda-forge + - bioconda + +dependencies: + - bioconda::htslib=1.22.1 + - bioconda::samtools=1.22.1 + - bioconda::strobealign=0.16.1 + - conda-forge::pigz=2.8 diff --git a/modules/nf-core/strobealign/main.nf b/modules/nf-core/strobealign/main.nf new file mode 100644 index 00000000..26ab2489 --- /dev/null +++ b/modules/nf-core/strobealign/main.nf @@ -0,0 +1,108 @@ +process STROBEALIGN { + tag "${meta.id}" + label 'process_high' + + 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/59/59cce6872df48a1e5cc9ccee89f066210694c6ec9f62d9c931cc6925ca0f6a5f/data' : + 'community.wave.seqera.io/library/htslib_samtools_strobealign_pigz:4fa4f439c6bea386' }" + + input: + tuple val(meta) , path(reads), path(fasta), path(index) + val sort_bam + + output: + tuple val(meta), path("*.bam") , emit: bam , optional: true + tuple val(meta), path("*.cram") , emit: cram, optional: true + tuple val(meta), path("*.csi") , emit: csi , optional: true + tuple val(meta), path("*.crai") , emit: crai, optional: true + tuple val(meta), path("*.paf.gz") , emit: paf , optional: true + tuple val(meta), path("*.tsv.gz") , emit: tsv , optional: true + tuple val(meta), path("*.sti") , emit: sti , optional: true + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def args2 = task.ext.args2 ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + // Determine output file extension and command + def samtools_command = sort_bam ? 'sort' : 'view' + def extension = args.contains("-x") + ? "paf" + : args.contains("--aemb") + ? "tsv" + : args.contains("--create-index") + ? "sti" + : args2.contains("--output-fmt cram") + ? "cram" + : sort_bam && args2.contains("-O cram") + ? "cram" + : !sort_bam && args2.contains("-C") + ? "cram" + : "bam" + def reference = fasta && extension == "cram" ? "--reference ${fasta}" : "" + if (!fasta && extension == "cram") { + error("Fasta reference is required for CRAM output") + } + def output_cmd = extension == "bam" || extension == "cram" + ? "samtools ${samtools_command} ${args2} ${reference} --threads ${task.cpus} -o ${prefix}.${extension} -" + : extension == "paf" + ? "pigz ${args2} > ${prefix}.paf.gz" + : extension == "tsv" + ? "pigz ${args2} > ${prefix}.tsv.gz" + : extension == "sti" + ? "tee ${prefix}.log > /dev/null" + : error("Unable to determine output command for extension: ${extension}") + + """ + strobealign \\ + ${args} \\ + -t ${task.cpus} \\ + ${fasta} \\ + ${reads} \\ + | ${output_cmd} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + strobealign: \$(echo \$(strobealign --version)) + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def args2 = task.ext.args2 ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def extension = args.contains("-x") + ? "paf" + : args.contains("--aemb") + ? "tsv" + : args2.contains("--output-fmt cram") + ? "cram" + : sort_bam && args2.contains("-O cram") + ? "cram" + : !sort_bam && args2.contains("-C") + ? "cram" + : "bam" + + """ + touch ${prefix}.${extension} + touch ${prefix}.csi + touch ${prefix}.crai + echo "" | pigz > ${prefix}.paf.gz + echo "" | pigz > ${prefix}.tsv.gz + touch ${prefix}.sti + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + strobealign: \$(echo \$(strobealign --version)) + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/strobealign/meta.yml b/modules/nf-core/strobealign/meta.yml new file mode 100644 index 00000000..e4ede404 --- /dev/null +++ b/modules/nf-core/strobealign/meta.yml @@ -0,0 +1,142 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "strobealign" +description: "Align short reads using dynamic seed size with strobemers" +keywords: + - strobealign + - strobemers + - alignment + - map + - fastq + - bam + - sam +tools: + - "strobealign": + description: "Align short reads using dynamic seed size with strobemers" + homepage: "https://github.com/ksahlin/strobealign" + documentation: "https://github.com/ksahlin/strobealign?tab=readme-ov-file#usage" + tool_dev_url: "https://github.com/ksahlin/strobealign" + doi: "10.1186/s13059-022-02831-7" + licence: ["MIT"] + identifier: biotools:strobealign + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files of size 1 and 2 for single-end and paired-end data, + respectively. + ontologies: + - edam: "http://edamontology.org/data_2044" # Sequence + - edam: "http://edamontology.org/format_1930" # FASTQ + - - meta2: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Reference genome in FASTA format + pattern: "*.{fasta,fa}" + ontologies: + - edam: "http://edamontology.org/data_2044" # Sequence + - edam: "http://edamontology.org/format_1929" # FASTA + - - meta3: + type: map + description: | + Groovy Map containing reference information. + e.g. [ id:'test', single_end:false ] + - index: + type: file + description: Strobealign genome index file + pattern: "*.sti" + ontologies: + - edam: "http://edamontology.org/data_3210" # Genome index + - sort_bam: + type: boolean + description: use samtools sort (true) or samtools view (false) + pattern: "true or false" +output: + bam: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.bam": + type: file + description: Output BAM file containing read alignments + pattern: "*.{bam}" + ontologies: + - edam: "http://edamontology.org/format_2572" # BAM + cram: + - - meta: + type: file + description: Output BAM file containing read alignments + ontologies: [] + - "*.cram": + type: file + description: Output CRAM file containing read alignments + pattern: "*.{cram}" + ontologies: + - edam: "http://edamontology.org/format_3462" # CRAM + csi: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.csi": + type: file + description: Optional index file for BAM file + pattern: "*.{csi}" + ontologies: [] + crai: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.crai": + type: file + description: Optional index file for CRAM file + pattern: "*.{crai}" + ontologies: [] + paf: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.paf.gz": + type: file + description: Output PAF file containing read alignments + pattern: "*.{paf.gz}" + ontologies: [] + tsv: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.tsv.gz": + type: file + description: Output TSV file containing read alignments + pattern: "*.{tsv.gz}" + ontologies: + - edam: "http://edamontology.org/format_3475" # TSV + sti: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.sti": + type: file + description: Optional strobealign index file for fasta reference + pattern: "*.{sti}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@matthdsm" +maintainers: + - "@matthdsm" + - "@nvnieuwk" diff --git a/modules/nf-core/strobealign/tests/main.nf.test b/modules/nf-core/strobealign/tests/main.nf.test new file mode 100644 index 00000000..360637c0 --- /dev/null +++ b/modules/nf-core/strobealign/tests/main.nf.test @@ -0,0 +1,303 @@ +// TODO nf-core: Once you have added the required tests, please run the following command to build this file: +// nf-core modules test strobealign +nextflow_process { + + name "Test Process STROBEALIGN" + script "../main.nf" + config './nextflow.config' + process "STROBEALIGN" + + tag "modules" + tag "modules_nfcore" + tag "strobealign" + + test("fastq - sorted bam") { + when { + params { + module_args = "" + module_args2 = "--output-fmt bam --write-index" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.bam, + process.out.csi, + process.out.versions + ).match() } + ) + } + } + + test("fastq - unsorted bam") { + when { + params { + module_args = "" + module_args2 = "--output-fmt bam" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.bam, + process.out.versions + ).match() } + ) + } + } + + test("fastq - sorted cram") { + when { + params { + module_args = "" + module_args2 = "--output-fmt cram,version=3.0 --write-index" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + cram(process.out.cram[0][1], 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/sarscov2/genome/genome.fasta').getReadsMD5(), + file(process.out.crai[0][1]).exists(), + process.out.versions + ).match() } + ) + } + } + + test("fastq - unsorted cram") { + when { + params { + module_args = "" + module_args2 = "--output-fmt cram,version=3.0" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + cram(process.out.cram[0][1], 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/sarscov2/genome/genome.fasta').getReadsMD5(), + process.out.versions + ).match() } + ) + } + } + + test("fastq - paf") { + when { + params { + module_args = "-x" + module_args2 = "" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.paf, + process.out.versions + ).match() } + ) + } + } + + test("fastq - tsv") { + when { + params { + module_args = "--aemb" + module_args2 = "" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.tsv, + process.out.versions + ).match() } + ) + } + } + + test("fastq - sti") { + when { + params { + module_args = "--create-index" + module_args2 = "" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.sti, + process.out.versions + ).match() } + ) + } + } + + test("stub") { + options "-stub" + when { + params { + module_args = "" + module_args2 = "" + } + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) + ], + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + ] + input[2] = [[:], []] + input[3] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/strobealign/tests/main.nf.test.snap b/modules/nf-core/strobealign/tests/main.nf.test.snap new file mode 100644 index 00000000..2b8f54dd --- /dev/null +++ b/modules/nf-core/strobealign/tests/main.nf.test.snap @@ -0,0 +1,274 @@ +{ + "fastq - sorted cram": { + "content": [ + "f3a1593b170cf1e9b9008b3afb77cc53", + true, + [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T12:55:51.0954" + }, + "fastq - sti": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.r150.sti:md5,1fa95f6ba0167a729ddc6a444eb5e8f7" + ] + ], + [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T12:31:45.186708" + }, + "fastq - unsorted cram": { + "content": [ + "57aeef88ed701a8ebc8e2f0a381b2a6", + [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T12:42:46.49042" + }, + "fastq - tsv": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.tsv.gz:md5,1fcb7444ba029b7f41b3a836fec7ecac" + ] + ], + [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T12:31:39.58768" + }, + "stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "test.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paf.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "5": [ + [ + { + "id": "test", + "single_end": false + }, + "test.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "6": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sti:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "7": [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "cram": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "paf": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paf.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "sti": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sti:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tsv": [ + [ + { + "id": "test", + "single_end": false + }, + "test.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions": [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T11:56:39.765352" + }, + "fastq - unsorted bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,740d88010349b3cd487a8b6244c64c0d" + ] + ], + [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T12:31:18.225205" + }, + "fastq - paf": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.paf.gz:md5,0992a1eb3dff9beca5849b9d1fc66390" + ] + ], + [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T12:31:34.790627" + }, + "fastq - sorted bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,c9bf092d8998eac47b6b85afe9aa9038" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam.csi:md5,8d53854f92b3f263db0ed27f4bbad054" + ] + ], + [ + "versions.yml:md5,5de873596967072366007d67fe652250" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-16T12:31:12.870782" + } +} \ No newline at end of file diff --git a/modules/nf-core/strobealign/tests/nextflow.config b/modules/nf-core/strobealign/tests/nextflow.config new file mode 100644 index 00000000..7c6b31b6 --- /dev/null +++ b/modules/nf-core/strobealign/tests/nextflow.config @@ -0,0 +1,6 @@ +process { + withName: STROBEALIGN { + ext.args = params.module_args + ext.args2 = params.module_args2 + } +} diff --git a/nextflow_schema.json b/nextflow_schema.json index d6a4828f..1003fc1b 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -55,7 +55,7 @@ "type": "string", "default": "bowtie2", "description": "Which aligner to use", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "star"] + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star"] }, "markdup": { "type": "string", diff --git a/subworkflows/nf-core/fastq_align_dna/main.nf b/subworkflows/nf-core/fastq_align_dna/main.nf index 6239522f..aa80527c 100644 --- a/subworkflows/nf-core/fastq_align_dna/main.nf +++ b/subworkflows/nf-core/fastq_align_dna/main.nf @@ -10,6 +10,7 @@ include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' +include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" @@ -36,6 +37,8 @@ workflow FASTQ_ALIGN_DNA { return [meta, reads, index, fasta] snap : aligner == 'snap' return [meta, reads, index] + strobe : aligner == 'strobe' + return [meta, reads, fasta, index] other : true } .set{ch_to_align} @@ -47,28 +50,33 @@ workflow FASTQ_ALIGN_DNA { // Align fastq files to reference genome and (optionally) sort BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 - ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) + ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions.first()) BWAMEM1_MEM (ch_to_align.bwamem, sort) // If aligner is bwa-mem - ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) - ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) + ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) + ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions.first()) BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 - ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) + ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions.first()) DRAGMAP_ALIGN(ch_to_align.dragmap, sort) // If aligner is dragmap - ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) - ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) + ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) + ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) SNAP_ALIGN(ch_to_align.snap) // If aligner is snap - ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) - ch_bam_index.mix(SNAP_ALIGN.out.bai) + ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) + ch_bam_index.mix(SNAP_ALIGN.out.bai) ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions.first()) + STROBEALIGN(ch_to_align.strobe, sort) // If aligner is strobealign + ch_bam = ch_bam.mix(STROBEALIGN.out.bam) + ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) + ch_versions = ch_versions.mix(STROBEALIGN.out.versions.first()) + emit: bam = ch_bam // channel: [ [meta], bam ] bam_index = ch_bam_index // channel: [ [meta], csi/bai ] diff --git a/subworkflows/nf-core/fastq_align_dna/meta.yml b/subworkflows/nf-core/fastq_align_dna/meta.yml index cd452612..26c3e237 100644 --- a/subworkflows/nf-core/fastq_align_dna/meta.yml +++ b/subworkflows/nf-core/fastq_align_dna/meta.yml @@ -9,12 +9,14 @@ keywords: - bwamem2 - dragmap - snapaligner + - strobealign components: - bowtie2/align - bwa/mem - bwamem2/mem - dragmap/align - snapaligner/align + - strobealign input: - meta: type: map @@ -53,6 +55,7 @@ input: - bwamem2 - dragmap - snap + - strobealign - sort_bam: type: boolean description: sort output diff --git a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test index 48988102..b65eec69 100644 --- a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test +++ b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test @@ -22,6 +22,7 @@ nextflow_workflow { tag "snapaligner" tag "snapaligner/index" tag "snapaligner/align" + tag "strobealign" test("test_fastq_align_bowtie2_SE") { setup { @@ -355,6 +356,46 @@ nextflow_workflow { } } + then { + assertAll( + { assert workflow.success}, + { assert snapshot(workflow.out).match()} + ) + } + } + test ("test_fastq_align_strobealign_SE"){ + when { + workflow { + """ + input[0] = Channel.of([[ id:'test', single_end:true ], [file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)]]) + input[1] = [[:],[]] + input[2] = Channel.of([ [ id:'genome' ],file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)]) + input[3] = "strobealign" + input[4] = true + """ + } + } + + then { + assertAll( + { assert workflow.success}, + { assert snapshot(workflow.out).match()} + ) + } + } + test ("test_fastq_align_strobealign_PE"){ + when { + workflow { + """ + input[0] = Channel.of([[ id:'test', single_end:false ], [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)]]) + input[1] = [[:],[]] + input[2] = Channel.of([ [ id:'genome' ],file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)]) + input[3] = "strobealign" + input[4] = true + """ + } + } + then { assertAll( { assert workflow.success}, diff --git a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap index a4fd38bc..9e34d924 100644 --- a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap +++ b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap @@ -9,14 +9,14 @@ ], [ - "versions.yml:md5,0e1a9cd2ce7baf650bec3dd365fbced7" + "versions.yml:md5,792091aac50160e3fbc865eba482e0c4" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:57:56.74202649" + "timestamp": "2025-09-23T11:46:20.36265064" }, "test_fastq_align_dragmap_PE": { "content": [ @@ -37,6 +37,53 @@ }, "timestamp": "2024-03-14T08:28:25.283436546" }, + "test_fastq_align_strobealign_PE": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,1d8fb5dce75cbfb87955c7ee03c17a5f" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bam:md5,1d8fb5dce75cbfb87955c7ee03c17a5f" + ] + ], + "bam_index": [ + + ], + "reports": [ + + ], + "versions": [ + "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-23T14:32:08.743821" + }, "test_fastq_align_bwa_mem_SE": { "content": [ "test.bam", @@ -47,14 +94,14 @@ ], [ - "versions.yml:md5,83f7314fe48e4c905a39e47723c78039" + "versions.yml:md5,315f4ae70b5322c025925d84c887da18" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:56:27.900928171" + "timestamp": "2025-09-23T11:20:12.631487104" }, "test_fastq_align_bwamem2_SE": { "content": [ @@ -66,14 +113,14 @@ ], [ - "versions.yml:md5,0e1a9cd2ce7baf650bec3dd365fbced7" + "versions.yml:md5,792091aac50160e3fbc865eba482e0c4" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:57:28.080810832" + "timestamp": "2025-09-23T11:46:07.813351063" }, "test_fastq_align_bwa_mem_PE": { "content": [ @@ -85,14 +132,14 @@ ], [ - "versions.yml:md5,83f7314fe48e4c905a39e47723c78039" + "versions.yml:md5,315f4ae70b5322c025925d84c887da18" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-27T08:56:55.897418514" + "timestamp": "2025-09-23T11:20:21.322039351" }, "test_fastq_align_bowtie2_SE": { "content": [ @@ -144,7 +191,7 @@ "id": "test", "single_end": false }, - "test.bam:md5,1f4f6c38e40ddd5da7f644bb0f794aa8" + "test.bam:md5,504bcc1ac7f8d8e1e728276a4ce4f4d4" ] ], "1": [ @@ -154,7 +201,7 @@ ], "3": [ - "versions.yml:md5,ef9883fd373e293fbf6a98985d3c0308" + "versions.yml:md5,e98be7da5d37b69852090365352c3534" ], "bam": [ [ @@ -162,7 +209,7 @@ "id": "test", "single_end": false }, - "test.bam:md5,1f4f6c38e40ddd5da7f644bb0f794aa8" + "test.bam:md5,504bcc1ac7f8d8e1e728276a4ce4f4d4" ] ], "bam_index": [ @@ -172,15 +219,62 @@ ], "versions": [ - "versions.yml:md5,ef9883fd373e293fbf6a98985d3c0308" + "versions.yml:md5,e98be7da5d37b69852090365352c3534" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-23T12:03:34.617919741" + }, + "test_fastq_align_strobealign_SE": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,30a9339ac99b881844cf8514f719f204" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ], + "bam": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,30a9339ac99b881844cf8514f719f204" + ] + ], + "bam_index": [ + + ], + "reports": [ + + ], + "versions": [ + "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-03-14T08:19:36.298315938" + "timestamp": "2025-09-23T14:32:01.424171" }, "test_fastq_align_snapaligner_SE": { "content": [ @@ -191,7 +285,7 @@ "id": "test", "single_end": true }, - "test.bam:md5,6b3188b8e48ec5c155cfe02b9a24d37a" + "test.bam:md5,9de00a20df23dc66ddf0d9bba2e486c3" ] ], "1": [ @@ -201,7 +295,7 @@ ], "3": [ - "versions.yml:md5,ef9883fd373e293fbf6a98985d3c0308" + "versions.yml:md5,e98be7da5d37b69852090365352c3534" ], "bam": [ [ @@ -209,7 +303,7 @@ "id": "test", "single_end": true }, - "test.bam:md5,6b3188b8e48ec5c155cfe02b9a24d37a" + "test.bam:md5,9de00a20df23dc66ddf0d9bba2e486c3" ] ], "bam_index": [ @@ -219,14 +313,14 @@ ], "versions": [ - "versions.yml:md5,ef9883fd373e293fbf6a98985d3c0308" + "versions.yml:md5,e98be7da5d37b69852090365352c3534" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nextflow": "25.04.7" }, - "timestamp": "2025-03-25T08:46:43.073714962" + "timestamp": "2025-09-23T12:03:25.88186957" } } \ No newline at end of file diff --git a/subworkflows/nf-core/fastq_align_dna/tests/nextflow.config b/subworkflows/nf-core/fastq_align_dna/tests/nextflow.config deleted file mode 100644 index 87892757..00000000 --- a/subworkflows/nf-core/fastq_align_dna/tests/nextflow.config +++ /dev/null @@ -1,12 +0,0 @@ -process { - withName: BOWTIE2_BUILD { - } - withName: BWA_INDEX { - } - withName: BWAMEM2_INDEX { - } - withName: DRAGMAP_HASHTABLE { - } - withName: SNAPALIGNER_INDEX { - } -} From 35d1d62685acfb9995876bc3b33115703b2abf8b Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:31:30 +0100 Subject: [PATCH 049/228] clean up subwf --- subworkflows/nf-core/fastq_align_dna/main.nf | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/subworkflows/nf-core/fastq_align_dna/main.nf b/subworkflows/nf-core/fastq_align_dna/main.nf index aa80527c..95cdf670 100644 --- a/subworkflows/nf-core/fastq_align_dna/main.nf +++ b/subworkflows/nf-core/fastq_align_dna/main.nf @@ -5,12 +5,12 @@ // -include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" -include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' -include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' -include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" -include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' -include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" +include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" +include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' +include { BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' +include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" +include { SNAPALIGNER_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' +include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" @@ -67,10 +67,10 @@ workflow FASTQ_ALIGN_DNA { ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) - SNAP_ALIGN(ch_to_align.snap) // If aligner is snap - ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) - ch_bam_index.mix(SNAP_ALIGN.out.bai) - ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions.first()) + SNAPALIGNER_ALIGN(ch_to_align.snap) // If aligner is snap + ch_bam = ch_bam.mix(SNAPALIGNER_ALIGN.out.bam) + ch_bam_index.mix(SNAPALIGNER_ALIGN.out.bai) + ch_versions = ch_versions.mix(SNAPALIGNER_ALIGN.out.versions.first()) STROBEALIGN(ch_to_align.strobe, sort) // If aligner is strobealign ch_bam = ch_bam.mix(STROBEALIGN.out.bam) From 97b80716a50e483a4435776d3152e8546df8a651 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:31:43 +0100 Subject: [PATCH 050/228] bump nf-schema --- nextflow.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index d9645896..a7453b62 100644 --- a/nextflow.config +++ b/nextflow.config @@ -280,7 +280,7 @@ manifest { // Nextflow plugins plugins { - id 'nf-schema@2.5.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.6.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet } validation { From a07c9751d32a16f466eac2b81ad694a85ca885b6 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:38:24 +0100 Subject: [PATCH 051/228] bump fastp --- modules.json | 4 +- modules/nf-core/fastp/environment.yml | 5 +- modules/nf-core/fastp/main.nf | 14 +- modules/nf-core/fastp/meta.yml | 72 ++-- modules/nf-core/fastp/tests/main.nf.test | 313 +++++++++++------- modules/nf-core/fastp/tests/main.nf.test.snap | 243 +++++--------- modules/nf-core/fastp/tests/tags.yml | 2 - workflows/preprocessing.nf | 2 +- 8 files changed, 337 insertions(+), 318 deletions(-) delete mode 100644 modules/nf-core/fastp/tests/tags.yml diff --git a/modules.json b/modules.json index cd0c8667..d46b407d 100644 --- a/modules.json +++ b/modules.json @@ -47,7 +47,7 @@ }, "fastp": { "branch": "master", - "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", + "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", "installed_by": ["modules"], "patch": "modules/nf-core/fastp/fastp.diff" }, @@ -156,7 +156,7 @@ "strobealign": { "branch": "master", "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", - "installed_by": ["_", "a", "d", "f", "g", "i", "l", "n", "q", "s", "t"] + "installed_by": ["fastq_align_dna", "modules"] } } }, diff --git a/modules/nf-core/fastp/environment.yml b/modules/nf-core/fastp/environment.yml index 26d4aca5..0c36eed2 100644 --- a/modules/nf-core/fastp/environment.yml +++ b/modules/nf-core/fastp/environment.yml @@ -1,5 +1,8 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda dependencies: - - bioconda::fastp=0.23.4 + # renovate: datasource=conda depName=bioconda/fastp + - bioconda::fastp=1.0.1 diff --git a/modules/nf-core/fastp/main.nf b/modules/nf-core/fastp/main.nf index 02b69407..85013f5d 100644 --- a/modules/nf-core/fastp/main.nf +++ b/modules/nf-core/fastp/main.nf @@ -4,12 +4,11 @@ process FASTP { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/fastp:0.23.4--h5f740d0_0' : - 'biocontainers/fastp:0.23.4--h5f740d0_0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/527b18847a97451091dba07a886b24f17f742a861f9f6c9a6bfb79d4f1f3bf9d/data' : + 'community.wave.seqera.io/library/fastp:1.0.1--c8b87fe62dcc103c' }" input: - tuple val(meta), path(reads) - path adapter_fasta + tuple val(meta), path(reads), path(adapter_fasta) val discard_trimmed_pass val save_trimmed_fail val save_merged @@ -48,7 +47,7 @@ process FASTP { $adapter_list \\ $fail_fastq \\ $args \\ - 2> >(tee ${prefix}.fastp.log >&2) \\ + 2>| >(tee ${prefix}.fastp.log >&2) \\ | gzip -c > ${prefix}.fastp.fastq.gz cat <<-END_VERSIONS > versions.yml @@ -69,7 +68,7 @@ process FASTP { $adapter_list \\ $fail_fastq \\ $args \\ - 2> >(tee ${prefix}.fastp.log >&2) + 2>| >(tee ${prefix}.fastp.log >&2) cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -92,8 +91,9 @@ process FASTP { $fail_fastq \\ $merge_fastq \\ --thread $task.cpus \\ + --detect_adapter_for_pe \\ $args \\ - 2> >(tee ${prefix}.fastp.log >&2) + 2>| >(tee ${prefix}.fastp.log >&2) cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/fastp/meta.yml b/modules/nf-core/fastp/meta.yml index 159404d0..324025fe 100644 --- a/modules/nf-core/fastp/meta.yml +++ b/modules/nf-core/fastp/meta.yml @@ -24,24 +24,27 @@ input: List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. If you wish to run interleaved paired-end data, supply as single-end data but with `--interleaved_in` in your `modules.conf`'s `ext.args` for the module. - - - adapter_fasta: + ontologies: [] + - adapter_fasta: type: file description: File in FASTA format containing possible adapters to remove. pattern: "*.{fasta,fna,fas,fa}" - - - discard_trimmed_pass: - type: boolean - description: Specify true to not write any reads that pass trimming thresholds. - | This can be used to use fastp for the output report only. - - - save_trimmed_fail: - type: boolean - description: Specify true to save files that failed to pass trimming thresholds - ending in `*.fail.fastq.gz` - - - save_merged: - type: boolean - description: Specify true to save all merged reads to a file ending in `*.merged.fastq.gz` + ontologies: [] + - discard_trimmed_pass: + type: boolean + description: | + Specify true to not write any reads that pass trimming thresholds. + This can be used to use fastp for the output report only. + - save_trimmed_fail: + type: boolean + description: Specify true to save files that failed to pass trimming thresholds + ending in `*.fail.fastq.gz` + - save_merged: + type: boolean + description: Specify true to save all merged reads to a file ending in `*.merged.fastq.gz` output: - - reads: - - meta: + reads: + - - meta: type: map description: | Groovy Map containing sample information @@ -50,8 +53,10 @@ output: type: file description: The trimmed/modified/unmerged fastq reads pattern: "*fastp.fastq.gz" - - json: - - meta: + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + json: + - - meta: type: map description: | Groovy Map containing sample information @@ -60,8 +65,10 @@ output: type: file description: Results in JSON format pattern: "*.json" - - html: - - meta: + ontologies: + - edam: http://edamontology.org/format_3464 # JSON + html: + - - meta: type: map description: | Groovy Map containing sample information @@ -70,8 +77,9 @@ output: type: file description: Results in HTML format pattern: "*.html" - - log: - - meta: + ontologies: [] + log: + - - meta: type: map description: | Groovy Map containing sample information @@ -80,8 +88,9 @@ output: type: file description: fastq log file pattern: "*.log" - - reads_fail: - - meta: + ontologies: [] + reads_fail: + - - meta: type: map description: | Groovy Map containing sample information @@ -90,8 +99,10 @@ output: type: file description: Reads the failed the preprocessing pattern: "*fail.fastq.gz" - - reads_merged: - - meta: + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + reads_merged: + - - meta: type: map description: | Groovy Map containing sample information @@ -100,11 +111,14 @@ output: type: file description: Reads that were successfully merged pattern: "*.{merged.fastq.gz}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" - "@kevinmenden" diff --git a/modules/nf-core/fastp/tests/main.nf.test b/modules/nf-core/fastp/tests/main.nf.test index 30dbb8aa..5125705c 100644 --- a/modules/nf-core/fastp/tests/main.nf.test +++ b/modules/nf-core/fastp/tests/main.nf.test @@ -13,14 +13,19 @@ nextflow_process { process { """ + adapter_fasta = [] // empty list for no adapter file! + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], - [ 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_1.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -31,11 +36,11 @@ nextflow_process { { assert path(process.out.html.get(0).get(1)).getText().contains("single end (151 cycles)") }, { assert path(process.out.log.get(0).get(1)).getText().contains("reads passed filter: 99") }, { assert snapshot( - process.out.json, process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.versions).match() } + process.out.versions).match() + } ) } } @@ -46,20 +51,22 @@ nextflow_process { process { """ - adapter_fasta = [] - save_trimmed_pass = true - save_trimmed_fail = false - save_merged = false + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = false input[0] = Channel.of([ [ 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) ] + [ + 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) + ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -70,7 +77,6 @@ nextflow_process { { assert path(process.out.html.get(0).get(1)).getText().contains("The input has little adapter percentage (~0.000000%), probably it's trimmed before.") }, { assert path(process.out.log.get(0).get(1)).getText().contains("Q30 bases: 12281(88.3716%)") }, { assert snapshot( - process.out.json, process.out.reads, process.out.reads_fail, process.out.reads_merged, @@ -85,14 +91,19 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) ] + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -106,7 +117,6 @@ nextflow_process { { assert process.out.reads_merged == [] }, { assert snapshot( process.out.reads, - process.out.json, process.out.versions).match() } ) } @@ -118,14 +128,19 @@ nextflow_process { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = true + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], // 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_1.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = true - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -136,7 +151,6 @@ nextflow_process { { assert path(process.out.html.get(0).get(1)).getText().contains("single end (151 cycles)") }, { assert path(process.out.log.get(0).get(1)).getText().contains("reads passed filter: 99") }, { assert snapshot( - process.out.json, process.out.reads, process.out.reads_fail, process.out.reads_merged, @@ -151,15 +165,22 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = true + save_merged = false + input[0] = Channel.of([ [ 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)] + [ + 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) + ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = true - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -173,7 +194,6 @@ nextflow_process { process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.json, process.out.versions).match() } ) } @@ -184,15 +204,22 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = true + input[0] = Channel.of([ [ 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) ] + [ + 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) + ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = true + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -203,7 +230,6 @@ nextflow_process { { assert path(process.out.html.get(0).get(1)).getText().contains("The input has little adapter percentage (~0.000000%), probably it's trimmed before.") }, { assert path(process.out.log.get(0).get(1)).getText().contains("total reads: 75") }, { assert snapshot( - process.out.json, process.out.reads, process.out.reads_fail, process.out.reads_merged, @@ -217,15 +243,22 @@ nextflow_process { when { process { """ + adapter_fasta = file(params.modules_testdata_base_path + 'delete_me/fastp/adapters.fasta', checkIfExists: true) + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = true + input[0] = Channel.of([ [ 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) ] + [ + 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) + ], + adapter_fasta ]) - input[1] = Channel.of([ file(params.modules_testdata_base_path + 'delete_me/fastp/adapters.fasta', checkIfExists: true) ]) + input[1] = false input[2] = false - input[3] = false - input[4] = true + input[3] = true """ } } @@ -236,7 +269,6 @@ nextflow_process { { assert path(process.out.html.get(0).get(1)).getText().contains("
    ") }, { assert path(process.out.log.get(0).get(1)).getText().contains("total bases: 13683") }, { assert snapshot( - process.out.json, process.out.reads, process.out.reads_fail, process.out.reads_merged, @@ -250,14 +282,20 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = true + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], - [ 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_1.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = true - input[3] = false - input[4] = false + + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -268,7 +306,6 @@ nextflow_process { { assert path(process.out.html.get(0).get(1)).getText().contains("single end (151 cycles)") }, { assert path(process.out.log.get(0).get(1)).getText().contains("reads passed filter: 99") }, { assert snapshot( - process.out.json, process.out.reads, process.out.reads, process.out.reads_fail, @@ -285,15 +322,22 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = true + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ 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) ] + [ + 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) + ], + adapter_fasta ]) - input[1] = [] - input[2] = true - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -304,7 +348,6 @@ nextflow_process { { assert path(process.out.html.get(0).get(1)).getText().contains("The input has little adapter percentage (~0.000000%), probably it's trimmed before.") }, { assert path(process.out.log.get(0).get(1)).getText().contains("Q30 bases: 12281(88.3716%)") }, { assert snapshot( - process.out.json, process.out.reads, process.out.reads, process.out.reads_fail, @@ -324,14 +367,19 @@ nextflow_process { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], - [ 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_1.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -352,20 +400,20 @@ nextflow_process { process { """ - adapter_fasta = [] - save_trimmed_pass = true - save_trimmed_fail = false - save_merged = false + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = false input[0] = Channel.of([ [ 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) ] + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -386,14 +434,19 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) ] + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -414,14 +467,19 @@ nextflow_process { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = true + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], // 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_1.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = true - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -442,15 +500,20 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = true + save_merged = false + input[0] = Channel.of([ [ 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)] + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = true - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -470,15 +533,20 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = true + input[0] = Channel.of([ [ 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) ] + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = false - input[3] = false - input[4] = true + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -498,15 +566,22 @@ nextflow_process { when { process { """ + adapter_fasta = file(params.modules_testdata_base_path + 'delete_me/fastp/adapters.fasta', checkIfExists: true) + discard_trimmed_pass = false + save_trimmed_fail = false + save_merged = true + input[0] = Channel.of([ [ 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) ] + [ + 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) + ], + adapter_fasta ]) - input[1] = Channel.of([ file(params.modules_testdata_base_path + 'delete_me/fastp/adapters.fasta', checkIfExists: true) ]) - input[2] = false - input[3] = false - input[4] = true + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -526,14 +601,19 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = true + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ id:'test', single_end:true ], - [ 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_1.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = true - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -553,15 +633,20 @@ nextflow_process { when { process { """ + adapter_fasta = [] + discard_trimmed_pass = true + save_trimmed_fail = false + save_merged = false + input[0] = Channel.of([ [ 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) ] + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ], + adapter_fasta ]) - input[1] = [] - input[2] = true - input[3] = false - input[4] = false + input[1] = discard_trimmed_pass + input[2] = save_trimmed_fail + input[3] = save_merged """ } } @@ -573,4 +658,4 @@ nextflow_process { ) } } -} \ No newline at end of file +} diff --git a/modules/nf-core/fastp/tests/main.nf.test.snap b/modules/nf-core/fastp/tests/main.nf.test.snap index 54be7e45..a30c680d 100644 --- a/modules/nf-core/fastp/tests/main.nf.test.snap +++ b/modules/nf-core/fastp/tests/main.nf.test.snap @@ -39,7 +39,7 @@ ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -78,27 +78,18 @@ ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T14:31:10.841098" + "timestamp": "2025-09-11T09:55:42.073182" }, "test_fastp_paired_end": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.fastp.json:md5,1e0f8e27e71728e2b63fc64086be95cd" - ] - ], [ [ { @@ -118,26 +109,17 @@ ], [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:43:28.665779" + "timestamp": "2025-09-19T16:23:12.436191" }, "test_fastp_paired_end_merged_adapterlist": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.fastp.json:md5,5914ca3f21ce162123a824e33e8564f6" - ] - ], [ [ { @@ -163,26 +145,17 @@ ] ], [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:44:18.210375" + "timestamp": "2025-09-19T16:23:32.267735" }, "test_fastp_single_end_qc_only": { "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastp.json:md5,5cc5f01e449309e0e689ed6f51a2294a" - ] - ], [ ], @@ -202,14 +175,14 @@ ], [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:44:27.380974" + "timestamp": "2025-09-19T16:23:36.149003" }, "test_fastp_paired_end_trim_fail": { "content": [ @@ -242,23 +215,14 @@ ], [ - [ - { - "id": "test", - "single_end": false - }, - "test.fastp.json:md5,4c3268ddb50ea5b33125984776aa3519" - ] - ], - [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:43:58.749589" + "timestamp": "2025-09-19T16:23:24.23891" }, "fastp - stub test_fastp_interleaved": { "content": [ @@ -306,7 +270,7 @@ ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -351,15 +315,15 @@ ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:50:00.270029" + "timestamp": "2025-09-11T09:55:19.47199" }, "test_fastp_single_end - stub": { "content": [ @@ -407,7 +371,7 @@ ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -452,15 +416,15 @@ ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:49:42.502789" + "timestamp": "2025-09-11T09:55:09.617001" }, "test_fastp_paired_end_merged_adapterlist - stub": { "content": [ @@ -517,7 +481,7 @@ ] ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -571,15 +535,15 @@ ] ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:54:53.458252" + "timestamp": "2025-09-11T09:55:37.413738" }, "test_fastp_paired_end_merged - stub": { "content": [ @@ -636,7 +600,7 @@ ] ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -690,27 +654,18 @@ ] ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:50:27.689379" + "timestamp": "2025-09-11T09:55:32.965652" }, "test_fastp_paired_end_merged": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.fastp.json:md5,b712fd68ed0322f4bec49ff2a5237fcc" - ] - ], [ [ { @@ -736,14 +691,14 @@ ] ], [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:44:08.68476" + "timestamp": "2025-09-19T16:23:28.074624" }, "test_fastp_paired_end - stub": { "content": [ @@ -794,7 +749,7 @@ ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -842,27 +797,18 @@ ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:49:51.679221" + "timestamp": "2025-09-11T09:55:14.414258" }, "test_fastp_single_end": { "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastp.json:md5,c852d7a6dba5819e4ac8d9673bedcacc" - ] - ], [ [ { @@ -879,14 +825,14 @@ ], [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:43:18.834322" + "timestamp": "2025-09-19T16:23:08.469846" }, "test_fastp_single_end_trim_fail - stub": { "content": [ @@ -940,7 +886,7 @@ ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -991,15 +937,15 @@ ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T14:05:36.898142" + "timestamp": "2025-09-11T09:55:23.871395" }, "test_fastp_paired_end_trim_fail - stub": { "content": [ @@ -1060,7 +1006,7 @@ ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -1118,15 +1064,15 @@ ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T14:05:49.212847" + "timestamp": "2025-09-11T09:55:28.399328" }, "fastp test_fastp_interleaved": { "content": [ @@ -1140,35 +1086,17 @@ ] ], [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastp.json:md5,b24e0624df5cc0b11cd5ba21b726fb22" - ] - ], - [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:43:38.910832" + "timestamp": "2025-09-19T16:23:16.479494" }, "test_fastp_single_end_trim_fail": { "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.fastp.json:md5,9a7ee180f000e8d00c7fb67f06293eb5" - ] - ], [ [ { @@ -1191,26 +1119,17 @@ ], [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:43:48.22378" + "timestamp": "2025-09-19T16:23:20.299076" }, "test_fastp_paired_end_qc_only": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.fastp.json:md5,623064a45912dac6f2b64e3f2e9901df" - ] - ], [ ], @@ -1230,14 +1149,14 @@ ], [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T13:44:36.334938" + "timestamp": "2025-09-19T16:23:40.113724" }, "test_fastp_paired_end_qc_only - stub": { "content": [ @@ -1279,7 +1198,7 @@ ], "6": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ], "html": [ [ @@ -1318,14 +1237,14 @@ ], "versions": [ - "versions.yml:md5,48ffc994212fb1fc9f83a74fa69c9f02" + "versions.yml:md5,c4974822658d02533e660fae343f281b" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T14:31:27.096468" + "timestamp": "2025-09-11T09:55:46.696419" } } \ No newline at end of file diff --git a/modules/nf-core/fastp/tests/tags.yml b/modules/nf-core/fastp/tests/tags.yml deleted file mode 100644 index c1afcce7..00000000 --- a/modules/nf-core/fastp/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -fastp: - - modules/nf-core/fastp/** diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 68e017b1..48c7b0d1 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -205,7 +205,7 @@ workflow PREPROCESSING { // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq], adapter_fasta, save_trimmed, save_merged) - FASTP(ch_fastq_per_sample, [], false, false, false) + FASTP(ch_fastq_per_sample.map{ meta, fastq -> return [meta, fastq, []] }, false, false, false) ch_multiqc_files = ch_multiqc_files.mix( FASTP.out.json.map { _meta, json -> return json From 76146afe67d3b4e87a47cb208bc1549cf63a0778 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:39:13 +0100 Subject: [PATCH 052/228] ditch fastqc --- .nf-core.yml | 2 +- modules.json | 5 - modules/nf-core/fastqc/environment.yml | 7 - modules/nf-core/fastqc/main.nf | 64 --- modules/nf-core/fastqc/meta.yml | 72 ---- modules/nf-core/fastqc/tests/main.nf.test | 309 -------------- .../nf-core/fastqc/tests/main.nf.test.snap | 392 ------------------ 7 files changed, 1 insertion(+), 850 deletions(-) delete mode 100644 modules/nf-core/fastqc/environment.yml delete mode 100644 modules/nf-core/fastqc/main.nf delete mode 100644 modules/nf-core/fastqc/meta.yml delete mode 100644 modules/nf-core/fastqc/tests/main.nf.test delete mode 100644 modules/nf-core/fastqc/tests/main.nf.test.snap diff --git a/.nf-core.yml b/.nf-core.yml index dc7ee414..09005197 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -38,5 +38,5 @@ template: name: preprocessing org: nf-cmgg outdir: . - skip_features: [] + skip_features: ["fastqc"] version: 2.1.0dev diff --git a/modules.json b/modules.json index d46b407d..f665a1c2 100644 --- a/modules.json +++ b/modules.json @@ -51,11 +51,6 @@ "installed_by": ["modules"], "patch": "modules/nf-core/fastp/fastp.diff" }, - "fastqc": { - "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"] - }, "md5sum": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml deleted file mode 100644 index f9f54ee9..00000000 --- a/modules/nf-core/fastqc/environment.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json -channels: - - conda-forge - - bioconda -dependencies: - - bioconda::fastqc=0.12.1 diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf deleted file mode 100644 index 23e16634..00000000 --- a/modules/nf-core/fastqc/main.nf +++ /dev/null @@ -1,64 +0,0 @@ -process FASTQC { - tag "${meta.id}" - label 'process_medium' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/fastqc:0.12.1--hdfd78af_0' : - 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" - - input: - tuple val(meta), path(reads) - - output: - tuple val(meta), path("*.html"), emit: html - tuple val(meta), path("*.zip") , emit: zip - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - // Make list of old name and new name pairs to use for renaming in the bash while loop - def old_new_pairs = reads instanceof Path || reads.size() == 1 ? [[ reads, "${prefix}.${reads.extension}" ]] : reads.withIndex().collect { entry, index -> [ entry, "${prefix}_${index + 1}.${entry.extension}" ] } - def rename_to = old_new_pairs*.join(' ').join(' ') - def renamed_files = old_new_pairs.collect{ _old_name, new_name -> new_name }.join(' ') - - // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) - // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 - // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label - def memory_in_mb = task.memory ? task.memory.toUnit('MB') / task.cpus : null - // FastQC memory value allowed range (100 - 10000) - def fastqc_memory = memory_in_mb > 10000 ? 10000 : (memory_in_mb < 100 ? 100 : memory_in_mb) - - """ - printf "%s %s\\n" ${rename_to} | while read old_name new_name; do - [ -f "\${new_name}" ] || ln -s \$old_name \$new_name - done - - fastqc \\ - ${args} \\ - --threads ${task.cpus} \\ - --memory ${fastqc_memory} \\ - ${renamed_files} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) - END_VERSIONS - """ - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - """ - touch ${prefix}.html - touch ${prefix}.zip - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) - END_VERSIONS - """ -} diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml deleted file mode 100644 index c8d9d025..00000000 --- a/modules/nf-core/fastqc/meta.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: fastqc -description: Run FastQC on sequenced reads -keywords: - - quality control - - qc - - adapters - - fastq -tools: - - fastqc: - description: | - FastQC gives general quality metrics about your reads. - It provides information about the quality score distribution - across your reads, the per base sequence content (%A/C/G/T). - - You get information about adapter contamination and other - overrepresented sequences. - homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ - documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ - licence: ["GPL-2.0-only"] - identifier: biotools:fastqc -input: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. - ontologies: [] -output: - html: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.html": - type: file - description: FastQC report - pattern: "*_{fastqc.html}" - ontologies: [] - zip: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.zip": - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" - ontologies: [] - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -authors: - - "@drpatelh" - - "@grst" - - "@ewels" - - "@FelixKrueger" -maintainers: - - "@drpatelh" - - "@grst" - - "@ewels" - - "@FelixKrueger" diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test deleted file mode 100644 index e9d79a07..00000000 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ /dev/null @@ -1,309 +0,0 @@ -nextflow_process { - - name "Test Process FASTQC" - script "../main.nf" - process "FASTQC" - - tag "modules" - tag "modules_nfcore" - tag "fastqc" - - test("sarscov2 single-end [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [ id: 'test', single_end:true ], - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. - // looks like this:
    Mon 2 Oct 2023
    test.gz
    - // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 paired-end [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [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 process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 interleaved [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 paired-end [bam]") { - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 multiple [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [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), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, - { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, - { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 custom_prefix") { - - when { - process { - """ - input[0] = Channel.of([ - [ id:'mysample', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 single-end [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [ id: 'test', single_end:true ], - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 paired-end [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [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(process.out).match() } - ) - } - } - - test("sarscov2 interleaved [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 paired-end [bam] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 multiple [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [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), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 custom_prefix - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [ id:'mysample', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } -} diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap deleted file mode 100644 index d5db3092..00000000 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ /dev/null @@ -1,392 +0,0 @@ -{ - "sarscov2 custom_prefix": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:16.374038" - }, - "sarscov2 single-end [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": true - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": true - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:24.993809" - }, - "sarscov2 custom_prefix - stub": { - "content": [ - { - "0": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:03:10.93942" - }, - "sarscov2 interleaved [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:42.355718" - }, - "sarscov2 paired-end [bam]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:53.276274" - }, - "sarscov2 multiple [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:05.527626" - }, - "sarscov2 paired-end [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:31.188871" - }, - "sarscov2 paired-end [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:34.273566" - }, - "sarscov2 multiple [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:03:02.304411" - }, - "sarscov2 single-end [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:19.095607" - }, - "sarscov2 interleaved [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:44.640184" - }, - "sarscov2 paired-end [bam] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:53.550742" - } -} \ No newline at end of file From 75914494829a656f9706039b134382be7996b2c7 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:40:20 +0100 Subject: [PATCH 053/228] bump md5sum --- modules.json | 2 +- modules/nf-core/md5sum/tests/nextflow.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules.json b/modules.json index f665a1c2..02f245b1 100644 --- a/modules.json +++ b/modules.json @@ -53,7 +53,7 @@ }, "md5sum": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "mosdepth": { diff --git a/modules/nf-core/md5sum/tests/nextflow.config b/modules/nf-core/md5sum/tests/nextflow.config index de999064..4acada55 100644 --- a/modules/nf-core/md5sum/tests/nextflow.config +++ b/modules/nf-core/md5sum/tests/nextflow.config @@ -1,2 +1,2 @@ -process.ext.args = '--tag' \ No newline at end of file +process.ext.args = '--tag' From 343b30b67c895cc9b7e229927b8f0165e86199e1 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:41:00 +0100 Subject: [PATCH 054/228] bump mosdepth --- modules.json | 2 +- modules/nf-core/mosdepth/environment.yml | 6 +- modules/nf-core/mosdepth/main.nf | 4 +- modules/nf-core/mosdepth/meta.yml | 76 ++++++---- .../nf-core/mosdepth/tests/main.nf.test.snap | 132 +++++++++--------- .../nf-core/mosdepth/tests/quantized.config | 2 +- modules/nf-core/mosdepth/tests/tags.yml | 2 - .../nf-core/mosdepth/tests/threshold.config | 2 +- modules/nf-core/mosdepth/tests/window.config | 2 +- 9 files changed, 124 insertions(+), 104 deletions(-) delete mode 100644 modules/nf-core/mosdepth/tests/tags.yml diff --git a/modules.json b/modules.json index 02f245b1..5f6ae14d 100644 --- a/modules.json +++ b/modules.json @@ -58,7 +58,7 @@ }, "mosdepth": { "branch": "master", - "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, diff --git a/modules/nf-core/mosdepth/environment.yml b/modules/nf-core/mosdepth/environment.yml index e9379873..97c93721 100644 --- a/modules/nf-core/mosdepth/environment.yml +++ b/modules/nf-core/mosdepth/environment.yml @@ -1,6 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda dependencies: # renovate: datasource=conda depName=bioconda/mosdepth - - mosdepth=0.3.8 + - mosdepth=0.3.11=h0ec343a_1 + # renovate: datasource=conda depName=bioconda/htslib + - htslib=1.22.1 diff --git a/modules/nf-core/mosdepth/main.nf b/modules/nf-core/mosdepth/main.nf index 3631cdb3..8166ac0b 100644 --- a/modules/nf-core/mosdepth/main.nf +++ b/modules/nf-core/mosdepth/main.nf @@ -4,8 +4,8 @@ process MOSDEPTH { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mosdepth:0.3.8--hd299d5a_0' : - 'biocontainers/mosdepth:0.3.8--hd299d5a_0'}" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/00/00d32b53160c26794959da7303ee6e2107afd4d292060c9f287b0af1fddbd847/data' : + 'community.wave.seqera.io/library/mosdepth_htslib:0f58993cb6d93294'}" input: tuple val(meta), path(bam), path(bai), path(bed), path(fasta) diff --git a/modules/nf-core/mosdepth/meta.yml b/modules/nf-core/mosdepth/meta.yml index dc783c90..af1ea44a 100644 --- a/modules/nf-core/mosdepth/meta.yml +++ b/modules/nf-core/mosdepth/meta.yml @@ -23,14 +23,17 @@ input: type: file description: Input BAM/CRAM file pattern: "*.{bam,cram}" + ontologies: [] - bai: type: file description: Index for BAM/CRAM file pattern: "*.{bai,crai}" + ontologies: [] - bed: type: file description: BED file with intersected intervals pattern: "*.{bed}" + ontologies: [] - - meta2: type: map description: | @@ -40,9 +43,10 @@ input: type: file description: Reference genome FASTA file pattern: "*.{fa,fasta}" + ontologies: [] output: - - global_txt: - - meta: + global_txt: + - - meta: type: map description: | Groovy Map containing sample information @@ -51,8 +55,9 @@ output: type: file description: Text file with global cumulative coverage distribution pattern: "*.{global.dist.txt}" - - summary_txt: - - meta: + ontologies: [] + summary_txt: + - - meta: type: map description: | Groovy Map containing sample information @@ -61,8 +66,9 @@ output: type: file description: Text file with summary mean depths per chromosome and regions pattern: "*.{summary.txt}" - - regions_txt: - - meta: + ontologies: [] + regions_txt: + - - meta: type: map description: | Groovy Map containing sample information @@ -71,8 +77,9 @@ output: type: file description: Text file with region cumulative coverage distribution pattern: "*.{region.dist.txt}" - - per_base_d4: - - meta: + ontologies: [] + per_base_d4: + - - meta: type: map description: | Groovy Map containing sample information @@ -81,8 +88,9 @@ output: type: file description: D4 file with per-base coverage pattern: "*.{per-base.d4}" - - per_base_bed: - - meta: + ontologies: [] + per_base_bed: + - - meta: type: map description: | Groovy Map containing sample information @@ -91,8 +99,9 @@ output: type: file description: BED file with per-base coverage pattern: "*.{per-base.bed.gz}" - - per_base_csi: - - meta: + ontologies: [] + per_base_csi: + - - meta: type: map description: | Groovy Map containing sample information @@ -101,8 +110,9 @@ output: type: file description: Index file for BED file with per-base coverage pattern: "*.{per-base.bed.gz.csi}" - - regions_bed: - - meta: + ontologies: [] + regions_bed: + - - meta: type: map description: | Groovy Map containing sample information @@ -111,8 +121,9 @@ output: type: file description: BED file with per-region coverage pattern: "*.{regions.bed.gz}" - - regions_csi: - - meta: + ontologies: [] + regions_csi: + - - meta: type: map description: | Groovy Map containing sample information @@ -121,8 +132,9 @@ output: type: file description: Index file for BED file with per-region coverage pattern: "*.{regions.bed.gz.csi}" - - quantized_bed: - - meta: + ontologies: [] + quantized_bed: + - - meta: type: map description: | Groovy Map containing sample information @@ -131,8 +143,9 @@ output: type: file description: BED file with binned coverage pattern: "*.{quantized.bed.gz}" - - quantized_csi: - - meta: + ontologies: [] + quantized_csi: + - - meta: type: map description: | Groovy Map containing sample information @@ -141,8 +154,9 @@ output: type: file description: Index file for BED file with binned coverage pattern: "*.{quantized.bed.gz.csi}" - - thresholds_bed: - - meta: + ontologies: [] + thresholds_bed: + - - meta: type: map description: | Groovy Map containing sample information @@ -152,8 +166,9 @@ output: description: BED file with the number of bases in each region that are covered at or above each threshold pattern: "*.{thresholds.bed.gz}" - - thresholds_csi: - - meta: + ontologies: [] + thresholds_csi: + - - meta: type: map description: | Groovy Map containing sample information @@ -162,11 +177,14 @@ output: type: file description: Index file for BED file with threshold coverage pattern: "*.{thresholds.bed.gz.csi}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@joseespinosa" - "@drpatelh" diff --git a/modules/nf-core/mosdepth/tests/main.nf.test.snap b/modules/nf-core/mosdepth/tests/main.nf.test.snap index c604540b..a063dd9f 100644 --- a/modules/nf-core/mosdepth/tests/main.nf.test.snap +++ b/modules/nf-core/mosdepth/tests/main.nf.test.snap @@ -39,7 +39,7 @@ ] ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ [ @@ -222,15 +222,15 @@ ] ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:33:16.953408231" + "timestamp": "2025-09-23T13:06:13.219131" }, "homo_sapiens - cram, crai, bed": { "content": [ @@ -260,7 +260,7 @@ ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ [ @@ -289,7 +289,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "6": [ @@ -307,7 +307,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,e7df086f0a36e88ca231e143d43bd3f9" + "test.regions.bed.gz.csi:md5,c33ac5c86370039463796f01434fc0e4" ] ], "8": [ @@ -340,7 +340,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "per_base_d4": [ @@ -367,7 +367,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,e7df086f0a36e88ca231e143d43bd3f9" + "test.regions.bed.gz.csi:md5,c33ac5c86370039463796f01434fc0e4" ] ], "regions_txt": [ @@ -395,15 +395,15 @@ ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:32:50.160217828" + "timestamp": "2025-09-23T13:22:14.011309" }, "homo_sapiens - bam, bai, [] - quantized": { "content": [ @@ -433,7 +433,7 @@ ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ @@ -456,7 +456,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "6": [ @@ -480,7 +480,7 @@ "id": "test", "single_end": true }, - "test.quantized.bed.gz.csi:md5,4f69e6ace50206a2768be66ded3a56f0" + "test.quantized.bed.gz.csi:md5,c0a3176a59010639455a4aefb3f247ef" ] ], "global_txt": [ @@ -507,7 +507,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "per_base_d4": [ @@ -528,7 +528,7 @@ "id": "test", "single_end": true }, - "test.quantized.bed.gz.csi:md5,4f69e6ace50206a2768be66ded3a56f0" + "test.quantized.bed.gz.csi:md5,c0a3176a59010639455a4aefb3f247ef" ] ], "regions_bed": [ @@ -556,15 +556,15 @@ ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:33:01.164885111" + "timestamp": "2025-09-23T13:22:22.818082" }, "homo_sapiens - bam, bai, bed": { "content": [ @@ -594,7 +594,7 @@ ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ [ @@ -623,7 +623,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "6": [ @@ -641,7 +641,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,e7df086f0a36e88ca231e143d43bd3f9" + "test.regions.bed.gz.csi:md5,c33ac5c86370039463796f01434fc0e4" ] ], "8": [ @@ -674,7 +674,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "per_base_d4": [ @@ -701,7 +701,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,e7df086f0a36e88ca231e143d43bd3f9" + "test.regions.bed.gz.csi:md5,c33ac5c86370039463796f01434fc0e4" ] ], "regions_txt": [ @@ -729,15 +729,15 @@ ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:32:39.071657456" + "timestamp": "2025-09-23T13:22:04.449943" }, "homo_sapiens - bam, bai, [] - window": { "content": [ @@ -767,7 +767,7 @@ ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ [ @@ -796,7 +796,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "6": [ @@ -814,7 +814,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,2a30bcb7f5c7632136b3efce24723970" + "test.regions.bed.gz.csi:md5,17a2cbe22a948d7c004b90a1f28347a1" ] ], "8": [ @@ -847,7 +847,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "per_base_d4": [ @@ -874,7 +874,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,2a30bcb7f5c7632136b3efce24723970" + "test.regions.bed.gz.csi:md5,17a2cbe22a948d7c004b90a1f28347a1" ] ], "regions_txt": [ @@ -902,15 +902,15 @@ ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:32:55.631776118" + "timestamp": "2025-09-23T13:22:18.435089" }, "homo_sapiens - bam, bai, []": { "content": [ @@ -940,7 +940,7 @@ ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ @@ -963,7 +963,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "6": [ @@ -1002,7 +1002,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "per_base_d4": [ @@ -1039,15 +1039,15 @@ ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:32:33.642125299" + "timestamp": "2025-09-23T13:21:59.785829" }, "homo_sapiens - cram, crai, []": { "content": [ @@ -1077,7 +1077,7 @@ ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ @@ -1100,7 +1100,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "6": [ @@ -1139,7 +1139,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "per_base_d4": [ @@ -1176,15 +1176,15 @@ ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:32:44.704920941" + "timestamp": "2025-09-23T13:22:09.294766" }, "homo_sapiens - bam, bai, bed - thresholds": { "content": [ @@ -1222,11 +1222,11 @@ "id": "test", "single_end": true }, - "test.thresholds.bed.gz.csi:md5,219414a0751185adb98d2235d83ea055" + "test.thresholds.bed.gz.csi:md5,2c52ab89e7496af475de3cb2ca04c7b3" ] ], "12": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ], "2": [ [ @@ -1255,7 +1255,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "6": [ @@ -1273,7 +1273,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,e7df086f0a36e88ca231e143d43bd3f9" + "test.regions.bed.gz.csi:md5,c33ac5c86370039463796f01434fc0e4" ] ], "8": [ @@ -1306,7 +1306,7 @@ "id": "test", "single_end": true }, - "test.per-base.bed.gz.csi:md5,6f322dc9250522a701bd68bd18fa8294" + "test.per-base.bed.gz.csi:md5,6adccf94ed775c9f53422e3e9c7af27f" ] ], "per_base_d4": [ @@ -1333,7 +1333,7 @@ "id": "test", "single_end": true }, - "test.regions.bed.gz.csi:md5,e7df086f0a36e88ca231e143d43bd3f9" + "test.regions.bed.gz.csi:md5,c33ac5c86370039463796f01434fc0e4" ] ], "regions_txt": [ @@ -1369,18 +1369,18 @@ "id": "test", "single_end": true }, - "test.thresholds.bed.gz.csi:md5,219414a0751185adb98d2235d83ea055" + "test.thresholds.bed.gz.csi:md5,2c52ab89e7496af475de3cb2ca04c7b3" ] ], "versions": [ - "versions.yml:md5,87634e525fb18990cd98fe1080ad72ce" + "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-04-29T13:33:06.737266831" + "timestamp": "2025-09-23T13:22:27.300204" } } \ No newline at end of file diff --git a/modules/nf-core/mosdepth/tests/quantized.config b/modules/nf-core/mosdepth/tests/quantized.config index 63c55350..c208a4ce 100644 --- a/modules/nf-core/mosdepth/tests/quantized.config +++ b/modules/nf-core/mosdepth/tests/quantized.config @@ -1,3 +1,3 @@ process { ext.args = "--quantize 0:1:4:100:200" -} \ No newline at end of file +} diff --git a/modules/nf-core/mosdepth/tests/tags.yml b/modules/nf-core/mosdepth/tests/tags.yml deleted file mode 100644 index 5cd2e08e..00000000 --- a/modules/nf-core/mosdepth/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -mosdepth: - - "modules/nf-core/mosdepth/**" diff --git a/modules/nf-core/mosdepth/tests/threshold.config b/modules/nf-core/mosdepth/tests/threshold.config index 9b014ddf..3302da60 100644 --- a/modules/nf-core/mosdepth/tests/threshold.config +++ b/modules/nf-core/mosdepth/tests/threshold.config @@ -1,3 +1,3 @@ process { ext.args = "--thresholds 1,10,20,30" -} \ No newline at end of file +} diff --git a/modules/nf-core/mosdepth/tests/window.config b/modules/nf-core/mosdepth/tests/window.config index 7a0f755c..7f0d08d6 100644 --- a/modules/nf-core/mosdepth/tests/window.config +++ b/modules/nf-core/mosdepth/tests/window.config @@ -1,3 +1,3 @@ process { ext.args = "--by 100" -} \ No newline at end of file +} From 876c89b590b3b2bc8c8a01178795c8fbfbd0dc47 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:41:27 +0100 Subject: [PATCH 055/228] bump multiqc --- modules.json | 2 +- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 42 +++--- modules/nf-core/multiqc/meta.yml | 130 +++++++++++------- .../multiqc/tests/custom_prefix.config | 5 + modules/nf-core/multiqc/tests/main.nf.test | 32 ++++- .../nf-core/multiqc/tests/main.nf.test.snap | 52 ++++--- 7 files changed, 168 insertions(+), 97 deletions(-) create mode 100644 modules/nf-core/multiqc/tests/custom_prefix.config diff --git a/modules.json b/modules.json index 5f6ae14d..c14f6122 100644 --- a/modules.json +++ b/modules.json @@ -64,7 +64,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "471cf3ca1617271b9b6fea09ea2ebdee78b874de", + "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", "installed_by": ["modules"] }, "picard/collecthsmetrics": { diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index 812fc4c5..d02016a0 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::multiqc=1.29 + - bioconda::multiqc=1.32 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 0ac3c369..335afccc 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,11 +3,11 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.29--pyhdfd78af_0' : - 'biocontainers/multiqc:1.29--pyhdfd78af_0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/8c/8c6c120d559d7ee04c7442b61ad7cf5a9e8970be5feefb37d68eeaa60c1034eb/data' : + 'community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf' }" input: - path multiqc_files, stageAs: "?/*" + path multiqc_files, stageAs: "?/*" path(multiqc_config) path(extra_multiqc_config) path(multiqc_logo) @@ -15,10 +15,10 @@ process MULTIQC { path(sample_names) output: - path "*multiqc_report.html", emit: report - path "*_data" , emit: data - path "*_plots" , optional:true, emit: plots - path "versions.yml" , emit: versions + 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"'), topic: versions, emit: versions_multiqc when: task.ext.when == null || task.ext.when @@ -26,38 +26,30 @@ process MULTIQC { 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 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 \\ + ${args} \\ + ${config} \\ + ${prefix} \\ + ${extra_config} \\ + ${logo} \\ + ${replace} \\ + ${samples} \\ . - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS """ stub: """ mkdir multiqc_data + touch multiqc_data/.stub mkdir multiqc_plots touch multiqc_report.html - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS """ } diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index b16c1879..4a908611 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,6 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into - a single report +description: Aggregate results from bioinformatics analyses across many samples + into a single report keywords: - QC - bioinformatics tools @@ -15,57 +15,85 @@ tools: licence: ["GPL-3.0-or-later"] identifier: biotools:multiqc input: - - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections - in multiqc_config. - pattern: "*.{yml,yaml}" - - - multiqc_logo: - type: file - description: Optional logo file for MultiQC - pattern: "*.{png}" - - - replace_names: + - multiqc_files: + type: file + description: | + List of reports / files recognised 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: | - 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}" - - - sample_names: + description: MultiQC report file + pattern: ".html" + ontologies: [] + data: + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + plots: + - "*_plots": type: file - description: | - Optional TSV file with headers, passed to the MultiQC --sample_names - argument. - pattern: "*.{tsv}" -output: - - report: - - "*multiqc_report.html": - type: file - description: MultiQC report file - pattern: "multiqc_report.html" - - data: - - "*_data": - type: directory - description: MultiQC data dir - pattern: "multiqc_data" - - plots: - - "*_plots": - type: file - description: Plots created by MultiQC - pattern: "*_data" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + description: Plots created by MultiQC + pattern: "*_data" + ontologies: [] + versions_multiqc: + - - ${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: string + description: The command used to generate the version of the tool +topics: + 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: string + description: The command used to generate the version of the tool authors: - "@abhi18av" - "@bunop" diff --git a/modules/nf-core/multiqc/tests/custom_prefix.config b/modules/nf-core/multiqc/tests/custom_prefix.config new file mode 100644 index 00000000..b30b1358 --- /dev/null +++ b/modules/nf-core/multiqc/tests/custom_prefix.config @@ -0,0 +1,5 @@ +process { + withName: 'MULTIQC' { + ext.prefix = "custom_prefix" + } +} diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index 33316a7d..d1ae8b06 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -30,7 +30,33 @@ nextflow_process { { assert process.success }, { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_single") } + { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions")}).match() } + ) + } + + } + + test("sarscov2 single-end [fastqc] - custom prefix") { + config "./custom_prefix.config" + + when { + process { + """ + input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) + input[1] = [] + input[2] = [] + input[3] = [] + input[4] = [] + input[5] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.report[0] ==~ ".*/custom_prefix.html" }, + { assert process.out.data[0] ==~ ".*/custom_prefix_data" } ) } @@ -56,7 +82,7 @@ nextflow_process { { assert process.success }, { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_config") } + { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions")}).match() } ) } } @@ -84,7 +110,7 @@ nextflow_process { { assert snapshot(process.out.report.collect { file(it).getName() } + process.out.data.collect { file(it).getName() } + process.out.plots.collect { file(it).getName() } + - process.out.versions ).match("multiqc_stub") } + process.out.findAll { key, val -> key.startsWith("versions")} ).match() } ) } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index 25caea81..f76049d3 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,41 +1,61 @@ { - "multiqc_versions_single": { + "sarscov2 single-end [fastqc]": { "content": [ - [ - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" - ] + { + "versions_multiqc": [ + [ + "MULTIQC", + "multiqc", + "1.32" + ] + ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-06-03T09:17:40.895950399" + "timestamp": "2025-10-28T15:27:59.813370216" }, - "multiqc_stub": { + "sarscov2 single-end [fastqc] - stub": { "content": [ [ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" + { + "versions_multiqc": [ + [ + "MULTIQC", + "multiqc", + "1.32" + ] + ] + } ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-06-03T09:18:16.875131107" + "timestamp": "2025-10-28T15:30:48.963962021" }, - "multiqc_versions_config": { + "sarscov2 single-end [fastqc] [config]": { "content": [ - [ - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" - ] + { + "versions_multiqc": [ + [ + "MULTIQC", + "multiqc", + "1.32" + ] + ] + } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-06-03T09:18:03.624717769" + "timestamp": "2025-10-28T15:29:30.664969334" } } \ No newline at end of file From 3833af420b1d6e338b515ca0b2e5df0ead879cdd Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:43:09 +0100 Subject: [PATCH 056/228] bump picard modules --- modules.json | 6 +- .../picard/collecthsmetrics/environment.yml | 5 +- .../nf-core/picard/collecthsmetrics/main.nf | 10 +- .../nf-core/picard/collecthsmetrics/meta.yml | 44 +++-- .../collecthsmetrics/tests/main.nf.test | 45 ++++- .../collecthsmetrics/tests/main.nf.test.snap | 156 +++++++++++++++--- .../picard/collecthsmetrics/tests/tags.yml | 2 - .../collectmultiplemetrics/environment.yml | 5 +- .../picard/collectmultiplemetrics/main.nf | 4 +- .../picard/collectmultiplemetrics/meta.yml | 26 ++- .../tests/main.nf.test.snap | 24 +-- .../picard/collectwgsmetrics/environment.yml | 5 +- .../nf-core/picard/collectwgsmetrics/main.nf | 4 +- .../nf-core/picard/collectwgsmetrics/meta.yml | 30 ++-- .../collectwgsmetrics/tests/main.nf.test.snap | 16 +- 15 files changed, 292 insertions(+), 90 deletions(-) delete mode 100644 modules/nf-core/picard/collecthsmetrics/tests/tags.yml diff --git a/modules.json b/modules.json index c14f6122..54019971 100644 --- a/modules.json +++ b/modules.json @@ -69,19 +69,19 @@ }, "picard/collecthsmetrics": { "branch": "master", - "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", - "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", + "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", - "git_sha": "49f4e50534fe4b64101e62ea41d5dc43b1324358", + "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, diff --git a/modules/nf-core/picard/collecthsmetrics/environment.yml b/modules/nf-core/picard/collecthsmetrics/environment.yml index 1d715d56..b4ac4fe0 100644 --- a/modules/nf-core/picard/collecthsmetrics/environment.yml +++ b/modules/nf-core/picard/collecthsmetrics/environment.yml @@ -1,5 +1,8 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda dependencies: - - bioconda::picard=3.3.0 + # renovate: datasource=conda depName=bioconda/picard + - bioconda::picard=3.4.0 diff --git a/modules/nf-core/picard/collecthsmetrics/main.nf b/modules/nf-core/picard/collecthsmetrics/main.nf index 6eb9aa0c..3a51548f 100644 --- a/modules/nf-core/picard/collecthsmetrics/main.nf +++ b/modules/nf-core/picard/collecthsmetrics/main.nf @@ -4,8 +4,8 @@ process PICARD_COLLECTHSMETRICS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/picard:3.3.0--hdfd78af_0' : - 'biocontainers/picard:3.3.0--hdfd78af_0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' : + 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: tuple val(meta), path(bam), path(bai), path(bait_intervals, stageAs: "bait/*"), path(target_intervals, stageAs: "target/*") ,path(fasta) ,path(fai) ,path(dict) @@ -20,7 +20,7 @@ process PICARD_COLLECTHSMETRICS { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" + def reference = ref ? "--REFERENCE_SEQUENCE ${ref}" : "" def avail_mem = 3072 if (!task.memory) { @@ -33,14 +33,14 @@ process PICARD_COLLECTHSMETRICS { def bait_intervallist_cmd = "" if (bait_intervals =~ /.(bed|bed.gz)$/){ bait_interval_list = bait_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") - bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." + bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." } def target_interval_list = target_intervals def target_intervallist_cmd = "" if (target_intervals =~ /.(bed|bed.gz)$/){ target_interval_list = target_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") - target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." + target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." } diff --git a/modules/nf-core/picard/collecthsmetrics/meta.yml b/modules/nf-core/picard/collecthsmetrics/meta.yml index ea6deda3..511ae959 100644 --- a/modules/nf-core/picard/collecthsmetrics/meta.yml +++ b/modules/nf-core/picard/collecthsmetrics/meta.yml @@ -28,51 +28,68 @@ input: type: file description: An aligned BAM/CRAM/SAM file pattern: "*.{bam,cram,sam}" + ontologies: [] - bai: type: file description: Optional aligned BAM/CRAM/SAM file index pattern: "*.{bai,crai,sai}" + ontologies: [] - bait_intervals: type: file description: An interval file that contains the locations of the baits used. pattern: "*.{interval_list,bed,bed.gz}" + ontologies: [] - target_intervals: type: file description: An interval file that contains the locations of the targets. pattern: "*.{interval_list,bed,bed.gz}" + ontologies: [] - - meta2: type: map description: | Groovy Map containing reference information e.g. [ id:'genome' ] - - fasta: + - ref: type: file description: | A reference file to calculate dropout metrics measuring reduced representation of reads. Optional input. - pattern: "*.{fa,fasta,fna}" + pattern: "*.{fa,fa.gz,fasta,fasta.gz,fna,fna.gz}" + ontologies: [] - - meta3: type: map description: | Groovy Map containing reference information e.g. [ id:'genome' ] - - fai: + - ref_fai: type: file - description: Index of FASTA file. Only needed when fasta is supplied. + description: Index of reference file. Only needed when reference is supplied. pattern: "*.fai" + ontologies: [] - - meta4: type: map description: | Groovy Map containing reference information e.g. [ id:'genome' ] - - dict: + - ref_dict: type: file description: Sequence dictionary of FASTA file. Only needed when bed interval lists are supplied. pattern: "*.dict" + ontologies: [] + - - meta5: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - ref_gzi: + type: file + description: Index of reference file. Only needed when gzipped reference is supplied. + pattern: "*.gzi" + ontologies: [] output: - - metrics: - - meta: + metrics: + - - meta: type: map description: | Groovy Map containing sample information @@ -81,11 +98,14 @@ output: type: file description: Alignment metrics files generated by picard pattern: "*_{metrics}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@projectoriented" - "@matthdsm" diff --git a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test index 3bbbd8cf..fe40e7b0 100644 --- a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test +++ b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test @@ -24,6 +24,45 @@ nextflow_process { input[1] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[2] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true)] input[3] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true)] + input[4] = [[:],[]] + """ + } + } + + then { + def size = path(process.out.metrics[0][1]).size() + def lines = path(process.out.metrics[0][1]).readLines()[0..100] + lines.remove(3) // remove timestamp + assertAll( + { assert process.success }, + { assert snapshot( + file(process.out.metrics[0][1]).name, + size, + lines, + process.out.versions + ).match() + } + ) + } + + } + + test("sarscov2 - bam - gzippedfa") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/picard/baits.interval_list', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/picard/targets.interval_list', checkIfExists: true) + ] + input[1] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true)] + input[2] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz.fai', checkIfExists: true)] + input[3] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true)] + input[4] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz.gzi', checkIfExists: true)] """ } } @@ -63,6 +102,7 @@ nextflow_process { input[1] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[2] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true)] input[3] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true)] + input[4] = [[:],[]] """ } } @@ -91,6 +131,7 @@ nextflow_process { input[1] = [[:],[]] input[2] = [[:],[]] input[3] = [[:],[]] + input[4] = [[:],[]] """ } } @@ -129,6 +170,7 @@ nextflow_process { input[1] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[2] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true)] input[3] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true)] + input[4] = [[:],[]] """ } } @@ -167,6 +209,7 @@ nextflow_process { input[1] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[2] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true)] input[3] = [[id:'genome'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.dict', checkIfExists: true)] + input[4] = [[:],[]] """ } } @@ -188,4 +231,4 @@ nextflow_process { } } -} \ No newline at end of file +} diff --git a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap index 4d21710a..11b0f7c5 100644 --- a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap @@ -106,26 +106,142 @@ "89\t0\t0" ], [ - "versions.yml:md5,bdfc7b655683e7b66f68e894c999805e" + "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T10:51:55.291163084" + "timestamp": "2025-09-15T10:37:59.62099935" + }, + "sarscov2 - bam - gzippedfa": { + "content": [ + "test.CollectHsMetrics.coverage_metrics", + 3601, + [ + "## htsjdk.samtools.metrics.StringHeader", + "# CollectHsMetrics --BAIT_INTERVALS baits/baits.interval_list --TARGET_INTERVALS targets/targets.interval_list --INPUT test.paired_end.sorted.bam --OUTPUT test.CollectHsMetrics.coverage_metrics --REFERENCE_SEQUENCE genome.fasta.gz --METRIC_ACCUMULATION_LEVEL ALL_READS --NEAR_DISTANCE 250 --MINIMUM_MAPPING_QUALITY 20 --MINIMUM_BASE_QUALITY 20 --CLIP_OVERLAPPING_READS true --INCLUDE_INDELS false --COVERAGE_CAP 200 --SAMPLE_SIZE 10000 --ALLELE_FRACTION 0.001 --ALLELE_FRACTION 0.005 --ALLELE_FRACTION 0.01 --ALLELE_FRACTION 0.02 --ALLELE_FRACTION 0.05 --ALLELE_FRACTION 0.1 --ALLELE_FRACTION 0.2 --ALLELE_FRACTION 0.3 --ALLELE_FRACTION 0.5 --VERBOSITY INFO --QUIET false --VALIDATION_STRINGENCY STRICT --COMPRESSION_LEVEL 5 --MAX_RECORDS_IN_RAM 500000 --CREATE_INDEX false --CREATE_MD5_FILE false --help false --version false --showHidden false --USE_JDK_DEFLATER false --USE_JDK_INFLATER false", + "## htsjdk.samtools.metrics.StringHeader", + "", + "## METRICS CLASS\tpicard.analysis.directed.HsMetrics", + "BAIT_SET\tBAIT_TERRITORY\tBAIT_DESIGN_EFFICIENCY\tON_BAIT_BASES\tNEAR_BAIT_BASES\tOFF_BAIT_BASES\tPCT_SELECTED_BASES\tPCT_OFF_BAIT\tON_BAIT_VS_SELECTED\tMEAN_BAIT_COVERAGE\tPCT_USABLE_BASES_ON_BAIT\tPCT_USABLE_BASES_ON_TARGET\tFOLD_ENRICHMENT\tHS_LIBRARY_SIZE\tHS_PENALTY_10X\tHS_PENALTY_20X\tHS_PENALTY_30X\tHS_PENALTY_40X\tHS_PENALTY_50X\tHS_PENALTY_100X\tTARGET_TERRITORY\tGENOME_SIZE\tTOTAL_READS\tPF_READS\tPF_BASES\tPF_UNIQUE_READS\tPF_UQ_READS_ALIGNED\tPF_BASES_ALIGNED\tPF_UQ_BASES_ALIGNED\tON_TARGET_BASES\tPCT_PF_READS\tPCT_PF_UQ_READS\tPCT_PF_UQ_READS_ALIGNED\tMEAN_TARGET_COVERAGE\tMEDIAN_TARGET_COVERAGE\tMAX_TARGET_COVERAGE\tMIN_TARGET_COVERAGE\tZERO_CVG_TARGETS_PCT\tPCT_EXC_DUPE\tPCT_EXC_ADAPTER\tPCT_EXC_MAPQ\tPCT_EXC_BASEQ\tPCT_EXC_OVERLAP\tPCT_EXC_OFF_TARGET\tFOLD_80_BASE_PENALTY\tPCT_TARGET_BASES_1X\tPCT_TARGET_BASES_2X\tPCT_TARGET_BASES_10X\tPCT_TARGET_BASES_20X\tPCT_TARGET_BASES_30X\tPCT_TARGET_BASES_40X\tPCT_TARGET_BASES_50X\tPCT_TARGET_BASES_100X\tPCT_TARGET_BASES_250X\tPCT_TARGET_BASES_500X\tPCT_TARGET_BASES_1000X\tPCT_TARGET_BASES_2500X\tPCT_TARGET_BASES_5000X\tPCT_TARGET_BASES_10000X\tPCT_TARGET_BASES_25000X\tPCT_TARGET_BASES_50000X\tPCT_TARGET_BASES_100000X\tAT_DROPOUT\tGC_DROPOUT\tHET_SNP_SENSITIVITY\tHET_SNP_Q\tSAMPLE\tLIBRARY\tREAD_GROUP", + "baits\t158\t0.594937\t725\t3985\t22691\t0.171892\t0.828108\t0.153928\t4.588608\t0.026225\t0.000181\t4.995204\t\t0\t0\t0\t0\t0\t0\t94\t29829\t200\t200\t27645\t200\t197\t27401\t27401\t5\t1\t1\t0.985\t0.053191\t0\t1\t0\t0.75\t0\t0\t0.005438\t0.054487\t0.259516\t0.680377\t?\t0.053191\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t76.595745\t23.404255\t0.015734\t0\t\t\t", + "", + "## HISTOGRAM\tjava.lang.Integer", + "coverage_or_base_quality\thigh_quality_coverage_count\tunfiltered_baseq_count", + "0\t89\t0", + "1\t5\t0", + "2\t0\t0", + "3\t0\t0", + "4\t0\t0", + "5\t0\t0", + "6\t0\t0", + "7\t0\t0", + "8\t0\t0", + "9\t0\t0", + "10\t0\t0", + "11\t0\t0", + "12\t0\t0", + "13\t0\t0", + "14\t0\t5", + "15\t0\t0", + "16\t0\t0", + "17\t0\t0", + "18\t0\t0", + "19\t0\t0", + "20\t0\t0", + "21\t0\t1", + "22\t0\t0", + "23\t0\t0", + "24\t0\t0", + "25\t0\t0", + "26\t0\t0", + "27\t0\t0", + "28\t0\t0", + "29\t0\t0", + "30\t0\t0", + "31\t0\t0", + "32\t0\t1", + "33\t0\t0", + "34\t0\t0", + "35\t0\t0", + "36\t0\t3", + "37\t0\t0", + "38\t0\t0", + "39\t0\t0", + "40\t0\t0", + "41\t0\t0", + "42\t0\t0", + "43\t0\t0", + "44\t0\t0", + "45\t0\t0", + "46\t0\t0", + "47\t0\t0", + "48\t0\t0", + "49\t0\t0", + "50\t0\t0", + "51\t0\t0", + "52\t0\t0", + "53\t0\t0", + "54\t0\t0", + "55\t0\t0", + "56\t0\t0", + "57\t0\t0", + "58\t0\t0", + "59\t0\t0", + "60\t0\t0", + "61\t0\t0", + "62\t0\t0", + "63\t0\t0", + "64\t0\t0", + "65\t0\t0", + "66\t0\t0", + "67\t0\t0", + "68\t0\t0", + "69\t0\t0", + "70\t0\t0", + "71\t0\t0", + "72\t0\t0", + "73\t0\t0", + "74\t0\t0", + "75\t0\t0", + "76\t0\t0", + "77\t0\t0", + "78\t0\t0", + "79\t0\t0", + "80\t0\t0", + "81\t0\t0", + "82\t0\t0", + "83\t0\t0", + "84\t0\t0", + "85\t0\t0", + "86\t0\t0", + "87\t0\t0", + "88\t0\t0", + "89\t0\t0" + ], + [ + "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-15T10:37:32.831030701" }, "versions": { "content": [ [ - "versions.yml:md5,bdfc7b655683e7b66f68e894c999805e" + "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T10:51:30.748857589" + "timestamp": "2025-09-15T10:37:42.492104283" }, "sarscov2 - bam - samebed": { "content": [ @@ -234,14 +350,14 @@ "89\t0\t0" ], [ - "versions.yml:md5,bdfc7b655683e7b66f68e894c999805e" + "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T10:52:43.803456585" + "timestamp": "2025-09-15T10:38:39.302597954" }, "sarscov2 - bam": { "content": [ @@ -350,14 +466,14 @@ "89\t0\t0" ], [ - "versions.yml:md5,bdfc7b655683e7b66f68e894c999805e" + "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T10:51:01.881343611" + "timestamp": "2025-09-15T10:37:15.861292725" }, "sarscov2 - bam - bed": { "content": [ @@ -466,13 +582,13 @@ "89\t0\t0" ], [ - "versions.yml:md5,bdfc7b655683e7b66f68e894c999805e" + "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T10:52:22.830749735" + "timestamp": "2025-09-15T10:38:18.912909604" } } \ No newline at end of file diff --git a/modules/nf-core/picard/collecthsmetrics/tests/tags.yml b/modules/nf-core/picard/collecthsmetrics/tests/tags.yml deleted file mode 100644 index b353f95e..00000000 --- a/modules/nf-core/picard/collecthsmetrics/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -picard/collecthsmetrics: - - "modules/nf-core/picard/collecthsmetrics/**" diff --git a/modules/nf-core/picard/collectmultiplemetrics/environment.yml b/modules/nf-core/picard/collectmultiplemetrics/environment.yml index 1d715d56..b4ac4fe0 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/environment.yml +++ b/modules/nf-core/picard/collectmultiplemetrics/environment.yml @@ -1,5 +1,8 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda dependencies: - - bioconda::picard=3.3.0 + # renovate: datasource=conda depName=bioconda/picard + - bioconda::picard=3.4.0 diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index de390df1..e4d74998 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -4,8 +4,8 @@ process PICARD_COLLECTMULTIPLEMETRICS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/picard:3.3.0--hdfd78af_0' : - 'biocontainers/picard:3.3.0--hdfd78af_0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' : + 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: tuple val(meta) , path(bam), path(bai) ,path(fasta) ,path(fai) diff --git a/modules/nf-core/picard/collectmultiplemetrics/meta.yml b/modules/nf-core/picard/collectmultiplemetrics/meta.yml index 2b7981ac..3f0bf610 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/meta.yml +++ b/modules/nf-core/picard/collectmultiplemetrics/meta.yml @@ -26,10 +26,12 @@ input: type: file description: SAM/BAM/CRAM file pattern: "*.{sam,bam,cram}" + ontologies: [] - bai: type: file description: Optional SAM/BAM/CRAM file index pattern: "*.{sai,bai,crai}" + ontologies: [] - - meta2: type: map description: | @@ -38,6 +40,7 @@ input: - fasta: type: file description: Genome fasta file + ontologies: [] - - meta3: type: map description: | @@ -47,9 +50,10 @@ input: type: file description: Index of FASTA file. Only needed when fasta is supplied. pattern: "*.fai" + ontologies: [] output: - - metrics: - - meta: + metrics: + - - meta: type: map description: | Groovy Map containing sample information @@ -58,8 +62,9 @@ output: type: file description: Alignment metrics files generated by picard pattern: "*_{metrics}" - - pdf: - - meta: + ontologies: [] + pdf: + - - meta: type: map description: | Groovy Map containing sample information @@ -68,11 +73,14 @@ output: type: file description: PDF plots of metrics pattern: "*.{pdf}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" maintainers: diff --git a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap index a76a3237..5a1de114 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap @@ -16,14 +16,14 @@ "test.CollectMultipleMetrics.read_length_histogram.pdf" ], [ - "versions.yml:md5,791db2719d57a997f8253b3ba97d62d7" + "versions.yml:md5,aca7ca0dc0012ee97698236828ba242a" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T11:05:12.591021247" + "timestamp": "2025-09-15T10:41:26.126816186" }, "test-picard-collectmultiplemetrics-cram": { "content": [ @@ -42,14 +42,14 @@ "test.CollectMultipleMetrics.read_length_histogram.pdf" ], [ - "versions.yml:md5,791db2719d57a997f8253b3ba97d62d7" + "versions.yml:md5,aca7ca0dc0012ee97698236828ba242a" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T11:06:08.499320579" + "timestamp": "2025-09-15T10:41:50.933556225" }, "test-picard-collectmultiplemetrics-nofasta": { "content": [ @@ -68,13 +68,13 @@ "test.CollectMultipleMetrics.read_length_histogram.pdf" ], [ - "versions.yml:md5,791db2719d57a997f8253b3ba97d62d7" + "versions.yml:md5,aca7ca0dc0012ee97698236828ba242a" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T11:05:42.117033611" + "timestamp": "2025-09-15T10:41:38.213084333" } } \ No newline at end of file diff --git a/modules/nf-core/picard/collectwgsmetrics/environment.yml b/modules/nf-core/picard/collectwgsmetrics/environment.yml index 13265842..186d4a4b 100644 --- a/modules/nf-core/picard/collectwgsmetrics/environment.yml +++ b/modules/nf-core/picard/collectwgsmetrics/environment.yml @@ -1,6 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda dependencies: - - bioconda::picard=3.3.0 + # renovate: datasource=conda depName=bioconda/picard + - bioconda::picard=3.4.0 - conda-forge::r-base=4.4.1 diff --git a/modules/nf-core/picard/collectwgsmetrics/main.nf b/modules/nf-core/picard/collectwgsmetrics/main.nf index 468e1c8a..cd4a7711 100644 --- a/modules/nf-core/picard/collectwgsmetrics/main.nf +++ b/modules/nf-core/picard/collectwgsmetrics/main.nf @@ -4,8 +4,8 @@ process PICARD_COLLECTWGSMETRICS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/picard:3.3.0--hdfd78af_0' : - 'biocontainers/picard:3.3.0--hdfd78af_0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' : + 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: tuple val(meta), path(bam), path(bai) ,path(fasta) ,path(fai) diff --git a/modules/nf-core/picard/collectwgsmetrics/meta.yml b/modules/nf-core/picard/collectwgsmetrics/meta.yml index bb748080..a27e0a88 100644 --- a/modules/nf-core/picard/collectwgsmetrics/meta.yml +++ b/modules/nf-core/picard/collectwgsmetrics/meta.yml @@ -26,10 +26,12 @@ input: type: file description: Aligned reads file pattern: "*.{bam, cram}" + ontologies: [] - bai: type: file description: (Optional) Aligned reads file index pattern: "*.{bai,crai}" + ontologies: [] - - meta2: type: map description: | @@ -39,6 +41,7 @@ input: type: file description: Genome fasta file pattern: "*.{fa,fasta,fna}" + ontologies: [] - - meta3: type: map description: | @@ -48,13 +51,15 @@ input: type: file description: Genome fasta file index pattern: "*.{fai}" - - - intervallist: - type: file - description: Picard Interval List. Defines which contigs to include. Can be - generated from a BED file with GATK BedToIntervalList. + ontologies: [] + - intervallist: + type: file + description: Picard Interval List. Defines which contigs to include. Can be generated + from a BED file with GATK BedToIntervalList. + ontologies: [] output: - - metrics: - - meta: + metrics: + - - meta: type: map description: | Groovy Map containing sample information @@ -63,11 +68,14 @@ output: type: file description: Alignment metrics files generated by picard pattern: "*_{metrics}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" - "@flowuenne" diff --git a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap index 1958fcde..d944d96b 100644 --- a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap @@ -3,26 +3,26 @@ "content": [ true, [ - "versions.yml:md5,9927db69fdd55176be5cdbd427d000c2" + "versions.yml:md5,0fa1034c5831e54d4534e6052a8d6b61" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T10:15:18.13771243" + "timestamp": "2025-09-15T10:45:19.40801445" }, "test-picard-collectwgsmetrics": { "content": [ true, [ - "versions.yml:md5,9927db69fdd55176be5cdbd427d000c2" + "versions.yml:md5,0fa1034c5831e54d4534e6052a8d6b61" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-10-18T10:14:57.786056996" + "timestamp": "2025-09-15T10:44:57.689335695" } } \ No newline at end of file From 4e99a19e42dab232842a5969f38a3f8a78e4aac2 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:48:09 +0100 Subject: [PATCH 057/228] bump samtools modules --- modules.json | 18 +- modules/nf-core/samtools/cat/environment.yml | 6 +- modules/nf-core/samtools/cat/main.nf | 4 +- modules/nf-core/samtools/cat/meta.yml | 23 +- .../nf-core/samtools/cat/samtools-cat.diff | 3 +- .../samtools/cat/tests/main.nf.test.snap | 16 +- modules/nf-core/samtools/cat/tests/tags.yml | 2 - .../nf-core/samtools/convert/environment.yml | 6 +- modules/nf-core/samtools/convert/main.nf | 6 +- modules/nf-core/samtools/convert/meta.yml | 36 +- .../samtools/convert/tests/main.nf.test | 2 +- .../samtools/convert/tests/main.nf.test.snap | 30 +- .../nf-core/samtools/convert/tests/tags.yml | 2 - .../nf-core/samtools/coverage/environment.yml | 6 +- modules/nf-core/samtools/coverage/main.nf | 11 +- modules/nf-core/samtools/coverage/meta.yml | 21 +- .../samtools/coverage/tests/main.nf.test | 67 +++- .../samtools/coverage/tests/main.nf.test.snap | 30 +- .../nf-core/samtools/coverage/tests/tags.yml | 2 - .../nf-core/samtools/flagstat/environment.yml | 6 +- modules/nf-core/samtools/flagstat/main.nf | 18 +- modules/nf-core/samtools/flagstat/meta.yml | 19 +- .../samtools/flagstat/tests/main.nf.test.snap | 24 +- .../nf-core/samtools/flagstat/tests/tags.yml | 2 - .../nf-core/samtools/idxstats/environment.yml | 6 +- modules/nf-core/samtools/idxstats/main.nf | 5 +- modules/nf-core/samtools/idxstats/meta.yml | 19 +- .../samtools/idxstats/tests/main.nf.test.snap | 20 +- .../nf-core/samtools/idxstats/tests/tags.yml | 2 - .../nf-core/samtools/import/environment.yml | 6 +- modules/nf-core/samtools/import/main.nf | 4 +- modules/nf-core/samtools/import/meta.yml | 29 +- .../nf-core/samtools/import/tests/tags.yml | 2 - .../nf-core/samtools/sormadup/environment.yml | 6 +- modules/nf-core/samtools/sormadup/main.nf | 4 +- modules/nf-core/samtools/sormadup/meta.yml | 39 +- .../samtools/sormadup/tests/cram.config | 2 +- .../samtools/sormadup/tests/main.nf.test.snap | 28 +- .../nf-core/samtools/sormadup/tests/tags.yml | 2 - modules/nf-core/samtools/sort/environment.yml | 6 +- modules/nf-core/samtools/sort/main.nf | 67 ++-- modules/nf-core/samtools/sort/meta.yml | 81 +++- .../nf-core/samtools/sort/tests/main.nf.test | 156 +++++++- .../samtools/sort/tests/main.nf.test.snap | 371 +++++++++--------- .../samtools/sort/tests/nextflow.config | 1 - modules/nf-core/samtools/sort/tests/tags.yml | 3 - .../nf-core/samtools/stats/environment.yml | 6 +- modules/nf-core/samtools/stats/main.nf | 16 +- modules/nf-core/samtools/stats/meta.yml | 35 +- .../samtools/stats/tests/main.nf.test.snap | 88 +++-- modules/nf-core/samtools/stats/tests/tags.yml | 2 - 51 files changed, 867 insertions(+), 499 deletions(-) delete mode 100644 modules/nf-core/samtools/cat/tests/tags.yml delete mode 100644 modules/nf-core/samtools/convert/tests/tags.yml delete mode 100644 modules/nf-core/samtools/coverage/tests/tags.yml delete mode 100644 modules/nf-core/samtools/flagstat/tests/tags.yml delete mode 100644 modules/nf-core/samtools/idxstats/tests/tags.yml delete mode 100644 modules/nf-core/samtools/import/tests/tags.yml delete mode 100644 modules/nf-core/samtools/sormadup/tests/tags.yml delete mode 100644 modules/nf-core/samtools/sort/tests/tags.yml delete mode 100644 modules/nf-core/samtools/stats/tests/tags.yml diff --git a/modules.json b/modules.json index 54019971..7d0d7bc8 100644 --- a/modules.json +++ b/modules.json @@ -87,52 +87,52 @@ }, "samtools/cat": { "branch": "master", - "git_sha": "b13f07be4c508d6ff6312d354d09f2493243e208", + "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/cat/samtools-cat.diff" }, "samtools/convert": { "branch": "master", - "git_sha": "b13f07be4c508d6ff6312d354d09f2493243e208", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", - "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, "samtools/flagstat": { "branch": "master", - "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", + "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", "installed_by": ["modules"] }, "samtools/idxstats": { "branch": "master", - "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", + "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"] }, "samtools/import": { "branch": "master", - "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", + "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"] }, "samtools/sormadup": { "branch": "master", - "git_sha": "38f3b0200093498b70ac2d63a83eac5642e3c873", + "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, "samtools/sort": { "branch": "master", - "git_sha": "b7800db9b069ed505db3f9d91b8c72faea9be17b", + "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "samtools/stats": { "branch": "master", - "git_sha": "2d20463181b1c38981a02e90d3084b5f9fa8d540", + "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, diff --git a/modules/nf-core/samtools/cat/environment.yml b/modules/nf-core/samtools/cat/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/cat/environment.yml +++ b/modules/nf-core/samtools/cat/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/cat/main.nf b/modules/nf-core/samtools/cat/main.nf index 61349e59..d200e501 100644 --- a/modules/nf-core/samtools/cat/main.nf +++ b/modules/nf-core/samtools/cat/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_CAT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(input_files, stageAs: "?/*") diff --git a/modules/nf-core/samtools/cat/meta.yml b/modules/nf-core/samtools/cat/meta.yml index dfb0f78c..a2ac0e21 100644 --- a/modules/nf-core/samtools/cat/meta.yml +++ b/modules/nf-core/samtools/cat/meta.yml @@ -27,9 +27,10 @@ input: type: file description: BAM/CRAM files pattern: "*.{bam,cram}" + ontologies: [] output: - - bam: - - meta: + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -38,8 +39,9 @@ output: type: file description: Concatenated BAM file pattern: "*.{bam}" - - cram: - - meta: + ontologies: [] + cram: + - - meta: type: map description: | Groovy Map containing sample information @@ -48,11 +50,14 @@ output: type: file description: Concatenated CRAM file pattern: "*.{cram}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/samtools/cat/samtools-cat.diff b/modules/nf-core/samtools/cat/samtools-cat.diff index 71c58b5c..5b6918b7 100644 --- a/modules/nf-core/samtools/cat/samtools-cat.diff +++ b/modules/nf-core/samtools/cat/samtools-cat.diff @@ -1,4 +1,4 @@ -Changes in module 'nf-core/samtools/cat' +Changes in component 'nf-core/samtools/cat' 'modules/nf-core/samtools/cat/environment.yml' is unchanged 'modules/nf-core/samtools/cat/meta.yml' is unchanged Changes in 'samtools/cat/main.nf': @@ -19,6 +19,5 @@ Changes in 'samtools/cat/main.nf': when: 'modules/nf-core/samtools/cat/tests/main.nf.test.snap' is unchanged -'modules/nf-core/samtools/cat/tests/tags.yml' is unchanged 'modules/nf-core/samtools/cat/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/samtools/cat/tests/main.nf.test.snap b/modules/nf-core/samtools/cat/tests/main.nf.test.snap index 9af1b19f..2143309a 100644 --- a/modules/nf-core/samtools/cat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/cat/tests/main.nf.test.snap @@ -14,14 +14,14 @@ "bams_stub_versions": { "content": [ [ - "versions.yml:md5,cd29ae344fb0bf5635527e1cb7a7d95f" + "versions.yml:md5,99695cce7873f354da5dd8660522cb4f" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T07:47:51.511914861" + "timestamp": "2025-09-10T13:02:09.79415" }, "bams_bam": { "content": [ @@ -58,13 +58,13 @@ "bams_versions": { "content": [ [ - "versions.yml:md5,cd29ae344fb0bf5635527e1cb7a7d95f" + "versions.yml:md5,99695cce7873f354da5dd8660522cb4f" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T08:47:50.783194958" + "timestamp": "2025-09-10T13:02:05.668116" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/cat/tests/tags.yml b/modules/nf-core/samtools/cat/tests/tags.yml deleted file mode 100644 index 97605570..00000000 --- a/modules/nf-core/samtools/cat/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/cat: - - "modules/nf-core/samtools/cat/**" diff --git a/modules/nf-core/samtools/convert/environment.yml b/modules/nf-core/samtools/convert/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/convert/environment.yml +++ b/modules/nf-core/samtools/convert/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/convert/main.nf b/modules/nf-core/samtools/convert/main.nf index 9942d052..f4003d42 100644 --- a/modules/nf-core/samtools/convert/main.nf +++ b/modules/nf-core/samtools/convert/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_CONVERT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(input), path(index), path(fasta), path(fai) @@ -48,7 +48,7 @@ process SAMTOOLS_CONVERT { """ touch ${prefix}.${output_extension} - touch ${prefix}.${index_extension} + touch ${prefix}.${output_extension}.${index_extension} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/convert/meta.yml b/modules/nf-core/samtools/convert/meta.yml index d5bfa161..519812ab 100644 --- a/modules/nf-core/samtools/convert/meta.yml +++ b/modules/nf-core/samtools/convert/meta.yml @@ -26,10 +26,12 @@ input: type: file description: BAM/CRAM file pattern: "*.{bam,cram}" + ontologies: [] - index: type: file description: BAM/CRAM index file pattern: "*.{bai,crai}" + ontologies: [] - - meta2: type: map description: | @@ -39,6 +41,7 @@ input: type: file description: Reference file to create the CRAM file pattern: "*.{fasta,fa}" + ontologies: [] - - meta3: type: map description: | @@ -48,9 +51,10 @@ input: type: file description: Reference index file to create the CRAM file pattern: "*.{fai}" + ontologies: [] output: - - bam: - - meta: + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -59,8 +63,9 @@ output: type: file description: filtered/converted BAM file pattern: "*{.bam}" - - cram: - - meta: + ontologies: [] + cram: + - - meta: type: map description: | Groovy Map containing sample information @@ -69,8 +74,9 @@ output: type: file description: filtered/converted CRAM file pattern: "*{cram}" - - bai: - - meta: + ontologies: [] + bai: + - - meta: type: map description: | Groovy Map containing sample information @@ -79,8 +85,9 @@ output: type: file description: filtered/converted BAM index pattern: "*{.bai}" - - crai: - - meta: + ontologies: [] + crai: + - - meta: type: map description: | Groovy Map containing sample information @@ -89,11 +96,14 @@ output: type: file description: filtered/converted CRAM index pattern: "*{.crai}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@FriederikeHanssen" - "@maxulysse" diff --git a/modules/nf-core/samtools/convert/tests/main.nf.test b/modules/nf-core/samtools/convert/tests/main.nf.test index 91a0c69e..cd603c53 100644 --- a/modules/nf-core/samtools/convert/tests/main.nf.test +++ b/modules/nf-core/samtools/convert/tests/main.nf.test @@ -74,7 +74,7 @@ nextflow_process { } test("sarscov2 - [bam, bai], fasta, fai - stub") { - + options "-stub" when { diff --git a/modules/nf-core/samtools/convert/tests/main.nf.test.snap b/modules/nf-core/samtools/convert/tests/main.nf.test.snap index a021254e..a9ef27e0 100644 --- a/modules/nf-core/samtools/convert/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/convert/tests/main.nf.test.snap @@ -22,26 +22,26 @@ "cram_to_bam_versions": { "content": [ [ - "versions.yml:md5,5bc6eb42ab2a1ea6661f8ee998467ad6" + "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T07:52:35.516411351" + "timestamp": "2025-09-10T13:05:31.58641" }, "bam_to_cram_versions": { "content": [ [ - "versions.yml:md5,5bc6eb42ab2a1ea6661f8ee998467ad6" + "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T07:52:24.694454205" + "timestamp": "2025-09-10T13:05:26.933516" }, "stub": { "content": [ @@ -67,11 +67,11 @@ "id": "test", "single_end": false }, - "test.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "4": [ - "versions.yml:md5,5bc6eb42ab2a1ea6661f8ee998467ad6" + "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" ], "bai": [ @@ -85,7 +85,7 @@ "id": "test", "single_end": false }, - "test.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "cram": [ @@ -98,15 +98,15 @@ ] ], "versions": [ - "versions.yml:md5,5bc6eb42ab2a1ea6661f8ee998467ad6" + "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T07:52:45.799885099" + "timestamp": "2025-09-10T13:05:36.333776" }, "bam_to_cram_index": { "content": [ diff --git a/modules/nf-core/samtools/convert/tests/tags.yml b/modules/nf-core/samtools/convert/tests/tags.yml deleted file mode 100644 index 030d5eb5..00000000 --- a/modules/nf-core/samtools/convert/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/convert: - - "modules/nf-core/samtools/convert/**" diff --git a/modules/nf-core/samtools/coverage/environment.yml b/modules/nf-core/samtools/coverage/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/coverage/environment.yml +++ b/modules/nf-core/samtools/coverage/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/coverage/main.nf b/modules/nf-core/samtools/coverage/main.nf index 11e347e8..e2adfddd 100644 --- a/modules/nf-core/samtools/coverage/main.nf +++ b/modules/nf-core/samtools/coverage/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_COVERAGE { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(input), path(input_index), path(fasta), path(fai) @@ -20,12 +20,17 @@ process SAMTOOLS_COVERAGE { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def reference = fasta ? "--reference ${fasta}" : "" + + if (input.name.endsWith('.cram') && (!fasta || !fai)) { + error "CRAM input file provided but no reference FASTA and/or FAI index for said reference, both are required for CRAM input." + } """ samtools \\ coverage \\ $args \\ -o ${prefix}.txt \\ - --reference ${fasta} \\ + $reference \\ $input cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/samtools/coverage/meta.yml b/modules/nf-core/samtools/coverage/meta.yml index fb9ba6f3..28dceb03 100644 --- a/modules/nf-core/samtools/coverage/meta.yml +++ b/modules/nf-core/samtools/coverage/meta.yml @@ -25,10 +25,12 @@ input: type: file description: BAM/CRAM/SAM file pattern: "*.{bam,cram,sam}" + ontologies: [] - input_index: type: file description: BAM/CRAM index file pattern: "*.{bai,crai}" + ontologies: [] - - meta2: type: map description: | @@ -38,6 +40,7 @@ input: type: file description: Reference genome file pattern: "*.{fa,fasta}" + ontologies: [] - - meta3: type: map description: | @@ -47,9 +50,10 @@ input: type: file description: Reference genome index file pattern: "*.fai" + ontologies: [] output: - - coverage: - - meta: + coverage: + - - meta: type: map description: | Groovy Map containing sample information @@ -59,11 +63,14 @@ output: description: Tabulated text containing the coverage at each position or region or an ASCII-art histogram (with --histogram). pattern: "*.txt" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@LouisLeNezet" maintainers: diff --git a/modules/nf-core/samtools/coverage/tests/main.nf.test b/modules/nf-core/samtools/coverage/tests/main.nf.test index 1e3ad5a4..ffd36109 100644 --- a/modules/nf-core/samtools/coverage/tests/main.nf.test +++ b/modules/nf-core/samtools/coverage/tests/main.nf.test @@ -20,12 +20,12 @@ nextflow_process { file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) ]) input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + [:], // meta map + [] ]) input[2] = Channel.of([ - [ id:'fai' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + [:], // meta map + [] ]) """ } @@ -69,6 +69,65 @@ nextflow_process { } } + test("test_samtools_coverage_cram_no_fasta") { + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + 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] = Channel.of([ + [:], // meta map + [] + ]) + input[2] = Channel.of([ + [ id:'fai' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll( + { assert !process.success }, + { assert process.stdout.toString().contains("CRAM input file provided but no reference FASTA and/or FAI index for said reference, both are required for CRAM input.") }, + ) + } + } + + test("test_samtools_coverage_cram_no_fai") { + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + 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] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = Channel.of([ + [:], // meta map + [] + ]) + """ + } + } + + then { + assertAll( + { assert !process.success }, + { assert process.stdout.toString().contains("CRAM input file provided but no reference FASTA and/or FAI index for said reference, both are required for CRAM input.") }, + ) + } + } + + test("test_samtools_coverage_stub") { options "-stub" diff --git a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap index b9ddb18d..68cc3697 100644 --- a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap @@ -12,7 +12,7 @@ ] ], "1": [ - "versions.yml:md5,9c876b9db54dc710c87c404e4b28243c" + "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" ], "coverage": [ [ @@ -24,15 +24,15 @@ ] ], "versions": [ - "versions.yml:md5,9c876b9db54dc710c87c404e4b28243c" + "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T07:53:42.773351407" + "timestamp": "2025-09-10T13:06:14.846123" }, "test_samtools_coverage_bam": { "content": [ @@ -47,7 +47,7 @@ ] ], "1": [ - "versions.yml:md5,9c876b9db54dc710c87c404e4b28243c" + "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" ], "coverage": [ [ @@ -59,15 +59,15 @@ ] ], "versions": [ - "versions.yml:md5,9c876b9db54dc710c87c404e4b28243c" + "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T07:53:22.798338025" + "timestamp": "2025-09-10T13:06:06.18797" }, "test_samtools_coverage_cram": { "content": [ @@ -82,7 +82,7 @@ ] ], "1": [ - "versions.yml:md5,9c876b9db54dc710c87c404e4b28243c" + "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" ], "coverage": [ [ @@ -94,14 +94,14 @@ ] ], "versions": [ - "versions.yml:md5,9c876b9db54dc710c87c404e4b28243c" + "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-09-16T07:53:32.409876082" + "timestamp": "2025-10-02T11:22:34.018328" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/coverage/tests/tags.yml b/modules/nf-core/samtools/coverage/tests/tags.yml deleted file mode 100644 index 2b4f53c2..00000000 --- a/modules/nf-core/samtools/coverage/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/coverage: - - "modules/nf-core/samtools/coverage/**" diff --git a/modules/nf-core/samtools/flagstat/environment.yml b/modules/nf-core/samtools/flagstat/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/flagstat/environment.yml +++ b/modules/nf-core/samtools/flagstat/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/flagstat/main.nf b/modules/nf-core/samtools/flagstat/main.nf index c23f3a5c..f148f56b 100644 --- a/modules/nf-core/samtools/flagstat/main.nf +++ b/modules/nf-core/samtools/flagstat/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_FLAGSTAT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(bam), path(bai) @@ -35,7 +35,19 @@ process SAMTOOLS_FLAGSTAT { stub: def prefix = task.ext.prefix ?: "${meta.id}" """ - touch ${prefix}.flagstat + cat <<-END_FLAGSTAT > ${prefix}.flagstat + 1000000 + 0 in total (QC-passed reads + QC-failed reads) + 0 + 0 secondary + 0 + 0 supplementary + 0 + 0 duplicates + 900000 + 0 mapped (90.00% : N/A) + 1000000 + 0 paired in sequencing + 500000 + 0 read1 + 500000 + 0 read2 + 800000 + 0 properly paired (80.00% : N/A) + 850000 + 0 with mate mapped to a different chr + 50000 + 0 with mate mapped to a different chr (mapQ>=5) + END_FLAGSTAT cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/flagstat/meta.yml b/modules/nf-core/samtools/flagstat/meta.yml index cdc4c254..ebbc15f2 100644 --- a/modules/nf-core/samtools/flagstat/meta.yml +++ b/modules/nf-core/samtools/flagstat/meta.yml @@ -29,13 +29,15 @@ input: type: file description: BAM/CRAM/SAM file pattern: "*.{bam,cram,sam}" + ontologies: [] - bai: type: file description: Index for BAM/CRAM/SAM file pattern: "*.{bai,crai,sai}" + ontologies: [] output: - - flagstat: - - meta: + flagstat: + - - meta: type: map description: | Groovy Map containing sample information @@ -44,11 +46,14 @@ output: type: file description: File containing samtools flagstat output pattern: "*.{flagstat}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" maintainers: diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap index 04c3852b..0a0a9b15 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -8,11 +8,11 @@ "id": "test", "single_end": false }, - "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.flagstat:md5,67394650dbae96d1a4fcc70484822159" ] ], "1": [ - "versions.yml:md5,108a155f2d4a99f50bf3176904208d27" + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" ], "flagstat": [ [ @@ -20,19 +20,19 @@ "id": "test", "single_end": false }, - "test.flagstat:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.flagstat:md5,67394650dbae96d1a4fcc70484822159" ] ], "versions": [ - "versions.yml:md5,108a155f2d4a99f50bf3176904208d27" + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T08:02:58.866491759" + "timestamp": "2025-09-15T15:02:00.813612" }, "BAM": { "content": [ @@ -47,7 +47,7 @@ ] ], "1": [ - "versions.yml:md5,108a155f2d4a99f50bf3176904208d27" + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" ], "flagstat": [ [ @@ -59,14 +59,14 @@ ] ], "versions": [ - "versions.yml:md5,108a155f2d4a99f50bf3176904208d27" + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T08:02:47.383332837" + "timestamp": "2025-09-15T15:01:55.232954" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/tests/tags.yml b/modules/nf-core/samtools/flagstat/tests/tags.yml deleted file mode 100644 index 2d2b7255..00000000 --- a/modules/nf-core/samtools/flagstat/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/flagstat: - - modules/nf-core/samtools/flagstat/** diff --git a/modules/nf-core/samtools/idxstats/environment.yml b/modules/nf-core/samtools/idxstats/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/idxstats/environment.yml +++ b/modules/nf-core/samtools/idxstats/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/idxstats/main.nf b/modules/nf-core/samtools/idxstats/main.nf index e2bb6b20..9181a1a5 100644 --- a/modules/nf-core/samtools/idxstats/main.nf +++ b/modules/nf-core/samtools/idxstats/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_IDXSTATS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(bam), path(bai) @@ -21,6 +21,7 @@ process SAMTOOLS_IDXSTATS { def prefix = task.ext.prefix ?: "${meta.id}" """ + # Note: --threads value represents *additional* CPUs to allocate (total CPUs = 1 + --threads). samtools \\ idxstats \\ --threads ${task.cpus-1} \\ diff --git a/modules/nf-core/samtools/idxstats/meta.yml b/modules/nf-core/samtools/idxstats/meta.yml index f0a6bcb2..96d42746 100644 --- a/modules/nf-core/samtools/idxstats/meta.yml +++ b/modules/nf-core/samtools/idxstats/meta.yml @@ -29,13 +29,15 @@ input: type: file description: BAM/CRAM/SAM file pattern: "*.{bam,cram,sam}" + ontologies: [] - bai: type: file description: Index for BAM/CRAM/SAM file pattern: "*.{bai,crai,sai}" + ontologies: [] output: - - idxstats: - - meta: + idxstats: + - - meta: type: map description: | Groovy Map containing sample information @@ -44,11 +46,14 @@ output: type: file description: File containing samtools idxstats output pattern: "*.{idxstats}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" maintainers: diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap index 2cc89a3b..d3e785e0 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -12,7 +12,7 @@ ] ], "1": [ - "versions.yml:md5,c8d7394830c3c1e5be150589571534fb" + "versions.yml:md5,6da44e5235401559cea62052bdc0197b" ], "idxstats": [ [ @@ -24,15 +24,15 @@ ] ], "versions": [ - "versions.yml:md5,c8d7394830c3c1e5be150589571534fb" + "versions.yml:md5,6da44e5235401559cea62052bdc0197b" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T08:11:56.466856235" + "timestamp": "2025-09-10T13:47:35.796569" }, "bam": { "content": [ @@ -47,7 +47,7 @@ ] ], "1": [ - "versions.yml:md5,c8d7394830c3c1e5be150589571534fb" + "versions.yml:md5,6da44e5235401559cea62052bdc0197b" ], "idxstats": [ [ @@ -59,14 +59,14 @@ ] ], "versions": [ - "versions.yml:md5,c8d7394830c3c1e5be150589571534fb" + "versions.yml:md5,6da44e5235401559cea62052bdc0197b" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T08:11:46.311550359" + "timestamp": "2025-09-10T13:47:31.86415" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/tests/tags.yml b/modules/nf-core/samtools/idxstats/tests/tags.yml deleted file mode 100644 index d3057c61..00000000 --- a/modules/nf-core/samtools/idxstats/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/idxstats: - - modules/nf-core/samtools/idxstats/** diff --git a/modules/nf-core/samtools/import/environment.yml b/modules/nf-core/samtools/import/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/import/environment.yml +++ b/modules/nf-core/samtools/import/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/import/main.nf b/modules/nf-core/samtools/import/main.nf index b6927949..0efbc75a 100644 --- a/modules/nf-core/samtools/import/main.nf +++ b/modules/nf-core/samtools/import/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_IMPORT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0': - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0': + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(reads) diff --git a/modules/nf-core/samtools/import/meta.yml b/modules/nf-core/samtools/import/meta.yml index 5c98b8be..2b86ce79 100644 --- a/modules/nf-core/samtools/import/meta.yml +++ b/modules/nf-core/samtools/import/meta.yml @@ -28,9 +28,11 @@ input: type: file description: fastq data to be converted to SAM/BAM/CRAM pattern: "*.{fastq,fq,fastq.gz,fq.gz}" + ontologies: + - edam: http://edamontology.org/format_1930 # FASTQ output: - - sam: - - meta: + sam: + - - meta: type: map description: | Groovy Map containing sample information @@ -39,8 +41,9 @@ output: type: file description: SAM file pattern: "*.sam" - - bam: - - meta: + ontologies: [] + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -49,8 +52,9 @@ output: type: file description: Unaligned BAM file pattern: "*.bam" - - cram: - - meta: + ontologies: [] + cram: + - - meta: type: map description: | Groovy Map containing sample information @@ -59,11 +63,14 @@ output: type: file description: Unaligned CRAM file pattern: "*.cram" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/samtools/import/tests/tags.yml b/modules/nf-core/samtools/import/tests/tags.yml deleted file mode 100644 index 89c89128..00000000 --- a/modules/nf-core/samtools/import/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/import: - - modules/nf-core/samtools/import/** diff --git a/modules/nf-core/samtools/sormadup/environment.yml b/modules/nf-core/samtools/sormadup/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/sormadup/environment.yml +++ b/modules/nf-core/samtools/sormadup/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/sormadup/main.nf b/modules/nf-core/samtools/sormadup/main.nf index 0ee7a0a7..25541ed8 100644 --- a/modules/nf-core/samtools/sormadup/main.nf +++ b/modules/nf-core/samtools/sormadup/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_SORMADUP { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(input), path(fasta) diff --git a/modules/nf-core/samtools/sormadup/meta.yml b/modules/nf-core/samtools/sormadup/meta.yml index bec58e87..bb6295bf 100644 --- a/modules/nf-core/samtools/sormadup/meta.yml +++ b/modules/nf-core/samtools/sormadup/meta.yml @@ -77,6 +77,7 @@ input: type: file description: BAM/CRAM/SAM files pattern: "*.{bam,cram,sam}" + ontologies: [] - - meta2: type: map description: | @@ -86,9 +87,10 @@ input: type: file description: Reference genome file pattern: "*.{fasta,fa,fna}" + ontologies: [] output: - - bam: - - meta: + bam: + - - meta: type: map description: | Groovy Map containing sample information @@ -97,8 +99,9 @@ output: type: file description: Sorted and duplicate marked BAM file pattern: "*.bam" - - cram: - - meta: + ontologies: [] + cram: + - - meta: type: map description: | Groovy Map containing sample information @@ -107,8 +110,9 @@ output: type: file description: Sorted and duplicate marked CRAM file pattern: "*.cram" - - csi: - - meta: + ontologies: [] + csi: + - - meta: type: map description: | Groovy Map containing sample information @@ -117,8 +121,9 @@ output: type: file description: Sorted and duplicate marked BAM index file pattern: "*.csi" - - crai: - - meta: + ontologies: [] + crai: + - - meta: type: map description: | Groovy Map containing sample information @@ -127,8 +132,9 @@ output: type: file description: Sorted and duplicate marked CRAM index file pattern: "*.crai" - - metrics: - - meta: + ontologies: [] + metrics: + - - meta: type: map description: | Groovy Map containing sample information @@ -137,11 +143,14 @@ output: type: file description: Duplicate metrics file pattern: "*.metrics" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/samtools/sormadup/tests/cram.config b/modules/nf-core/samtools/sormadup/tests/cram.config index 8d6ce11a..69897ef7 100644 --- a/modules/nf-core/samtools/sormadup/tests/cram.config +++ b/modules/nf-core/samtools/sormadup/tests/cram.config @@ -7,7 +7,7 @@ process { "-d 2500", // The optical duplicate distance "--barcode-name", // Use the UMI/barcode embedded in the read name (eigth colon delimited part). "--write-index", // Write csi/crai index - "--output-fmt cram", // Output format + "--output-fmt cram,version=3.0",// Output format "--output-fmt-option archive" // Cram compression level ].join(" ").trim()} } diff --git a/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap b/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap index 56776605..7d36514f 100644 --- a/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap @@ -30,7 +30,7 @@ ] ], "5": [ - "versions.yml:md5,ad563b12da6299eec5c39564782d0814" + "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" ], "bam": [ [ @@ -60,15 +60,15 @@ ] ], "versions": [ - "versions.yml:md5,ad563b12da6299eec5c39564782d0814" + "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-16T08:56:24.200237922" + "timestamp": "2025-09-10T14:41:27.357324" }, "sarscov2 - cram": { "content": [ @@ -80,15 +80,15 @@ "id": "test", "single_end": false }, - "test.merged.metrics:md5,548ff6d0d22ef710858639fe22e90004" + "test.merged.metrics:md5,02eebd31b097e165e1b18d84b023f18d" ] ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nextflow": "25.04.6" }, - "timestamp": "2025-02-05T12:24:12.517796" + "timestamp": "2025-09-10T15:34:19.685282" }, "sarscov2 - bam": { "content": [ @@ -99,7 +99,7 @@ "id": "test", "single_end": false }, - "test.bam:md5,4dd85f1abbd2806887c6942f9c84595a" + "test.bam:md5,22ccf80de9847da1fa532f7774580554" ] ], "1": [ @@ -121,7 +121,7 @@ ] ], "5": [ - "versions.yml:md5,ad563b12da6299eec5c39564782d0814" + "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" ], "bam": [ [ @@ -129,7 +129,7 @@ "id": "test", "single_end": false }, - "test.bam:md5,4dd85f1abbd2806887c6942f9c84595a" + "test.bam:md5,22ccf80de9847da1fa532f7774580554" ] ], "crai": [ @@ -151,14 +151,14 @@ ] ], "versions": [ - "versions.yml:md5,ad563b12da6299eec5c39564782d0814" + "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nextflow": "25.04.6" }, - "timestamp": "2025-02-05T11:48:51.866973" + "timestamp": "2025-09-10T14:41:11.744386" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sormadup/tests/tags.yml b/modules/nf-core/samtools/sormadup/tests/tags.yml deleted file mode 100644 index cf362be7..00000000 --- a/modules/nf-core/samtools/sormadup/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/sormadup: - - "modules/nf-core/samtools/sormadup/**" diff --git a/modules/nf-core/samtools/sort/environment.yml b/modules/nf-core/samtools/sort/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/sort/environment.yml +++ b/modules/nf-core/samtools/sort/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index 53bb171a..7b83e4a1 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -4,30 +4,40 @@ process SAMTOOLS_SORT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta) , path(bam), path(fasta) output: - tuple val(meta), path("*.bam"), emit: bam, optional: true - tuple val(meta), path("*.cram"), emit: cram, optional: true - tuple val(meta), path("*.crai"), emit: crai, optional: true - tuple val(meta), path("*.csi"), emit: csi, optional: true - path "versions.yml", emit: versions + tuple val(meta), path("${prefix}.bam"), emit: bam, optional: true + tuple val(meta), path("${prefix}.cram"), emit: cram, optional: true + tuple val(meta), path("${prefix}.sam"), emit: sam, optional: true + tuple val(meta), path("${prefix}.${extension}.crai"), emit: crai, optional: true + tuple val(meta), path("${prefix}.${extension}.csi"), emit: csi, optional: true + tuple val(meta), path("${prefix}.${extension}.bai"), emit: bai, optional: true + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), topic: versions, emit: versions_samtools when: task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - def extension = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt cram") ? "cram" : - "bam" + prefix = task.ext.prefix ?: "${meta.id}" + extension = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt cram") ? "cram" : + "bam" def reference = fasta ? "--reference ${fasta}" : "" def sort_memory = (task.memory.mega/task.cpus*0.75).intValue() + output_file = index_format ? "${prefix}.${extension}##idx##${prefix}.${extension}.${index_format} --write-index" : "${prefix}.${extension}" + if (index_format) { + if (!index_format.matches('bai|csi|crai')) { + error "Index format not one of bai, csi, crai." + } else if (extension == "sam") { + error "Indexing not compatible with SAM output" + } + } if ("$bam" == "${prefix}.bam") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" """ @@ -40,34 +50,29 @@ process SAMTOOLS_SORT { --threads $task.cpus \\ ${reference} \\ -m ${sort_memory}M \\ - -o ${prefix}.${extension} \\ + -o ${output_file} \\ - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - def extension = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt cram") ? "cram" : - "bam" + prefix = task.ext.prefix ?: "${meta.id}" + extension = args.contains("--output-fmt sam") ? "sam" : + args.contains("--output-fmt cram") ? "cram" : + "bam" + if (index_format) { + if (!index_format.matches('bai|csi|crai')) { + error "Index format not one of bai, csi, crai." + } else if (extension == "sam") { + error "Indexing not compatible with SAM output" + } + } + index = index_format ? "touch ${prefix}.${extension}.${index_format}" : "" + """ touch ${prefix}.${extension} - if [ "${extension}" == "bam" ]; - then - touch ${prefix}.${extension}.csi - elif [ "${extension}" == "cram" ]; - then - touch ${prefix}.${extension}.crai - fi + ${index} - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/samtools/sort/meta.yml b/modules/nf-core/samtools/sort/meta.yml index a9dbec5a..809a57fc 100644 --- a/modules/nf-core/samtools/sort/meta.yml +++ b/modules/nf-core/samtools/sort/meta.yml @@ -26,6 +26,7 @@ input: type: file description: BAM/CRAM/SAM file(s) pattern: "*.{bam,cram,sam}" + ontologies: [] - - meta2: type: map description: | @@ -36,52 +37,100 @@ input: description: Reference genome FASTA file pattern: "*.{fa,fasta,fna}" optional: true + ontologies: [] + - index_format: + type: string + description: Index format to use (optional) + pattern: "bai|csi|crai" output: - - bam: - - meta: + bam: + - - meta: type: map description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - "*.bam": + - "${prefix}.bam": type: file description: Sorted BAM file pattern: "*.{bam}" - - cram: - - meta: + ontologies: [] + cram: + - - meta: type: map description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - "*.cram": + - "${prefix}.cram": type: file description: Sorted CRAM file pattern: "*.{cram}" - - crai: - - meta: + ontologies: [] + sam: + - - meta: type: map description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - "*.crai": + - "${prefix}.sam": + type: file + description: Sorted SAM file + pattern: "*.{sam}" + ontologies: [] + crai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "${prefix}.${extension}.crai": type: file description: CRAM index file (optional) pattern: "*.crai" - - csi: - - meta: + ontologies: [] + csi: + - - meta: type: map description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - "*.csi": + - "${prefix}.${extension}.csi": type: file description: BAM index file (optional) pattern: "*.csi" - - versions: - - versions.yml: + ontologies: [] + bai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "${prefix}.${extension}.bai": type: file - description: File containing software versions - pattern: "versions.yml" + description: BAM index file (optional) + pattern: "*.bai" + ontologies: [] + versions_samtools: + - - ${task.process}: + type: string + description: The process the versions were collected from + - samtools: + type: string + description: The tool name + - "samtools version | sed '1!d;s/.* //'": + type: string + description: The command used to generate the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - samtools: + type: string + description: The tool name + - "samtools version | sed '1!d;s/.* //'": + type: string + description: The command used to generate the version of the tool authors: - "@drpatelh" - "@ewels" diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index b05e6691..df47bb25 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -8,7 +8,7 @@ nextflow_process { tag "samtools" tag "samtools/sort" - test("bam") { + test("bam_no_index") { config "./nextflow.config" @@ -23,6 +23,7 @@ nextflow_process { [ id:'fasta' ], // meta map file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ]) + input[2] = '' """ } } @@ -32,8 +33,72 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, - process.out.versions + process.out.bai, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match()} + ) + } + } + + test("bam_bai_index") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = 'bai' + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.bam, + process.out.bai, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match()} + ) + } + } + + test("bam_csi_index") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = 'csi' + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.bam, + process.out.csi, + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -57,6 +122,77 @@ nextflow_process { [ id:'fasta' ], // meta map file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ]) + input[2] = '' + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.bam, + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match()} + ) + } + } + + test("multiple bam bai index") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test2.paired_end.sorted.bam', checkIfExists: true) + ] + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = 'bai' + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.bam, + process.out.bai.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.findAll { key, val -> key.startsWith("versions") } + ).match()} + ) + } + } + + test("multiple bam csi index") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test2.paired_end.sorted.bam', checkIfExists: true) + ] + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = 'csi' """ } } @@ -67,7 +203,7 @@ nextflow_process { { assert snapshot( process.out.bam, process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -88,6 +224,7 @@ nextflow_process { [ id:'fasta' ], // meta map file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ]) + input[2] = '' """ } } @@ -98,7 +235,7 @@ nextflow_process { { assert snapshot( process.out.cram.collect { it.collect { it instanceof Map ? it : file(it).name } }, process.out.crai.collect { it.collect { it instanceof Map ? it : file(it).name } }, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -120,6 +257,7 @@ nextflow_process { [ id:'fasta' ], // meta map file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ]) + input[2] = '' """ } } @@ -127,7 +265,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions") }).match() } ) } } @@ -150,6 +288,7 @@ nextflow_process { [ id:'fasta' ], // meta map file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ]) + input[2] = '' """ } } @@ -157,7 +296,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions") }).match() } ) } } @@ -178,6 +317,7 @@ nextflow_process { [ id:'fasta' ], // meta map file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) ]) + input[2] = '' """ } } @@ -185,7 +325,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out.findAll { key, val -> key.startsWith("versions") }).match() } ) } } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test.snap b/modules/nf-core/samtools/sort/tests/main.nf.test.snap index 469891fe..4e618fa3 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -19,147 +19,77 @@ "test.sorted.cram.crai" ] ], - [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-09-16T08:49:58.207549273" + "timestamp": "2025-10-29T12:47:01.171084" }, - "bam - stub": { + "bam_csi_index": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,72ca1dff5344a5e5e6b892fe5f6b134d" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi:md5,01394e702c729cb478df914ffaf9f7f8" + ] + ], { - "0": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "crai": [ - - ], - "cram": [ - - ], - "csi": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-09-16T08:50:08.630951018" + "timestamp": "2025-10-29T12:46:00.961675" }, - "cram - stub": { + "bam - stub": { "content": [ { - "0": [ - - ], - "1": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" - ], - "bam": [ - - ], - "crai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "cram": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-09-16T08:50:19.061912443" + "timestamp": "2025-10-29T12:47:12.154354" }, - "multiple bam": { + "multiple bam bai index": { "content": [ [ [ @@ -167,7 +97,7 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,8a16ba90c7d294cbb4c33ac0f7127a12" + "test.sorted.bam:md5,3ffa2affc29f0aa6e7b36dded84625fe" ] ], [ @@ -176,85 +106,122 @@ "id": "test", "single_end": false }, - "test.sorted.bam.csi" + "test.sorted.bam.bai" ] ], - [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.09.0" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-10-08T11:59:55.479443" + "timestamp": "2025-10-29T12:46:25.488622" }, - "multiple bam - stub": { + "cram - stub": { "content": [ { - "0": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,8a16ba90c7d294cbb4c33ac0f7127a12" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-29T12:47:28.485045" + }, + "multiple bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,cd4eb0077f25e9cff395366b8883dd1f" + ] + ], + [ + + ], + { + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,d185916eaff9afeb4d0aeab3310371f9" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "4": [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" - ], - "bam": [ + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-29T12:46:13.168476" + }, + "multiple bam - stub": { + "content": [ + { + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,8a16ba90c7d294cbb4c33ac0f7127a12" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "crai": [ - - ], - "cram": [ - - ], - "csi": [ + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-29T12:47:21.628088" + }, + "bam_no_index": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,26b27d1f9bcb61c25da21b562349784e" + ] + ], + [ + + ], + { + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi:md5,d185916eaff9afeb4d0aeab3310371f9" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "versions": [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.09.0" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-10-08T11:36:13.781404" + "timestamp": "2025-10-29T12:45:47.139418" }, - "bam": { + "multiple bam csi index": { "content": [ [ [ @@ -262,7 +229,7 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,34aa85e86abefe637f7a4a9887f016fc" + "test.sorted.bam:md5,295503ba5342531a3310c33ad0efbc22" ] ], [ @@ -274,14 +241,56 @@ "test.sorted.bam.csi" ] ], + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-29T12:46:51.5531" + }, + "bam_bai_index": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,cae7564cb83bb4a5911205bf94124b54" + ] + ], [ - "versions.yml:md5,2659b187d681241451539d4c53500b9f" - ] + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.bai:md5,50dd467c169545a4d5d1f709f7e986e0" + ] + ], + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.09.0" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-10-08T11:59:46.372244" + "timestamp": "2025-10-29T12:45:52.796936" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/tests/nextflow.config b/modules/nf-core/samtools/sort/tests/nextflow.config index f642771f..723f62b2 100644 --- a/modules/nf-core/samtools/sort/tests/nextflow.config +++ b/modules/nf-core/samtools/sort/tests/nextflow.config @@ -2,7 +2,6 @@ process { withName: SAMTOOLS_SORT { ext.prefix = { "${meta.id}.sorted" } - ext.args = "--write-index" } } diff --git a/modules/nf-core/samtools/sort/tests/tags.yml b/modules/nf-core/samtools/sort/tests/tags.yml deleted file mode 100644 index cd63ea20..00000000 --- a/modules/nf-core/samtools/sort/tests/tags.yml +++ /dev/null @@ -1,3 +0,0 @@ -samtools/sort: - - modules/nf-core/samtools/sort/** - - tests/modules/nf-core/samtools/sort/** diff --git a/modules/nf-core/samtools/stats/environment.yml b/modules/nf-core/samtools/stats/environment.yml index 62054fc9..89e12a64 100644 --- a/modules/nf-core/samtools/stats/environment.yml +++ b/modules/nf-core/samtools/stats/environment.yml @@ -4,5 +4,7 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::htslib=1.21 - - bioconda::samtools=1.21 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/stats/main.nf b/modules/nf-core/samtools/stats/main.nf index 1e32e8a0..7b070ac3 100644 --- a/modules/nf-core/samtools/stats/main.nf +++ b/modules/nf-core/samtools/stats/main.nf @@ -4,15 +4,15 @@ process SAMTOOLS_STATS { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.21--h50ea8bc_0' : - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: tuple val(meta), path(input), path(input_index), path(fasta) output: tuple val(meta), path("*.stats"), emit: stats - path "versions.yml" , emit: versions + 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 @@ -27,21 +27,11 @@ process SAMTOOLS_STATS { ${reference} \\ ${input} \\ > ${prefix}.stats - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.stats - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/samtools/stats/meta.yml b/modules/nf-core/samtools/stats/meta.yml index 77b020f7..a20509ae 100644 --- a/modules/nf-core/samtools/stats/meta.yml +++ b/modules/nf-core/samtools/stats/meta.yml @@ -27,10 +27,12 @@ input: type: file description: BAM/CRAM file from alignment pattern: "*.{bam,cram}" + ontologies: [] - input_index: type: file description: BAI/CRAI file from alignment pattern: "*.{bai,crai}" + ontologies: [] - - meta2: type: map description: | @@ -40,9 +42,10 @@ input: type: file description: Reference file the CRAM was created with (optional) pattern: "*.{fasta,fa}" + ontologies: [] output: - - stats: - - meta: + stats: + - - meta: type: map description: | Groovy Map containing sample information @@ -51,11 +54,29 @@ output: type: file description: File containing samtools stats output pattern: "*.{stats}" - - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" + ontologies: [] + 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: string + description: The command used to generate the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - samtools: + type: string + description: The tool name + - samtools version | sed "1!d;s/.* //: + type: string + description: The command used to generate the version of the tool authors: - "@drpatelh" - "@FriederikeHanssen" diff --git a/modules/nf-core/samtools/stats/tests/main.nf.test.snap b/modules/nf-core/samtools/stats/tests/main.nf.test.snap index df507be7..94d981b2 100644 --- a/modules/nf-core/samtools/stats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/stats/tests/main.nf.test.snap @@ -8,11 +8,15 @@ "id": "test", "single_end": false }, - "test.stats:md5,a27fe55e49a341f92379bb20a65c6a06" + "test.stats:md5,f4aec6c41b73d34ac2fc6b3253aa39ba" ] ], "1": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ], "stats": [ [ @@ -20,19 +24,23 @@ "id": "test", "single_end": false }, - "test.stats:md5,a27fe55e49a341f92379bb20a65c6a06" + "test.stats:md5,f4aec6c41b73d34ac2fc6b3253aa39ba" ] ], - "versions": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + "versions_samtools": [ + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-09-16T09:29:16.767396182" + "timestamp": "2025-11-01T02:27:18.460724" }, "bam - stub": { "content": [ @@ -47,7 +55,11 @@ ] ], "1": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ], "stats": [ [ @@ -58,16 +70,20 @@ "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + "versions_samtools": [ + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-09-16T09:29:29.721580274" + "timestamp": "2025-11-01T02:27:30.245839" }, "cram - stub": { "content": [ @@ -82,7 +98,11 @@ ] ], "1": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ], "stats": [ [ @@ -93,16 +113,20 @@ "test.stats:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + "versions_samtools": [ + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-09-16T09:29:53.567964304" + "timestamp": "2025-11-01T02:27:39.041649" }, "bam": { "content": [ @@ -113,11 +137,15 @@ "id": "test", "single_end": false }, - "test.stats:md5,d53a2584376d78942839e9933a34d11b" + "test.stats:md5,41ba8ad30ddb598dadb177a54c222ab9" ] ], "1": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ], "stats": [ [ @@ -125,18 +153,22 @@ "id": "test", "single_end": false }, - "test.stats:md5,d53a2584376d78942839e9933a34d11b" + "test.stats:md5,41ba8ad30ddb598dadb177a54c222ab9" ] ], - "versions": [ - "versions.yml:md5,15b91d8c0e0440332e0fe4df80957043" + "versions_samtools": [ + [ + "SAMTOOLS_STATS", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2024-09-16T09:28:50.73610604" + "timestamp": "2025-11-01T02:26:55.988241" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/stats/tests/tags.yml b/modules/nf-core/samtools/stats/tests/tags.yml deleted file mode 100644 index 7c28e30f..00000000 --- a/modules/nf-core/samtools/stats/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/stats: - - modules/nf-core/samtools/stats/** From 9c17c7919d0e3490b2d139d512397d9da53cf575 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:50:55 +0100 Subject: [PATCH 058/228] fix snap config --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 512adf84..acb7eefc 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -112,7 +112,7 @@ process { // -xf 2 : expansion factor for reading compressed data //// SNAP - withName: SNAP_ALIGN { + withName: SNAPALIGNER_ALIGN { ext.args = { [ "-b-", From 14cafdd41f0011eea48e74901bbdaabe43cb7348 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:51:05 +0100 Subject: [PATCH 059/228] update ro-crate --- ro-crate-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 1bcdab89..632da7c3 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -23,7 +23,7 @@ "@type": "Dataset", "creativeWorkStatus": "InProgress", "datePublished": "2025-11-13T15:11:21+00:00", - "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP) or [`snap`](https://github.com/amplab/snap) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag\nfc_sample1,test,Homo sapiens,WES\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag\nfc_sample1,test,Homo sapiens,WES\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" From 1c8e34a4d4f3030217424a098293fa6a7d95d496 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:52:35 +0100 Subject: [PATCH 060/228] fix files-unchanged --- .github/workflows/linting.yml | 6 +- .prettierignore | 2 + .../fastq_align_dna/fastq_align_dna.diff | 85 ++++++++++++------- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 30e66026..7a527a34 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -11,7 +11,7 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Python 3.14 uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Install Nextflow uses: nf-core/setup-nextflow@v2 @@ -71,7 +71,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 with: name: linting-logs path: | diff --git a/.prettierignore b/.prettierignore index 2255e3e3..dd749d43 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,3 +12,5 @@ testing* bin/ .nf-test/ ro-crate-metadata.json +modules/nf-core/ +subworkflows/nf-core/ diff --git a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff index 44d24df2..3b39944b 100644 --- a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff +++ b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff @@ -1,8 +1,26 @@ Changes in component 'nf-core/fastq_align_dna' +'subworkflows/nf-core/fastq_align_dna/meta.yml' is unchanged Changes in 'fastq_align_dna/main.nf': --- subworkflows/nf-core/fastq_align_dna/main.nf +++ subworkflows/nf-core/fastq_align_dna/main.nf -@@ -15,51 +15,59 @@ +@@ -5,68 +5,77 @@ + // + + +-include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" +-include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' +-include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' +-include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" +-include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' +-include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" ++include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" ++include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' ++include { BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' ++include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" ++include { SNAPALIGNER_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' ++include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" + + workflow FASTQ_ALIGN_DNA { take: @@ -36,6 +54,8 @@ Changes in 'fastq_align_dna/main.nf': + return [meta, reads, index, fasta] + snap : aligner == 'snap' + return [meta, reads, index] ++ strobe : aligner == 'strobe' ++ return [meta, reads, fasta, index] + other : true + } + .set{ch_to_align} @@ -48,63 +68,66 @@ Changes in 'fastq_align_dna/main.nf': // Align fastq files to reference genome and (optionally) sort - if (aligner == 'bowtie2') { - BOWTIE2_ALIGN(ch_reads, ch_aligner_index, ch_fasta, false, sort) // if aligner is bowtie2 -- ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) ++ BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 + ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) - ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions) - } - else if (aligner == 'bwamem'){ - BWAMEM1_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem -- ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) -- ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) ++ ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions.first()) ++ ++ BWAMEM1_MEM (ch_to_align.bwamem, sort) // If aligner is bwa-mem + ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) + ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) - ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions) - } - else if (aligner == 'bwamem2'){ - BWAMEM2_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem2 -- ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) ++ ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions.first()) ++ ++ BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 + ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) - ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions) - } - else if (aligner == 'dragmap'){ - DRAGMAP_ALIGN(ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is dragmap -- ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) -- ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) ++ ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions.first()) ++ ++ DRAGMAP_ALIGN(ch_to_align.dragmap, sort) // If aligner is dragmap + ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) + ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) - ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions) - } - else if (aligner == 'snap'){ -- SNAP_ALIGN (ch_reads, ch_aligner_index) // If aligner is snap +- SNAP_ALIGN (ch_reads, ch_aligner_index) // If aligner is snap - ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) - ch_bam_index.mix(SNAP_ALIGN.out.bai) - ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions) - } +- else if (aligner == 'strobealign'){ +- STROBEALIGN (ch_reads, ch_fasta, ch_aligner_index, sort) // If aligner is strobealign +- ch_bam = ch_bam.mix(STROBEALIGN.out.bam) +- ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) +- ch_versions = ch_versions.mix(STROBEALIGN.out.versions) +- } - else { - error "Unknown aligner: ${aligner}" - } -+ BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 -+ ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) -+ ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions.first()) -+ -+ BWAMEM1_MEM (ch_to_align.bwamem, sort) // If aligner is bwa-mem -+ ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) -+ ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) -+ ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions.first()) -+ -+ BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 -+ ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) -+ ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions.first()) -+ -+ DRAGMAP_ALIGN(ch_to_align.dragmap, sort) // If aligner is dragmap -+ ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) -+ ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) + ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) + -+ SNAP_ALIGN(ch_to_align.snap) // If aligner is snap -+ ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) -+ ch_bam_index.mix(SNAP_ALIGN.out.bai) -+ ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions.first()) ++ SNAPALIGNER_ALIGN(ch_to_align.snap) // If aligner is snap ++ ch_bam = ch_bam.mix(SNAPALIGNER_ALIGN.out.bam) ++ ch_bam_index.mix(SNAPALIGNER_ALIGN.out.bai) ++ ch_versions = ch_versions.mix(SNAPALIGNER_ALIGN.out.versions.first()) ++ ++ STROBEALIGN(ch_to_align.strobe, sort) // If aligner is strobealign ++ ch_bam = ch_bam.mix(STROBEALIGN.out.bam) ++ ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) ++ ch_versions = ch_versions.mix(STROBEALIGN.out.versions.first()) emit: bam = ch_bam // channel: [ [meta], bam ] -'subworkflows/nf-core/fastq_align_dna/meta.yml' is unchanged -'subworkflows/nf-core/fastq_align_dna/tests/main.nf.test' is unchanged 'subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap' is unchanged -'subworkflows/nf-core/fastq_align_dna/tests/nextflow.config' is unchanged +'subworkflows/nf-core/fastq_align_dna/tests/main.nf.test' is unchanged ************************************************************ From a4555b6438af40e02b0ef1bf3d679bcf60127e55 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:18:50 +0100 Subject: [PATCH 061/228] patch modules --- modules.json | 12 +++--- .../nf-core/bowtie2/align/bowtie2-align.diff | 5 +-- modules/nf-core/bwa/mem/bwa-mem.diff | 5 +-- modules/nf-core/bwamem2/mem/bwamem2-mem.diff | 5 +-- .../nf-core/dragmap/align/dragmap-align.diff | 13 +++--- modules/nf-core/fastp/fastp.diff | 21 ---------- modules/nf-core/mosdepth/mosdepth.diff | 5 +-- .../nf-core/picard/collecthsmetrics/main.nf | 6 +-- .../picard-collecthsmetrics.diff | 40 +++++++++++++++---- .../picard-collectmultiplemetrics.diff | 4 +- .../picard-collectwgsmetrics.diff | 4 +- .../samtools/convert/samtools-convert.diff | 5 +-- .../samtools/coverage/samtools-coverage.diff | 5 +-- .../samtools/sormadup/samtools-sormadup.diff | 5 +-- modules/nf-core/samtools/sort/main.nf | 1 + .../nf-core/samtools/sort/samtools-sort.diff | 24 +++++------ .../samtools/stats/samtools-stats.diff | 5 +-- .../snapaligner/align/snapaligner-align.diff | 2 +- modules/nf-core/star/align/star-align.diff | 10 ++--- modules/nf-core/strobealign/strobealign.diff | 22 ++++++++++ subworkflows/local/bam_qc/meta.yml | 0 subworkflows/local/coverage/meta.yml | 0 subworkflows/local/fastq_align_rna/meta.yml | 0 .../local/fastq_to_aligned_cram/meta.yml | 0 .../local/fastq_to_unaligned_cram/meta.yml | 0 .../meta.yml | 0 .../nf-core/utils_nfcore_pipeline/main.nf | 2 +- .../utils_nfcore_pipeline.diff | 21 ++++++++++ 28 files changed, 131 insertions(+), 91 deletions(-) delete mode 100644 modules/nf-core/fastp/fastp.diff create mode 100644 modules/nf-core/strobealign/strobealign.diff create mode 100644 subworkflows/local/bam_qc/meta.yml create mode 100644 subworkflows/local/coverage/meta.yml create mode 100644 subworkflows/local/fastq_align_rna/meta.yml create mode 100644 subworkflows/local/fastq_to_aligned_cram/meta.yml create mode 100644 subworkflows/local/fastq_to_unaligned_cram/meta.yml create mode 100644 subworkflows/local/utils_nfcore_preprocessing_pipeline/meta.yml create mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff diff --git a/modules.json b/modules.json index 7d0d7bc8..d3c15c5a 100644 --- a/modules.json +++ b/modules.json @@ -48,8 +48,7 @@ "fastp": { "branch": "master", "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", - "installed_by": ["modules"], - "patch": "modules/nf-core/fastp/fastp.diff" + "installed_by": ["modules"] }, "md5sum": { "branch": "master", @@ -151,7 +150,8 @@ "strobealign": { "branch": "master", "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", - "installed_by": ["fastq_align_dna", "modules"] + "installed_by": ["fastq_align_dna", "modules"], + "patch": "modules/nf-core/strobealign/strobealign.diff" } } }, @@ -165,8 +165,7 @@ "fastq_align_dna": { "branch": "master", "git_sha": "070ddae7fb59384d3d85bf69eb9a1d71ab33ada9", - "installed_by": ["subworkflows"], - "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" + "installed_by": ["subworkflows"] }, "utils_nextflow_pipeline": { "branch": "master", @@ -176,7 +175,8 @@ "utils_nfcore_pipeline": { "branch": "master", "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", - "installed_by": ["subworkflows"] + "installed_by": ["subworkflows"], + "patch": "subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff" }, "utils_nfschema_plugin": { "branch": "master", diff --git a/modules/nf-core/bowtie2/align/bowtie2-align.diff b/modules/nf-core/bowtie2/align/bowtie2-align.diff index 1a6f0ab5..33d3a5cf 100644 --- a/modules/nf-core/bowtie2/align/bowtie2-align.diff +++ b/modules/nf-core/bowtie2/align/bowtie2-align.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/bowtie2/align' +Changes in component 'nf-core/bowtie2/align' 'modules/nf-core/bowtie2/align/environment.yml' is unchanged 'modules/nf-core/bowtie2/align/meta.yml' is unchanged Changes in 'bowtie2/align/main.nf': --- modules/nf-core/bowtie2/align/main.nf +++ modules/nf-core/bowtie2/align/main.nf @@ -8,9 +8,7 @@ - 'biocontainers/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:f70b31a2db15c023d641c32f433fb02cd04df5a6-0' }" + 'community.wave.seqera.io/library/bowtie2_htslib_samtools_pigz:edeb13799090a2a6' }" input: - tuple val(meta) , path(reads) @@ -19,7 +19,6 @@ Changes in 'bowtie2/align/main.nf': 'modules/nf-core/bowtie2/align/tests/main.nf.test.snap' is unchanged 'modules/nf-core/bowtie2/align/tests/large_index.config' is unchanged 'modules/nf-core/bowtie2/align/tests/sam2.config' is unchanged -'modules/nf-core/bowtie2/align/tests/tags.yml' is unchanged 'modules/nf-core/bowtie2/align/tests/main.nf.test' is unchanged 'modules/nf-core/bowtie2/align/tests/sam.config' is unchanged 'modules/nf-core/bowtie2/align/tests/cram_crai.config' is unchanged diff --git a/modules/nf-core/bwa/mem/bwa-mem.diff b/modules/nf-core/bwa/mem/bwa-mem.diff index e07a383f..07ca43b0 100644 --- a/modules/nf-core/bwa/mem/bwa-mem.diff +++ b/modules/nf-core/bwa/mem/bwa-mem.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/bwa/mem' +Changes in component 'nf-core/bwa/mem' 'modules/nf-core/bwa/mem/environment.yml' is unchanged 'modules/nf-core/bwa/mem/meta.yml' is unchanged Changes in 'bwa/mem/main.nf': --- modules/nf-core/bwa/mem/main.nf +++ modules/nf-core/bwa/mem/main.nf @@ -8,9 +8,7 @@ - 'biocontainers/mulled-v2-fe8faa35dbf6dc65a0f7f5d4ea12e31a79f73e40:1bd8542a8a0b42e0981337910954371d0230828e-0' }" + 'community.wave.seqera.io/library/bwa_htslib_samtools:83b50ff84ead50d0' }" input: - tuple val(meta) , path(reads) @@ -17,6 +17,5 @@ Changes in 'bwa/mem/main.nf': output: 'modules/nf-core/bwa/mem/tests/main.nf.test.snap' is unchanged -'modules/nf-core/bwa/mem/tests/tags.yml' is unchanged 'modules/nf-core/bwa/mem/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/bwamem2/mem/bwamem2-mem.diff b/modules/nf-core/bwamem2/mem/bwamem2-mem.diff index 7c300098..37262b6f 100644 --- a/modules/nf-core/bwamem2/mem/bwamem2-mem.diff +++ b/modules/nf-core/bwamem2/mem/bwamem2-mem.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/bwamem2/mem' +Changes in component 'nf-core/bwamem2/mem' 'modules/nf-core/bwamem2/mem/environment.yml' is unchanged 'modules/nf-core/bwamem2/mem/meta.yml' is unchanged Changes in 'bwamem2/mem/main.nf': --- modules/nf-core/bwamem2/mem/main.nf +++ modules/nf-core/bwamem2/mem/main.nf @@ -8,9 +8,7 @@ - 'biocontainers/mulled-v2-e5d375990341c5aef3c9aff74f96f66f65375ef6:2d15960ccea84e249a150b7f5d4db3a42fc2d6c3-0' }" + 'community.wave.seqera.io/library/bwa-mem2_htslib_samtools:db98f81f55b64113' }" input: - tuple val(meta), path(reads) @@ -17,6 +17,5 @@ Changes in 'bwamem2/mem/main.nf': output: 'modules/nf-core/bwamem2/mem/tests/main.nf.test.snap' is unchanged -'modules/nf-core/bwamem2/mem/tests/tags.yml' is unchanged 'modules/nf-core/bwamem2/mem/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/dragmap/align/dragmap-align.diff b/modules/nf-core/dragmap/align/dragmap-align.diff index 60188aab..cf4c75e6 100644 --- a/modules/nf-core/dragmap/align/dragmap-align.diff +++ b/modules/nf-core/dragmap/align/dragmap-align.diff @@ -1,22 +1,23 @@ -Changes in module 'nf-core/dragmap/align' +Changes in component 'nf-core/dragmap/align' 'modules/nf-core/dragmap/align/environment.yml' is unchanged 'modules/nf-core/dragmap/align/meta.yml' is unchanged Changes in 'dragmap/align/main.nf': --- modules/nf-core/dragmap/align/main.nf +++ modules/nf-core/dragmap/align/main.nf -@@ -8,9 +8,7 @@ - 'biocontainers/mulled-v2-580d344d9d4a496cd403932da8765f9e0187774d:7eed251370ac7f3537c3d9472cdb2f9f5d8da1c5-0' }" +@@ -9,10 +9,8 @@ + : 'biocontainers/mulled-v2-580d344d9d4a496cd403932da8765f9e0187774d:df80ed8d23d0a2c43181a2b3dd1b39f2d00fab5c-0'}" input: -- tuple val(meta) , path(reads) +- tuple val(meta), path(reads) - tuple val(meta2), path(hashmap) - tuple val(meta3), path(fasta) +- val sort_bam + tuple val(meta) , path(reads), path(hashmap), path(fasta) - val sort_bam ++ val sort_bam output: + tuple val(meta), path("*.sam"), emit: sam, optional: true 'modules/nf-core/dragmap/align/tests/main.nf.test.snap' is unchanged -'modules/nf-core/dragmap/align/tests/tags.yml' is unchanged 'modules/nf-core/dragmap/align/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/fastp/fastp.diff b/modules/nf-core/fastp/fastp.diff deleted file mode 100644 index 266c00b1..00000000 --- a/modules/nf-core/fastp/fastp.diff +++ /dev/null @@ -1,21 +0,0 @@ -Changes in module 'nf-core/fastp' -'modules/nf-core/fastp/environment.yml' is unchanged -'modules/nf-core/fastp/meta.yml' is unchanged -Changes in 'fastp/main.nf': ---- modules/nf-core/fastp/main.nf -+++ modules/nf-core/fastp/main.nf -@@ -92,7 +92,6 @@ - $fail_fastq \\ - $merge_fastq \\ - --thread $task.cpus \\ -- --detect_adapter_for_pe \\ - $args \\ - 2> >(tee ${prefix}.fastp.log >&2) - - -'modules/nf-core/fastp/tests/main.nf.test.snap' is unchanged -'modules/nf-core/fastp/tests/tags.yml' is unchanged -'modules/nf-core/fastp/tests/main.nf.test' is unchanged -'modules/nf-core/fastp/tests/nextflow.save_failed.config' is unchanged -'modules/nf-core/fastp/tests/nextflow.interleaved.config' is unchanged -************************************************************ diff --git a/modules/nf-core/mosdepth/mosdepth.diff b/modules/nf-core/mosdepth/mosdepth.diff index 53e32f2b..59a3adf0 100644 --- a/modules/nf-core/mosdepth/mosdepth.diff +++ b/modules/nf-core/mosdepth/mosdepth.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/mosdepth' +Changes in component 'nf-core/mosdepth' 'modules/nf-core/mosdepth/environment.yml' is unchanged 'modules/nf-core/mosdepth/meta.yml' is unchanged Changes in 'mosdepth/main.nf': --- modules/nf-core/mosdepth/main.nf +++ modules/nf-core/mosdepth/main.nf @@ -8,8 +8,7 @@ - 'biocontainers/mosdepth:0.3.8--hd299d5a_0'}" + 'community.wave.seqera.io/library/mosdepth_htslib:0f58993cb6d93294'}" input: - tuple val(meta), path(bam), path(bai), path(bed) @@ -18,7 +18,6 @@ Changes in 'mosdepth/main.nf': 'modules/nf-core/mosdepth/tests/main.nf.test.snap' is unchanged 'modules/nf-core/mosdepth/tests/threshold.config' is unchanged 'modules/nf-core/mosdepth/tests/quantized.config' is unchanged -'modules/nf-core/mosdepth/tests/tags.yml' is unchanged 'modules/nf-core/mosdepth/tests/main.nf.test' is unchanged 'modules/nf-core/mosdepth/tests/window.config' is unchanged ************************************************************ diff --git a/modules/nf-core/picard/collecthsmetrics/main.nf b/modules/nf-core/picard/collecthsmetrics/main.nf index 3a51548f..a1dc56d8 100644 --- a/modules/nf-core/picard/collecthsmetrics/main.nf +++ b/modules/nf-core/picard/collecthsmetrics/main.nf @@ -20,7 +20,7 @@ process PICARD_COLLECTHSMETRICS { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def reference = ref ? "--REFERENCE_SEQUENCE ${ref}" : "" + def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" def avail_mem = 3072 if (!task.memory) { @@ -33,14 +33,14 @@ process PICARD_COLLECTHSMETRICS { def bait_intervallist_cmd = "" if (bait_intervals =~ /.(bed|bed.gz)$/){ bait_interval_list = bait_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") - bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." + bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." } def target_interval_list = target_intervals def target_intervallist_cmd = "" if (target_intervals =~ /.(bed|bed.gz)$/){ target_interval_list = target_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") - target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." + target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." } diff --git a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff index 951f60dc..5907d093 100644 --- a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff +++ b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff @@ -1,23 +1,49 @@ -Changes in module 'nf-core/picard/collecthsmetrics' +Changes in component 'nf-core/picard/collecthsmetrics' 'modules/nf-core/picard/collecthsmetrics/environment.yml' is unchanged 'modules/nf-core/picard/collecthsmetrics/meta.yml' is unchanged Changes in 'picard/collecthsmetrics/main.nf': --- modules/nf-core/picard/collecthsmetrics/main.nf +++ modules/nf-core/picard/collecthsmetrics/main.nf -@@ -8,10 +8,7 @@ - 'biocontainers/picard:3.3.0--hdfd78af_0' }" +@@ -8,11 +8,7 @@ + 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: - tuple val(meta), path(bam), path(bai), path(bait_intervals, stageAs: "baits/*"), path(target_intervals, stageAs: 'targets/*') -- tuple val(meta2), path(fasta) -- tuple val(meta3), path(fai) -- tuple val(meta4), path(dict) +- tuple val(meta2), path(ref) +- tuple val(meta3), path(ref_fai) +- tuple val(meta4), path(ref_dict) +- tuple val(meta5), path(ref_gzi) // ref_gzi only required if reference is gzipped + tuple val(meta), path(bam), path(bai), path(bait_intervals, stageAs: "bait/*"), path(target_intervals, stageAs: "target/*") ,path(fasta) ,path(fai) ,path(dict) output: tuple val(meta), path("*_metrics") , emit: metrics +@@ -24,7 +20,7 @@ + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" +- def reference = ref ? "--REFERENCE_SEQUENCE ${ref}" : "" ++ def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" + + def avail_mem = 3072 + if (!task.memory) { +@@ -37,14 +33,14 @@ + def bait_intervallist_cmd = "" + if (bait_intervals =~ /.(bed|bed.gz)$/){ + bait_interval_list = bait_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") +- bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." ++ bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." + } + + def target_interval_list = target_intervals + def target_intervallist_cmd = "" + if (target_intervals =~ /.(bed|bed.gz)$/){ + target_interval_list = target_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") +- target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." ++ target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." + } + + 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap' is unchanged -'modules/nf-core/picard/collecthsmetrics/tests/tags.yml' is unchanged 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff index 6c796d52..489076fb 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff +++ b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/picard/collectmultiplemetrics' +Changes in component 'nf-core/picard/collectmultiplemetrics' 'modules/nf-core/picard/collectmultiplemetrics/environment.yml' is unchanged 'modules/nf-core/picard/collectmultiplemetrics/meta.yml' is unchanged Changes in 'picard/collectmultiplemetrics/main.nf': --- modules/nf-core/picard/collectmultiplemetrics/main.nf +++ modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -8,9 +8,7 @@ - 'biocontainers/picard:3.3.0--hdfd78af_0' }" + 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: - tuple val(meta) , path(bam), path(bai) diff --git a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff index 98d4a1eb..bf843c60 100644 --- a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff +++ b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/picard/collectwgsmetrics' +Changes in component 'nf-core/picard/collectwgsmetrics' 'modules/nf-core/picard/collectwgsmetrics/environment.yml' is unchanged 'modules/nf-core/picard/collectwgsmetrics/meta.yml' is unchanged Changes in 'picard/collectwgsmetrics/main.nf': --- modules/nf-core/picard/collectwgsmetrics/main.nf +++ modules/nf-core/picard/collectwgsmetrics/main.nf @@ -8,9 +8,7 @@ - 'biocontainers/picard:3.3.0--hdfd78af_0' }" + 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: - tuple val(meta), path(bam), path(bai) diff --git a/modules/nf-core/samtools/convert/samtools-convert.diff b/modules/nf-core/samtools/convert/samtools-convert.diff index 67617c31..bd28d5da 100644 --- a/modules/nf-core/samtools/convert/samtools-convert.diff +++ b/modules/nf-core/samtools/convert/samtools-convert.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/samtools/convert' +Changes in component 'nf-core/samtools/convert' 'modules/nf-core/samtools/convert/environment.yml' is unchanged 'modules/nf-core/samtools/convert/meta.yml' is unchanged Changes in 'samtools/convert/main.nf': --- modules/nf-core/samtools/convert/main.nf +++ modules/nf-core/samtools/convert/main.nf @@ -8,9 +8,7 @@ - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(index) @@ -17,6 +17,5 @@ Changes in 'samtools/convert/main.nf': tuple val(meta), path("*.bam") , emit: bam , optional: true 'modules/nf-core/samtools/convert/tests/main.nf.test.snap' is unchanged -'modules/nf-core/samtools/convert/tests/tags.yml' is unchanged 'modules/nf-core/samtools/convert/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/samtools/coverage/samtools-coverage.diff b/modules/nf-core/samtools/coverage/samtools-coverage.diff index 3b0e1f03..5dbbbd9e 100644 --- a/modules/nf-core/samtools/coverage/samtools-coverage.diff +++ b/modules/nf-core/samtools/coverage/samtools-coverage.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/samtools/coverage' +Changes in component 'nf-core/samtools/coverage' 'modules/nf-core/samtools/coverage/environment.yml' is unchanged 'modules/nf-core/samtools/coverage/meta.yml' is unchanged Changes in 'samtools/coverage/main.nf': --- modules/nf-core/samtools/coverage/main.nf +++ modules/nf-core/samtools/coverage/main.nf @@ -8,9 +8,7 @@ - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(input_index) @@ -17,6 +17,5 @@ Changes in 'samtools/coverage/main.nf': tuple val(meta), path("*.txt"), emit: coverage 'modules/nf-core/samtools/coverage/tests/main.nf.test.snap' is unchanged -'modules/nf-core/samtools/coverage/tests/tags.yml' is unchanged 'modules/nf-core/samtools/coverage/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/samtools/sormadup/samtools-sormadup.diff b/modules/nf-core/samtools/sormadup/samtools-sormadup.diff index 6da27c02..f614f937 100644 --- a/modules/nf-core/samtools/sormadup/samtools-sormadup.diff +++ b/modules/nf-core/samtools/sormadup/samtools-sormadup.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/samtools/sormadup' +Changes in component 'nf-core/samtools/sormadup' 'modules/nf-core/samtools/sormadup/environment.yml' is unchanged 'modules/nf-core/samtools/sormadup/meta.yml' is unchanged Changes in 'samtools/sormadup/main.nf': --- modules/nf-core/samtools/sormadup/main.nf +++ modules/nf-core/samtools/sormadup/main.nf @@ -8,8 +8,7 @@ - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input) @@ -17,7 +17,6 @@ Changes in 'samtools/sormadup/main.nf': 'modules/nf-core/samtools/sormadup/tests/main.nf.test.snap' is unchanged 'modules/nf-core/samtools/sormadup/tests/bam.config' is unchanged -'modules/nf-core/samtools/sormadup/tests/tags.yml' is unchanged 'modules/nf-core/samtools/sormadup/tests/cram.config' is unchanged 'modules/nf-core/samtools/sormadup/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index 7b83e4a1..4abb5f3c 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -9,6 +9,7 @@ process SAMTOOLS_SORT { input: tuple val(meta) , path(bam), path(fasta) + val index_format output: tuple val(meta), path("${prefix}.bam"), emit: bam, optional: true diff --git a/modules/nf-core/samtools/sort/samtools-sort.diff b/modules/nf-core/samtools/sort/samtools-sort.diff index 817f68c5..a7a10b78 100644 --- a/modules/nf-core/samtools/sort/samtools-sort.diff +++ b/modules/nf-core/samtools/sort/samtools-sort.diff @@ -1,39 +1,37 @@ -Changes in module 'nf-core/samtools/sort' +Changes in component 'nf-core/samtools/sort' 'modules/nf-core/samtools/sort/environment.yml' is unchanged 'modules/nf-core/samtools/sort/meta.yml' is unchanged Changes in 'samtools/sort/main.nf': --- modules/nf-core/samtools/sort/main.nf +++ modules/nf-core/samtools/sort/main.nf @@ -8,8 +8,7 @@ - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta) , path(bam) - tuple val(meta2), path(fasta) + tuple val(meta) , path(bam), path(fasta) + val index_format output: - tuple val(meta), path("*.bam"), emit: bam, optional: true - -@@ -28,6 +27,7 @@ - args.contains("--output-fmt cram") ? "cram" : - "bam" +@@ -31,6 +30,7 @@ + args.contains("--output-fmt cram") ? "cram" : + "bam" def reference = fasta ? "--reference ${fasta}" : "" + def sort_memory = (task.memory.mega/task.cpus*0.75).intValue() - if ("$bam" == "${prefix}.bam") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" - - """ -@@ -39,6 +39,7 @@ + output_file = index_format ? "${prefix}.${extension}##idx##${prefix}.${extension}.${index_format} --write-index" : "${prefix}.${extension}" + if (index_format) { + if (!index_format.matches('bai|csi|crai')) { +@@ -50,6 +50,7 @@ -T ${prefix} \\ --threads $task.cpus \\ ${reference} \\ + -m ${sort_memory}M \\ - -o ${prefix}.${extension} \\ + -o ${output_file} \\ - 'modules/nf-core/samtools/sort/tests/main.nf.test.snap' is unchanged -'modules/nf-core/samtools/sort/tests/tags.yml' is unchanged 'modules/nf-core/samtools/sort/tests/nextflow_cram.config' is unchanged 'modules/nf-core/samtools/sort/tests/nextflow.config' is unchanged 'modules/nf-core/samtools/sort/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/samtools/stats/samtools-stats.diff b/modules/nf-core/samtools/stats/samtools-stats.diff index dc243ad7..1ccaf8fe 100644 --- a/modules/nf-core/samtools/stats/samtools-stats.diff +++ b/modules/nf-core/samtools/stats/samtools-stats.diff @@ -1,11 +1,11 @@ -Changes in module 'nf-core/samtools/stats' +Changes in component 'nf-core/samtools/stats' 'modules/nf-core/samtools/stats/environment.yml' is unchanged 'modules/nf-core/samtools/stats/meta.yml' is unchanged Changes in 'samtools/stats/main.nf': --- modules/nf-core/samtools/stats/main.nf +++ modules/nf-core/samtools/stats/main.nf @@ -8,8 +8,7 @@ - 'biocontainers/samtools:1.21--h50ea8bc_0' }" + 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(input_index) @@ -16,6 +16,5 @@ Changes in 'samtools/stats/main.nf': tuple val(meta), path("*.stats"), emit: stats 'modules/nf-core/samtools/stats/tests/main.nf.test.snap' is unchanged -'modules/nf-core/samtools/stats/tests/tags.yml' is unchanged 'modules/nf-core/samtools/stats/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/snapaligner/align/snapaligner-align.diff b/modules/nf-core/snapaligner/align/snapaligner-align.diff index f6f326aa..34d23cd4 100644 --- a/modules/nf-core/snapaligner/align/snapaligner-align.diff +++ b/modules/nf-core/snapaligner/align/snapaligner-align.diff @@ -5,7 +5,7 @@ Changes in 'snapaligner/align/main.nf': --- modules/nf-core/snapaligner/align/main.nf +++ modules/nf-core/snapaligner/align/main.nf @@ -8,8 +8,7 @@ - 'biocontainers/snap-aligner:2.0.3--hd03093a_0' }" + 'community.wave.seqera.io/library/snap-aligner:2.0.5--23601d3a3a2ae452' }" input: - tuple val(meta) , path(reads, stageAs: "?/*") diff --git a/modules/nf-core/star/align/star-align.diff b/modules/nf-core/star/align/star-align.diff index 019f65d6..398da009 100644 --- a/modules/nf-core/star/align/star-align.diff +++ b/modules/nf-core/star/align/star-align.diff @@ -1,4 +1,6 @@ Changes in component 'nf-core/star/align' +'modules/nf-core/star/align/environment.yml' is unchanged +'modules/nf-core/star/align/meta.yml' is unchanged Changes in 'star/align/main.nf': --- modules/nf-core/star/align/main.nf +++ modules/nf-core/star/align/main.nf @@ -24,11 +26,9 @@ Changes in 'star/align/main.nf': def seq_center_arg = seq_center ? "'CN:$seq_center'" : "" attrRG = args.contains("--outSAMattrRGline") ? "" : "--outSAMattrRGline 'ID:$prefix' $seq_center_arg 'SM:$prefix' $seq_platform_arg" -'modules/nf-core/star/align/environment.yml' is unchanged -'modules/nf-core/star/align/meta.yml' is unchanged -'modules/nf-core/star/align/tests/nextflow.starfusion.config' is unchanged -'modules/nf-core/star/align/tests/main.nf.test' is unchanged -'modules/nf-core/star/align/tests/nextflow.arriba.config' is unchanged 'modules/nf-core/star/align/tests/main.nf.test.snap' is unchanged +'modules/nf-core/star/align/tests/nextflow.arriba.config' is unchanged +'modules/nf-core/star/align/tests/nextflow.starfusion.config' is unchanged 'modules/nf-core/star/align/tests/nextflow.config' is unchanged +'modules/nf-core/star/align/tests/main.nf.test' is unchanged ************************************************************ diff --git a/modules/nf-core/strobealign/strobealign.diff b/modules/nf-core/strobealign/strobealign.diff new file mode 100644 index 00000000..2e5880dd --- /dev/null +++ b/modules/nf-core/strobealign/strobealign.diff @@ -0,0 +1,22 @@ +Changes in component 'nf-core/strobealign' +'modules/nf-core/strobealign/environment.yml' is unchanged +'modules/nf-core/strobealign/meta.yml' is unchanged +Changes in 'strobealign/main.nf': +--- modules/nf-core/strobealign/main.nf ++++ modules/nf-core/strobealign/main.nf +@@ -8,9 +8,7 @@ + 'community.wave.seqera.io/library/htslib_samtools_strobealign_pigz:4fa4f439c6bea386' }" + + input: +- tuple val(meta) , path(reads) +- tuple val(meta2), path(fasta) +- tuple val(meta3), path(index) ++ tuple val(meta) , path(reads), path(fasta), path(index) + val sort_bam + + output: + +'modules/nf-core/strobealign/tests/main.nf.test.snap' is unchanged +'modules/nf-core/strobealign/tests/nextflow.config' is unchanged +'modules/nf-core/strobealign/tests/main.nf.test' is unchanged +************************************************************ diff --git a/subworkflows/local/bam_qc/meta.yml b/subworkflows/local/bam_qc/meta.yml new file mode 100644 index 00000000..e69de29b diff --git a/subworkflows/local/coverage/meta.yml b/subworkflows/local/coverage/meta.yml new file mode 100644 index 00000000..e69de29b diff --git a/subworkflows/local/fastq_align_rna/meta.yml b/subworkflows/local/fastq_align_rna/meta.yml new file mode 100644 index 00000000..e69de29b diff --git a/subworkflows/local/fastq_to_aligned_cram/meta.yml b/subworkflows/local/fastq_to_aligned_cram/meta.yml new file mode 100644 index 00000000..e69de29b diff --git a/subworkflows/local/fastq_to_unaligned_cram/meta.yml b/subworkflows/local/fastq_to_unaligned_cram/meta.yml new file mode 100644 index 00000000..e69de29b diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/meta.yml b/subworkflows/local/utils_nfcore_preprocessing_pipeline/meta.yml new file mode 100644 index 00000000..e69de29b diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a4..bfd25876 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -98,7 +98,7 @@ def workflowVersionToYAML() { // Get channel of software versions used in pipeline in YAML format // def softwareVersionsToYAML(ch_versions) { - return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(channel.of(workflowVersionToYAML())) + return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) } // diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff b/subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff new file mode 100644 index 00000000..38096acc --- /dev/null +++ b/subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff @@ -0,0 +1,21 @@ +Changes in component 'nf-core/utils_nfcore_pipeline' +'subworkflows/nf-core/utils_nfcore_pipeline/meta.yml' is unchanged +Changes in 'utils_nfcore_pipeline/main.nf': +--- subworkflows/nf-core/utils_nfcore_pipeline/main.nf ++++ subworkflows/nf-core/utils_nfcore_pipeline/main.nf +@@ -98,7 +98,7 @@ + // Get channel of software versions used in pipeline in YAML format + // + def softwareVersionsToYAML(ch_versions) { +- return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(channel.of(workflowVersionToYAML())) ++ return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) + } + + // + +'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test' is unchanged +'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap' is unchanged +'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap' is unchanged +'subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config' is unchanged +'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test' is unchanged +************************************************************ From 3f9cc7cef00e198146b9d0f9724a7b15068d647d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:25:27 +0100 Subject: [PATCH 062/228] re-add analysis profiles --- nextflow.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nextflow.config b/nextflow.config index a7453b62..01378b19 100644 --- a/nextflow.config +++ b/nextflow.config @@ -185,6 +185,12 @@ profiles { } test { includeConfig 'conf/test.config' } test_full { includeConfig 'conf/test_full.config' } + s3_ugent { includeConfig 'conf/profiles/s3_ugent.config' } + // analysis profiles + sWGS { includeConfig 'conf/profiles/sWGS.config' } + WGS { includeConfig 'conf/profiles/WGS.config' } + WES { includeConfig 'conf/profiles/WES.config' } + copgt { includeConfig 'conf/profiles/copgt.config' } } // Load nf-core custom profiles from different institutions From ef8d686b45c2230ebfd21f84c3b2eff78fee06ab Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:55:17 +0100 Subject: [PATCH 063/228] set cram output to v3 to ensure downstream compatibility --- conf/modules.config | 8 ++++---- subworkflows/local/bam_qc/main.nf | 1 - workflows/preprocessing.nf | 26 ++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index acb7eefc..56bf31d1 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -48,7 +48,7 @@ process { ext.args = { [ meta.readgroup ? "--rg-line \"@RG\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\t") + "\"" : "", - "--output-fmt cram", + "--output-fmt cram,version=3.0", "--output-fmt-option archive", ].join(" ").trim() } @@ -153,7 +153,7 @@ process { "-d 2500", params.umi_aware ? "--barcode-name" : "", "--write-index", - "--output-fmt cram", + "--output-fmt cram,version=3.0", "--output-fmt-option archive", ].join(" ").trim() } @@ -165,7 +165,7 @@ process { ext.args = { [ "--write-index", - "--output-fmt cram", + "--output-fmt cram,version=3.0", "--output-fmt-option archive", ].join(" ").trim() } @@ -190,7 +190,7 @@ process { ext.args = { [ "-C", - "--output-fmt cram", + "--output-fmt cram,version=3.0", "--output-fmt-option archive", ].join(" ").trim() } diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index bd2cc469..e35555a8 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -23,7 +23,6 @@ workflow BAM_QC { .set { ch_bam_bai_fasta } SAMTOOLS_STATS(ch_bam_bai_fasta) - ch_versions = ch_versions.mix(SAMTOOLS_STATS.out.versions.first()) ch_bam_bai_fasta .map { meta, bam, bai, _fasta -> diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 48c7b0d1..f90dd2eb 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -446,6 +446,32 @@ workflow PREPROCESSING { // // Collate and save software versions // + def topic_versions = Channel.topic("versions") + .distinct() + .branch { entry -> + versions_file: entry instanceof Path + versions_tuple: true + } + + def topic_versions_string = topic_versions.versions_tuple + .map { process, tool, version -> + [ process[process.lastIndexOf(':')+1..-1], " ${tool}: ${version}" ] + } + .groupTuple(by:0) + .map { process, tool_versions -> + tool_versions.unique().sort() + "${process}:\n${tool_versions.join('\n')}" + } + + softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + .mix(topic_versions_string) + .collectFile( + storeDir: "${params.outdir}/pipeline_info", + name: 'nf_cmgg_preprocessing_software_mqc_versions.yml', + sort: true, + newLine: true + ).set { ch_collated_versions } + softwareVersionsToYAML(ch_versions) .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'preprocessing_software_mqc_versions.yml', sort: true, newLine: true) .set { ch_collated_versions } From 915702a421b8202fc37aa7f48218d862e83c9697 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:55:54 +0100 Subject: [PATCH 064/228] bump subwf --- modules.json | 5 ++--- .../utils_nfcore_pipeline.diff | 21 ------------------- 2 files changed, 2 insertions(+), 24 deletions(-) delete mode 100644 subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff diff --git a/modules.json b/modules.json index d3c15c5a..f5872c3f 100644 --- a/modules.json +++ b/modules.json @@ -174,9 +174,8 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", - "installed_by": ["subworkflows"], - "patch": "subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff" + "git_sha": "df4d1c8cdee98a1bbbed8fc51e82296568e0f9c1", + "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff b/subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff deleted file mode 100644 index 38096acc..00000000 --- a/subworkflows/nf-core/utils_nfcore_pipeline/utils_nfcore_pipeline.diff +++ /dev/null @@ -1,21 +0,0 @@ -Changes in component 'nf-core/utils_nfcore_pipeline' -'subworkflows/nf-core/utils_nfcore_pipeline/meta.yml' is unchanged -Changes in 'utils_nfcore_pipeline/main.nf': ---- subworkflows/nf-core/utils_nfcore_pipeline/main.nf -+++ subworkflows/nf-core/utils_nfcore_pipeline/main.nf -@@ -98,7 +98,7 @@ - // Get channel of software versions used in pipeline in YAML format - // - def softwareVersionsToYAML(ch_versions) { -- return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(channel.of(workflowVersionToYAML())) -+ return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) - } - - // - -'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test' is unchanged -'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap' is unchanged -'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.function.nf.test.snap' is unchanged -'subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config' is unchanged -'subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test' is unchanged -************************************************************ From 05707f513829df79851980d7edded46dad1e6d77 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:26:41 +0100 Subject: [PATCH 065/228] fix snapshots --- .../local/bam_qc/main.nf.test.snap | 47 +++++----- .../local/coverage/main.nf.test.snap | 36 ++++---- .../fastq_to_aligned_cram/main.nf.test.snap | 36 ++++---- .../fastq_to_unaligned_cram/main.nf.test.snap | 10 +- tests/workflows/preprocessing.nf.test.snap | 91 +++++++++---------- 5 files changed, 107 insertions(+), 113 deletions(-) diff --git a/tests/subworkflows/local/bam_qc/main.nf.test.snap b/tests/subworkflows/local/bam_qc/main.nf.test.snap index daa07dff..2403cda0 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test.snap +++ b/tests/subworkflows/local/bam_qc/main.nf.test.snap @@ -68,23 +68,22 @@ "id": "test", "single_end": false }, - "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" + "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] ], "versions": [ - "versions.yml:md5,1e3d06d4435935cb6c01c1d94dad41c3", - "versions.yml:md5,25efd393aac661d8cb2aa8669127abac", - "versions.yml:md5,28cad528cb128dd7bdad050758f1801c", - "versions.yml:md5,ebcad29c0749995f2306fbcf31b03c8c", - "versions.yml:md5,ff0b9222ca016f9d2a7fa1d24010eccf" + "versions.yml:md5,15389a9f97668f320b9628da1903a93b", + "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5", + "versions.yml:md5,593804078c060457d011f7f6b650e500", + "versions.yml:md5,f5507938ec419f55239e3faa9f99376f" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:17:45.293786329" + "timestamp": "2025-12-02T12:48:55.096074" }, "Bam QC - Samtools": { "content": [ @@ -125,21 +124,20 @@ "id": "test", "single_end": false }, - "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" + "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] ], "versions": [ - "versions.yml:md5,1e3d06d4435935cb6c01c1d94dad41c3", - "versions.yml:md5,28cad528cb128dd7bdad050758f1801c", - "versions.yml:md5,ff0b9222ca016f9d2a7fa1d24010eccf" + "versions.yml:md5,15389a9f97668f320b9628da1903a93b", + "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:19:09.897986912" + "timestamp": "2025-12-02T12:50:04.027873" }, "Bam QC - WGSmetrics": { "content": [ @@ -210,22 +208,21 @@ "id": "test", "single_end": false }, - "test.stats:md5,18292ec37f6ff9eff458683e3abf638b" + "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] ], "versions": [ - "versions.yml:md5,1e3d06d4435935cb6c01c1d94dad41c3", - "versions.yml:md5,25efd393aac661d8cb2aa8669127abac", - "versions.yml:md5,28cad528cb128dd7bdad050758f1801c", - "versions.yml:md5,5da695471744af2707c6864e2773aa27", - "versions.yml:md5,ff0b9222ca016f9d2a7fa1d24010eccf" + "versions.yml:md5,15389a9f97668f320b9628da1903a93b", + "versions.yml:md5,3d2d9acb75406ea94b547be23a45601b", + "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5", + "versions.yml:md5,f5507938ec419f55239e3faa9f99376f" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:18:47.271352687" + "timestamp": "2025-12-02T12:49:52.298773" } } \ No newline at end of file diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 7c779621..2891b942 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -49,9 +49,9 @@ ] ], "14": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ], "2": [ [ @@ -123,7 +123,7 @@ "single_end": false, "tag": "WES" }, - "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" + "test.quantized.bed.gz.csi:md5,22e9d1096b7afd3d628526c831b26397" ] ], "mosdepth_global": [ @@ -176,7 +176,7 @@ "single_end": false, "tag": "WES" }, - "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" + "test.quantized.bed.gz.csi:md5,22e9d1096b7afd3d628526c831b26397" ] ], "mosdepth_regions": [ @@ -246,17 +246,17 @@ ] ], "versions": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", + "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:20:02.213734734" + "timestamp": "2025-12-02T12:34:24.897893" }, "Coverage - seqcap": { "content": [ @@ -301,8 +301,8 @@ ], "14": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", + "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ], "2": [ [ @@ -374,7 +374,7 @@ "single_end": false, "tag": "seqcap" }, - "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" + "test.quantized.bed.gz.csi:md5,22e9d1096b7afd3d628526c831b26397" ] ], "mosdepth_global": [ @@ -427,7 +427,7 @@ "single_end": false, "tag": "seqcap" }, - "test.quantized.bed.gz.csi:md5,39f0a425a3f11134e247141c0890fa89" + "test.quantized.bed.gz.csi:md5,22e9d1096b7afd3d628526c831b26397" ] ], "mosdepth_regions": [ @@ -490,15 +490,15 @@ ] ], "versions": [ - "versions.yml:md5,2d22ebfca674911d28ac60f352a98b1b", - "versions.yml:md5,d7c2bc4717e6518d6ce017a70a3f1df0" + "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", + "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:19:32.672589279" + "timestamp": "2025-12-02T12:34:05.200571" } } \ No newline at end of file diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index bcaa1414..50296e7d 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -84,18 +84,18 @@ ] ], "versions": [ - "versions.yml:md5,7e9be834e78aaf958ee23618377d8da5", - "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", + "versions.yml:md5,9598e8236a8fbab0f6745715fa0de9d3", + "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:24:09.28415088" + "timestamp": "2025-12-02T12:52:20.737608" }, "fastq to cram - bwa - samtools sormadup": { "content": [ @@ -137,21 +137,21 @@ } } }, - "test.merged.metrics:md5,6e4d03a56877997e0e035d267550e381" + "test.merged.metrics:md5,a4129081c3f2f10e6f6ecdf8b1c44852" ] ], "versions": [ - "versions.yml:md5,7d966b1716b0f134534741313257f0ec", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" + "versions.yml:md5,53fb2eac4cab0b817e852418eb0ba719", + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:28:32.155644934" + "timestamp": "2025-12-02T13:04:47.356008" }, "fastq to cram - star - bamsormadup": { "content": [ @@ -197,16 +197,16 @@ ] ], "versions": [ - "versions.yml:md5,7e9be834e78aaf958ee23618377d8da5", + "versions.yml:md5,9598e8236a8fbab0f6745715fa0de9d3", "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:27:31.44516813" + "timestamp": "2025-12-02T13:04:21.082358" }, "fastq to cram - bwa - samtools sort": { "content": [ diff --git a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap index 3dfdcb8b..39fd0d73 100644 --- a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap @@ -16,15 +16,15 @@ ] ], "versions": [ - "versions.yml:md5,422c9b3605121c3528ee755bbdb12a85", - "versions.yml:md5,f494e9f15ef064e11d31abca2f2ba51c" + "versions.yml:md5,7d0123b33defe52fceb94bd95f802978", + "versions.yml:md5,f253e859e7aa43e34481f5493c4e847b" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:30:55.301756415" + "timestamp": "2025-12-02T13:05:20.48603" } } \ No newline at end of file diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 36fadad2..348c1fd2 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -102,7 +102,7 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, - "sample1.fastp.json:md5,543fb8fe4512975ce7dafd5287cae601" + "sample1.fastp.json:md5,caf903cc79784ceaa71d6ef743c02ff3" ] ], "md5sums": [ @@ -261,7 +261,7 @@ "id": "sample1" } }, - "sample1.quantized.bed.gz.csi:md5,ac24f9c737b984091364b3c5b1f45567" + "sample1.quantized.bed.gz.csi:md5,efa0455ec39b49b96fd44c1efcbef8ab" ] ], "mosdepth_regions": [ @@ -580,7 +580,7 @@ "id": "sample1" } }, - "sample1.stats:md5,0653e8f1834d58c557ad463c36ae6b61" + "sample1.stats:md5,33a10d02ce404301e012f07841815f59" ] ], "sormadup_metrics": [ @@ -613,27 +613,26 @@ ], "versions": [ - "versions.yml:md5,321e55c8f19102dc87a10e981635edda", - "versions.yml:md5,3e9382a1dc62d4f405bcfb58fe6b7768", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", - "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", - "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", - "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,02acae00818ba01a01e2bdb03b574343", + "versions.yml:md5,23b060bcc18a02fc8f981102ef3a3006", + "versions.yml:md5,31df076e5d21d61db772cb39643350e2", + "versions.yml:md5,b702df83d9ece54caa0e765a6286cdd2", + "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", + "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", + "versions.yml:md5,cdce7da7ce14e29fbd9fd72e88505ffa", + "versions.yml:md5,d00b52835d019d68e58aafd218429a75", "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", - "versions.yml:md5,ebdd9fe0c553612c66238375b920f178", - "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" + "versions.yml:md5,f567cdcfb384cc7a2d9ff4dc850f3bad", + "versions.yml:md5,fe9b8b3a8dc895efcf8f7c0b3248ff2d" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-21T14:24:42.558578431" + "timestamp": "2025-12-02T13:07:39.314799" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -738,7 +737,7 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, - "sample1.fastp.json:md5,543fb8fe4512975ce7dafd5287cae601" + "sample1.fastp.json:md5,caf903cc79784ceaa71d6ef743c02ff3" ] ], "md5sums": [ @@ -907,7 +906,7 @@ "id": "sample1" } }, - "sample1.stats:md5,0653e8f1834d58c557ad463c36ae6b61" + "sample1.stats:md5,33a10d02ce404301e012f07841815f59" ] ], "sormadup_metrics": [ @@ -940,23 +939,22 @@ ], "versions": [ - "versions.yml:md5,321e55c8f19102dc87a10e981635edda", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", - "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", - "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", + "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", - "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868" + "versions.yml:md5,cdce7da7ce14e29fbd9fd72e88505ffa", + "versions.yml:md5,d00b52835d019d68e58aafd218429a75", + "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", + "versions.yml:md5,f567cdcfb384cc7a2d9ff4dc850f3bad", + "versions.yml:md5,fe9b8b3a8dc895efcf8f7c0b3248ff2d" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-21T14:29:48.196853611" + "timestamp": "2025-12-02T13:12:08.110112" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1058,7 +1056,7 @@ "aligner": "bwamem", "count": 1 }, - "sample1.fastp.json:md5,543fb8fe4512975ce7dafd5287cae601" + "sample1.fastp.json:md5,caf903cc79784ceaa71d6ef743c02ff3" ] ], "md5sums": [ @@ -1211,7 +1209,7 @@ "id": "sample1" } }, - "sample1.quantized.bed.gz.csi:md5,ac24f9c737b984091364b3c5b1f45567" + "sample1.quantized.bed.gz.csi:md5,efa0455ec39b49b96fd44c1efcbef8ab" ] ], "mosdepth_regions": [ @@ -1453,7 +1451,7 @@ "id": "sample1" } }, - "sample1.stats:md5,0653e8f1834d58c557ad463c36ae6b61" + "sample1.stats:md5,33a10d02ce404301e012f07841815f59" ] ], "sormadup_metrics": [ @@ -1485,26 +1483,25 @@ ], "versions": [ - "versions.yml:md5,2dbfdf50978986550dbe621f1d49fea7", - "versions.yml:md5,321e55c8f19102dc87a10e981635edda", - "versions.yml:md5,3e9382a1dc62d4f405bcfb58fe6b7768", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,4445e842758f99d74d032eab0af01ff6", - "versions.yml:md5,67e17554941666c3f3da7ab6e3b1ac5d", - "versions.yml:md5,84a41fdb642c270c5f36846cd7d8f033", - "versions.yml:md5,8ede2c6189fe1f73ef7e36b42528473c", - "versions.yml:md5,a18197a27823760677276bdf9a17c0b6", - "versions.yml:md5,bfc234edc6fd6d67600cac71c66ecd10", + "versions.yml:md5,1d2a9b13790c70a69a1f62facc9b3a6c", + "versions.yml:md5,23b060bcc18a02fc8f981102ef3a3006", + "versions.yml:md5,31df076e5d21d61db772cb39643350e2", + "versions.yml:md5,b702df83d9ece54caa0e765a6286cdd2", + "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", + "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", + "versions.yml:md5,cdce7da7ce14e29fbd9fd72e88505ffa", + "versions.yml:md5,d00b52835d019d68e58aafd218429a75", "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", - "versions.yml:md5,fecf2763ae04725fa0ca7c995018dcea" + "versions.yml:md5,f567cdcfb384cc7a2d9ff4dc850f3bad", + "versions.yml:md5,fe9b8b3a8dc895efcf8f7c0b3248ff2d" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-21T14:28:06.35129428" + "timestamp": "2025-12-02T13:10:35.894317" } } \ No newline at end of file From 3677efd7c51980ec654751bf2614797bfa88dc77 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:37:54 +0100 Subject: [PATCH 066/228] drop githubworkflow since we have no bot --- .../workflows/template-version-comment.yml | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 .github/workflows/template-version-comment.yml diff --git a/.github/workflows/template-version-comment.yml b/.github/workflows/template-version-comment.yml deleted file mode 100644 index c5988af9..00000000 --- a/.github/workflows/template-version-comment.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: nf-core template version comment -# This workflow is triggered on PRs to check if the pipeline template version matches the latest nf-core version. -# It posts a comment to the PR, even if it comes from a fork. - -on: pull_request_target - -jobs: - template_version: - runs-on: ubuntu-latest - steps: - - name: Check out pipeline code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - ref: ${{ github.event.pull_request.head.sha }} - - - name: Read template version from .nf-core.yml - uses: nichmor/minimal-read-yaml@1f7205277e25e156e1f63815781db80a6d490b8f # v0.0.2 - id: read_yml - with: - config: ${{ github.workspace }}/.nf-core.yml - - - name: Install nf-core - run: | - python -m pip install --upgrade pip - pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} - - - name: Check nf-core outdated - id: nf_core_outdated - run: echo "OUTPUT=$(pip list --outdated | grep nf-core)" >> ${GITHUB_ENV} - - - name: Post nf-core template version comment - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 - if: | - contains(env.OUTPUT, 'nf-core') - with: - repo-token: ${{ secrets.NF_CORE_BOT_AUTH_TOKEN }} - allow-repeats: false - message: | - > [!WARNING] - > Newer version of the nf-core template is available. - > - > Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. - > Please update your pipeline to the latest version. - > - > For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). - # From ad890074a3848ce35087616fc0a20e2047b38c4b Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:47:25 +0100 Subject: [PATCH 067/228] fix test --- .../local/fastq_to_aligned_cram/main.nf | 5 ++--- .../fastq_to_aligned_cram/main.nf.test.snap | 22 +++++++++---------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 76ea8b63..c00f4d75 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -110,10 +110,9 @@ workflow FASTQ_TO_CRAM { } else if (markdup == "false" || markdup == false) { // Merge bam files and compress - // SAMTOOLS_SORT([meta, [bam, bam], fasta]) - SAMTOOLS_SORT(ch_bam_fasta) + // SAMTOOLS_SORT([meta, [bam, bam], fasta],index_format) + SAMTOOLS_SORT(ch_bam_fasta, "crai") ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORT.out.cram.join(SAMTOOLS_SORT.out.crai, failOnMismatch: true, failOnDuplicate: true)) - ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions.first()) } else { error("markdup: ${markdup} not supported") diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index 50296e7d..d1459def 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -28,17 +28,16 @@ ], "versions": [ - "versions.yml:md5,a7ccfeb53d42f57673ea59012c30e897", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:30:29.475396941" + "timestamp": "2025-12-02T13:40:29.319628" }, "fastq to cram - bwa - bamsormadup": { "content": [ @@ -237,16 +236,15 @@ ], "versions": [ - "versions.yml:md5,a7ccfeb53d42f57673ea59012c30e897", - "versions.yml:md5,d92f130d879deee51a23917c6e272233", - "versions.yml:md5,d92f130d879deee51a23917c6e272233" + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", + "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:29:30.443653387" + "timestamp": "2025-12-02T13:40:06.599667" } } \ No newline at end of file From f4490fc292ac4c2059193b4383b3eb52a967e3f9 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 19:42:20 +0100 Subject: [PATCH 068/228] try to fix bclconvert on GCP --- conf/profiles/s3_ugent.config | 1 + main.nf | 8 +++---- modules.json | 3 ++- modules/nf-core/bclconvert/bclconvert.diff | 25 ++++++++++++++++++++++ modules/nf-core/bclconvert/main.nf | 4 ++-- 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 modules/nf-core/bclconvert/bclconvert.diff diff --git a/conf/profiles/s3_ugent.config b/conf/profiles/s3_ugent.config index d29f80a0..7e2fe67a 100644 --- a/conf/profiles/s3_ugent.config +++ b/conf/profiles/s3_ugent.config @@ -1,4 +1,5 @@ aws { + profile = "ugent" client { endpoint = "https://s3.ugent.be" protocol = "https" diff --git a/main.nf b/main.nf index ee3fa058..640ad840 100644 --- a/main.nf +++ b/main.nf @@ -66,8 +66,8 @@ workflow { publish: demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) - demultiplex_reports = PREPROCESSING.out.demultiplex_reports.map { meta, reports -> [ meta, files("${reports.toUri()}/*") ] }.transpose(by:1) - demultiplex_logs = PREPROCESSING.out.demultiplex_logs.map { meta, logs -> [ meta, files("${logs.toUri()}/*") ] }.transpose(by:1) + demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by:1) + demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) fastp_json = PREPROCESSING.out.fastp_json fastp_html = PREPROCESSING.out.fastp_html ucrams = PREPROCESSING.out.ucrams @@ -107,11 +107,11 @@ output { bin >> "Interop/${bin.name}" } } demultiplex_reports { path { meta, report -> - def out_path = meta.lane ? "Reports/LOO${meta.lane}/${report.name}" as String : "Reports/${report.name}" + def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" report >> out_path } } demultiplex_logs { path { meta, log -> - def out_path = meta.lane ? "Logs/LOO${meta.lane}/${log.name}" as String : "Logs/${log.name}" + def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" log >> out_path } } fastp_json { path { meta, json -> diff --git a/modules.json b/modules.json index f5872c3f..f1b67967 100644 --- a/modules.json +++ b/modules.json @@ -13,7 +13,8 @@ "bclconvert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["bcl_demultiplex", "modules"] + "installed_by": ["bcl_demultiplex", "modules"], + "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, "biobambam/bamsormadup": { "branch": "master", diff --git a/modules/nf-core/bclconvert/bclconvert.diff b/modules/nf-core/bclconvert/bclconvert.diff new file mode 100644 index 00000000..dc0dee2d --- /dev/null +++ b/modules/nf-core/bclconvert/bclconvert.diff @@ -0,0 +1,25 @@ +Changes in component 'nf-core/bclconvert' +'modules/nf-core/bclconvert/LICENSE' is unchanged +'modules/nf-core/bclconvert/Dockerfile' is unchanged +'modules/nf-core/bclconvert/README.md' is unchanged +'modules/nf-core/bclconvert/.gitignore' is unchanged +'modules/nf-core/bclconvert/meta.yml' is unchanged +Changes in 'bclconvert/main.nf': +--- modules/nf-core/bclconvert/main.nf ++++ modules/nf-core/bclconvert/main.nf +@@ -12,8 +12,8 @@ + tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true + tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true + tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true +- tuple val(meta), path("output/Reports") , emit: reports +- tuple val(meta), path("output/Logs") , emit: logs ++ tuple val(meta), path("output/Reports/*") , emit: reports ++ tuple val(meta), path("output/Logs/*") , emit: logs + tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true + path("versions.yml") , emit: versions + + +'modules/nf-core/bclconvert/tests/main.nf.test.snap' is unchanged +'modules/nf-core/bclconvert/tests/nextflow.config' is unchanged +'modules/nf-core/bclconvert/tests/main.nf.test' is unchanged +************************************************************ diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index 82ad6b19..b61f2240 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -12,8 +12,8 @@ process BCLCONVERT { tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true - tuple val(meta), path("output/Reports") , emit: reports - tuple val(meta), path("output/Logs") , emit: logs + tuple val(meta), path("output/Reports/*") , emit: reports + tuple val(meta), path("output/Logs/*") , emit: logs tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true path("versions.yml") , emit: versions From e192be17db11606ac9bff3dcd067fc34b764c6a6 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:34:38 +0100 Subject: [PATCH 069/228] update bcl-convert config for gcp --- conf/modules.config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 56bf31d1..85c1c3c0 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -14,13 +14,13 @@ process { // BCL convert withName: BCLCONVERT { + cpus = 32 + memory = 64.GB ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", "--force", - "--bcl-num-parallel-tiles ${task.cpus}", - "--bcl-num-conversion-threads ${task.cpus}", - "--bcl-num-compression-threads ${task.cpus}", + "--strict", ].join(" ").trim() } } From 2c24f7bb8b83ffc59347e7d6270a14f0fdae28c8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:48:05 +0100 Subject: [PATCH 070/228] add dynamic disk allocation --- conf/modules.config | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/modules.config b/conf/modules.config index 85c1c3c0..05b20842 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -16,6 +16,7 @@ process { withName: BCLCONVERT { cpus = 32 memory = 64.GB + disk = { 500.GB * task.attempt } ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", From 2fcc5e77bada5848bb9f5f6c3fe977a7ad451177 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:17:19 +0100 Subject: [PATCH 071/228] increase mem --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 05b20842..da061387 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -15,7 +15,7 @@ process { // BCL convert withName: BCLCONVERT { cpus = 32 - memory = 64.GB + memory = 128.GB disk = { 500.GB * task.attempt } ext.args = { [ From de0daecc01bd13bc6115716cabd975400dfeb089 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:20:12 +0100 Subject: [PATCH 072/228] fix linting --- .nf-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nf-core.yml b/.nf-core.yml index 09005197..2b4bcc77 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -27,7 +27,7 @@ lint: template_strings: - bin/cmgg_genelists nf_test_content: false -nf_core_version: 3.4.1 +nf_core_version: 3.5.1 repository_type: pipeline template: author: Matthias De Smet, Nicolas Vannieuwkerke From 1231634495929e22dbe3cf78f656ffde7cfdb0c3 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 19:56:58 +0100 Subject: [PATCH 073/228] fix module config --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index da061387..1cedbcfa 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -21,7 +21,7 @@ process { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", "--force", - "--strict", + "--strict-mode true", ].join(" ").trim() } } From f3495f6393b324933f1a61a2f9c34a669200a600 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 20:19:17 +0100 Subject: [PATCH 074/228] update contributors --- nextflow.config | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/nextflow.config b/nextflow.config index 01378b19..d72f24cf 100644 --- a/nextflow.config +++ b/nextflow.config @@ -257,22 +257,21 @@ dag { manifest { name = 'nf-cmgg/preprocessing' contributors = [ - // TODO nf-core: Update the field with the details of the contributors to your pipeline. New with Nextflow version 24.10.0 [ name: 'Matthias De Smet', - affiliation: '', - email: '', - github: '', - contribution: [], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: '' + affiliation: 'Center for Medical Genetics Ghent, Ghent University, Belgium', + email: 'matthias.desmet@ugent.be', + github: '@matthdsm', + contribution: ["author","maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: 'https://orcid.org/0000-0003-2555-3114' ], [ name: ' Nicolas Vannieuwkerke', - affiliation: '', - email: '', - github: '', - contribution: [], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: '' + affiliation: 'Center for Medical Genetics Ghent, Ghent University Hospital, Belgium', + email: 'nicolas.vannieuwkerke@ugent.be', + github: '@nvnieuwk', + contribution: ["maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: 'https://orcid.org/0009-0003-5619-1555' ], ] homePage = 'https://github.com/nf-cmgg/preprocessing' From 3713ccfe2efc6d620e51ffa9ed1091938c8e8db5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 2 Dec 2025 20:19:55 +0100 Subject: [PATCH 075/228] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bf9c031..e929fc1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 2.1.0dev - Update the output handling to use the new workflow output definitions. +- Bump all modules to latest versions. ## v2.0.6 From 02697a6fddb0893961e646a9100fd75e36a22c63 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 3 Dec 2025 08:51:27 +0100 Subject: [PATCH 076/228] increase disk, set stageOutMode --- conf/modules.config | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 1cedbcfa..f5416df9 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -16,7 +16,9 @@ process { withName: BCLCONVERT { cpus = 32 memory = 128.GB - disk = { 500.GB * task.attempt } + disk = { 1.TB * task.attempt } + stageOutMode = 'copy' + ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", From 753f55b61b1c644492301493b8ab20d683725809 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 3 Dec 2025 09:07:04 +0100 Subject: [PATCH 077/228] add strobealign config --- conf/modules.config | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index f5416df9..0678b28b 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -130,6 +130,18 @@ process { } } + //// STROBEALIGN + withName: STROBEALIGN { + ext.args = { + [ + meta.readgroup ? "--rg-id ${meta.readgroup.ID}" : "", + meta.readgroup ? "--rg " + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join(" --rg ") : "", + "-C", + ].join(" ").trim() + } + } + + //// STAR withName: STAR_ALIGN { ext.args = { [ From fe0791ad046cc42e6ede61f06eea4b0fa6d55ec8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:21:57 +0100 Subject: [PATCH 078/228] add 50001 (spot pre-empted) to retry codes --- conf/base.config | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/conf/base.config b/conf/base.config index 4f3a0d41..67db29f3 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,22 +10,15 @@ process { - // TODO nf-core: Check the defaults for all processes cpus = { 1 * task.attempt } memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } - maxRetries = 1 + errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001) ? 'retry' : 'finish' } + maxRetries = 3 maxErrors = '-1' // Process-specific resource requirements - // NOTE - Please try and reuse the labels below as much as possible. - // These labels are used and recognised by default in DSL2 files hosted on nf-core/modules. - // If possible, it would be nice to keep the same label naming convention when - // adding in your local modules too. - // TODO nf-core: Customise requirements for specific processes. - // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors withLabel:process_single { cpus = { 1 } memory = { 6.GB * task.attempt } From 6227b4bc56ddb76e4f7e653bcb2b33c83d3c2486 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:07:53 +0100 Subject: [PATCH 079/228] output files in library subdir where possible --- main.nf | 58 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/main.nf b/main.nf index 640ad840..913e2305 100644 --- a/main.nf +++ b/main.nf @@ -115,46 +115,46 @@ output { log >> out_path } } fastp_json { path { meta, json -> - json >> "${meta.samplename}/${json.name}" + json >> meta.library ? "${meta.library}/${meta.samplename}/${json.name}" : "${meta.samplename}/${json.name}" } } fastp_html { path { meta, html -> - html >> "${meta.samplename}/${html.name}" + html >> meta.library ? "${meta.library}/${meta.samplename}/${html.name}" : "${meta.samplename}/${html.name}" } } ucrams { path { meta, cram -> - cram >> "${meta.samplename}/${meta.samplename}.unaligned.cram" + cram >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.unaligned.cram" : "${meta.samplename}/${meta.samplename}.unaligned.cram" } } crams { path { meta, cram, crai -> - cram >> "${meta.samplename}/${meta.samplename}.cram" - crai >> "${meta.samplename}/${meta.samplename}.cram.crai" + cram >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" : "${meta.samplename}/${meta.samplename}.cram" + crai >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" : "${meta.samplename}/${meta.samplename}.cram.crai" } } align_reports { path { meta, log -> - log >> "${meta.samplename}/${log.name}" + log >> meta.library ? "${meta.library}/${meta.samplename}/${log.name}" : "${meta.samplename}/${log.name}" } } sormadup_metrics { path { meta, metrics -> - metrics >> "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" + metrics >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" } } - mosdepth_global { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_summary { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_regions { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_per_base_d4 { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_per_base_bed { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_per_base_csi { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_regions_bed { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_regions_csi { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_quantized_bed { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_quantized_csi { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_thresholds_bed { path { meta, _file -> "${meta.samplename}/" } } - mosdepth_thresholds_csi { path { meta, _file -> "${meta.samplename}/" } } - samtools_coverage { path { meta, _file -> "${meta.samplename}/" } } - panelcoverage { path { meta, _file -> "${meta.samplename}/" } } - samtools_stats { path { meta, _file -> "${meta.samplename}/" } } - samtools_flagstat { path { meta, _file -> "${meta.samplename}/" } } - samtools_idxstats { path { meta, _file -> "${meta.samplename}/" } } - picard_multiplemetrics { path { meta, _file -> "${meta.samplename}/" } } - picard_multiplemetrics_pdf { path { meta, _file -> "${meta.samplename}/" } } - picard_wgsmetrics { path { meta, _file -> "${meta.samplename}/" } } - picard_hsmetrics { path { meta, _file -> "${meta.samplename}/" } } - md5sums { path { meta, _file -> "${meta.samplename}/" } } + mosdepth_global { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_summary { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_regions { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_per_base_d4 { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_per_base_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_per_base_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_regions_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_regions_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_quantized_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_quantized_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_thresholds_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + mosdepth_thresholds_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + samtools_coverage { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + panelcoverage { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + samtools_stats { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + samtools_flagstat { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + samtools_idxstats { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + picard_multiplemetrics { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + picard_multiplemetrics_pdf { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + picard_wgsmetrics { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + picard_hsmetrics { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + md5sums { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } multiqc_report { path "multiqc/" } multiqc_data { path "multiqc/" } multiqc_plots { path "multiqc/" } From 58a6bed14647c542867f81cbedf050b2cfc53218 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:37:59 +0100 Subject: [PATCH 080/228] fix output definition, retain library in meta --- main.nf | 133 ++++++++++++++++++++++++++++--------- nextflow.config | 1 - workflows/preprocessing.nf | 2 +- 3 files changed, 104 insertions(+), 32 deletions(-) diff --git a/main.nf b/main.nf index 913e2305..70f05632 100644 --- a/main.nf +++ b/main.nf @@ -115,46 +115,119 @@ output { log >> out_path } } fastp_json { path { meta, json -> - json >> meta.library ? "${meta.library}/${meta.samplename}/${json.name}" : "${meta.samplename}/${json.name}" + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" + json >> out_path } } fastp_html { path { meta, html -> - html >> meta.library ? "${meta.library}/${meta.samplename}/${html.name}" : "${meta.samplename}/${html.name}" + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path } } ucrams { path { meta, cram -> - cram >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.unaligned.cram" : "${meta.samplename}/${meta.samplename}.unaligned.cram" + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.unaligned.cram" as String : "${meta.samplename}/${meta.samplename}.unaligned.cram" + cram >> out_path } } crams { path { meta, cram, crai -> - cram >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" : "${meta.samplename}/${meta.samplename}.cram" - crai >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" : "${meta.samplename}/${meta.samplename}.cram.crai" + def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" + def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" + cram >> out_cram + crai >> out_crai } } align_reports { path { meta, log -> - log >> meta.library ? "${meta.library}/${meta.samplename}/${log.name}" : "${meta.samplename}/${log.name}" + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" + log >> out_path } } sormadup_metrics { path { meta, metrics -> - metrics >> meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" - } } - mosdepth_global { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_summary { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_regions { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_per_base_d4 { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_per_base_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_per_base_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_regions_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_regions_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_quantized_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_quantized_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_thresholds_bed { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - mosdepth_thresholds_csi { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - samtools_coverage { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - panelcoverage { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - samtools_stats { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - samtools_flagstat { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - samtools_idxstats { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - picard_multiplemetrics { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - picard_multiplemetrics_pdf { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - picard_wgsmetrics { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - picard_hsmetrics { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } - md5sums { path { meta, _file -> meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/" } } + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" + metrics >> out_path + } } + mosdepth_global { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_summary { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_regions { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_per_base_d4 { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_per_base_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_per_base_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_regions_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_regions_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_quantized_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_quantized_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_thresholds_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_thresholds_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_coverage { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + panelcoverage { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_stats { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_flagstat { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_idxstats { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_multiplemetrics { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_multiplemetrics_pdf { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_wgsmetrics { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_hsmetrics { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + md5sums { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } multiqc_report { path "multiqc/" } multiqc_data { path "multiqc/" } multiqc_plots { path "multiqc/" } diff --git a/nextflow.config b/nextflow.config index d72f24cf..b41984a0 100644 --- a/nextflow.config +++ b/nextflow.config @@ -9,7 +9,6 @@ // Global default params, used in configs params { - // TODO nf-core: Specify your pipeline's command line flags // Input options input = null diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index f90dd2eb..486c49ef 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -189,7 +189,7 @@ workflow PREPROCESSING { .transpose() .map { meta_fastq, count -> [meta_fastq[0] + ['count': count], meta_fastq[1]] } .map { meta, fastq -> - return [meta - meta.subMap('fcid', 'lane', 'library'), fastq] + return [meta - meta.subMap('fcid', 'lane'), fastq] } .set { ch_fastq_per_sample } From 8728f8c9b15f861afd5146774fc368f19b7a39ca Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:45:30 +0100 Subject: [PATCH 081/228] fix outdir issue --- nextflow.config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nextflow.config b/nextflow.config index b41984a0..91cb7cf6 100644 --- a/nextflow.config +++ b/nextflow.config @@ -294,3 +294,8 @@ validation { // Load modules.config for DSL2 module specific options includeConfig 'conf/modules.config' + +// Set default output dir and publish mode +// Temporary fix until the nf-core template supports workflow output definitions +workflow.output.mode = params.publish_dir_mode +outputDir = params.outdir From d95df0f09239e86e5be6b48d7c77350cc755f885 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:57:31 +0100 Subject: [PATCH 082/228] add per-library multiqc --- conf/modules.config | 8 +- main.nf | 21 +-- modules.json | 3 +- modules/nf-core/multiqc/main.nf | 3 +- modules/nf-core/multiqc/multiqc.diff | 27 ++++ workflows/preprocessing.nf | 187 +++++++++++++-------------- 6 files changed, 144 insertions(+), 105 deletions(-) create mode 100644 modules/nf-core/multiqc/multiqc.diff diff --git a/conf/modules.config b/conf/modules.config index 0678b28b..e1603297 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -247,9 +247,15 @@ process { // MultiQC - withName: MULTIQC { + withName: MULTIQC_MAIN { + ext.prefix = { params.multiqc_title ? params.multiqc_title : "multiqc" } ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } } + + withName: MULTIQC_LIBRARY { + ext.prefix = { meta.id ? "multiqc_library_${meta.id}" : "multiqc_library" } + ext.args = { meta.id ? "--title \"${meta.id} - Pool Summary\"" : '' } + } } env { diff --git a/main.nf b/main.nf index 70f05632..87371efa 100644 --- a/main.nf +++ b/main.nf @@ -61,7 +61,7 @@ workflow { params.outdir, params.monochrome_logs, params.hook_url, - PREPROCESSING.out.multiqc_report, + PREPROCESSING.out.multiqc_main_report, ) publish: @@ -96,10 +96,12 @@ workflow { picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics md5sums = PREPROCESSING.out.md5sums - multiqc_report = PREPROCESSING.out.multiqc_report - multiqc_data = PREPROCESSING.out.multiqc_data - multiqc_plots = PREPROCESSING.out.multiqc_plots - + multiqc_main_report = PREPROCESSING.out.multiqc_main_report + multiqc_main_data = PREPROCESSING.out.multiqc_main_data + multiqc_main_plots = PREPROCESSING.out.multiqc_main_plots + multiqc_library_report = PREPROCESSING.out.multiqc_library_report + multiqc_library_data = PREPROCESSING.out.multiqc_library_data + multiqc_library_plots = PREPROCESSING.out.multiqc_library_plots } output { @@ -228,7 +230,10 @@ output { def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" return out_path } } - multiqc_report { path "multiqc/" } - multiqc_data { path "multiqc/" } - multiqc_plots { path "multiqc/" } + multiqc_main_report { path "multiqc/" } + multiqc_main_data { path "multiqc/" } + multiqc_main_plots { path "multiqc/" } + multiqc_library_report { path "multiqc/" } + multiqc_library_data { path "multiqc/" } + multiqc_library_plots { path "multiqc/" } } diff --git a/modules.json b/modules.json index f1b67967..cbebbe1e 100644 --- a/modules.json +++ b/modules.json @@ -65,7 +65,8 @@ "multiqc": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": ["modules"] + "installed_by": ["modules"], + "patch": "modules/nf-core/multiqc/multiqc.diff" }, "picard/collecthsmetrics": { "branch": "master", diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 335afccc..2a9feaa3 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,4 +1,5 @@ process MULTIQC { + tag "$meta.id" label 'process_single' conda "${moduleDir}/environment.yml" @@ -7,7 +8,7 @@ process MULTIQC { 'community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf' }" input: - path multiqc_files, stageAs: "?/*" + tuple val(meta), path(multiqc_files, stageAs: "?/*") path(multiqc_config) path(extra_multiqc_config) path(multiqc_logo) diff --git a/modules/nf-core/multiqc/multiqc.diff b/modules/nf-core/multiqc/multiqc.diff new file mode 100644 index 00000000..947ff7e3 --- /dev/null +++ b/modules/nf-core/multiqc/multiqc.diff @@ -0,0 +1,27 @@ +Changes in component 'nf-core/multiqc' +'modules/nf-core/multiqc/environment.yml' is unchanged +'modules/nf-core/multiqc/meta.yml' is unchanged +Changes in 'multiqc/main.nf': +--- modules/nf-core/multiqc/main.nf ++++ modules/nf-core/multiqc/main.nf +@@ -1,4 +1,5 @@ + process MULTIQC { ++ tag "$meta.id" + label 'process_single' + + conda "${moduleDir}/environment.yml" +@@ -7,7 +8,7 @@ + 'community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf' }" + + input: +- path multiqc_files, stageAs: "?/*" ++ tuple val(meta), path(multiqc_files, stageAs: "?/*") + path(multiqc_config) + path(extra_multiqc_config) + path(multiqc_logo) + +'modules/nf-core/multiqc/tests/main.nf.test.snap' is unchanged +'modules/nf-core/multiqc/tests/nextflow.config' is unchanged +'modules/nf-core/multiqc/tests/main.nf.test' is unchanged +'modules/nf-core/multiqc/tests/custom_prefix.config' is unchanged +************************************************************ diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 486c49ef..ccdbea4d 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -7,25 +7,26 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules -include { FASTP } from '../modules/nf-core/fastp/main' -include { MD5SUM } from '../modules/nf-core/md5sum/main' -include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' -include { MULTIQC } from '../modules/nf-core/multiqc/main' -include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' +include { FASTP } from '../modules/nf-core/fastp/main' +include { MD5SUM } from '../modules/nf-core/md5sum/main' +include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' +include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' +include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' +include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' // Subworkflows -include { BAM_QC } from '../subworkflows/local/bam_qc/main' -include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' -include { COVERAGE } from '../subworkflows/local/coverage/main' -include { FASTQ_TO_UCRAM } from '../subworkflows/local/fastq_to_unaligned_cram/main' -include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' +include { BAM_QC } from '../subworkflows/local/bam_qc/main' +include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' +include { COVERAGE } from '../subworkflows/local/coverage/main' +include { FASTQ_TO_UCRAM } from '../subworkflows/local/fastq_to_unaligned_cram/main' +include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' // Functions -include { paramsSummaryMap } from 'plugin/nf-schema' -include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' -include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -78,12 +79,8 @@ workflow PREPROCESSING { BCL_DEMULTIPLEX(ch_illumina_flowcell.flowcell, "bclconvert") BCL_DEMULTIPLEX.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) ch_multiqc_files = ch_multiqc_files.mix( - BCL_DEMULTIPLEX.out.reports.map { _meta, reports -> - return reports - }, - BCL_DEMULTIPLEX.out.stats.map { _meta, stats -> - return stats - }, + BCL_DEMULTIPLEX.out.reports, + BCL_DEMULTIPLEX.out.stats ) ch_versions = ch_versions.mix(BCL_DEMULTIPLEX.out.versions) @@ -206,11 +203,7 @@ workflow PREPROCESSING { // Run QC, trimming and adapter removal // FASTP([meta, fastq], adapter_fasta, save_trimmed, save_merged) FASTP(ch_fastq_per_sample.map{ meta, fastq -> return [meta, fastq, []] }, false, false, false) - ch_multiqc_files = ch_multiqc_files.mix( - FASTP.out.json.map { _meta, json -> - return json - } - ) + ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) ch_versions = ch_versions.mix(FASTP.out.versions.first()) // edit meta.id to match sample name @@ -274,7 +267,7 @@ workflow PREPROCESSING { markdup, ) - ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics.map { _meta, metrics -> metrics }) + ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics) ch_versions = ch_versions.mix(FASTQ_TO_CRAM.out.versions) @@ -339,18 +332,10 @@ workflow PREPROCESSING { if (params.run_coverage) { COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) ch_multiqc_files = ch_multiqc_files.mix( - COVERAGE.out.mosdepth_summary.map { _meta, txt -> - return txt - }, - COVERAGE.out.mosdepth_global.map { _meta, txt -> - return txt - }, - COVERAGE.out.mosdepth_regions.map { _meta, txt -> - return txt - }, - COVERAGE.out.samtools_coverage.map { _meta, txt -> - return txt - }, + COVERAGE.out.mosdepth_summary, + COVERAGE.out.mosdepth_global, + COVERAGE.out.mosdepth_regions, + COVERAGE.out.samtools_coverage, ) mosdepth_global_out = COVERAGE.out.mosdepth_global mosdepth_summary_out = COVERAGE.out.mosdepth_summary @@ -403,24 +388,13 @@ workflow PREPROCESSING { BAM_QC(ch_cram_crai_roi_fasta_fai_dict, params.disable_picard_metrics) ch_multiqc_files = ch_multiqc_files.mix( - BAM_QC.out.samtools_stats.map { _meta, txt -> - return txt - }, - BAM_QC.out.samtools_flagstat.map { _meta, txt -> - return txt - }, - BAM_QC.out.samtools_idxstats.map { _meta, txt -> - return txt - }, - BAM_QC.out.picard_multiplemetrics.map { _meta, txt -> - return txt - }, - BAM_QC.out.picard_wgsmetrics.map { _meta, txt -> - return txt - }, - BAM_QC.out.picard_hsmetrics.map { _meta, txt -> - return txt - }, + BAM_QC.out.samtools_stats, + BAM_QC.out.samtools_flagstat, + BAM_QC.out.samtools_idxstats, + BAM_QC.out.picard_multiplemetrics, + BAM_QC.out.picard_wgsmetrics, + BAM_QC.out.picard_wgsmetrics, + BAM_QC.out.picard_hsmetrics, ) ch_versions = ch_versions.mix(BAM_QC.out.versions) @@ -486,11 +460,24 @@ workflow PREPROCESSING { ch_workflow_summary = channel.value(paramsSummaryMultiqc(summary_params)) ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + + ch_multiqc_library_files = ch_multiqc_files + .filter { meta, _file -> + meta.library != null && meta.library != "" + } + .map { meta, file -> + return [["id": meta.library] ?: meta.samplename, file] + } + .groupTuple() + ch_multiqc_library_files.dump(tag: "MULTIQC files per library", pretty: true) + + ch_multiqc_files = ch_multiqc_files.map{ _meta, files -> files }.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) + ch_multiqc_files = ch_multiqc_files.map { file -> [["id": "main"], file] }.groupTuple() + ch_multiqc_files.dump(tag: "MULTIQC files", pretty: true) - MULTIQC( + MULTIQC_MAIN( ch_multiqc_files.collect(), ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), @@ -499,42 +486,54 @@ workflow PREPROCESSING { [], ) + MULTIQC_LIBRARY( + ch_multiqc_library_files, + ch_multiqc_config.toList(), + ch_multiqc_custom_config.toList(), + ch_multiqc_logo.toList(), + [], + [], + ) + emit: - demultiplex_interop = BCL_DEMULTIPLEX.out.interop - demultiplex_reports = BCL_DEMULTIPLEX.out.reports - demultiplex_logs = BCL_DEMULTIPLEX.out.logs - fastp_json = FASTP.out.json - fastp_html = FASTP.out.html - ucrams = FASTQ_TO_UCRAM.out.cram - crams = FASTQ_TO_CRAM.out.cram_crai - align_reports = FASTQ_TO_CRAM.out.align_reports - sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics - mosdepth_global = mosdepth_global_out - mosdepth_summary = mosdepth_summary_out - mosdepth_regions = mosdepth_regions_out - mosdepth_per_base_d4 = mosdepth_per_base_d4_out - mosdepth_per_base_bed = mosdepth_per_base_bed_out - mosdepth_per_base_csi = mosdepth_per_base_csi_out - mosdepth_regions_bed = mosdepth_regions_bed_out - mosdepth_regions_csi = mosdepth_regions_csi_out - mosdepth_quantized_bed = mosdepth_quantized_bed_out - mosdepth_quantized_csi = mosdepth_quantized_csi_out - mosdepth_thresholds_bed = mosdepth_thresholds_bed_out - mosdepth_thresholds_csi = mosdepth_thresholds_csi_out - samtools_coverage = samtools_coverage_out - panelcoverage = panelcoverage_out - samtools_stats = BAM_QC.out.samtools_stats - samtools_flagstat = BAM_QC.out.samtools_flagstat - samtools_idxstats = BAM_QC.out.samtools_idxstats - picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics - picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf - picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics - picard_hsmetrics = BAM_QC.out.picard_hsmetrics - md5sums = MD5SUM.out.checksum - multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html - multiqc_data = MULTIQC.out.data - multiqc_plots = MULTIQC.out.plots - versions = ch_versions // channel: [ path(versions.yml) ] + demultiplex_interop = BCL_DEMULTIPLEX.out.interop + demultiplex_reports = BCL_DEMULTIPLEX.out.reports + demultiplex_logs = BCL_DEMULTIPLEX.out.logs + fastp_json = FASTP.out.json + fastp_html = FASTP.out.html + ucrams = FASTQ_TO_UCRAM.out.cram + crams = FASTQ_TO_CRAM.out.cram_crai + align_reports = FASTQ_TO_CRAM.out.align_reports + sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics + mosdepth_global = mosdepth_global_out + mosdepth_summary = mosdepth_summary_out + mosdepth_regions = mosdepth_regions_out + mosdepth_per_base_d4 = mosdepth_per_base_d4_out + mosdepth_per_base_bed = mosdepth_per_base_bed_out + mosdepth_per_base_csi = mosdepth_per_base_csi_out + mosdepth_regions_bed = mosdepth_regions_bed_out + mosdepth_regions_csi = mosdepth_regions_csi_out + mosdepth_quantized_bed = mosdepth_quantized_bed_out + mosdepth_quantized_csi = mosdepth_quantized_csi_out + mosdepth_thresholds_bed = mosdepth_thresholds_bed_out + mosdepth_thresholds_csi = mosdepth_thresholds_csi_out + samtools_coverage = samtools_coverage_out + panelcoverage = panelcoverage_out + samtools_stats = BAM_QC.out.samtools_stats + samtools_flagstat = BAM_QC.out.samtools_flagstat + samtools_idxstats = BAM_QC.out.samtools_idxstats + picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics + picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf + picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics + picard_hsmetrics = BAM_QC.out.picard_hsmetrics + md5sums = MD5SUM.out.checksum + multiqc_main_report = MULTIQC_MAIN.out.report.toList() + multiqc_main_data = MULTIQC_MAIN.out.data + multiqc_main_plots = MULTIQC_MAIN.out.plots + multiqc_library_report = MULTIQC_LIBRARY.out.report.toList() + multiqc_library_data = MULTIQC_LIBRARY.out.data + multiqc_library_plots = MULTIQC_LIBRARY.out.plots + versions = ch_versions } /* From 1fc03e9b108d5c727d84d7856fc5b7d6f78c99d1 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 13:06:43 +0100 Subject: [PATCH 083/228] improve logic --- nextflow.config | 4 ++++ workflows/preprocessing.nf | 29 +++++++++++++++-------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/nextflow.config b/nextflow.config index 91cb7cf6..6e2cfcae 100644 --- a/nextflow.config +++ b/nextflow.config @@ -238,18 +238,22 @@ nextflow.enable.configProcessNamesValidation = false timeline { enabled = true + overwrite = true file = "${params.outdir}/pipeline_info/execution_timeline_${params.trace_report_suffix}.html" } report { enabled = true + overwrite = true file = "${params.outdir}/pipeline_info/execution_report_${params.trace_report_suffix}.html" } trace { enabled = true + overwrite = true file = "${params.outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt" } dag { enabled = true + overwrite = true file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index ccdbea4d..11615222 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -461,24 +461,25 @@ workflow PREPROCESSING { ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) - ch_multiqc_library_files = ch_multiqc_files - .filter { meta, _file -> - meta.library != null && meta.library != "" - } - .map { meta, file -> - return [["id": meta.library] ?: meta.samplename, file] + ch_multiqc_files = ch_multiqc_files.map { meta, files -> + return [meta.library ? [id: meta.library] : [id: 'main'], files] } .groupTuple() - ch_multiqc_library_files.dump(tag: "MULTIQC files per library", pretty: true) + .branch { meta, files -> + main: meta.id == 'main' + return files.flatten() + library: meta.id != 'main' + return [meta, files.flatten()] + } + ch_multiqc_files.main.dump(tag: "MULTIQC files - main", pretty: true) + ch_multiqc_files.library.dump(tag: "MULTIQC files - library", pretty: true) - ch_multiqc_files = ch_multiqc_files.map{ _meta, files -> files }.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) - ch_multiqc_files = ch_multiqc_files.map { file -> [["id": "main"], file] }.groupTuple() - ch_multiqc_files.dump(tag: "MULTIQC files", pretty: true) + ch_multiqc_files.main = ch_multiqc_files.main.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + ch_multiqc_files.main = ch_multiqc_files.main.mix(ch_collated_versions) + ch_multiqc_files.main = ch_multiqc_files.main.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) MULTIQC_MAIN( - ch_multiqc_files.collect(), + ch_multiqc_files.main.collect().map{ files -> [[id: 'main'], files] }, ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), @@ -487,7 +488,7 @@ workflow PREPROCESSING { ) MULTIQC_LIBRARY( - ch_multiqc_library_files, + ch_multiqc_files.library, ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), From 9d6cd02d0f3730c5a65de118c078dfcc24bdd352 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:10:36 +0100 Subject: [PATCH 084/228] fix for MQC errors --- workflows/preprocessing.nf | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 11615222..fc51cbf6 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -444,23 +444,27 @@ workflow PREPROCESSING { name: 'nf_cmgg_preprocessing_software_mqc_versions.yml', sort: true, newLine: true - ).set { ch_collated_versions } - - softwareVersionsToYAML(ch_versions) - .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'preprocessing_software_mqc_versions.yml', sort: true, newLine: true) + ) + .map { file -> [[id: 'main'], file] } // add meta for multiqc .set { ch_collated_versions } // // MODULE: MultiQC // - ch_multiqc_config = channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_config = channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) ch_multiqc_custom_config = params.multiqc_config ? channel.fromPath(params.multiqc_config, checkIfExists: true) : channel.empty() - ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() + + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") ch_workflow_summary = channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) + ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml').map{ file -> [[id: 'main'], file] }) + + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true).map{ file -> [[id: 'main'], file] }) + ch_multiqc_files = ch_multiqc_files.map { meta, files -> return [meta.library ? [id: meta.library] : [id: 'main'], files] } @@ -474,10 +478,6 @@ workflow PREPROCESSING { ch_multiqc_files.main.dump(tag: "MULTIQC files - main", pretty: true) ch_multiqc_files.library.dump(tag: "MULTIQC files - library", pretty: true) - ch_multiqc_files.main = ch_multiqc_files.main.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files.main = ch_multiqc_files.main.mix(ch_collated_versions) - ch_multiqc_files.main = ch_multiqc_files.main.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) - MULTIQC_MAIN( ch_multiqc_files.main.collect().map{ files -> [[id: 'main'], files] }, ch_multiqc_config.toList(), From ff2b95e4bdbc1a13241151d5ebde5c472753bca5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:24:58 +0100 Subject: [PATCH 085/228] update test samplesheet --- tests/inputs/fastq.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/inputs/fastq.yml b/tests/inputs/fastq.yml index bfb9e2d0..20a5ec56 100644 --- a/tests/inputs/fastq.yml +++ b/tests/inputs/fastq.yml @@ -2,14 +2,14 @@ # fastq inputs - id: sample1_L001 samplename: fastq_paired1 - library: test + library: test_library organism: Homo sapiens tag: WES fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz - id: sample1_L002 samplename: fastq_paired1 - library: test + library: test_library organism: Homo sapiens tag: WES fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz From 768997a22a33a4adfe406a6dd7b173cd3dc67341 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 4 Dec 2025 17:30:24 +0100 Subject: [PATCH 086/228] fix topics mess --- modules/nf-core/multiqc/main.nf | 2 +- workflows/preprocessing.nf | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 2a9feaa3..1d691b15 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -19,7 +19,7 @@ process MULTIQC { 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"'), topic: versions, emit: versions_multiqc + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions_multiqc when: task.ext.when == null || task.ext.when diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index fc51cbf6..c737d2b1 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -468,12 +468,11 @@ workflow PREPROCESSING { ch_multiqc_files = ch_multiqc_files.map { meta, files -> return [meta.library ? [id: meta.library] : [id: 'main'], files] } - .groupTuple() .branch { meta, files -> main: meta.id == 'main' - return files.flatten() + return files library: meta.id != 'main' - return [meta, files.flatten()] + return [meta, files instanceof List ? files : [files]] } ch_multiqc_files.main.dump(tag: "MULTIQC files - main", pretty: true) ch_multiqc_files.library.dump(tag: "MULTIQC files - library", pretty: true) @@ -488,7 +487,7 @@ workflow PREPROCESSING { ) MULTIQC_LIBRARY( - ch_multiqc_files.library, + ch_multiqc_files.library.transpose(by:1).groupTuple(), ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), @@ -529,9 +528,9 @@ workflow PREPROCESSING { picard_hsmetrics = BAM_QC.out.picard_hsmetrics md5sums = MD5SUM.out.checksum multiqc_main_report = MULTIQC_MAIN.out.report.toList() - multiqc_main_data = MULTIQC_MAIN.out.data - multiqc_main_plots = MULTIQC_MAIN.out.plots - multiqc_library_report = MULTIQC_LIBRARY.out.report.toList() + multiqc_main_data = MULTIQC_MAIN.out.data.toList() + multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() + multiqc_library_report = MULTIQC_LIBRARY.out.report multiqc_library_data = MULTIQC_LIBRARY.out.data multiqc_library_plots = MULTIQC_LIBRARY.out.plots versions = ch_versions From dd391dca6809817dd2a4c40e70900e23cbdad1e1 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Thu, 4 Dec 2025 17:31:15 +0100 Subject: [PATCH 087/228] patch multiqc --- modules.json | 130 ++++++++++++++++++++------- modules/nf-core/multiqc/multiqc.diff | 17 +++- 2 files changed, 111 insertions(+), 36 deletions(-) diff --git a/modules.json b/modules.json index cbebbe1e..de8e0ac9 100644 --- a/modules.json +++ b/modules.json @@ -8,151 +8,207 @@ "bcl2fastq": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["bcl_demultiplex"] + "installed_by": [ + "bcl_demultiplex" + ] }, "bclconvert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["bcl_demultiplex", "modules"], + "installed_by": [ + "bcl_demultiplex", + "modules" + ], "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, "biobambam/bamsormadup": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, "bowtie2/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", "git_sha": "d86336f3e7ae0d5f76c67b0859409769cfeb2af2", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, "dragmap/align": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, "fastp": { "branch": "master", "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "md5sum": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "mosdepth": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, "multiqc": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/multiqc/multiqc.diff" }, "picard/collecthsmetrics": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, "samtools/cat": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/cat/samtools-cat.diff" }, "samtools/convert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, "samtools/flagstat": { "branch": "master", "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/idxstats": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/import": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/sormadup": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, "samtools/sort": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "samtools/stats": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, "snapaligner/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, "star/align": { "branch": "master", "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/star/align/star-align.diff" }, "strobealign": { "branch": "master", "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/strobealign/strobealign.diff" } } @@ -162,30 +218,40 @@ "bcl_demultiplex": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "fastq_align_dna": { "branch": "master", "git_sha": "070ddae7fb59384d3d85bf69eb9a1d71ab33ada9", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "df4d1c8cdee98a1bbbed8fc51e82296568e0f9c1", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfschema_plugin": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] } } } } } -} +} \ No newline at end of file diff --git a/modules/nf-core/multiqc/multiqc.diff b/modules/nf-core/multiqc/multiqc.diff index 947ff7e3..36396fa5 100644 --- a/modules/nf-core/multiqc/multiqc.diff +++ b/modules/nf-core/multiqc/multiqc.diff @@ -1,6 +1,4 @@ Changes in component 'nf-core/multiqc' -'modules/nf-core/multiqc/environment.yml' is unchanged -'modules/nf-core/multiqc/meta.yml' is unchanged Changes in 'multiqc/main.nf': --- modules/nf-core/multiqc/main.nf +++ modules/nf-core/multiqc/main.nf @@ -19,9 +17,20 @@ Changes in 'multiqc/main.nf': path(multiqc_config) path(extra_multiqc_config) path(multiqc_logo) +@@ -18,7 +19,7 @@ + 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"'), topic: versions, emit: versions_multiqc ++ tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions_multiqc + + when: + task.ext.when == null || task.ext.when +'modules/nf-core/multiqc/environment.yml' is unchanged +'modules/nf-core/multiqc/meta.yml' is unchanged +'modules/nf-core/multiqc/tests/custom_prefix.config' is unchanged +'modules/nf-core/multiqc/tests/main.nf.test' is unchanged 'modules/nf-core/multiqc/tests/main.nf.test.snap' is unchanged 'modules/nf-core/multiqc/tests/nextflow.config' is unchanged -'modules/nf-core/multiqc/tests/main.nf.test' is unchanged -'modules/nf-core/multiqc/tests/custom_prefix.config' is unchanged ************************************************************ From 5a7c1e718d828c9ae3944e38bc7ac1f18c68e90a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:54:25 +0100 Subject: [PATCH 088/228] fix tests, add changelog --- CHANGELOG.md | 1 + tests/workflows/preprocessing.nf.test.snap | 782 ++++++++++++++++++++- 2 files changed, 762 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e929fc1e..69949def 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update the output handling to use the new workflow output definitions. - Bump all modules to latest versions. +- The workflow now outputs data in a subdirectory per `library`, including a library specific MultiQC report ## v2.0.6 diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 348c1fd2..961504d8 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -20,6 +20,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "sample_type": "DNA", @@ -55,6 +56,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "readgroup": { "CN": "CMGG", @@ -78,6 +80,7 @@ { "id": "sample1", "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -120,6 +123,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "sample_type": "DNA", @@ -137,6 +141,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -163,6 +168,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -189,6 +195,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -218,6 +225,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -244,6 +252,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -270,6 +279,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -296,6 +306,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -322,6 +333,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -348,6 +360,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -374,15 +387,286 @@ "mosdepth_thresholds_csi": [ ], - "multiqc_data": [ - "multiqc_data" + "multiqc_library_data": [ + [ + "biobambam2_deduplication.txt:md5,992b5decb6d017254ee9b02fbe076d81", + "fastp-insert-size-plot.txt:md5,66fec5f01198da8ecd97410ec1727021", + "fastp-seq-content-gc-plot_Read_1_After_filtering.txt:md5,23420affa90c1523becba23c09653a92", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.txt:md5,27bb3440b4edeab8a9dc2ec1077cfc0e", + "fastp-seq-content-gc-plot_Read_2_After_filtering.txt:md5,e49276ebe93bb8294ca51e6a0916e703", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.txt:md5,f7bf2354433b3514893f0fe18e7f7877", + "fastp-seq-content-n-plot_Read_1_After_filtering.txt:md5,6c20997febd11ea6c80fe13a1761898b", + "fastp-seq-content-n-plot_Read_1_Before_filtering.txt:md5,a1d1cdbb1a1fb48b6d6bdf1f2192b2b7", + "fastp-seq-content-n-plot_Read_2_After_filtering.txt:md5,e1d8dcf05d785f863cfb17c96c1f58a4", + "fastp-seq-content-n-plot_Read_2_Before_filtering.txt:md5,30bfcca763531e4ee1638031d5359e48", + "fastp-seq-quality-plot_Read_1_After_filtering.txt:md5,2b0a42468f68992639ac8eacbf533134", + "fastp-seq-quality-plot_Read_1_Before_filtering.txt:md5,4e6fea487fecc2ee55db1518ff30a0b5", + "fastp-seq-quality-plot_Read_2_After_filtering.txt:md5,72a6d8295748db4de13d6dc1d1eb83dc", + "fastp-seq-quality-plot_Read_2_Before_filtering.txt:md5,3b1c7675660e838e75d1d5c62c0f3a61", + "fastp_filtered_reads_plot.txt:md5,9e506f1c8dbad71540697d11af4ba6df", + "llms-full.txt:md5,a9dd5cb0ccb6d732ac915af862770693", + "mosdepth-coverage-per-contig-single.txt:md5,e5dd72804ecbe8429179eaae01118d39", + "mosdepth-cumcoverage-dist-id.txt:md5,49f3ec6d8639c9b0f794e4bf96bd11c4", + "mosdepth_cov_dist.txt:md5,704ae312ab6109b1724e3fac0dc740ed", + "mosdepth_cumcov_dist.txt:md5,704ae312ab6109b1724e3fac0dc740ed", + "mosdepth_perchrom.txt:md5,e5dd72804ecbe8429179eaae01118d39", + "multiqc.log:md5,0bf142cd568af28e39f166591e28b550", + "multiqc.parquet:md5,c66e2b2f6ba202acf3cda2ebbd7b2a06", + "multiqc_biobambam2_dups.txt:md5,31c942ce8964d0941cb79f8c9de8aa04", + "multiqc_citations.txt:md5,294fadee817c59c64f1b985ac204b224", + "multiqc_data.json:md5,0c06c19b2156369fab669049b6e37eb5", + "multiqc_fastp.txt:md5,f917618024634bb24850390c8f4836e7", + "multiqc_general_stats.txt:md5,439ff0539fa18ba86b79e990c42dff75", + "multiqc_picard_AlignmentSummaryMetrics.txt:md5,3f32124a666ad5fa6dda93759cf450f0", + "multiqc_picard_HsMetrics.txt:md5,a5ccd0c64f6e2944a559280aaabce595", + "multiqc_picard_baseContent.txt:md5,deba2098af2de348792a37b405eab78c", + "multiqc_picard_quality_by_cycle.txt:md5,eca76b6ed78d34d66e1e185c7158868f", + "multiqc_picard_quality_score_distribution.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", + "multiqc_samtools_coverage.txt:md5,2b8ac198265a850d581d453eacb402cd", + "multiqc_samtools_flagstat.txt:md5,5ce133683245100011b77cd676471de1", + "multiqc_samtools_idxstats.txt:md5,7e542f20dd27d352b5d2be33e1920220", + "multiqc_samtools_stats.txt:md5,1dd571a033605b1224ebac95deceee0b", + "multiqc_sources.txt:md5,26011ccef291bca153e14a43437b4bbc", + "picard_MarkIlluminaAdapters_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "picard_MeanQualityByCycle_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "picard_MeanQualityByCycle_histogram_1.txt:md5,eca76b6ed78d34d66e1e185c7158868f", + "picard_QualityScoreDistribution_histogram.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", + "picard_alignment_readlength_plot.txt:md5,891edbc18f01189de8c5bf52320ee6c7", + "picard_alignment_summary_Aligned_Bases.txt:md5,7d13622d8d4083fe2a4be5bf92ea77e6", + "picard_alignment_summary_Aligned_Reads.txt:md5,ed831c3df4e4465d9c6fb52ce731ee71", + "picard_base_distribution_by_cycle__Adenine.txt:md5,989b9c396dfa032d8ca02f57b7cc6e7d", + "picard_base_distribution_by_cycle__Cytosine.txt:md5,dc7b79f9ab4bc66db25b509e423abf2b", + "picard_base_distribution_by_cycle__Guanine.txt:md5,1f2a16426851c0e434558d437ac482e3", + "picard_base_distribution_by_cycle__Thymine.txt:md5,cbc90b7275fa29bf09d4be71fc443df1", + "picard_base_distribution_by_cycle__Undetermined.txt:md5,e0a643aff9cf4b0d277c4da6c798c6dc", + "picard_hsmetrics_table.txt:md5,a170b91563f01fc311048a9f1983ac87", + "picard_percentage_target_bases.txt:md5,f29ba29d0df56128046793ff26ca5950", + "picard_quality_by_cycle.txt:md5,f89d83da6f5a7fa00511a8959c2bd3c2", + "picard_quality_score_distribution.txt:md5,9d72562e154dba19a69180e2875ae8e9", + "samtools-coverage-table.txt:md5,0f9fe2b460eb659d5ce23deba4ee62d8", + "samtools-coverage_BQ.txt:md5,68b97b7434bd35c71d3d14de478ba1b9", + "samtools-coverage_Bases.txt:md5,f8fcf650945e7b347409d678fae3b006", + "samtools-coverage_Coverage.txt:md5,bc62f359fced9778f869022dd4ab6647", + "samtools-coverage_MQ.txt:md5,5f9ece387a8e160cedbb02874c46000b", + "samtools-coverage_Mean_depth.txt:md5,4d5f58688b4c653b617c709717475c25", + "samtools-coverage_Reads.txt:md5,3667b340251346e538e6f078adcec945", + "samtools-flagstat-pct-table.txt:md5,8b0e71fcfbb55f6e8b0e6949fb146e0c", + "samtools-flagstat-table.txt:md5,6203dc05b5eaee4f529300986aebbb3c", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", + "samtools-idxstats-mapped-reads-plot_Raw_Counts.txt:md5,e8f2b29a779d322cd56b00f4958ef841", + "samtools-stats-dp.txt:md5,07153313edc4f7a3754e9821c85ca0cf", + "samtools_alignment_plot.txt:md5,d60abeeecbb005aff19c12f19a726057" + ] + ], + "multiqc_library_plots": [ + [ + [ + "biobambam2_deduplication-cnt.pdf:md5,8dcf3c25c3a6d362a312683b0cc52254", + "biobambam2_deduplication-pct.pdf:md5,f38a15e73459aefdbf92f53a602eecab", + "fastp-insert-size-plot.pdf:md5,761cc56448ee9500fadf80330b6e6c18", + "fastp-seq-content-gc-plot_Read_1_After_filtering.pdf:md5,e4ba12f4f0c3961dfe7343a420210f74", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.pdf:md5,cbf4e5d5cd4bccc836ef8a4b00789608", + "fastp-seq-content-gc-plot_Read_2_After_filtering.pdf:md5,5c452cc418222a26b85bf2779ccc0e5f", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.pdf:md5,148e583db6040c29d07ae06ade0aae37", + "fastp-seq-content-n-plot_Read_1_After_filtering.pdf:md5,fdda12e04eceaabad0260e7694ca1a47", + "fastp-seq-content-n-plot_Read_1_Before_filtering.pdf:md5,f2d6ba7286870d31dbcdfdc501fa0fe4", + "fastp-seq-content-n-plot_Read_2_After_filtering.pdf:md5,7fc668801cd69b020c5f0dcb7ab780f4", + "fastp-seq-content-n-plot_Read_2_Before_filtering.pdf:md5,9c21674378164f3bd7010aedaf9f9c62", + "fastp-seq-quality-plot_Read_1_After_filtering.pdf:md5,8d69018e6c7babd707ed91a30a2f4373", + "fastp-seq-quality-plot_Read_1_Before_filtering.pdf:md5,1c14e7b644546b647e1525b0035d7095", + "fastp-seq-quality-plot_Read_2_After_filtering.pdf:md5,d30a990dc6d11a33b3a0bd385b7e2765", + "fastp-seq-quality-plot_Read_2_Before_filtering.pdf:md5,569074e2210e477a45c1196d967e0e03", + "fastp_filtered_reads_plot-cnt.pdf:md5,1572b3a72a231623c8ae927b4cb7a0ae", + "fastp_filtered_reads_plot-pct.pdf:md5,d3a4c1a1372f7b914ae6dac6b0b117aa", + "mosdepth-coverage-per-contig-single-cnt.pdf:md5,b532e220dbd44f1b5bccae17f3a423da", + "mosdepth-coverage-per-contig-single-pct.pdf:md5,eb539598e0da9e9c0f16033ff345594b", + "mosdepth-cumcoverage-dist-id.pdf:md5,017ca25a754de8ad1e59bb8e5f9384a9", + "picard_alignment_readlength_plot.pdf:md5,0f360805d8f8d8aeacf3aaae1dc6eb06", + "picard_alignment_summary_Aligned_Bases-cnt.pdf:md5,e0e630f9c98be95f6b26b895721925ca", + "picard_alignment_summary_Aligned_Bases-pct.pdf:md5,0afa444f1854208d7252dfd45c06a000", + "picard_alignment_summary_Aligned_Reads-cnt.pdf:md5,0419bd8fcd699e40575e7c1619937b3e", + "picard_alignment_summary_Aligned_Reads-pct.pdf:md5,aa9bb7e84867a2bd953756a95bc0f311", + "picard_base_distribution_by_cycle__Adenine.pdf:md5,e5a1c8fd676d7267bf0e16baff152f96", + "picard_base_distribution_by_cycle__Cytosine.pdf:md5,8093c223e5fc64be9db36341ee801a6a", + "picard_base_distribution_by_cycle__Guanine.pdf:md5,82d32c26160589945f4c395c98220cb4", + "picard_base_distribution_by_cycle__Thymine.pdf:md5,1c1ed09619d30f34ce0ddc9464d26706", + "picard_base_distribution_by_cycle__Undetermined.pdf:md5,785db14b8f88f7b5675a991172a3ea2a", + "picard_hsmetrics_table.pdf:md5,fc9411cf48ebd47c0c261f919849dd46", + "picard_percentage_target_bases.pdf:md5,3752afa592927e547bf0c03e1d1006eb", + "picard_quality_by_cycle.pdf:md5,673292cc4b18e8cca83522991b81a996", + "picard_quality_score_distribution.pdf:md5,88f913aed3ae94590bf10d11a2b59a09", + "samtools-coverage-table.pdf:md5,26da9fd5643611f77ae7d511d9b92a04", + "samtools-coverage_BQ-cnt.pdf:md5,d2602d8ee5faee419b10283104b12e46", + "samtools-coverage_BQ-log.pdf:md5,04983f8664bf34583140efef4594c91d", + "samtools-coverage_Bases-cnt.pdf:md5,e7d204151b84a425c030605c40e5ac98", + "samtools-coverage_Bases-log.pdf:md5,eb3195e76bc390a13bd786ce17994208", + "samtools-coverage_Coverage-cnt.pdf:md5,4cd335d85e8071f4d6b34c07da7e58b3", + "samtools-coverage_Coverage-log.pdf:md5,1a6d4126fd6390139db86ac9c59c10b8", + "samtools-coverage_MQ-cnt.pdf:md5,19b1ec40e0a622c79429cd2e5db6a2ab", + "samtools-coverage_MQ-log.pdf:md5,6bd0213a8e9437ea972d060a45dd32e0", + "samtools-coverage_Mean_depth-cnt.pdf:md5,2e6766ac06b6d61b1eec6e5a4a8e773e", + "samtools-coverage_Mean_depth-log.pdf:md5,a89995d4c79a6119465fb4899129ef73", + "samtools-coverage_Reads-cnt.pdf:md5,f3ed81fba0bd8fdf860db5d4541fb66c", + "samtools-coverage_Reads-log.pdf:md5,9aae76e8a17ae18bc7e1ea222736b4ff", + "samtools-flagstat-pct-table.pdf:md5,e6debd913a8442f56cc22c714021e0a7", + "samtools-flagstat-table.pdf:md5,28f63086a0ac9b57da1f0911b7f8940d", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.pdf:md5,ae4ddcc627dada8d861a8c15e49d97f1", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.pdf:md5,543a323fa0cede66f19ad512222954f4", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.pdf:md5,3e874efbf35563c0e52fd47611822494", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.pdf:md5,c18b4695893cde28c41de39fb16dbcee", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.pdf:md5,d4b9c1b844d0cf4e29d112dc755682b4", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.pdf:md5,f3bef9d1890b8a69acb9c52e07ce7ea3", + "samtools-stats-dp.pdf:md5,9872a7fcbd9e6047c6b3c9aca5a36ced", + "samtools_alignment_plot-cnt.pdf:md5,288be15b7710eadf32e6ba47511fe140", + "samtools_alignment_plot-pct.pdf:md5,6e4103b696b62faaa47989881f202dbe" + ], + [ + "biobambam2_deduplication-cnt.png:md5,5707c3cf44cff88666c3c7b4970ab021", + "biobambam2_deduplication-pct.png:md5,b2a0fece791ff0532a426f3faeecf3f4", + "fastp-insert-size-plot.png:md5,40a7c7edc7062c92d088e8974dd1fbe9", + "fastp-seq-content-gc-plot_Read_1_After_filtering.png:md5,ff993de7c7a0b2f4dd17aaf509c8209b", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.png:md5,124351c45a1bd7d611fd3ba89510018b", + "fastp-seq-content-gc-plot_Read_2_After_filtering.png:md5,058842506a3200770c46a4a70b64ce48", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.png:md5,985bf206443edf1417e2a0f9354abe3c", + "fastp-seq-content-n-plot_Read_1_After_filtering.png:md5,7855b3938c2b48578b2e1ca3486783de", + "fastp-seq-content-n-plot_Read_1_Before_filtering.png:md5,b9276b3bd8f2c57a51d12f76273fc322", + "fastp-seq-content-n-plot_Read_2_After_filtering.png:md5,45684fe478e5d2912848c032c3bc8ee4", + "fastp-seq-content-n-plot_Read_2_Before_filtering.png:md5,97606f1910cdbb47f68d5b7ac9f9bf4b", + "fastp-seq-quality-plot_Read_1_After_filtering.png:md5,44fe9279b3f2279c19d2ce541b9c6c19", + "fastp-seq-quality-plot_Read_1_Before_filtering.png:md5,93c06663d6ed02d11f4e5eab97d48917", + "fastp-seq-quality-plot_Read_2_After_filtering.png:md5,99219cc1b64c80e6ac8cf653add1990c", + "fastp-seq-quality-plot_Read_2_Before_filtering.png:md5,5d655406be9a2ff9a68ec461f51cfcc5", + "fastp_filtered_reads_plot-cnt.png:md5,75911dd91d24adfaae185ebcf0a8455a", + "fastp_filtered_reads_plot-pct.png:md5,4b3c0fd7f90c7c83b50c557d4aa3b6a5", + "mosdepth-coverage-per-contig-single-cnt.png:md5,ff9cec471c8a882b3ad608312b950332", + "mosdepth-coverage-per-contig-single-pct.png:md5,8f17612654e4217dd673c2788b473e7c", + "mosdepth-cumcoverage-dist-id.png:md5,64f3a8071bca0d22a72c72090b2eb638", + "picard_alignment_readlength_plot.png:md5,7c5708c6ed659731111242666746905e", + "picard_alignment_summary_Aligned_Bases-cnt.png:md5,ccd4cdf7a4b1f3f2a39adf2e0c700ed4", + "picard_alignment_summary_Aligned_Bases-pct.png:md5,de5771f0fc6d2feaf7ea1bef7b4f57ed", + "picard_alignment_summary_Aligned_Reads-cnt.png:md5,fa8f7e289fd84f0dfb877758b926c421", + "picard_alignment_summary_Aligned_Reads-pct.png:md5,18be469adf5d34e7296aa9e0feb10274", + "picard_base_distribution_by_cycle__Adenine.png:md5,b59076e9793e4a403228c477f99c6cf8", + "picard_base_distribution_by_cycle__Cytosine.png:md5,7c42741dd1ee386af449d29e21a8389d", + "picard_base_distribution_by_cycle__Guanine.png:md5,27a487a8587c180f08d3afb58e71fb17", + "picard_base_distribution_by_cycle__Thymine.png:md5,f99b137a9975db372a29c0400652eca4", + "picard_base_distribution_by_cycle__Undetermined.png:md5,e7428923e6530f7bd00ca05bf2b0dabe", + "picard_hsmetrics_table.png:md5,70c4f98f3056ebd1a5d49f4f91ab3001", + "picard_percentage_target_bases.png:md5,1e70e6c776d49296f3f8debc3b893851", + "picard_quality_by_cycle.png:md5,23c7dc421bf1a8b9c61e7abdea1b96e9", + "picard_quality_score_distribution.png:md5,f129878e0583e69cac53ec51cac62f4e", + "samtools-coverage-table.png:md5,ffc0a23dcfe8a1b44e7c585898a412ba", + "samtools-coverage_BQ-cnt.png:md5,42a7bfacd302c7924d59701a585957f8", + "samtools-coverage_BQ-log.png:md5,67d6d4c8072743a32dfa30dd22edd5fe", + "samtools-coverage_Bases-cnt.png:md5,8790b6226f16810deceb82c6834b21be", + "samtools-coverage_Bases-log.png:md5,7bdd54947c3ab74d06b9fc11cc35cb51", + "samtools-coverage_Coverage-cnt.png:md5,cdff6829f5d017e67668e6b77b8648fd", + "samtools-coverage_Coverage-log.png:md5,13441e809c66563bf7284ebe4038f368", + "samtools-coverage_MQ-cnt.png:md5,59265e8998386d8a6521296508b4f4e6", + "samtools-coverage_MQ-log.png:md5,0282c8f2fb311eb3830f6d33a8e0d2ef", + "samtools-coverage_Mean_depth-cnt.png:md5,7f0aa59d888da55c8b7e5ca00011b2fc", + "samtools-coverage_Mean_depth-log.png:md5,ab01268969d553decb36658ca785dac0", + "samtools-coverage_Reads-cnt.png:md5,f77fe84d95f5bebd12aa764ab377b6e7", + "samtools-coverage_Reads-log.png:md5,34d3ebbc83f073531328d633466cfcd9", + "samtools-flagstat-pct-table.png:md5,30a84ce2464168d8dedf65b47725e2e1", + "samtools-flagstat-table.png:md5,a828ba0e94ebd04d2ac50ecc43b007fd", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.png:md5,91267791bafff119d985db6b24f813dc", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.png:md5,d1c9fd2633128ed5af7113cedeba91d8", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.png:md5,eb81f43f6c5778f957ce85137758235e", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.png:md5,b1b15467c4b7e34b2a724c2fe9daefa8", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.png:md5,64927987623ac1715e607470f6bf055a", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.png:md5,09773cf98a65a96710a4fac9e2600ed9", + "samtools-stats-dp.png:md5,fe29585e232244237558512103d78fdc", + "samtools_alignment_plot-cnt.png:md5,e5523404a7622df41efaf24fb98ef4c5", + "samtools_alignment_plot-pct.png:md5,7945231e29b09915dee17a9fa620ef62" + ], + [ + "biobambam2_deduplication-cnt.svg:md5,effd09d8ad9d34872090a0bae6f5e967", + "biobambam2_deduplication-pct.svg:md5,e58bfa9f92464f78673fd1ad9e2450d0", + "fastp-insert-size-plot.svg:md5,83bcd604041b4fa6053dcb0d33f21fed", + "fastp-seq-content-gc-plot_Read_1_After_filtering.svg:md5,03a57f9e891bb8aeac9a4979b0e7e513", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.svg:md5,fe77090c3ee62106e5cdd0d243744ced", + "fastp-seq-content-gc-plot_Read_2_After_filtering.svg:md5,fc70efca2a6feb2ebd02712323ab858f", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.svg:md5,a9aeaf418a4af53db36fa495652538b5", + "fastp-seq-content-n-plot_Read_1_After_filtering.svg:md5,c45ccd2c9670cfc6a8fe7e7c411fa792", + "fastp-seq-content-n-plot_Read_1_Before_filtering.svg:md5,78d3817a16b013f647a23564878f1542", + "fastp-seq-content-n-plot_Read_2_After_filtering.svg:md5,f33d2472e82e715f9d33b6781d4671b2", + "fastp-seq-content-n-plot_Read_2_Before_filtering.svg:md5,e7bdb138105422f2eca236628ac1c024", + "fastp-seq-quality-plot_Read_1_After_filtering.svg:md5,353db00f7a3f20c0c07838236e88a5ed", + "fastp-seq-quality-plot_Read_1_Before_filtering.svg:md5,69cef5512260a6af8955d9785966a806", + "fastp-seq-quality-plot_Read_2_After_filtering.svg:md5,46f0ee90d934323da913b14927888a75", + "fastp-seq-quality-plot_Read_2_Before_filtering.svg:md5,bf833093bbc86d88a297d48ac7ad64ad", + "fastp_filtered_reads_plot-cnt.svg:md5,89f162c2fe82f89d487564c26b007003", + "fastp_filtered_reads_plot-pct.svg:md5,74c611b014426ffc6990fd278dd5077d", + "mosdepth-coverage-per-contig-single-cnt.svg:md5,4e8ee59993d08a72eb4545fb8378a8ba", + "mosdepth-coverage-per-contig-single-pct.svg:md5,6c79f39035c6cb6db7f135eefb155a0e", + "mosdepth-cumcoverage-dist-id.svg:md5,587529190643bec79f4c4da65e68fdae", + "picard_alignment_readlength_plot.svg:md5,b0bf8f98c4bfd66b8848b5cf645812a6", + "picard_alignment_summary_Aligned_Bases-cnt.svg:md5,1e4c349f358aa1375f00eeb19a638898", + "picard_alignment_summary_Aligned_Bases-pct.svg:md5,1b2f81b0a0a23d54f62946a266d352b1", + "picard_alignment_summary_Aligned_Reads-cnt.svg:md5,9ee533f876f4af410f0fdd3da6427d89", + "picard_alignment_summary_Aligned_Reads-pct.svg:md5,713905bb8f964ccbf5d0b730447ae9a1", + "picard_base_distribution_by_cycle__Adenine.svg:md5,1a8b1b45ba9b22e9c230adcfce962dd8", + "picard_base_distribution_by_cycle__Cytosine.svg:md5,82a8225f9561a6296aa0b2bb801bf568", + "picard_base_distribution_by_cycle__Guanine.svg:md5,a3bb637662550e5712909ebb90268b11", + "picard_base_distribution_by_cycle__Thymine.svg:md5,316858766a810aa7bac94e9fa82f6a0e", + "picard_base_distribution_by_cycle__Undetermined.svg:md5,f09460fa07c95a4b8d326c62eaeb7099", + "picard_hsmetrics_table.svg:md5,2882442c46a78a971612f03b60cdc9a7", + "picard_percentage_target_bases.svg:md5,bf71b0901b3f91350ea786c293500cd9", + "picard_quality_by_cycle.svg:md5,83b907ec1941f942498b8c19ac15d335", + "picard_quality_score_distribution.svg:md5,4b5a6ac776863aab6a0874a1788e838c", + "samtools-coverage-table.svg:md5,1d344020db642dc8ed73ce65384eaed9", + "samtools-coverage_BQ-cnt.svg:md5,e618e68a0e1d475030a5b86d05217ae6", + "samtools-coverage_BQ-log.svg:md5,d7af1801f148ea9bda9c0d105afc8270", + "samtools-coverage_Bases-cnt.svg:md5,af0bf231e9dfc5545686c9d0d7fc0bac", + "samtools-coverage_Bases-log.svg:md5,d6070217bb54d7f966b21c8563571945", + "samtools-coverage_Coverage-cnt.svg:md5,ffeb1e8ffd6318d30c9ffd72f8701eb8", + "samtools-coverage_Coverage-log.svg:md5,81aafb2970773832ccc95a6a87c0db12", + "samtools-coverage_MQ-cnt.svg:md5,9aaa9307dbe314b04e1e2f78dec852db", + "samtools-coverage_MQ-log.svg:md5,e530d20e0b9ac5ea89a1d7e99e561da3", + "samtools-coverage_Mean_depth-cnt.svg:md5,b3366c179f143419ef91bc2016e717d2", + "samtools-coverage_Mean_depth-log.svg:md5,c13a4e5c2f1e78b77c5bed76598d3e6b", + "samtools-coverage_Reads-cnt.svg:md5,153e7705058794c16bee02ce37daba50", + "samtools-coverage_Reads-log.svg:md5,68f3871ec68b060e54380d353e1a0ded", + "samtools-flagstat-pct-table.svg:md5,7a64df60de3c53a62ce1b9bc62d1e600", + "samtools-flagstat-table.svg:md5,9d6e77d29691f652ed21a493866c226b", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.svg:md5,aee092dd5c492ae70e542cab5b11e8a6", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.svg:md5,a7ef56dd58e80e225252e5bd78c830f2", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.svg:md5,613dcab15c764fafd2151da9b3d5c55e", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.svg:md5,b1f82c95aed78d4e219f16cc7d3f41c3", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.svg:md5,4855e19f8503ef463a338bfcab7af3a5", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.svg:md5,b98efafd11eea5fd5292e247d4530821", + "samtools-stats-dp.svg:md5,5c9cc7aeefc2a540d2b93bcdeda7aa39", + "samtools_alignment_plot-cnt.svg:md5,0a2910be102b4c0ef6ac156a25a67005", + "samtools_alignment_plot-pct.svg:md5,061886f9d0f5839eccb706a784f7eec7" + ] + ] + ], + "multiqc_library_report": [ + "multiqc_library_test.html:md5,20fd67ac14ace887e5f5b76f02dc2b20" + ], + "multiqc_main_data": [ + [ + [ + "llms-full.txt:md5,769bfe8a8b5b73ff5e31e480d5d129c9", + "multiqc.log:md5,1ec335a68a9d72f823a7bf0bf42e028c", + "multiqc.parquet:md5,73d600bb80fc3459bfba5edc970fc949", + "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", + "multiqc_data.json:md5,8ad88f47321bfad770cdc2387d5fa6f9", + "multiqc_software_versions.txt:md5,3e70a45b35aa87dab44c6b2b61033f14", + "multiqc_sources.txt:md5,d2a044df39ce3c6abe5cdc2d67473490" + ] + ] ], - "multiqc_plots": [ - "multiqc_plots" + "multiqc_main_plots": [ + [ + + ] ], - "multiqc_report": [ + "multiqc_main_report": [ [ - "multiqc_report.html" + "multiqc.html:md5,a05f843b1b044c86a850de70980b8af2" ] ], "panelcoverage": [ @@ -403,6 +687,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "sample_type": "DNA", @@ -429,6 +714,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "sample_type": "DNA", @@ -460,6 +746,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "sample_type": "DNA", @@ -485,6 +772,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -511,6 +799,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -537,6 +826,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -563,6 +853,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -589,6 +880,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -632,7 +924,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T13:07:39.314799" + "timestamp": "2025-12-04T19:48:21.07529" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -655,6 +947,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "sample_type": "DNA", @@ -690,6 +983,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "readgroup": { "CN": "CMGG", @@ -713,6 +1007,7 @@ { "id": "sample1", "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -755,6 +1050,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "sample_type": "DNA", @@ -802,15 +1098,162 @@ "mosdepth_thresholds_csi": [ ], - "multiqc_data": [ - "multiqc_data" + "multiqc_library_data": [ + [ + "biobambam2_deduplication.txt:md5,992b5decb6d017254ee9b02fbe076d81", + "fastp-insert-size-plot.txt:md5,66fec5f01198da8ecd97410ec1727021", + "fastp-seq-content-gc-plot_Read_1_After_filtering.txt:md5,23420affa90c1523becba23c09653a92", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.txt:md5,27bb3440b4edeab8a9dc2ec1077cfc0e", + "fastp-seq-content-gc-plot_Read_2_After_filtering.txt:md5,e49276ebe93bb8294ca51e6a0916e703", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.txt:md5,f7bf2354433b3514893f0fe18e7f7877", + "fastp-seq-content-n-plot_Read_1_After_filtering.txt:md5,6c20997febd11ea6c80fe13a1761898b", + "fastp-seq-content-n-plot_Read_1_Before_filtering.txt:md5,a1d1cdbb1a1fb48b6d6bdf1f2192b2b7", + "fastp-seq-content-n-plot_Read_2_After_filtering.txt:md5,e1d8dcf05d785f863cfb17c96c1f58a4", + "fastp-seq-content-n-plot_Read_2_Before_filtering.txt:md5,30bfcca763531e4ee1638031d5359e48", + "fastp-seq-quality-plot_Read_1_After_filtering.txt:md5,2b0a42468f68992639ac8eacbf533134", + "fastp-seq-quality-plot_Read_1_Before_filtering.txt:md5,4e6fea487fecc2ee55db1518ff30a0b5", + "fastp-seq-quality-plot_Read_2_After_filtering.txt:md5,72a6d8295748db4de13d6dc1d1eb83dc", + "fastp-seq-quality-plot_Read_2_Before_filtering.txt:md5,3b1c7675660e838e75d1d5c62c0f3a61", + "fastp_filtered_reads_plot.txt:md5,9e506f1c8dbad71540697d11af4ba6df", + "llms-full.txt:md5,02c5ed19814d3afd16ea5fccc3516865", + "multiqc.log:md5,faa526e1b74af6acf779e92caf5bd77a", + "multiqc.parquet:md5,f991c38b80ea4795193224a782e94750", + "multiqc_biobambam2_dups.txt:md5,31c942ce8964d0941cb79f8c9de8aa04", + "multiqc_citations.txt:md5,b64ab308dbc3a2e58e15527370655958", + "multiqc_data.json:md5,ea17bc7fc0063bb30073f9b5b3cc7bfb", + "multiqc_fastp.txt:md5,f917618024634bb24850390c8f4836e7", + "multiqc_general_stats.txt:md5,21152415bf3b3720dede9ada054ae5e1", + "multiqc_samtools_flagstat.txt:md5,5ce133683245100011b77cd676471de1", + "multiqc_samtools_idxstats.txt:md5,7e542f20dd27d352b5d2be33e1920220", + "multiqc_samtools_stats.txt:md5,1dd571a033605b1224ebac95deceee0b", + "multiqc_sources.txt:md5,08a7aa04a68650ae860f494ae1b5d4d2", + "samtools-flagstat-pct-table.txt:md5,8b0e71fcfbb55f6e8b0e6949fb146e0c", + "samtools-flagstat-table.txt:md5,6203dc05b5eaee4f529300986aebbb3c", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", + "samtools-idxstats-mapped-reads-plot_Raw_Counts.txt:md5,e8f2b29a779d322cd56b00f4958ef841", + "samtools-stats-dp.txt:md5,07153313edc4f7a3754e9821c85ca0cf", + "samtools_alignment_plot.txt:md5,d60abeeecbb005aff19c12f19a726057" + ] + ], + "multiqc_library_plots": [ + [ + [ + "biobambam2_deduplication-cnt.pdf:md5,32dc6feb5cfb2a681e1baea64ed174d2", + "biobambam2_deduplication-pct.pdf:md5,c210b96ff301c4699a981b7a747dd642", + "fastp-insert-size-plot.pdf:md5,ac28b57e2270b846462ec69d469403de", + "fastp-seq-content-gc-plot_Read_1_After_filtering.pdf:md5,70fc95d50564a9e34ffedaab55c7e3a3", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.pdf:md5,bfdadfab1ef45191268e8f19b5b56756", + "fastp-seq-content-gc-plot_Read_2_After_filtering.pdf:md5,be9b2f8bb0276f4da8cf20595035bb33", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.pdf:md5,a00ca04dd4577aa4706975016bf82618", + "fastp-seq-content-n-plot_Read_1_After_filtering.pdf:md5,9dd66bed0bb685993e1ac70aad2405a1", + "fastp-seq-content-n-plot_Read_1_Before_filtering.pdf:md5,95d07c4ea09e4ffb8473e84648eea599", + "fastp-seq-content-n-plot_Read_2_After_filtering.pdf:md5,c9550470037ba6eec53118c5db3ed62a", + "fastp-seq-content-n-plot_Read_2_Before_filtering.pdf:md5,9a9dff340890cd43c6ee7a689112c49e", + "fastp-seq-quality-plot_Read_1_After_filtering.pdf:md5,e3f499d8d0ccf8bf0df604e96f7be9cb", + "fastp-seq-quality-plot_Read_1_Before_filtering.pdf:md5,c490b53f4a9cddbd3659256aedbeb4cd", + "fastp-seq-quality-plot_Read_2_After_filtering.pdf:md5,31011ec67fc23ff867c60c45b9681396", + "fastp-seq-quality-plot_Read_2_Before_filtering.pdf:md5,b75dad16330483e160720bd89649167d", + "fastp_filtered_reads_plot-cnt.pdf:md5,e34eea79aa92a8f0a1cafa522d1204f3", + "fastp_filtered_reads_plot-pct.pdf:md5,0f6b66deb6fbff878987ca29069cb016", + "samtools-flagstat-pct-table.pdf:md5,781be091183f24877110f8d5be0ebbec", + "samtools-flagstat-table.pdf:md5,bc1eff95cf645832e0dee6d86bcf503b", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.pdf:md5,f392b8070efe5b7a4bd20993c0e66bfa", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.pdf:md5,282ddb8116e7c774149d24015d2a56bd", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.pdf:md5,824315ee6e029d3b42f37f02b9374734", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.pdf:md5,cd587a5ace7868b2b24fdd16ad079e40", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.pdf:md5,2be7c8ff5b10d0ee1fb6b01f4c2100ee", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.pdf:md5,f2caf54746b77da42fe4200fc1f2eb96", + "samtools-stats-dp.pdf:md5,8b63ef11ded4b2224f9d5f6d3f059c7a", + "samtools_alignment_plot-cnt.pdf:md5,3d6c545941eec5834f4c991ecf0be42c", + "samtools_alignment_plot-pct.pdf:md5,a62b1d31109315eacb4ce42c63ae0aef" + ], + [ + "biobambam2_deduplication-cnt.png:md5,5707c3cf44cff88666c3c7b4970ab021", + "biobambam2_deduplication-pct.png:md5,b2a0fece791ff0532a426f3faeecf3f4", + "fastp-insert-size-plot.png:md5,40a7c7edc7062c92d088e8974dd1fbe9", + "fastp-seq-content-gc-plot_Read_1_After_filtering.png:md5,ff993de7c7a0b2f4dd17aaf509c8209b", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.png:md5,124351c45a1bd7d611fd3ba89510018b", + "fastp-seq-content-gc-plot_Read_2_After_filtering.png:md5,058842506a3200770c46a4a70b64ce48", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.png:md5,985bf206443edf1417e2a0f9354abe3c", + "fastp-seq-content-n-plot_Read_1_After_filtering.png:md5,7855b3938c2b48578b2e1ca3486783de", + "fastp-seq-content-n-plot_Read_1_Before_filtering.png:md5,b9276b3bd8f2c57a51d12f76273fc322", + "fastp-seq-content-n-plot_Read_2_After_filtering.png:md5,45684fe478e5d2912848c032c3bc8ee4", + "fastp-seq-content-n-plot_Read_2_Before_filtering.png:md5,97606f1910cdbb47f68d5b7ac9f9bf4b", + "fastp-seq-quality-plot_Read_1_After_filtering.png:md5,44fe9279b3f2279c19d2ce541b9c6c19", + "fastp-seq-quality-plot_Read_1_Before_filtering.png:md5,93c06663d6ed02d11f4e5eab97d48917", + "fastp-seq-quality-plot_Read_2_After_filtering.png:md5,99219cc1b64c80e6ac8cf653add1990c", + "fastp-seq-quality-plot_Read_2_Before_filtering.png:md5,5d655406be9a2ff9a68ec461f51cfcc5", + "fastp_filtered_reads_plot-cnt.png:md5,75911dd91d24adfaae185ebcf0a8455a", + "fastp_filtered_reads_plot-pct.png:md5,4b3c0fd7f90c7c83b50c557d4aa3b6a5", + "samtools-flagstat-pct-table.png:md5,30a84ce2464168d8dedf65b47725e2e1", + "samtools-flagstat-table.png:md5,a828ba0e94ebd04d2ac50ecc43b007fd", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.png:md5,91267791bafff119d985db6b24f813dc", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.png:md5,d1c9fd2633128ed5af7113cedeba91d8", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.png:md5,eb81f43f6c5778f957ce85137758235e", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.png:md5,b1b15467c4b7e34b2a724c2fe9daefa8", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.png:md5,64927987623ac1715e607470f6bf055a", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.png:md5,09773cf98a65a96710a4fac9e2600ed9", + "samtools-stats-dp.png:md5,fe29585e232244237558512103d78fdc", + "samtools_alignment_plot-cnt.png:md5,e5523404a7622df41efaf24fb98ef4c5", + "samtools_alignment_plot-pct.png:md5,7945231e29b09915dee17a9fa620ef62" + ], + [ + "biobambam2_deduplication-cnt.svg:md5,9de3a4196707cc54a09ccab579551b45", + "biobambam2_deduplication-pct.svg:md5,383483ee720a0b93282f11cef90d8412", + "fastp-insert-size-plot.svg:md5,03e25e27d6f08e7eeef62edaac78705d", + "fastp-seq-content-gc-plot_Read_1_After_filtering.svg:md5,16db74211fea2dd026208e1ff8932921", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.svg:md5,ebce58ed6cef4ed79ea2ddd5d796e61e", + "fastp-seq-content-gc-plot_Read_2_After_filtering.svg:md5,2e6b93f07296d37a5fd08f493793ecf2", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.svg:md5,865602ee9731648cf55a8f6c6e3fcb20", + "fastp-seq-content-n-plot_Read_1_After_filtering.svg:md5,c38f3a392319e4b9e2147a96b33e1186", + "fastp-seq-content-n-plot_Read_1_Before_filtering.svg:md5,b8416f1f456e3a189822f22c26e388ad", + "fastp-seq-content-n-plot_Read_2_After_filtering.svg:md5,5c54a86a023e9ac204ece6eca7f4da3d", + "fastp-seq-content-n-plot_Read_2_Before_filtering.svg:md5,74ecf94d1bc8a2ea1315bad82e8da636", + "fastp-seq-quality-plot_Read_1_After_filtering.svg:md5,2136357bde8a33774139d892f78f24f8", + "fastp-seq-quality-plot_Read_1_Before_filtering.svg:md5,79c1c221969bdbcd7254eb8d9c6e15f2", + "fastp-seq-quality-plot_Read_2_After_filtering.svg:md5,a55b84e706aa6aaa796e74f29bc32ec7", + "fastp-seq-quality-plot_Read_2_Before_filtering.svg:md5,ddfc609e5a87d598e8abe9777130e8e6", + "fastp_filtered_reads_plot-cnt.svg:md5,5fd1528dbf165823db88a7cf666ecb23", + "fastp_filtered_reads_plot-pct.svg:md5,d8adcea8718c87a360b9d329e31cc64b", + "samtools-flagstat-pct-table.svg:md5,3a27df4db014b18226c51f41868c8387", + "samtools-flagstat-table.svg:md5,0c0bca9b4b56b6f1a7bac9b23be4bbe4", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.svg:md5,62227493b8c1c4abf2b9a56dee4aaee1", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.svg:md5,7e0a96a8947202ada7f3539f614aafbd", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.svg:md5,addf085c4878ef4c72bf2de0b1da73c5", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.svg:md5,198bee66f3e5232a1f389abf312f3230", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.svg:md5,1e1de4b4dfdaebb6c6c9cb6ecf78fc0d", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.svg:md5,2a42c274765d0a37f3eeef4b605ad55c", + "samtools-stats-dp.svg:md5,c3d026b17b884a56736a66cdba55865b", + "samtools_alignment_plot-cnt.svg:md5,55cf5b87a08d2fb1c4ee34099146a8b1", + "samtools_alignment_plot-pct.svg:md5,123f6620c817c04bb14336aae67dcaac" + ] + ] ], - "multiqc_plots": [ - "multiqc_plots" + "multiqc_library_report": [ + "multiqc_library_test.html:md5,379d95b311027e666745448a9e27fe65" ], - "multiqc_report": [ + "multiqc_main_data": [ [ - "multiqc_report.html" + [ + "llms-full.txt:md5,d188ca7a55d62d188c5c13608585d75c", + "multiqc.log:md5,4832cad68754c77e2de90985272b0342", + "multiqc.parquet:md5,182ff0904414468b20c9197f08ecf956", + "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", + "multiqc_data.json:md5,a9e50ebc69822d508d72da06c16bf9ff", + "multiqc_software_versions.txt:md5,4e94b4dd017aacfd34b89230176af1af", + "multiqc_sources.txt:md5,d2a044df39ce3c6abe5cdc2d67473490" + ] + ] + ], + "multiqc_main_plots": [ + [ + + ] + ], + "multiqc_main_report": [ + [ + "multiqc.html:md5,f3b0258eb0cd1c0ee4f206368de6b662" ] ], "panelcoverage": [ @@ -837,6 +1280,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -863,6 +1307,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -889,6 +1334,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -915,6 +1361,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", @@ -954,7 +1401,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T13:12:08.110112" + "timestamp": "2025-12-04T19:54:04.990092" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -977,6 +1424,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "sample_type": "DNA", "samplename": "sample1", @@ -1011,6 +1459,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "readgroup": { "CN": "CMGG", @@ -1033,6 +1482,7 @@ { "id": "sample1", "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1074,6 +1524,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "sample_type": "DNA", "samplename": "sample1", @@ -1090,6 +1541,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1115,6 +1567,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1140,6 +1593,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1168,6 +1622,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1193,6 +1648,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1227,6 +1683,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1252,15 +1709,290 @@ "mosdepth_thresholds_csi": [ ], - "multiqc_data": [ - "multiqc_data" + "multiqc_library_data": [ + [ + "biobambam2_deduplication.txt:md5,992b5decb6d017254ee9b02fbe076d81", + "fastp-insert-size-plot.txt:md5,66fec5f01198da8ecd97410ec1727021", + "fastp-seq-content-gc-plot_Read_1_After_filtering.txt:md5,23420affa90c1523becba23c09653a92", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.txt:md5,27bb3440b4edeab8a9dc2ec1077cfc0e", + "fastp-seq-content-gc-plot_Read_2_After_filtering.txt:md5,e49276ebe93bb8294ca51e6a0916e703", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.txt:md5,f7bf2354433b3514893f0fe18e7f7877", + "fastp-seq-content-n-plot_Read_1_After_filtering.txt:md5,6c20997febd11ea6c80fe13a1761898b", + "fastp-seq-content-n-plot_Read_1_Before_filtering.txt:md5,a1d1cdbb1a1fb48b6d6bdf1f2192b2b7", + "fastp-seq-content-n-plot_Read_2_After_filtering.txt:md5,e1d8dcf05d785f863cfb17c96c1f58a4", + "fastp-seq-content-n-plot_Read_2_Before_filtering.txt:md5,30bfcca763531e4ee1638031d5359e48", + "fastp-seq-quality-plot_Read_1_After_filtering.txt:md5,2b0a42468f68992639ac8eacbf533134", + "fastp-seq-quality-plot_Read_1_Before_filtering.txt:md5,4e6fea487fecc2ee55db1518ff30a0b5", + "fastp-seq-quality-plot_Read_2_After_filtering.txt:md5,72a6d8295748db4de13d6dc1d1eb83dc", + "fastp-seq-quality-plot_Read_2_Before_filtering.txt:md5,3b1c7675660e838e75d1d5c62c0f3a61", + "fastp_filtered_reads_plot.txt:md5,9e506f1c8dbad71540697d11af4ba6df", + "llms-full.txt:md5,5f245d44b703b37991e2130e2247adb9", + "mosdepth-coverage-per-contig-single.txt:md5,0c5d8872c18169b771168ca9fa7d40b2", + "mosdepth-cumcoverage-dist-id.txt:md5,2592e72a312feb3363dece668fb2ea90", + "mosdepth_cov_dist.txt:md5,f74eeba67b67d59def037884af206551", + "mosdepth_cumcov_dist.txt:md5,f74eeba67b67d59def037884af206551", + "mosdepth_perchrom.txt:md5,0c5d8872c18169b771168ca9fa7d40b2", + "multiqc.log:md5,443bae2f4f1af6e82ae0c2623b5d5b26", + "multiqc.parquet:md5,64c797120e6fe75c00726dd5a05b8613", + "multiqc_biobambam2_dups.txt:md5,31c942ce8964d0941cb79f8c9de8aa04", + "multiqc_citations.txt:md5,294fadee817c59c64f1b985ac204b224", + "multiqc_data.json:md5,b021f17bc01883a1e6bb04642de162ba", + "multiqc_fastp.txt:md5,f917618024634bb24850390c8f4836e7", + "multiqc_general_stats.txt:md5,94493aa967cdafb4c5f78b8981b1a185", + "multiqc_picard_AlignmentSummaryMetrics.txt:md5,3f32124a666ad5fa6dda93759cf450f0", + "multiqc_picard_baseContent.txt:md5,deba2098af2de348792a37b405eab78c", + "multiqc_picard_quality_by_cycle.txt:md5,eca76b6ed78d34d66e1e185c7158868f", + "multiqc_picard_quality_score_distribution.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", + "multiqc_picard_wgsmetrics.txt:md5,54691f0bafd26c22b3339ac5133e3e59", + "multiqc_samtools_coverage.txt:md5,2b8ac198265a850d581d453eacb402cd", + "multiqc_samtools_flagstat.txt:md5,5ce133683245100011b77cd676471de1", + "multiqc_samtools_idxstats.txt:md5,7e542f20dd27d352b5d2be33e1920220", + "multiqc_samtools_stats.txt:md5,1dd571a033605b1224ebac95deceee0b", + "multiqc_sources.txt:md5,8bbd0fb5a901bd8e6da470a94357b8c7", + "picard_MarkIlluminaAdapters_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "picard_MeanQualityByCycle_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "picard_MeanQualityByCycle_histogram_1.txt:md5,eca76b6ed78d34d66e1e185c7158868f", + "picard_QualityScoreDistribution_histogram.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", + "picard_alignment_readlength_plot.txt:md5,891edbc18f01189de8c5bf52320ee6c7", + "picard_alignment_summary_Aligned_Bases.txt:md5,7d13622d8d4083fe2a4be5bf92ea77e6", + "picard_alignment_summary_Aligned_Reads.txt:md5,ed831c3df4e4465d9c6fb52ce731ee71", + "picard_base_distribution_by_cycle__Adenine.txt:md5,989b9c396dfa032d8ca02f57b7cc6e7d", + "picard_base_distribution_by_cycle__Cytosine.txt:md5,dc7b79f9ab4bc66db25b509e423abf2b", + "picard_base_distribution_by_cycle__Guanine.txt:md5,1f2a16426851c0e434558d437ac482e3", + "picard_base_distribution_by_cycle__Thymine.txt:md5,cbc90b7275fa29bf09d4be71fc443df1", + "picard_base_distribution_by_cycle__Undetermined.txt:md5,e0a643aff9cf4b0d277c4da6c798c6dc", + "picard_quality_by_cycle.txt:md5,f89d83da6f5a7fa00511a8959c2bd3c2", + "picard_quality_score_distribution.txt:md5,9d72562e154dba19a69180e2875ae8e9", + "picard_wgs_metrics_bases.txt:md5,5efebe4a352e7d44392faded88e10ec9", + "picard_wgs_metrics_histogram_Counts_Histogram.txt:md5,681e302aec63d9b5fa8966ee8ee2373a", + "picard_wgs_metrics_histogram_Percentage_Drop-Off.txt:md5,b37badd0338d073b2557c2492c472280", + "samtools-coverage-table.txt:md5,0f9fe2b460eb659d5ce23deba4ee62d8", + "samtools-coverage_BQ.txt:md5,68b97b7434bd35c71d3d14de478ba1b9", + "samtools-coverage_Bases.txt:md5,f8fcf650945e7b347409d678fae3b006", + "samtools-coverage_Coverage.txt:md5,bc62f359fced9778f869022dd4ab6647", + "samtools-coverage_MQ.txt:md5,5f9ece387a8e160cedbb02874c46000b", + "samtools-coverage_Mean_depth.txt:md5,4d5f58688b4c653b617c709717475c25", + "samtools-coverage_Reads.txt:md5,3667b340251346e538e6f078adcec945", + "samtools-flagstat-pct-table.txt:md5,8b0e71fcfbb55f6e8b0e6949fb146e0c", + "samtools-flagstat-table.txt:md5,6203dc05b5eaee4f529300986aebbb3c", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", + "samtools-idxstats-mapped-reads-plot_Raw_Counts.txt:md5,e8f2b29a779d322cd56b00f4958ef841", + "samtools-stats-dp.txt:md5,07153313edc4f7a3754e9821c85ca0cf", + "samtools_alignment_plot.txt:md5,d60abeeecbb005aff19c12f19a726057" + ] ], - "multiqc_plots": [ - "multiqc_plots" + "multiqc_library_plots": [ + [ + [ + "biobambam2_deduplication-cnt.pdf:md5,076943b1c590633eede4b60e8aa2434c", + "biobambam2_deduplication-pct.pdf:md5,32d4caca75efe889205de73e3a0a4d97", + "fastp-insert-size-plot.pdf:md5,f1023409a45dc9d8a0931659b0dc697d", + "fastp-seq-content-gc-plot_Read_1_After_filtering.pdf:md5,acbf529d4de4de437a3b71ef99d27698", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.pdf:md5,04621f82d0b3f8d97bf99b8d59b9988e", + "fastp-seq-content-gc-plot_Read_2_After_filtering.pdf:md5,9e23be66eacb942bd55f0459836bc111", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.pdf:md5,93b6b5bda685f45fb8c81747d0bccd7f", + "fastp-seq-content-n-plot_Read_1_After_filtering.pdf:md5,a8c81efa4e85a5258b6c8930d5543c3d", + "fastp-seq-content-n-plot_Read_1_Before_filtering.pdf:md5,5fe572924ab5149f71f9c33a3aa2ef26", + "fastp-seq-content-n-plot_Read_2_After_filtering.pdf:md5,6332b41f6963f9c9a0ef57e307cd636c", + "fastp-seq-content-n-plot_Read_2_Before_filtering.pdf:md5,25511034f06bb9c2d1ba499568285338", + "fastp-seq-quality-plot_Read_1_After_filtering.pdf:md5,a5d9dbd669760bd35cabff4a957c72e0", + "fastp-seq-quality-plot_Read_1_Before_filtering.pdf:md5,5d8a4222b4d43f2383759d6612faf1af", + "fastp-seq-quality-plot_Read_2_After_filtering.pdf:md5,5eaaa59e813d0b5e86c833fa7030fa63", + "fastp-seq-quality-plot_Read_2_Before_filtering.pdf:md5,8386c931c7b0ccd2f1fda5caa10d4612", + "fastp_filtered_reads_plot-cnt.pdf:md5,07f08edd555887949d5732358c2adf56", + "fastp_filtered_reads_plot-pct.pdf:md5,25516919ae1120b1e05ad36a296ae49e", + "mosdepth-coverage-per-contig-single-cnt.pdf:md5,e31c2589a014aa1e1e6ac997119ad675", + "mosdepth-coverage-per-contig-single-pct.pdf:md5,6435a5fe0f4b51d95e6a4b6acdd2f3d5", + "mosdepth-cumcoverage-dist-id.pdf:md5,5d4af4029371ddba1ed19ed38f88c8f2", + "picard_alignment_readlength_plot.pdf:md5,aa1f2ae479ecae2c3ab65cf265987258", + "picard_alignment_summary_Aligned_Bases-cnt.pdf:md5,13b9efa703cde16499f597103e511ce9", + "picard_alignment_summary_Aligned_Bases-pct.pdf:md5,5d53049cb3bfe99985fbf840095b960f", + "picard_alignment_summary_Aligned_Reads-cnt.pdf:md5,89bd672088e27c155cf2d5a06f8b03b4", + "picard_alignment_summary_Aligned_Reads-pct.pdf:md5,ea3c23c71d88ceba0cb38629cb5ed9bd", + "picard_base_distribution_by_cycle__Adenine.pdf:md5,0305b7ed8db6442e58f6df0939aae0c2", + "picard_base_distribution_by_cycle__Cytosine.pdf:md5,9fc115666272868eea3201b4ad329e6f", + "picard_base_distribution_by_cycle__Guanine.pdf:md5,ea999ac900f032148ef8dc8311fbaf21", + "picard_base_distribution_by_cycle__Thymine.pdf:md5,75fee9ea401481bd3a89d2e9dbc93b64", + "picard_base_distribution_by_cycle__Undetermined.pdf:md5,5084d6ea1d038c2ad803ee61ea3d4beb", + "picard_quality_by_cycle.pdf:md5,d46426fb7f451c50f7ea3900fbee909c", + "picard_quality_score_distribution.pdf:md5,c4bace227e4be936499b16d8b791c4d2", + "picard_wgs_metrics_bases.pdf:md5,8f385b4242b2839521d355da67d1601c", + "picard_wgs_metrics_histogram_Counts_Histogram.pdf:md5,6d1fd94aab4dae5f06f9ab2fd18a2d14", + "picard_wgs_metrics_histogram_Percentage_Drop-Off.pdf:md5,2973a0bd94ce539443fe3f144d60a57d", + "samtools-coverage-table.pdf:md5,43f6c1db01c3d6e0cbeb598d8462c3bb", + "samtools-coverage_BQ-cnt.pdf:md5,a0e08adcfcf5963508675e5f73f3ddc4", + "samtools-coverage_BQ-log.pdf:md5,7cfa56d3008e2cbdd5ac1e6dd01a0da5", + "samtools-coverage_Bases-cnt.pdf:md5,fe22f1634930da794d44c425cd3f9f75", + "samtools-coverage_Bases-log.pdf:md5,a91260f7858bb59b05994a60c98b3d09", + "samtools-coverage_Coverage-cnt.pdf:md5,28224f499e3b6101c2996159f75e52b6", + "samtools-coverage_Coverage-log.pdf:md5,d24bb4c34863c442d9081d8c8c2ec92a", + "samtools-coverage_MQ-cnt.pdf:md5,be7f66cb438e5857125034f8308f1a9d", + "samtools-coverage_MQ-log.pdf:md5,0e67e1921c296fa19c8fc5b5b2808a4d", + "samtools-coverage_Mean_depth-cnt.pdf:md5,2422e0664ff8f9e22a64e9f60c29dc01", + "samtools-coverage_Mean_depth-log.pdf:md5,ccb6cda145cf3e19266e2de300bf5107", + "samtools-coverage_Reads-cnt.pdf:md5,be0940f017942fd1ea7eb3b7472e78a9", + "samtools-coverage_Reads-log.pdf:md5,147469231619cf8c5a1bcbfedd1536f9", + "samtools-flagstat-pct-table.pdf:md5,4da35ccf697cab3209ff58e65ea22985", + "samtools-flagstat-table.pdf:md5,ecf1cd68a33e2ffacd09bc26acd78c4f", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.pdf:md5,564d74b6292e8e644e80ebbc4f36cbe3", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.pdf:md5,008360a325c47b0eba81acf03f486221", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.pdf:md5,7e7b33224bcf3053b9f074c70d0e4342", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.pdf:md5,9f8fc3a6ff912245f7a3c5189bf9fcb1", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.pdf:md5,f4d9ff73a8b429e998c0fcbc143c468e", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.pdf:md5,eccf04a5b6928eaf4306b7404f2fd945", + "samtools-stats-dp.pdf:md5,022199feb31379c5b5fb74ee031d8697", + "samtools_alignment_plot-cnt.pdf:md5,889e13551f5a50465e5046bd101e8647", + "samtools_alignment_plot-pct.pdf:md5,d66282dbb006fcae5f4c582f7892ca43" + ], + [ + "biobambam2_deduplication-cnt.png:md5,5707c3cf44cff88666c3c7b4970ab021", + "biobambam2_deduplication-pct.png:md5,b2a0fece791ff0532a426f3faeecf3f4", + "fastp-insert-size-plot.png:md5,40a7c7edc7062c92d088e8974dd1fbe9", + "fastp-seq-content-gc-plot_Read_1_After_filtering.png:md5,ff993de7c7a0b2f4dd17aaf509c8209b", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.png:md5,124351c45a1bd7d611fd3ba89510018b", + "fastp-seq-content-gc-plot_Read_2_After_filtering.png:md5,058842506a3200770c46a4a70b64ce48", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.png:md5,985bf206443edf1417e2a0f9354abe3c", + "fastp-seq-content-n-plot_Read_1_After_filtering.png:md5,7855b3938c2b48578b2e1ca3486783de", + "fastp-seq-content-n-plot_Read_1_Before_filtering.png:md5,b9276b3bd8f2c57a51d12f76273fc322", + "fastp-seq-content-n-plot_Read_2_After_filtering.png:md5,45684fe478e5d2912848c032c3bc8ee4", + "fastp-seq-content-n-plot_Read_2_Before_filtering.png:md5,97606f1910cdbb47f68d5b7ac9f9bf4b", + "fastp-seq-quality-plot_Read_1_After_filtering.png:md5,44fe9279b3f2279c19d2ce541b9c6c19", + "fastp-seq-quality-plot_Read_1_Before_filtering.png:md5,93c06663d6ed02d11f4e5eab97d48917", + "fastp-seq-quality-plot_Read_2_After_filtering.png:md5,99219cc1b64c80e6ac8cf653add1990c", + "fastp-seq-quality-plot_Read_2_Before_filtering.png:md5,5d655406be9a2ff9a68ec461f51cfcc5", + "fastp_filtered_reads_plot-cnt.png:md5,75911dd91d24adfaae185ebcf0a8455a", + "fastp_filtered_reads_plot-pct.png:md5,4b3c0fd7f90c7c83b50c557d4aa3b6a5", + "mosdepth-coverage-per-contig-single-cnt.png:md5,4d6f6bf53791c7438153194cf5c28b58", + "mosdepth-coverage-per-contig-single-pct.png:md5,8f17612654e4217dd673c2788b473e7c", + "mosdepth-cumcoverage-dist-id.png:md5,9a1b83a02f39658f5896ed4b665f7327", + "picard_alignment_readlength_plot.png:md5,7c5708c6ed659731111242666746905e", + "picard_alignment_summary_Aligned_Bases-cnt.png:md5,ccd4cdf7a4b1f3f2a39adf2e0c700ed4", + "picard_alignment_summary_Aligned_Bases-pct.png:md5,de5771f0fc6d2feaf7ea1bef7b4f57ed", + "picard_alignment_summary_Aligned_Reads-cnt.png:md5,fa8f7e289fd84f0dfb877758b926c421", + "picard_alignment_summary_Aligned_Reads-pct.png:md5,18be469adf5d34e7296aa9e0feb10274", + "picard_base_distribution_by_cycle__Adenine.png:md5,b59076e9793e4a403228c477f99c6cf8", + "picard_base_distribution_by_cycle__Cytosine.png:md5,7c42741dd1ee386af449d29e21a8389d", + "picard_base_distribution_by_cycle__Guanine.png:md5,27a487a8587c180f08d3afb58e71fb17", + "picard_base_distribution_by_cycle__Thymine.png:md5,f99b137a9975db372a29c0400652eca4", + "picard_base_distribution_by_cycle__Undetermined.png:md5,e7428923e6530f7bd00ca05bf2b0dabe", + "picard_quality_by_cycle.png:md5,23c7dc421bf1a8b9c61e7abdea1b96e9", + "picard_quality_score_distribution.png:md5,f129878e0583e69cac53ec51cac62f4e", + "picard_wgs_metrics_bases.png:md5,6ae01c3c3e7a7f6bac5dd44e0e29dd6a", + "picard_wgs_metrics_histogram_Counts_Histogram.png:md5,cfd66c498f788418c650ec052c12c737", + "picard_wgs_metrics_histogram_Percentage_Drop-Off.png:md5,2b050e4750a49c843e8fd8a1c2e01424", + "samtools-coverage-table.png:md5,ffc0a23dcfe8a1b44e7c585898a412ba", + "samtools-coverage_BQ-cnt.png:md5,42a7bfacd302c7924d59701a585957f8", + "samtools-coverage_BQ-log.png:md5,67d6d4c8072743a32dfa30dd22edd5fe", + "samtools-coverage_Bases-cnt.png:md5,8790b6226f16810deceb82c6834b21be", + "samtools-coverage_Bases-log.png:md5,7bdd54947c3ab74d06b9fc11cc35cb51", + "samtools-coverage_Coverage-cnt.png:md5,cdff6829f5d017e67668e6b77b8648fd", + "samtools-coverage_Coverage-log.png:md5,13441e809c66563bf7284ebe4038f368", + "samtools-coverage_MQ-cnt.png:md5,59265e8998386d8a6521296508b4f4e6", + "samtools-coverage_MQ-log.png:md5,0282c8f2fb311eb3830f6d33a8e0d2ef", + "samtools-coverage_Mean_depth-cnt.png:md5,7f0aa59d888da55c8b7e5ca00011b2fc", + "samtools-coverage_Mean_depth-log.png:md5,ab01268969d553decb36658ca785dac0", + "samtools-coverage_Reads-cnt.png:md5,f77fe84d95f5bebd12aa764ab377b6e7", + "samtools-coverage_Reads-log.png:md5,34d3ebbc83f073531328d633466cfcd9", + "samtools-flagstat-pct-table.png:md5,30a84ce2464168d8dedf65b47725e2e1", + "samtools-flagstat-table.png:md5,a828ba0e94ebd04d2ac50ecc43b007fd", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.png:md5,91267791bafff119d985db6b24f813dc", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.png:md5,d1c9fd2633128ed5af7113cedeba91d8", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.png:md5,eb81f43f6c5778f957ce85137758235e", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.png:md5,b1b15467c4b7e34b2a724c2fe9daefa8", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.png:md5,64927987623ac1715e607470f6bf055a", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.png:md5,09773cf98a65a96710a4fac9e2600ed9", + "samtools-stats-dp.png:md5,fe29585e232244237558512103d78fdc", + "samtools_alignment_plot-cnt.png:md5,e5523404a7622df41efaf24fb98ef4c5", + "samtools_alignment_plot-pct.png:md5,7945231e29b09915dee17a9fa620ef62" + ], + [ + "biobambam2_deduplication-cnt.svg:md5,cfd25e0ac46d01b09f2196fc10487a97", + "biobambam2_deduplication-pct.svg:md5,c7ed58b8de114475f6ef551cc38246b6", + "fastp-insert-size-plot.svg:md5,463e2ebba19326fc07286ec96074439c", + "fastp-seq-content-gc-plot_Read_1_After_filtering.svg:md5,df2eff4d156ad7f187fa80e3340cbc9c", + "fastp-seq-content-gc-plot_Read_1_Before_filtering.svg:md5,de22f2c91d8abe074f24aada92336dae", + "fastp-seq-content-gc-plot_Read_2_After_filtering.svg:md5,c1119ba28aa972dcde0725e9ece9b452", + "fastp-seq-content-gc-plot_Read_2_Before_filtering.svg:md5,bf51d5e029164a62af8a97002bafaf91", + "fastp-seq-content-n-plot_Read_1_After_filtering.svg:md5,1cd1bb467239c3375c0670deb40910e4", + "fastp-seq-content-n-plot_Read_1_Before_filtering.svg:md5,58312bc31b5df1f981ddfaa464747d6a", + "fastp-seq-content-n-plot_Read_2_After_filtering.svg:md5,4b4d0bb5ee8e778e36d0b22b50e588ac", + "fastp-seq-content-n-plot_Read_2_Before_filtering.svg:md5,5a4346d963e57ef9dc93049473b299d4", + "fastp-seq-quality-plot_Read_1_After_filtering.svg:md5,8df1ad718fba86d1dc9100f686805969", + "fastp-seq-quality-plot_Read_1_Before_filtering.svg:md5,2ab2d86c525286641d2add385a2776b8", + "fastp-seq-quality-plot_Read_2_After_filtering.svg:md5,57fc98afa287a7efcb4cda584aaa1b03", + "fastp-seq-quality-plot_Read_2_Before_filtering.svg:md5,0255426c3f1eb52d8cc79e15becc30a2", + "fastp_filtered_reads_plot-cnt.svg:md5,e824977b86925e3f373258ecdd4043e3", + "fastp_filtered_reads_plot-pct.svg:md5,481a650cbb8337fd7324909c08782fbb", + "mosdepth-coverage-per-contig-single-cnt.svg:md5,54a9e9adab8aec8840883d8fbfd9a5d0", + "mosdepth-coverage-per-contig-single-pct.svg:md5,131d4cac8f19f0b95032c7233af5823e", + "mosdepth-cumcoverage-dist-id.svg:md5,179007d2d118f6a8e418e43aeaeb9c59", + "picard_alignment_readlength_plot.svg:md5,8251fdfdcf8d1cfcafa2c5e4274b5dd1", + "picard_alignment_summary_Aligned_Bases-cnt.svg:md5,fd201a6cf172881e6f665f3bf709e47d", + "picard_alignment_summary_Aligned_Bases-pct.svg:md5,000fee385374691cee56da73f6b1a6e3", + "picard_alignment_summary_Aligned_Reads-cnt.svg:md5,2dab47d583abe346da10f9cc7326afcf", + "picard_alignment_summary_Aligned_Reads-pct.svg:md5,d4a37067193df967815f12979b3af04c", + "picard_base_distribution_by_cycle__Adenine.svg:md5,218b08544c23a6efa4658d7f3752e104", + "picard_base_distribution_by_cycle__Cytosine.svg:md5,ab5e2bc1042bb94494552650de3f5572", + "picard_base_distribution_by_cycle__Guanine.svg:md5,b55b38dd248d4bb58d45727640b08bdb", + "picard_base_distribution_by_cycle__Thymine.svg:md5,3207e557593827437917773a6d7a3076", + "picard_base_distribution_by_cycle__Undetermined.svg:md5,ce646cb1a14cf74c5d07cd95ea3ea6fa", + "picard_quality_by_cycle.svg:md5,8d09b50d5323d7d08e78694e2b4f5783", + "picard_quality_score_distribution.svg:md5,252451413c9a1305642aeca9540fe95b", + "picard_wgs_metrics_bases.svg:md5,2433b911e40ebe4bf49fabfdd473f488", + "picard_wgs_metrics_histogram_Counts_Histogram.svg:md5,90789c6587b1924a203de3ea67051e1d", + "picard_wgs_metrics_histogram_Percentage_Drop-Off.svg:md5,57bf92e2f97b6698a78761e9133d696d", + "samtools-coverage-table.svg:md5,dc9a03bbcdc8e6c85ecdcbc473c284e5", + "samtools-coverage_BQ-cnt.svg:md5,3bf9dd0ff0afb7dac4e82c3cc0debee6", + "samtools-coverage_BQ-log.svg:md5,3503b4d291a6bc5f13321ea35367173c", + "samtools-coverage_Bases-cnt.svg:md5,1da43ab7b821f0950bc5fcd9d0ef4de6", + "samtools-coverage_Bases-log.svg:md5,5d6d1e30f71dc901bc854891f8a86c8b", + "samtools-coverage_Coverage-cnt.svg:md5,bd068ea990b4a9ab34f8ed7906ab4df7", + "samtools-coverage_Coverage-log.svg:md5,a84dbdcc47032a0802f0f4303fff79e5", + "samtools-coverage_MQ-cnt.svg:md5,a34d1b3ef3307b7f239f345c4c46417c", + "samtools-coverage_MQ-log.svg:md5,f0d92ed6064fe3857222add705200ebf", + "samtools-coverage_Mean_depth-cnt.svg:md5,beb5c52e77b588aff06211996b5c9c58", + "samtools-coverage_Mean_depth-log.svg:md5,bf0fe9b38385d501bfdc0eb8ae32dc0c", + "samtools-coverage_Reads-cnt.svg:md5,a0f29b2d300f8d441cf0444dfed15d2c", + "samtools-coverage_Reads-log.svg:md5,2b286ec78f439cc836c27b894355a649", + "samtools-flagstat-pct-table.svg:md5,a861423dc06a2c4343ac008da572cae6", + "samtools-flagstat-table.svg:md5,7e3929334dc02949b8a8624cee0b74f7", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.svg:md5,6beb4644520950ba9d88aa2fc76f97ca", + "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.svg:md5,bdd312d3b7078cf983b55365b073c8da", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.svg:md5,cacd164220e021555bfab9d77d1604d6", + "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.svg:md5,a0afc475e749152c8a1f68348e126468", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.svg:md5,70ee0003a9ad53ef889f8b1e6ab29fbd", + "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.svg:md5,10677c752400f74cb2d80b448a7ecb6e", + "samtools-stats-dp.svg:md5,7a82a092680d0a2f74bc6bd7ddaff3ff", + "samtools_alignment_plot-cnt.svg:md5,57bf2b3f8ae396795a58e41c6a13eaad", + "samtools_alignment_plot-pct.svg:md5,11319f379dfc395ae27e63e58911a7dc" + ] + ] + ], + "multiqc_library_report": [ + "multiqc_library_test.html:md5,39501e6d3e661aa5268cc7bc3013842e" + ], + "multiqc_main_data": [ + [ + [ + "llms-full.txt:md5,5c2ab84efb61df9527a502df6d502f6b", + "multiqc.log:md5,b1c042eb498add3a6e44b5b1198a11a3", + "multiqc.parquet:md5,38b4675edf61dc905c4e5001dc8dcde1", + "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", + "multiqc_data.json:md5,3372e515c6d7aee673f28f47c22507ba", + "multiqc_software_versions.txt:md5,b957e99d3c8616d8a0326be3f6114ced", + "multiqc_sources.txt:md5,d2a044df39ce3c6abe5cdc2d67473490" + ] + ] + ], + "multiqc_main_plots": [ + [ + + ] ], - "multiqc_report": [ + "multiqc_main_report": [ [ - "multiqc_report.html" + "multiqc.html:md5,62160777bc781484c4e2434e8c6009ff" ] ], "panelcoverage": [ @@ -1284,6 +2016,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "sample_type": "DNA", "samplename": "sample1", @@ -1314,6 +2047,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "sample_type": "DNA", "samplename": "sample1", @@ -1344,6 +2078,7 @@ "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, "id": "sample1", + "library": "test", "organism": "Homo sapiens", "sample_type": "DNA", "samplename": "sample1", @@ -1360,6 +2095,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1385,6 +2121,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1410,6 +2147,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1435,6 +2173,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1460,6 +2199,7 @@ "groupSize": 1, "groupTarget": { "samplename": "sample1", + "library": "test", "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", @@ -1502,6 +2242,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T13:10:35.894317" + "timestamp": "2025-12-04T19:51:58.967318" } } \ No newline at end of file From 00bcfcb60ff3166b586bba44a2556eb8314db370 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:01:04 +0100 Subject: [PATCH 089/228] fix linting --- modules.json | 130 +++++++-------------------- modules/nf-core/multiqc/multiqc.diff | 8 +- 2 files changed, 36 insertions(+), 102 deletions(-) diff --git a/modules.json b/modules.json index de8e0ac9..cbebbe1e 100644 --- a/modules.json +++ b/modules.json @@ -8,207 +8,151 @@ "bcl2fastq": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "bcl_demultiplex" - ] + "installed_by": ["bcl_demultiplex"] }, "bclconvert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "bcl_demultiplex", - "modules" - ], + "installed_by": ["bcl_demultiplex", "modules"], "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, "biobambam/bamsormadup": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, "bowtie2/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", "git_sha": "d86336f3e7ae0d5f76c67b0859409769cfeb2af2", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, "dragmap/align": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, "fastp": { "branch": "master", "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "md5sum": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "mosdepth": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, "multiqc": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/multiqc/multiqc.diff" }, "picard/collecthsmetrics": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, "samtools/cat": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/cat/samtools-cat.diff" }, "samtools/convert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, "samtools/flagstat": { "branch": "master", "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/idxstats": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/import": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/sormadup": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, "samtools/sort": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "samtools/stats": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, "snapaligner/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, "star/align": { "branch": "master", "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" }, "strobealign": { "branch": "master", "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/strobealign/strobealign.diff" } } @@ -218,40 +162,30 @@ "bcl_demultiplex": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "fastq_align_dna": { "branch": "master", "git_sha": "070ddae7fb59384d3d85bf69eb9a1d71ab33ada9", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "df4d1c8cdee98a1bbbed8fc51e82296568e0f9c1", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] } } } } } -} \ No newline at end of file +} diff --git a/modules/nf-core/multiqc/multiqc.diff b/modules/nf-core/multiqc/multiqc.diff index 36396fa5..73a5eb45 100644 --- a/modules/nf-core/multiqc/multiqc.diff +++ b/modules/nf-core/multiqc/multiqc.diff @@ -1,4 +1,6 @@ Changes in component 'nf-core/multiqc' +'modules/nf-core/multiqc/environment.yml' is unchanged +'modules/nf-core/multiqc/meta.yml' is unchanged Changes in 'multiqc/main.nf': --- modules/nf-core/multiqc/main.nf +++ modules/nf-core/multiqc/main.nf @@ -27,10 +29,8 @@ Changes in 'multiqc/main.nf': when: task.ext.when == null || task.ext.when -'modules/nf-core/multiqc/environment.yml' is unchanged -'modules/nf-core/multiqc/meta.yml' is unchanged -'modules/nf-core/multiqc/tests/custom_prefix.config' is unchanged -'modules/nf-core/multiqc/tests/main.nf.test' is unchanged 'modules/nf-core/multiqc/tests/main.nf.test.snap' is unchanged 'modules/nf-core/multiqc/tests/nextflow.config' is unchanged +'modules/nf-core/multiqc/tests/main.nf.test' is unchanged +'modules/nf-core/multiqc/tests/custom_prefix.config' is unchanged ************************************************************ From e917d7fdc21c479de687536920146f7660804426 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:43:05 +0100 Subject: [PATCH 090/228] fix more tests --- tests/workflows/preprocessing.nf.test | 27 +- tests/workflows/preprocessing.nf.test.snap | 690 +-------------------- 2 files changed, 36 insertions(+), 681 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index 2f1c5e4c..54a187ec 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -58,9 +58,12 @@ nextflow_workflow { assert workflow.success assert snapshot( sanitizeOutput(workflow.out, unstableKeys:[ - "multiqc_report", - "multiqc_plots", - "multiqc_data", + "multiqc_main_report", + "multiqc_main_data", + "multiqc_main_plots", + "multiqc_library_report", + "multiqc_library_data", + "multiqc_library_plots", "md5sums", "fastp_html", "crams", @@ -124,9 +127,12 @@ nextflow_workflow { assert workflow.success assert snapshot( sanitizeOutput(workflow.out, unstableKeys:[ - "multiqc_report", - "multiqc_plots", - "multiqc_data", + "multiqc_main_report", + "multiqc_main_data", + "multiqc_main_plots", + "multiqc_library_report", + "multiqc_library_data", + "multiqc_library_plots", "md5sums", "fastp_html", "crams", @@ -193,9 +199,12 @@ nextflow_workflow { assert workflow.success assert snapshot( sanitizeOutput(workflow.out, unstableKeys:[ - "multiqc_report", - "multiqc_plots", - "multiqc_data", + "multiqc_main_report", + "multiqc_main_data", + "multiqc_main_plots", + "multiqc_library_report", + "multiqc_library_data", + "multiqc_library_plots", "md5sums", "fastp_html", "crams", diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 961504d8..4a0b52f8 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -388,275 +388,17 @@ ], "multiqc_library_data": [ - [ - "biobambam2_deduplication.txt:md5,992b5decb6d017254ee9b02fbe076d81", - "fastp-insert-size-plot.txt:md5,66fec5f01198da8ecd97410ec1727021", - "fastp-seq-content-gc-plot_Read_1_After_filtering.txt:md5,23420affa90c1523becba23c09653a92", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.txt:md5,27bb3440b4edeab8a9dc2ec1077cfc0e", - "fastp-seq-content-gc-plot_Read_2_After_filtering.txt:md5,e49276ebe93bb8294ca51e6a0916e703", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.txt:md5,f7bf2354433b3514893f0fe18e7f7877", - "fastp-seq-content-n-plot_Read_1_After_filtering.txt:md5,6c20997febd11ea6c80fe13a1761898b", - "fastp-seq-content-n-plot_Read_1_Before_filtering.txt:md5,a1d1cdbb1a1fb48b6d6bdf1f2192b2b7", - "fastp-seq-content-n-plot_Read_2_After_filtering.txt:md5,e1d8dcf05d785f863cfb17c96c1f58a4", - "fastp-seq-content-n-plot_Read_2_Before_filtering.txt:md5,30bfcca763531e4ee1638031d5359e48", - "fastp-seq-quality-plot_Read_1_After_filtering.txt:md5,2b0a42468f68992639ac8eacbf533134", - "fastp-seq-quality-plot_Read_1_Before_filtering.txt:md5,4e6fea487fecc2ee55db1518ff30a0b5", - "fastp-seq-quality-plot_Read_2_After_filtering.txt:md5,72a6d8295748db4de13d6dc1d1eb83dc", - "fastp-seq-quality-plot_Read_2_Before_filtering.txt:md5,3b1c7675660e838e75d1d5c62c0f3a61", - "fastp_filtered_reads_plot.txt:md5,9e506f1c8dbad71540697d11af4ba6df", - "llms-full.txt:md5,a9dd5cb0ccb6d732ac915af862770693", - "mosdepth-coverage-per-contig-single.txt:md5,e5dd72804ecbe8429179eaae01118d39", - "mosdepth-cumcoverage-dist-id.txt:md5,49f3ec6d8639c9b0f794e4bf96bd11c4", - "mosdepth_cov_dist.txt:md5,704ae312ab6109b1724e3fac0dc740ed", - "mosdepth_cumcov_dist.txt:md5,704ae312ab6109b1724e3fac0dc740ed", - "mosdepth_perchrom.txt:md5,e5dd72804ecbe8429179eaae01118d39", - "multiqc.log:md5,0bf142cd568af28e39f166591e28b550", - "multiqc.parquet:md5,c66e2b2f6ba202acf3cda2ebbd7b2a06", - "multiqc_biobambam2_dups.txt:md5,31c942ce8964d0941cb79f8c9de8aa04", - "multiqc_citations.txt:md5,294fadee817c59c64f1b985ac204b224", - "multiqc_data.json:md5,0c06c19b2156369fab669049b6e37eb5", - "multiqc_fastp.txt:md5,f917618024634bb24850390c8f4836e7", - "multiqc_general_stats.txt:md5,439ff0539fa18ba86b79e990c42dff75", - "multiqc_picard_AlignmentSummaryMetrics.txt:md5,3f32124a666ad5fa6dda93759cf450f0", - "multiqc_picard_HsMetrics.txt:md5,a5ccd0c64f6e2944a559280aaabce595", - "multiqc_picard_baseContent.txt:md5,deba2098af2de348792a37b405eab78c", - "multiqc_picard_quality_by_cycle.txt:md5,eca76b6ed78d34d66e1e185c7158868f", - "multiqc_picard_quality_score_distribution.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", - "multiqc_samtools_coverage.txt:md5,2b8ac198265a850d581d453eacb402cd", - "multiqc_samtools_flagstat.txt:md5,5ce133683245100011b77cd676471de1", - "multiqc_samtools_idxstats.txt:md5,7e542f20dd27d352b5d2be33e1920220", - "multiqc_samtools_stats.txt:md5,1dd571a033605b1224ebac95deceee0b", - "multiqc_sources.txt:md5,26011ccef291bca153e14a43437b4bbc", - "picard_MarkIlluminaAdapters_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "picard_MeanQualityByCycle_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "picard_MeanQualityByCycle_histogram_1.txt:md5,eca76b6ed78d34d66e1e185c7158868f", - "picard_QualityScoreDistribution_histogram.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", - "picard_alignment_readlength_plot.txt:md5,891edbc18f01189de8c5bf52320ee6c7", - "picard_alignment_summary_Aligned_Bases.txt:md5,7d13622d8d4083fe2a4be5bf92ea77e6", - "picard_alignment_summary_Aligned_Reads.txt:md5,ed831c3df4e4465d9c6fb52ce731ee71", - "picard_base_distribution_by_cycle__Adenine.txt:md5,989b9c396dfa032d8ca02f57b7cc6e7d", - "picard_base_distribution_by_cycle__Cytosine.txt:md5,dc7b79f9ab4bc66db25b509e423abf2b", - "picard_base_distribution_by_cycle__Guanine.txt:md5,1f2a16426851c0e434558d437ac482e3", - "picard_base_distribution_by_cycle__Thymine.txt:md5,cbc90b7275fa29bf09d4be71fc443df1", - "picard_base_distribution_by_cycle__Undetermined.txt:md5,e0a643aff9cf4b0d277c4da6c798c6dc", - "picard_hsmetrics_table.txt:md5,a170b91563f01fc311048a9f1983ac87", - "picard_percentage_target_bases.txt:md5,f29ba29d0df56128046793ff26ca5950", - "picard_quality_by_cycle.txt:md5,f89d83da6f5a7fa00511a8959c2bd3c2", - "picard_quality_score_distribution.txt:md5,9d72562e154dba19a69180e2875ae8e9", - "samtools-coverage-table.txt:md5,0f9fe2b460eb659d5ce23deba4ee62d8", - "samtools-coverage_BQ.txt:md5,68b97b7434bd35c71d3d14de478ba1b9", - "samtools-coverage_Bases.txt:md5,f8fcf650945e7b347409d678fae3b006", - "samtools-coverage_Coverage.txt:md5,bc62f359fced9778f869022dd4ab6647", - "samtools-coverage_MQ.txt:md5,5f9ece387a8e160cedbb02874c46000b", - "samtools-coverage_Mean_depth.txt:md5,4d5f58688b4c653b617c709717475c25", - "samtools-coverage_Reads.txt:md5,3667b340251346e538e6f078adcec945", - "samtools-flagstat-pct-table.txt:md5,8b0e71fcfbb55f6e8b0e6949fb146e0c", - "samtools-flagstat-table.txt:md5,6203dc05b5eaee4f529300986aebbb3c", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", - "samtools-idxstats-mapped-reads-plot_Raw_Counts.txt:md5,e8f2b29a779d322cd56b00f4958ef841", - "samtools-stats-dp.txt:md5,07153313edc4f7a3754e9821c85ca0cf", - "samtools_alignment_plot.txt:md5,d60abeeecbb005aff19c12f19a726057" - ] + "multiqc_library_test_data" ], "multiqc_library_plots": [ - [ - [ - "biobambam2_deduplication-cnt.pdf:md5,8dcf3c25c3a6d362a312683b0cc52254", - "biobambam2_deduplication-pct.pdf:md5,f38a15e73459aefdbf92f53a602eecab", - "fastp-insert-size-plot.pdf:md5,761cc56448ee9500fadf80330b6e6c18", - "fastp-seq-content-gc-plot_Read_1_After_filtering.pdf:md5,e4ba12f4f0c3961dfe7343a420210f74", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.pdf:md5,cbf4e5d5cd4bccc836ef8a4b00789608", - "fastp-seq-content-gc-plot_Read_2_After_filtering.pdf:md5,5c452cc418222a26b85bf2779ccc0e5f", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.pdf:md5,148e583db6040c29d07ae06ade0aae37", - "fastp-seq-content-n-plot_Read_1_After_filtering.pdf:md5,fdda12e04eceaabad0260e7694ca1a47", - "fastp-seq-content-n-plot_Read_1_Before_filtering.pdf:md5,f2d6ba7286870d31dbcdfdc501fa0fe4", - "fastp-seq-content-n-plot_Read_2_After_filtering.pdf:md5,7fc668801cd69b020c5f0dcb7ab780f4", - "fastp-seq-content-n-plot_Read_2_Before_filtering.pdf:md5,9c21674378164f3bd7010aedaf9f9c62", - "fastp-seq-quality-plot_Read_1_After_filtering.pdf:md5,8d69018e6c7babd707ed91a30a2f4373", - "fastp-seq-quality-plot_Read_1_Before_filtering.pdf:md5,1c14e7b644546b647e1525b0035d7095", - "fastp-seq-quality-plot_Read_2_After_filtering.pdf:md5,d30a990dc6d11a33b3a0bd385b7e2765", - "fastp-seq-quality-plot_Read_2_Before_filtering.pdf:md5,569074e2210e477a45c1196d967e0e03", - "fastp_filtered_reads_plot-cnt.pdf:md5,1572b3a72a231623c8ae927b4cb7a0ae", - "fastp_filtered_reads_plot-pct.pdf:md5,d3a4c1a1372f7b914ae6dac6b0b117aa", - "mosdepth-coverage-per-contig-single-cnt.pdf:md5,b532e220dbd44f1b5bccae17f3a423da", - "mosdepth-coverage-per-contig-single-pct.pdf:md5,eb539598e0da9e9c0f16033ff345594b", - "mosdepth-cumcoverage-dist-id.pdf:md5,017ca25a754de8ad1e59bb8e5f9384a9", - "picard_alignment_readlength_plot.pdf:md5,0f360805d8f8d8aeacf3aaae1dc6eb06", - "picard_alignment_summary_Aligned_Bases-cnt.pdf:md5,e0e630f9c98be95f6b26b895721925ca", - "picard_alignment_summary_Aligned_Bases-pct.pdf:md5,0afa444f1854208d7252dfd45c06a000", - "picard_alignment_summary_Aligned_Reads-cnt.pdf:md5,0419bd8fcd699e40575e7c1619937b3e", - "picard_alignment_summary_Aligned_Reads-pct.pdf:md5,aa9bb7e84867a2bd953756a95bc0f311", - "picard_base_distribution_by_cycle__Adenine.pdf:md5,e5a1c8fd676d7267bf0e16baff152f96", - "picard_base_distribution_by_cycle__Cytosine.pdf:md5,8093c223e5fc64be9db36341ee801a6a", - "picard_base_distribution_by_cycle__Guanine.pdf:md5,82d32c26160589945f4c395c98220cb4", - "picard_base_distribution_by_cycle__Thymine.pdf:md5,1c1ed09619d30f34ce0ddc9464d26706", - "picard_base_distribution_by_cycle__Undetermined.pdf:md5,785db14b8f88f7b5675a991172a3ea2a", - "picard_hsmetrics_table.pdf:md5,fc9411cf48ebd47c0c261f919849dd46", - "picard_percentage_target_bases.pdf:md5,3752afa592927e547bf0c03e1d1006eb", - "picard_quality_by_cycle.pdf:md5,673292cc4b18e8cca83522991b81a996", - "picard_quality_score_distribution.pdf:md5,88f913aed3ae94590bf10d11a2b59a09", - "samtools-coverage-table.pdf:md5,26da9fd5643611f77ae7d511d9b92a04", - "samtools-coverage_BQ-cnt.pdf:md5,d2602d8ee5faee419b10283104b12e46", - "samtools-coverage_BQ-log.pdf:md5,04983f8664bf34583140efef4594c91d", - "samtools-coverage_Bases-cnt.pdf:md5,e7d204151b84a425c030605c40e5ac98", - "samtools-coverage_Bases-log.pdf:md5,eb3195e76bc390a13bd786ce17994208", - "samtools-coverage_Coverage-cnt.pdf:md5,4cd335d85e8071f4d6b34c07da7e58b3", - "samtools-coverage_Coverage-log.pdf:md5,1a6d4126fd6390139db86ac9c59c10b8", - "samtools-coverage_MQ-cnt.pdf:md5,19b1ec40e0a622c79429cd2e5db6a2ab", - "samtools-coverage_MQ-log.pdf:md5,6bd0213a8e9437ea972d060a45dd32e0", - "samtools-coverage_Mean_depth-cnt.pdf:md5,2e6766ac06b6d61b1eec6e5a4a8e773e", - "samtools-coverage_Mean_depth-log.pdf:md5,a89995d4c79a6119465fb4899129ef73", - "samtools-coverage_Reads-cnt.pdf:md5,f3ed81fba0bd8fdf860db5d4541fb66c", - "samtools-coverage_Reads-log.pdf:md5,9aae76e8a17ae18bc7e1ea222736b4ff", - "samtools-flagstat-pct-table.pdf:md5,e6debd913a8442f56cc22c714021e0a7", - "samtools-flagstat-table.pdf:md5,28f63086a0ac9b57da1f0911b7f8940d", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.pdf:md5,ae4ddcc627dada8d861a8c15e49d97f1", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.pdf:md5,543a323fa0cede66f19ad512222954f4", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.pdf:md5,3e874efbf35563c0e52fd47611822494", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.pdf:md5,c18b4695893cde28c41de39fb16dbcee", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.pdf:md5,d4b9c1b844d0cf4e29d112dc755682b4", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.pdf:md5,f3bef9d1890b8a69acb9c52e07ce7ea3", - "samtools-stats-dp.pdf:md5,9872a7fcbd9e6047c6b3c9aca5a36ced", - "samtools_alignment_plot-cnt.pdf:md5,288be15b7710eadf32e6ba47511fe140", - "samtools_alignment_plot-pct.pdf:md5,6e4103b696b62faaa47989881f202dbe" - ], - [ - "biobambam2_deduplication-cnt.png:md5,5707c3cf44cff88666c3c7b4970ab021", - "biobambam2_deduplication-pct.png:md5,b2a0fece791ff0532a426f3faeecf3f4", - "fastp-insert-size-plot.png:md5,40a7c7edc7062c92d088e8974dd1fbe9", - "fastp-seq-content-gc-plot_Read_1_After_filtering.png:md5,ff993de7c7a0b2f4dd17aaf509c8209b", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.png:md5,124351c45a1bd7d611fd3ba89510018b", - "fastp-seq-content-gc-plot_Read_2_After_filtering.png:md5,058842506a3200770c46a4a70b64ce48", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.png:md5,985bf206443edf1417e2a0f9354abe3c", - "fastp-seq-content-n-plot_Read_1_After_filtering.png:md5,7855b3938c2b48578b2e1ca3486783de", - "fastp-seq-content-n-plot_Read_1_Before_filtering.png:md5,b9276b3bd8f2c57a51d12f76273fc322", - "fastp-seq-content-n-plot_Read_2_After_filtering.png:md5,45684fe478e5d2912848c032c3bc8ee4", - "fastp-seq-content-n-plot_Read_2_Before_filtering.png:md5,97606f1910cdbb47f68d5b7ac9f9bf4b", - "fastp-seq-quality-plot_Read_1_After_filtering.png:md5,44fe9279b3f2279c19d2ce541b9c6c19", - "fastp-seq-quality-plot_Read_1_Before_filtering.png:md5,93c06663d6ed02d11f4e5eab97d48917", - "fastp-seq-quality-plot_Read_2_After_filtering.png:md5,99219cc1b64c80e6ac8cf653add1990c", - "fastp-seq-quality-plot_Read_2_Before_filtering.png:md5,5d655406be9a2ff9a68ec461f51cfcc5", - "fastp_filtered_reads_plot-cnt.png:md5,75911dd91d24adfaae185ebcf0a8455a", - "fastp_filtered_reads_plot-pct.png:md5,4b3c0fd7f90c7c83b50c557d4aa3b6a5", - "mosdepth-coverage-per-contig-single-cnt.png:md5,ff9cec471c8a882b3ad608312b950332", - "mosdepth-coverage-per-contig-single-pct.png:md5,8f17612654e4217dd673c2788b473e7c", - "mosdepth-cumcoverage-dist-id.png:md5,64f3a8071bca0d22a72c72090b2eb638", - "picard_alignment_readlength_plot.png:md5,7c5708c6ed659731111242666746905e", - "picard_alignment_summary_Aligned_Bases-cnt.png:md5,ccd4cdf7a4b1f3f2a39adf2e0c700ed4", - "picard_alignment_summary_Aligned_Bases-pct.png:md5,de5771f0fc6d2feaf7ea1bef7b4f57ed", - "picard_alignment_summary_Aligned_Reads-cnt.png:md5,fa8f7e289fd84f0dfb877758b926c421", - "picard_alignment_summary_Aligned_Reads-pct.png:md5,18be469adf5d34e7296aa9e0feb10274", - "picard_base_distribution_by_cycle__Adenine.png:md5,b59076e9793e4a403228c477f99c6cf8", - "picard_base_distribution_by_cycle__Cytosine.png:md5,7c42741dd1ee386af449d29e21a8389d", - "picard_base_distribution_by_cycle__Guanine.png:md5,27a487a8587c180f08d3afb58e71fb17", - "picard_base_distribution_by_cycle__Thymine.png:md5,f99b137a9975db372a29c0400652eca4", - "picard_base_distribution_by_cycle__Undetermined.png:md5,e7428923e6530f7bd00ca05bf2b0dabe", - "picard_hsmetrics_table.png:md5,70c4f98f3056ebd1a5d49f4f91ab3001", - "picard_percentage_target_bases.png:md5,1e70e6c776d49296f3f8debc3b893851", - "picard_quality_by_cycle.png:md5,23c7dc421bf1a8b9c61e7abdea1b96e9", - "picard_quality_score_distribution.png:md5,f129878e0583e69cac53ec51cac62f4e", - "samtools-coverage-table.png:md5,ffc0a23dcfe8a1b44e7c585898a412ba", - "samtools-coverage_BQ-cnt.png:md5,42a7bfacd302c7924d59701a585957f8", - "samtools-coverage_BQ-log.png:md5,67d6d4c8072743a32dfa30dd22edd5fe", - "samtools-coverage_Bases-cnt.png:md5,8790b6226f16810deceb82c6834b21be", - "samtools-coverage_Bases-log.png:md5,7bdd54947c3ab74d06b9fc11cc35cb51", - "samtools-coverage_Coverage-cnt.png:md5,cdff6829f5d017e67668e6b77b8648fd", - "samtools-coverage_Coverage-log.png:md5,13441e809c66563bf7284ebe4038f368", - "samtools-coverage_MQ-cnt.png:md5,59265e8998386d8a6521296508b4f4e6", - "samtools-coverage_MQ-log.png:md5,0282c8f2fb311eb3830f6d33a8e0d2ef", - "samtools-coverage_Mean_depth-cnt.png:md5,7f0aa59d888da55c8b7e5ca00011b2fc", - "samtools-coverage_Mean_depth-log.png:md5,ab01268969d553decb36658ca785dac0", - "samtools-coverage_Reads-cnt.png:md5,f77fe84d95f5bebd12aa764ab377b6e7", - "samtools-coverage_Reads-log.png:md5,34d3ebbc83f073531328d633466cfcd9", - "samtools-flagstat-pct-table.png:md5,30a84ce2464168d8dedf65b47725e2e1", - "samtools-flagstat-table.png:md5,a828ba0e94ebd04d2ac50ecc43b007fd", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.png:md5,91267791bafff119d985db6b24f813dc", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.png:md5,d1c9fd2633128ed5af7113cedeba91d8", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.png:md5,eb81f43f6c5778f957ce85137758235e", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.png:md5,b1b15467c4b7e34b2a724c2fe9daefa8", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.png:md5,64927987623ac1715e607470f6bf055a", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.png:md5,09773cf98a65a96710a4fac9e2600ed9", - "samtools-stats-dp.png:md5,fe29585e232244237558512103d78fdc", - "samtools_alignment_plot-cnt.png:md5,e5523404a7622df41efaf24fb98ef4c5", - "samtools_alignment_plot-pct.png:md5,7945231e29b09915dee17a9fa620ef62" - ], - [ - "biobambam2_deduplication-cnt.svg:md5,effd09d8ad9d34872090a0bae6f5e967", - "biobambam2_deduplication-pct.svg:md5,e58bfa9f92464f78673fd1ad9e2450d0", - "fastp-insert-size-plot.svg:md5,83bcd604041b4fa6053dcb0d33f21fed", - "fastp-seq-content-gc-plot_Read_1_After_filtering.svg:md5,03a57f9e891bb8aeac9a4979b0e7e513", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.svg:md5,fe77090c3ee62106e5cdd0d243744ced", - "fastp-seq-content-gc-plot_Read_2_After_filtering.svg:md5,fc70efca2a6feb2ebd02712323ab858f", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.svg:md5,a9aeaf418a4af53db36fa495652538b5", - "fastp-seq-content-n-plot_Read_1_After_filtering.svg:md5,c45ccd2c9670cfc6a8fe7e7c411fa792", - "fastp-seq-content-n-plot_Read_1_Before_filtering.svg:md5,78d3817a16b013f647a23564878f1542", - "fastp-seq-content-n-plot_Read_2_After_filtering.svg:md5,f33d2472e82e715f9d33b6781d4671b2", - "fastp-seq-content-n-plot_Read_2_Before_filtering.svg:md5,e7bdb138105422f2eca236628ac1c024", - "fastp-seq-quality-plot_Read_1_After_filtering.svg:md5,353db00f7a3f20c0c07838236e88a5ed", - "fastp-seq-quality-plot_Read_1_Before_filtering.svg:md5,69cef5512260a6af8955d9785966a806", - "fastp-seq-quality-plot_Read_2_After_filtering.svg:md5,46f0ee90d934323da913b14927888a75", - "fastp-seq-quality-plot_Read_2_Before_filtering.svg:md5,bf833093bbc86d88a297d48ac7ad64ad", - "fastp_filtered_reads_plot-cnt.svg:md5,89f162c2fe82f89d487564c26b007003", - "fastp_filtered_reads_plot-pct.svg:md5,74c611b014426ffc6990fd278dd5077d", - "mosdepth-coverage-per-contig-single-cnt.svg:md5,4e8ee59993d08a72eb4545fb8378a8ba", - "mosdepth-coverage-per-contig-single-pct.svg:md5,6c79f39035c6cb6db7f135eefb155a0e", - "mosdepth-cumcoverage-dist-id.svg:md5,587529190643bec79f4c4da65e68fdae", - "picard_alignment_readlength_plot.svg:md5,b0bf8f98c4bfd66b8848b5cf645812a6", - "picard_alignment_summary_Aligned_Bases-cnt.svg:md5,1e4c349f358aa1375f00eeb19a638898", - "picard_alignment_summary_Aligned_Bases-pct.svg:md5,1b2f81b0a0a23d54f62946a266d352b1", - "picard_alignment_summary_Aligned_Reads-cnt.svg:md5,9ee533f876f4af410f0fdd3da6427d89", - "picard_alignment_summary_Aligned_Reads-pct.svg:md5,713905bb8f964ccbf5d0b730447ae9a1", - "picard_base_distribution_by_cycle__Adenine.svg:md5,1a8b1b45ba9b22e9c230adcfce962dd8", - "picard_base_distribution_by_cycle__Cytosine.svg:md5,82a8225f9561a6296aa0b2bb801bf568", - "picard_base_distribution_by_cycle__Guanine.svg:md5,a3bb637662550e5712909ebb90268b11", - "picard_base_distribution_by_cycle__Thymine.svg:md5,316858766a810aa7bac94e9fa82f6a0e", - "picard_base_distribution_by_cycle__Undetermined.svg:md5,f09460fa07c95a4b8d326c62eaeb7099", - "picard_hsmetrics_table.svg:md5,2882442c46a78a971612f03b60cdc9a7", - "picard_percentage_target_bases.svg:md5,bf71b0901b3f91350ea786c293500cd9", - "picard_quality_by_cycle.svg:md5,83b907ec1941f942498b8c19ac15d335", - "picard_quality_score_distribution.svg:md5,4b5a6ac776863aab6a0874a1788e838c", - "samtools-coverage-table.svg:md5,1d344020db642dc8ed73ce65384eaed9", - "samtools-coverage_BQ-cnt.svg:md5,e618e68a0e1d475030a5b86d05217ae6", - "samtools-coverage_BQ-log.svg:md5,d7af1801f148ea9bda9c0d105afc8270", - "samtools-coverage_Bases-cnt.svg:md5,af0bf231e9dfc5545686c9d0d7fc0bac", - "samtools-coverage_Bases-log.svg:md5,d6070217bb54d7f966b21c8563571945", - "samtools-coverage_Coverage-cnt.svg:md5,ffeb1e8ffd6318d30c9ffd72f8701eb8", - "samtools-coverage_Coverage-log.svg:md5,81aafb2970773832ccc95a6a87c0db12", - "samtools-coverage_MQ-cnt.svg:md5,9aaa9307dbe314b04e1e2f78dec852db", - "samtools-coverage_MQ-log.svg:md5,e530d20e0b9ac5ea89a1d7e99e561da3", - "samtools-coverage_Mean_depth-cnt.svg:md5,b3366c179f143419ef91bc2016e717d2", - "samtools-coverage_Mean_depth-log.svg:md5,c13a4e5c2f1e78b77c5bed76598d3e6b", - "samtools-coverage_Reads-cnt.svg:md5,153e7705058794c16bee02ce37daba50", - "samtools-coverage_Reads-log.svg:md5,68f3871ec68b060e54380d353e1a0ded", - "samtools-flagstat-pct-table.svg:md5,7a64df60de3c53a62ce1b9bc62d1e600", - "samtools-flagstat-table.svg:md5,9d6e77d29691f652ed21a493866c226b", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.svg:md5,aee092dd5c492ae70e542cab5b11e8a6", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.svg:md5,a7ef56dd58e80e225252e5bd78c830f2", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.svg:md5,613dcab15c764fafd2151da9b3d5c55e", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.svg:md5,b1f82c95aed78d4e219f16cc7d3f41c3", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.svg:md5,4855e19f8503ef463a338bfcab7af3a5", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.svg:md5,b98efafd11eea5fd5292e247d4530821", - "samtools-stats-dp.svg:md5,5c9cc7aeefc2a540d2b93bcdeda7aa39", - "samtools_alignment_plot-cnt.svg:md5,0a2910be102b4c0ef6ac156a25a67005", - "samtools_alignment_plot-pct.svg:md5,061886f9d0f5839eccb706a784f7eec7" - ] - ] + "multiqc_library_test_plots" ], "multiqc_library_report": [ - "multiqc_library_test.html:md5,20fd67ac14ace887e5f5b76f02dc2b20" + "multiqc_library_test.html" ], "multiqc_main_data": [ [ - [ - "llms-full.txt:md5,769bfe8a8b5b73ff5e31e480d5d129c9", - "multiqc.log:md5,1ec335a68a9d72f823a7bf0bf42e028c", - "multiqc.parquet:md5,73d600bb80fc3459bfba5edc970fc949", - "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", - "multiqc_data.json:md5,8ad88f47321bfad770cdc2387d5fa6f9", - "multiqc_software_versions.txt:md5,3e70a45b35aa87dab44c6b2b61033f14", - "multiqc_sources.txt:md5,d2a044df39ce3c6abe5cdc2d67473490" - ] + "multiqc_data" ] ], "multiqc_main_plots": [ @@ -666,7 +408,7 @@ ], "multiqc_main_report": [ [ - "multiqc.html:md5,a05f843b1b044c86a850de70980b8af2" + "multiqc.html" ] ], "panelcoverage": [ @@ -924,7 +666,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T19:48:21.07529" + "timestamp": "2025-12-04T20:36:50.85925" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -1099,151 +841,17 @@ ], "multiqc_library_data": [ - [ - "biobambam2_deduplication.txt:md5,992b5decb6d017254ee9b02fbe076d81", - "fastp-insert-size-plot.txt:md5,66fec5f01198da8ecd97410ec1727021", - "fastp-seq-content-gc-plot_Read_1_After_filtering.txt:md5,23420affa90c1523becba23c09653a92", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.txt:md5,27bb3440b4edeab8a9dc2ec1077cfc0e", - "fastp-seq-content-gc-plot_Read_2_After_filtering.txt:md5,e49276ebe93bb8294ca51e6a0916e703", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.txt:md5,f7bf2354433b3514893f0fe18e7f7877", - "fastp-seq-content-n-plot_Read_1_After_filtering.txt:md5,6c20997febd11ea6c80fe13a1761898b", - "fastp-seq-content-n-plot_Read_1_Before_filtering.txt:md5,a1d1cdbb1a1fb48b6d6bdf1f2192b2b7", - "fastp-seq-content-n-plot_Read_2_After_filtering.txt:md5,e1d8dcf05d785f863cfb17c96c1f58a4", - "fastp-seq-content-n-plot_Read_2_Before_filtering.txt:md5,30bfcca763531e4ee1638031d5359e48", - "fastp-seq-quality-plot_Read_1_After_filtering.txt:md5,2b0a42468f68992639ac8eacbf533134", - "fastp-seq-quality-plot_Read_1_Before_filtering.txt:md5,4e6fea487fecc2ee55db1518ff30a0b5", - "fastp-seq-quality-plot_Read_2_After_filtering.txt:md5,72a6d8295748db4de13d6dc1d1eb83dc", - "fastp-seq-quality-plot_Read_2_Before_filtering.txt:md5,3b1c7675660e838e75d1d5c62c0f3a61", - "fastp_filtered_reads_plot.txt:md5,9e506f1c8dbad71540697d11af4ba6df", - "llms-full.txt:md5,02c5ed19814d3afd16ea5fccc3516865", - "multiqc.log:md5,faa526e1b74af6acf779e92caf5bd77a", - "multiqc.parquet:md5,f991c38b80ea4795193224a782e94750", - "multiqc_biobambam2_dups.txt:md5,31c942ce8964d0941cb79f8c9de8aa04", - "multiqc_citations.txt:md5,b64ab308dbc3a2e58e15527370655958", - "multiqc_data.json:md5,ea17bc7fc0063bb30073f9b5b3cc7bfb", - "multiqc_fastp.txt:md5,f917618024634bb24850390c8f4836e7", - "multiqc_general_stats.txt:md5,21152415bf3b3720dede9ada054ae5e1", - "multiqc_samtools_flagstat.txt:md5,5ce133683245100011b77cd676471de1", - "multiqc_samtools_idxstats.txt:md5,7e542f20dd27d352b5d2be33e1920220", - "multiqc_samtools_stats.txt:md5,1dd571a033605b1224ebac95deceee0b", - "multiqc_sources.txt:md5,08a7aa04a68650ae860f494ae1b5d4d2", - "samtools-flagstat-pct-table.txt:md5,8b0e71fcfbb55f6e8b0e6949fb146e0c", - "samtools-flagstat-table.txt:md5,6203dc05b5eaee4f529300986aebbb3c", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", - "samtools-idxstats-mapped-reads-plot_Raw_Counts.txt:md5,e8f2b29a779d322cd56b00f4958ef841", - "samtools-stats-dp.txt:md5,07153313edc4f7a3754e9821c85ca0cf", - "samtools_alignment_plot.txt:md5,d60abeeecbb005aff19c12f19a726057" - ] + "multiqc_library_test_data" ], "multiqc_library_plots": [ - [ - [ - "biobambam2_deduplication-cnt.pdf:md5,32dc6feb5cfb2a681e1baea64ed174d2", - "biobambam2_deduplication-pct.pdf:md5,c210b96ff301c4699a981b7a747dd642", - "fastp-insert-size-plot.pdf:md5,ac28b57e2270b846462ec69d469403de", - "fastp-seq-content-gc-plot_Read_1_After_filtering.pdf:md5,70fc95d50564a9e34ffedaab55c7e3a3", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.pdf:md5,bfdadfab1ef45191268e8f19b5b56756", - "fastp-seq-content-gc-plot_Read_2_After_filtering.pdf:md5,be9b2f8bb0276f4da8cf20595035bb33", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.pdf:md5,a00ca04dd4577aa4706975016bf82618", - "fastp-seq-content-n-plot_Read_1_After_filtering.pdf:md5,9dd66bed0bb685993e1ac70aad2405a1", - "fastp-seq-content-n-plot_Read_1_Before_filtering.pdf:md5,95d07c4ea09e4ffb8473e84648eea599", - "fastp-seq-content-n-plot_Read_2_After_filtering.pdf:md5,c9550470037ba6eec53118c5db3ed62a", - "fastp-seq-content-n-plot_Read_2_Before_filtering.pdf:md5,9a9dff340890cd43c6ee7a689112c49e", - "fastp-seq-quality-plot_Read_1_After_filtering.pdf:md5,e3f499d8d0ccf8bf0df604e96f7be9cb", - "fastp-seq-quality-plot_Read_1_Before_filtering.pdf:md5,c490b53f4a9cddbd3659256aedbeb4cd", - "fastp-seq-quality-plot_Read_2_After_filtering.pdf:md5,31011ec67fc23ff867c60c45b9681396", - "fastp-seq-quality-plot_Read_2_Before_filtering.pdf:md5,b75dad16330483e160720bd89649167d", - "fastp_filtered_reads_plot-cnt.pdf:md5,e34eea79aa92a8f0a1cafa522d1204f3", - "fastp_filtered_reads_plot-pct.pdf:md5,0f6b66deb6fbff878987ca29069cb016", - "samtools-flagstat-pct-table.pdf:md5,781be091183f24877110f8d5be0ebbec", - "samtools-flagstat-table.pdf:md5,bc1eff95cf645832e0dee6d86bcf503b", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.pdf:md5,f392b8070efe5b7a4bd20993c0e66bfa", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.pdf:md5,282ddb8116e7c774149d24015d2a56bd", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.pdf:md5,824315ee6e029d3b42f37f02b9374734", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.pdf:md5,cd587a5ace7868b2b24fdd16ad079e40", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.pdf:md5,2be7c8ff5b10d0ee1fb6b01f4c2100ee", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.pdf:md5,f2caf54746b77da42fe4200fc1f2eb96", - "samtools-stats-dp.pdf:md5,8b63ef11ded4b2224f9d5f6d3f059c7a", - "samtools_alignment_plot-cnt.pdf:md5,3d6c545941eec5834f4c991ecf0be42c", - "samtools_alignment_plot-pct.pdf:md5,a62b1d31109315eacb4ce42c63ae0aef" - ], - [ - "biobambam2_deduplication-cnt.png:md5,5707c3cf44cff88666c3c7b4970ab021", - "biobambam2_deduplication-pct.png:md5,b2a0fece791ff0532a426f3faeecf3f4", - "fastp-insert-size-plot.png:md5,40a7c7edc7062c92d088e8974dd1fbe9", - "fastp-seq-content-gc-plot_Read_1_After_filtering.png:md5,ff993de7c7a0b2f4dd17aaf509c8209b", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.png:md5,124351c45a1bd7d611fd3ba89510018b", - "fastp-seq-content-gc-plot_Read_2_After_filtering.png:md5,058842506a3200770c46a4a70b64ce48", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.png:md5,985bf206443edf1417e2a0f9354abe3c", - "fastp-seq-content-n-plot_Read_1_After_filtering.png:md5,7855b3938c2b48578b2e1ca3486783de", - "fastp-seq-content-n-plot_Read_1_Before_filtering.png:md5,b9276b3bd8f2c57a51d12f76273fc322", - "fastp-seq-content-n-plot_Read_2_After_filtering.png:md5,45684fe478e5d2912848c032c3bc8ee4", - "fastp-seq-content-n-plot_Read_2_Before_filtering.png:md5,97606f1910cdbb47f68d5b7ac9f9bf4b", - "fastp-seq-quality-plot_Read_1_After_filtering.png:md5,44fe9279b3f2279c19d2ce541b9c6c19", - "fastp-seq-quality-plot_Read_1_Before_filtering.png:md5,93c06663d6ed02d11f4e5eab97d48917", - "fastp-seq-quality-plot_Read_2_After_filtering.png:md5,99219cc1b64c80e6ac8cf653add1990c", - "fastp-seq-quality-plot_Read_2_Before_filtering.png:md5,5d655406be9a2ff9a68ec461f51cfcc5", - "fastp_filtered_reads_plot-cnt.png:md5,75911dd91d24adfaae185ebcf0a8455a", - "fastp_filtered_reads_plot-pct.png:md5,4b3c0fd7f90c7c83b50c557d4aa3b6a5", - "samtools-flagstat-pct-table.png:md5,30a84ce2464168d8dedf65b47725e2e1", - "samtools-flagstat-table.png:md5,a828ba0e94ebd04d2ac50ecc43b007fd", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.png:md5,91267791bafff119d985db6b24f813dc", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.png:md5,d1c9fd2633128ed5af7113cedeba91d8", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.png:md5,eb81f43f6c5778f957ce85137758235e", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.png:md5,b1b15467c4b7e34b2a724c2fe9daefa8", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.png:md5,64927987623ac1715e607470f6bf055a", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.png:md5,09773cf98a65a96710a4fac9e2600ed9", - "samtools-stats-dp.png:md5,fe29585e232244237558512103d78fdc", - "samtools_alignment_plot-cnt.png:md5,e5523404a7622df41efaf24fb98ef4c5", - "samtools_alignment_plot-pct.png:md5,7945231e29b09915dee17a9fa620ef62" - ], - [ - "biobambam2_deduplication-cnt.svg:md5,9de3a4196707cc54a09ccab579551b45", - "biobambam2_deduplication-pct.svg:md5,383483ee720a0b93282f11cef90d8412", - "fastp-insert-size-plot.svg:md5,03e25e27d6f08e7eeef62edaac78705d", - "fastp-seq-content-gc-plot_Read_1_After_filtering.svg:md5,16db74211fea2dd026208e1ff8932921", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.svg:md5,ebce58ed6cef4ed79ea2ddd5d796e61e", - "fastp-seq-content-gc-plot_Read_2_After_filtering.svg:md5,2e6b93f07296d37a5fd08f493793ecf2", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.svg:md5,865602ee9731648cf55a8f6c6e3fcb20", - "fastp-seq-content-n-plot_Read_1_After_filtering.svg:md5,c38f3a392319e4b9e2147a96b33e1186", - "fastp-seq-content-n-plot_Read_1_Before_filtering.svg:md5,b8416f1f456e3a189822f22c26e388ad", - "fastp-seq-content-n-plot_Read_2_After_filtering.svg:md5,5c54a86a023e9ac204ece6eca7f4da3d", - "fastp-seq-content-n-plot_Read_2_Before_filtering.svg:md5,74ecf94d1bc8a2ea1315bad82e8da636", - "fastp-seq-quality-plot_Read_1_After_filtering.svg:md5,2136357bde8a33774139d892f78f24f8", - "fastp-seq-quality-plot_Read_1_Before_filtering.svg:md5,79c1c221969bdbcd7254eb8d9c6e15f2", - "fastp-seq-quality-plot_Read_2_After_filtering.svg:md5,a55b84e706aa6aaa796e74f29bc32ec7", - "fastp-seq-quality-plot_Read_2_Before_filtering.svg:md5,ddfc609e5a87d598e8abe9777130e8e6", - "fastp_filtered_reads_plot-cnt.svg:md5,5fd1528dbf165823db88a7cf666ecb23", - "fastp_filtered_reads_plot-pct.svg:md5,d8adcea8718c87a360b9d329e31cc64b", - "samtools-flagstat-pct-table.svg:md5,3a27df4db014b18226c51f41868c8387", - "samtools-flagstat-table.svg:md5,0c0bca9b4b56b6f1a7bac9b23be4bbe4", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.svg:md5,62227493b8c1c4abf2b9a56dee4aaee1", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.svg:md5,7e0a96a8947202ada7f3539f614aafbd", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.svg:md5,addf085c4878ef4c72bf2de0b1da73c5", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.svg:md5,198bee66f3e5232a1f389abf312f3230", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.svg:md5,1e1de4b4dfdaebb6c6c9cb6ecf78fc0d", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.svg:md5,2a42c274765d0a37f3eeef4b605ad55c", - "samtools-stats-dp.svg:md5,c3d026b17b884a56736a66cdba55865b", - "samtools_alignment_plot-cnt.svg:md5,55cf5b87a08d2fb1c4ee34099146a8b1", - "samtools_alignment_plot-pct.svg:md5,123f6620c817c04bb14336aae67dcaac" - ] - ] + "multiqc_library_test_plots" ], "multiqc_library_report": [ - "multiqc_library_test.html:md5,379d95b311027e666745448a9e27fe65" + "multiqc_library_test.html" ], "multiqc_main_data": [ [ - [ - "llms-full.txt:md5,d188ca7a55d62d188c5c13608585d75c", - "multiqc.log:md5,4832cad68754c77e2de90985272b0342", - "multiqc.parquet:md5,182ff0904414468b20c9197f08ecf956", - "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", - "multiqc_data.json:md5,a9e50ebc69822d508d72da06c16bf9ff", - "multiqc_software_versions.txt:md5,4e94b4dd017aacfd34b89230176af1af", - "multiqc_sources.txt:md5,d2a044df39ce3c6abe5cdc2d67473490" - ] + "multiqc_data" ] ], "multiqc_main_plots": [ @@ -1253,7 +861,7 @@ ], "multiqc_main_report": [ [ - "multiqc.html:md5,f3b0258eb0cd1c0ee4f206368de6b662" + "multiqc.html" ] ], "panelcoverage": [ @@ -1401,7 +1009,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T19:54:04.990092" + "timestamp": "2025-12-04T20:42:53.576667" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1710,279 +1318,17 @@ ], "multiqc_library_data": [ - [ - "biobambam2_deduplication.txt:md5,992b5decb6d017254ee9b02fbe076d81", - "fastp-insert-size-plot.txt:md5,66fec5f01198da8ecd97410ec1727021", - "fastp-seq-content-gc-plot_Read_1_After_filtering.txt:md5,23420affa90c1523becba23c09653a92", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.txt:md5,27bb3440b4edeab8a9dc2ec1077cfc0e", - "fastp-seq-content-gc-plot_Read_2_After_filtering.txt:md5,e49276ebe93bb8294ca51e6a0916e703", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.txt:md5,f7bf2354433b3514893f0fe18e7f7877", - "fastp-seq-content-n-plot_Read_1_After_filtering.txt:md5,6c20997febd11ea6c80fe13a1761898b", - "fastp-seq-content-n-plot_Read_1_Before_filtering.txt:md5,a1d1cdbb1a1fb48b6d6bdf1f2192b2b7", - "fastp-seq-content-n-plot_Read_2_After_filtering.txt:md5,e1d8dcf05d785f863cfb17c96c1f58a4", - "fastp-seq-content-n-plot_Read_2_Before_filtering.txt:md5,30bfcca763531e4ee1638031d5359e48", - "fastp-seq-quality-plot_Read_1_After_filtering.txt:md5,2b0a42468f68992639ac8eacbf533134", - "fastp-seq-quality-plot_Read_1_Before_filtering.txt:md5,4e6fea487fecc2ee55db1518ff30a0b5", - "fastp-seq-quality-plot_Read_2_After_filtering.txt:md5,72a6d8295748db4de13d6dc1d1eb83dc", - "fastp-seq-quality-plot_Read_2_Before_filtering.txt:md5,3b1c7675660e838e75d1d5c62c0f3a61", - "fastp_filtered_reads_plot.txt:md5,9e506f1c8dbad71540697d11af4ba6df", - "llms-full.txt:md5,5f245d44b703b37991e2130e2247adb9", - "mosdepth-coverage-per-contig-single.txt:md5,0c5d8872c18169b771168ca9fa7d40b2", - "mosdepth-cumcoverage-dist-id.txt:md5,2592e72a312feb3363dece668fb2ea90", - "mosdepth_cov_dist.txt:md5,f74eeba67b67d59def037884af206551", - "mosdepth_cumcov_dist.txt:md5,f74eeba67b67d59def037884af206551", - "mosdepth_perchrom.txt:md5,0c5d8872c18169b771168ca9fa7d40b2", - "multiqc.log:md5,443bae2f4f1af6e82ae0c2623b5d5b26", - "multiqc.parquet:md5,64c797120e6fe75c00726dd5a05b8613", - "multiqc_biobambam2_dups.txt:md5,31c942ce8964d0941cb79f8c9de8aa04", - "multiqc_citations.txt:md5,294fadee817c59c64f1b985ac204b224", - "multiqc_data.json:md5,b021f17bc01883a1e6bb04642de162ba", - "multiqc_fastp.txt:md5,f917618024634bb24850390c8f4836e7", - "multiqc_general_stats.txt:md5,94493aa967cdafb4c5f78b8981b1a185", - "multiqc_picard_AlignmentSummaryMetrics.txt:md5,3f32124a666ad5fa6dda93759cf450f0", - "multiqc_picard_baseContent.txt:md5,deba2098af2de348792a37b405eab78c", - "multiqc_picard_quality_by_cycle.txt:md5,eca76b6ed78d34d66e1e185c7158868f", - "multiqc_picard_quality_score_distribution.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", - "multiqc_picard_wgsmetrics.txt:md5,54691f0bafd26c22b3339ac5133e3e59", - "multiqc_samtools_coverage.txt:md5,2b8ac198265a850d581d453eacb402cd", - "multiqc_samtools_flagstat.txt:md5,5ce133683245100011b77cd676471de1", - "multiqc_samtools_idxstats.txt:md5,7e542f20dd27d352b5d2be33e1920220", - "multiqc_samtools_stats.txt:md5,1dd571a033605b1224ebac95deceee0b", - "multiqc_sources.txt:md5,8bbd0fb5a901bd8e6da470a94357b8c7", - "picard_MarkIlluminaAdapters_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "picard_MeanQualityByCycle_histogram.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - "picard_MeanQualityByCycle_histogram_1.txt:md5,eca76b6ed78d34d66e1e185c7158868f", - "picard_QualityScoreDistribution_histogram.txt:md5,6ec87b3288ada8fb9456a3cd1e801514", - "picard_alignment_readlength_plot.txt:md5,891edbc18f01189de8c5bf52320ee6c7", - "picard_alignment_summary_Aligned_Bases.txt:md5,7d13622d8d4083fe2a4be5bf92ea77e6", - "picard_alignment_summary_Aligned_Reads.txt:md5,ed831c3df4e4465d9c6fb52ce731ee71", - "picard_base_distribution_by_cycle__Adenine.txt:md5,989b9c396dfa032d8ca02f57b7cc6e7d", - "picard_base_distribution_by_cycle__Cytosine.txt:md5,dc7b79f9ab4bc66db25b509e423abf2b", - "picard_base_distribution_by_cycle__Guanine.txt:md5,1f2a16426851c0e434558d437ac482e3", - "picard_base_distribution_by_cycle__Thymine.txt:md5,cbc90b7275fa29bf09d4be71fc443df1", - "picard_base_distribution_by_cycle__Undetermined.txt:md5,e0a643aff9cf4b0d277c4da6c798c6dc", - "picard_quality_by_cycle.txt:md5,f89d83da6f5a7fa00511a8959c2bd3c2", - "picard_quality_score_distribution.txt:md5,9d72562e154dba19a69180e2875ae8e9", - "picard_wgs_metrics_bases.txt:md5,5efebe4a352e7d44392faded88e10ec9", - "picard_wgs_metrics_histogram_Counts_Histogram.txt:md5,681e302aec63d9b5fa8966ee8ee2373a", - "picard_wgs_metrics_histogram_Percentage_Drop-Off.txt:md5,b37badd0338d073b2557c2492c472280", - "samtools-coverage-table.txt:md5,0f9fe2b460eb659d5ce23deba4ee62d8", - "samtools-coverage_BQ.txt:md5,68b97b7434bd35c71d3d14de478ba1b9", - "samtools-coverage_Bases.txt:md5,f8fcf650945e7b347409d678fae3b006", - "samtools-coverage_Coverage.txt:md5,bc62f359fced9778f869022dd4ab6647", - "samtools-coverage_MQ.txt:md5,5f9ece387a8e160cedbb02874c46000b", - "samtools-coverage_Mean_depth.txt:md5,4d5f58688b4c653b617c709717475c25", - "samtools-coverage_Reads.txt:md5,3667b340251346e538e6f078adcec945", - "samtools-flagstat-pct-table.txt:md5,8b0e71fcfbb55f6e8b0e6949fb146e0c", - "samtools-flagstat-table.txt:md5,6203dc05b5eaee4f529300986aebbb3c", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts.txt:md5,ef2707df6eaa2bbc3989d17fd2fca0ce", - "samtools-idxstats-mapped-reads-plot_Raw_Counts.txt:md5,e8f2b29a779d322cd56b00f4958ef841", - "samtools-stats-dp.txt:md5,07153313edc4f7a3754e9821c85ca0cf", - "samtools_alignment_plot.txt:md5,d60abeeecbb005aff19c12f19a726057" - ] + "multiqc_library_test_data" ], "multiqc_library_plots": [ - [ - [ - "biobambam2_deduplication-cnt.pdf:md5,076943b1c590633eede4b60e8aa2434c", - "biobambam2_deduplication-pct.pdf:md5,32d4caca75efe889205de73e3a0a4d97", - "fastp-insert-size-plot.pdf:md5,f1023409a45dc9d8a0931659b0dc697d", - "fastp-seq-content-gc-plot_Read_1_After_filtering.pdf:md5,acbf529d4de4de437a3b71ef99d27698", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.pdf:md5,04621f82d0b3f8d97bf99b8d59b9988e", - "fastp-seq-content-gc-plot_Read_2_After_filtering.pdf:md5,9e23be66eacb942bd55f0459836bc111", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.pdf:md5,93b6b5bda685f45fb8c81747d0bccd7f", - "fastp-seq-content-n-plot_Read_1_After_filtering.pdf:md5,a8c81efa4e85a5258b6c8930d5543c3d", - "fastp-seq-content-n-plot_Read_1_Before_filtering.pdf:md5,5fe572924ab5149f71f9c33a3aa2ef26", - "fastp-seq-content-n-plot_Read_2_After_filtering.pdf:md5,6332b41f6963f9c9a0ef57e307cd636c", - "fastp-seq-content-n-plot_Read_2_Before_filtering.pdf:md5,25511034f06bb9c2d1ba499568285338", - "fastp-seq-quality-plot_Read_1_After_filtering.pdf:md5,a5d9dbd669760bd35cabff4a957c72e0", - "fastp-seq-quality-plot_Read_1_Before_filtering.pdf:md5,5d8a4222b4d43f2383759d6612faf1af", - "fastp-seq-quality-plot_Read_2_After_filtering.pdf:md5,5eaaa59e813d0b5e86c833fa7030fa63", - "fastp-seq-quality-plot_Read_2_Before_filtering.pdf:md5,8386c931c7b0ccd2f1fda5caa10d4612", - "fastp_filtered_reads_plot-cnt.pdf:md5,07f08edd555887949d5732358c2adf56", - "fastp_filtered_reads_plot-pct.pdf:md5,25516919ae1120b1e05ad36a296ae49e", - "mosdepth-coverage-per-contig-single-cnt.pdf:md5,e31c2589a014aa1e1e6ac997119ad675", - "mosdepth-coverage-per-contig-single-pct.pdf:md5,6435a5fe0f4b51d95e6a4b6acdd2f3d5", - "mosdepth-cumcoverage-dist-id.pdf:md5,5d4af4029371ddba1ed19ed38f88c8f2", - "picard_alignment_readlength_plot.pdf:md5,aa1f2ae479ecae2c3ab65cf265987258", - "picard_alignment_summary_Aligned_Bases-cnt.pdf:md5,13b9efa703cde16499f597103e511ce9", - "picard_alignment_summary_Aligned_Bases-pct.pdf:md5,5d53049cb3bfe99985fbf840095b960f", - "picard_alignment_summary_Aligned_Reads-cnt.pdf:md5,89bd672088e27c155cf2d5a06f8b03b4", - "picard_alignment_summary_Aligned_Reads-pct.pdf:md5,ea3c23c71d88ceba0cb38629cb5ed9bd", - "picard_base_distribution_by_cycle__Adenine.pdf:md5,0305b7ed8db6442e58f6df0939aae0c2", - "picard_base_distribution_by_cycle__Cytosine.pdf:md5,9fc115666272868eea3201b4ad329e6f", - "picard_base_distribution_by_cycle__Guanine.pdf:md5,ea999ac900f032148ef8dc8311fbaf21", - "picard_base_distribution_by_cycle__Thymine.pdf:md5,75fee9ea401481bd3a89d2e9dbc93b64", - "picard_base_distribution_by_cycle__Undetermined.pdf:md5,5084d6ea1d038c2ad803ee61ea3d4beb", - "picard_quality_by_cycle.pdf:md5,d46426fb7f451c50f7ea3900fbee909c", - "picard_quality_score_distribution.pdf:md5,c4bace227e4be936499b16d8b791c4d2", - "picard_wgs_metrics_bases.pdf:md5,8f385b4242b2839521d355da67d1601c", - "picard_wgs_metrics_histogram_Counts_Histogram.pdf:md5,6d1fd94aab4dae5f06f9ab2fd18a2d14", - "picard_wgs_metrics_histogram_Percentage_Drop-Off.pdf:md5,2973a0bd94ce539443fe3f144d60a57d", - "samtools-coverage-table.pdf:md5,43f6c1db01c3d6e0cbeb598d8462c3bb", - "samtools-coverage_BQ-cnt.pdf:md5,a0e08adcfcf5963508675e5f73f3ddc4", - "samtools-coverage_BQ-log.pdf:md5,7cfa56d3008e2cbdd5ac1e6dd01a0da5", - "samtools-coverage_Bases-cnt.pdf:md5,fe22f1634930da794d44c425cd3f9f75", - "samtools-coverage_Bases-log.pdf:md5,a91260f7858bb59b05994a60c98b3d09", - "samtools-coverage_Coverage-cnt.pdf:md5,28224f499e3b6101c2996159f75e52b6", - "samtools-coverage_Coverage-log.pdf:md5,d24bb4c34863c442d9081d8c8c2ec92a", - "samtools-coverage_MQ-cnt.pdf:md5,be7f66cb438e5857125034f8308f1a9d", - "samtools-coverage_MQ-log.pdf:md5,0e67e1921c296fa19c8fc5b5b2808a4d", - "samtools-coverage_Mean_depth-cnt.pdf:md5,2422e0664ff8f9e22a64e9f60c29dc01", - "samtools-coverage_Mean_depth-log.pdf:md5,ccb6cda145cf3e19266e2de300bf5107", - "samtools-coverage_Reads-cnt.pdf:md5,be0940f017942fd1ea7eb3b7472e78a9", - "samtools-coverage_Reads-log.pdf:md5,147469231619cf8c5a1bcbfedd1536f9", - "samtools-flagstat-pct-table.pdf:md5,4da35ccf697cab3209ff58e65ea22985", - "samtools-flagstat-table.pdf:md5,ecf1cd68a33e2ffacd09bc26acd78c4f", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.pdf:md5,564d74b6292e8e644e80ebbc4f36cbe3", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.pdf:md5,008360a325c47b0eba81acf03f486221", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.pdf:md5,7e7b33224bcf3053b9f074c70d0e4342", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.pdf:md5,9f8fc3a6ff912245f7a3c5189bf9fcb1", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.pdf:md5,f4d9ff73a8b429e998c0fcbc143c468e", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.pdf:md5,eccf04a5b6928eaf4306b7404f2fd945", - "samtools-stats-dp.pdf:md5,022199feb31379c5b5fb74ee031d8697", - "samtools_alignment_plot-cnt.pdf:md5,889e13551f5a50465e5046bd101e8647", - "samtools_alignment_plot-pct.pdf:md5,d66282dbb006fcae5f4c582f7892ca43" - ], - [ - "biobambam2_deduplication-cnt.png:md5,5707c3cf44cff88666c3c7b4970ab021", - "biobambam2_deduplication-pct.png:md5,b2a0fece791ff0532a426f3faeecf3f4", - "fastp-insert-size-plot.png:md5,40a7c7edc7062c92d088e8974dd1fbe9", - "fastp-seq-content-gc-plot_Read_1_After_filtering.png:md5,ff993de7c7a0b2f4dd17aaf509c8209b", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.png:md5,124351c45a1bd7d611fd3ba89510018b", - "fastp-seq-content-gc-plot_Read_2_After_filtering.png:md5,058842506a3200770c46a4a70b64ce48", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.png:md5,985bf206443edf1417e2a0f9354abe3c", - "fastp-seq-content-n-plot_Read_1_After_filtering.png:md5,7855b3938c2b48578b2e1ca3486783de", - "fastp-seq-content-n-plot_Read_1_Before_filtering.png:md5,b9276b3bd8f2c57a51d12f76273fc322", - "fastp-seq-content-n-plot_Read_2_After_filtering.png:md5,45684fe478e5d2912848c032c3bc8ee4", - "fastp-seq-content-n-plot_Read_2_Before_filtering.png:md5,97606f1910cdbb47f68d5b7ac9f9bf4b", - "fastp-seq-quality-plot_Read_1_After_filtering.png:md5,44fe9279b3f2279c19d2ce541b9c6c19", - "fastp-seq-quality-plot_Read_1_Before_filtering.png:md5,93c06663d6ed02d11f4e5eab97d48917", - "fastp-seq-quality-plot_Read_2_After_filtering.png:md5,99219cc1b64c80e6ac8cf653add1990c", - "fastp-seq-quality-plot_Read_2_Before_filtering.png:md5,5d655406be9a2ff9a68ec461f51cfcc5", - "fastp_filtered_reads_plot-cnt.png:md5,75911dd91d24adfaae185ebcf0a8455a", - "fastp_filtered_reads_plot-pct.png:md5,4b3c0fd7f90c7c83b50c557d4aa3b6a5", - "mosdepth-coverage-per-contig-single-cnt.png:md5,4d6f6bf53791c7438153194cf5c28b58", - "mosdepth-coverage-per-contig-single-pct.png:md5,8f17612654e4217dd673c2788b473e7c", - "mosdepth-cumcoverage-dist-id.png:md5,9a1b83a02f39658f5896ed4b665f7327", - "picard_alignment_readlength_plot.png:md5,7c5708c6ed659731111242666746905e", - "picard_alignment_summary_Aligned_Bases-cnt.png:md5,ccd4cdf7a4b1f3f2a39adf2e0c700ed4", - "picard_alignment_summary_Aligned_Bases-pct.png:md5,de5771f0fc6d2feaf7ea1bef7b4f57ed", - "picard_alignment_summary_Aligned_Reads-cnt.png:md5,fa8f7e289fd84f0dfb877758b926c421", - "picard_alignment_summary_Aligned_Reads-pct.png:md5,18be469adf5d34e7296aa9e0feb10274", - "picard_base_distribution_by_cycle__Adenine.png:md5,b59076e9793e4a403228c477f99c6cf8", - "picard_base_distribution_by_cycle__Cytosine.png:md5,7c42741dd1ee386af449d29e21a8389d", - "picard_base_distribution_by_cycle__Guanine.png:md5,27a487a8587c180f08d3afb58e71fb17", - "picard_base_distribution_by_cycle__Thymine.png:md5,f99b137a9975db372a29c0400652eca4", - "picard_base_distribution_by_cycle__Undetermined.png:md5,e7428923e6530f7bd00ca05bf2b0dabe", - "picard_quality_by_cycle.png:md5,23c7dc421bf1a8b9c61e7abdea1b96e9", - "picard_quality_score_distribution.png:md5,f129878e0583e69cac53ec51cac62f4e", - "picard_wgs_metrics_bases.png:md5,6ae01c3c3e7a7f6bac5dd44e0e29dd6a", - "picard_wgs_metrics_histogram_Counts_Histogram.png:md5,cfd66c498f788418c650ec052c12c737", - "picard_wgs_metrics_histogram_Percentage_Drop-Off.png:md5,2b050e4750a49c843e8fd8a1c2e01424", - "samtools-coverage-table.png:md5,ffc0a23dcfe8a1b44e7c585898a412ba", - "samtools-coverage_BQ-cnt.png:md5,42a7bfacd302c7924d59701a585957f8", - "samtools-coverage_BQ-log.png:md5,67d6d4c8072743a32dfa30dd22edd5fe", - "samtools-coverage_Bases-cnt.png:md5,8790b6226f16810deceb82c6834b21be", - "samtools-coverage_Bases-log.png:md5,7bdd54947c3ab74d06b9fc11cc35cb51", - "samtools-coverage_Coverage-cnt.png:md5,cdff6829f5d017e67668e6b77b8648fd", - "samtools-coverage_Coverage-log.png:md5,13441e809c66563bf7284ebe4038f368", - "samtools-coverage_MQ-cnt.png:md5,59265e8998386d8a6521296508b4f4e6", - "samtools-coverage_MQ-log.png:md5,0282c8f2fb311eb3830f6d33a8e0d2ef", - "samtools-coverage_Mean_depth-cnt.png:md5,7f0aa59d888da55c8b7e5ca00011b2fc", - "samtools-coverage_Mean_depth-log.png:md5,ab01268969d553decb36658ca785dac0", - "samtools-coverage_Reads-cnt.png:md5,f77fe84d95f5bebd12aa764ab377b6e7", - "samtools-coverage_Reads-log.png:md5,34d3ebbc83f073531328d633466cfcd9", - "samtools-flagstat-pct-table.png:md5,30a84ce2464168d8dedf65b47725e2e1", - "samtools-flagstat-table.png:md5,a828ba0e94ebd04d2ac50ecc43b007fd", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.png:md5,91267791bafff119d985db6b24f813dc", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.png:md5,d1c9fd2633128ed5af7113cedeba91d8", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.png:md5,eb81f43f6c5778f957ce85137758235e", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.png:md5,b1b15467c4b7e34b2a724c2fe9daefa8", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.png:md5,64927987623ac1715e607470f6bf055a", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.png:md5,09773cf98a65a96710a4fac9e2600ed9", - "samtools-stats-dp.png:md5,fe29585e232244237558512103d78fdc", - "samtools_alignment_plot-cnt.png:md5,e5523404a7622df41efaf24fb98ef4c5", - "samtools_alignment_plot-pct.png:md5,7945231e29b09915dee17a9fa620ef62" - ], - [ - "biobambam2_deduplication-cnt.svg:md5,cfd25e0ac46d01b09f2196fc10487a97", - "biobambam2_deduplication-pct.svg:md5,c7ed58b8de114475f6ef551cc38246b6", - "fastp-insert-size-plot.svg:md5,463e2ebba19326fc07286ec96074439c", - "fastp-seq-content-gc-plot_Read_1_After_filtering.svg:md5,df2eff4d156ad7f187fa80e3340cbc9c", - "fastp-seq-content-gc-plot_Read_1_Before_filtering.svg:md5,de22f2c91d8abe074f24aada92336dae", - "fastp-seq-content-gc-plot_Read_2_After_filtering.svg:md5,c1119ba28aa972dcde0725e9ece9b452", - "fastp-seq-content-gc-plot_Read_2_Before_filtering.svg:md5,bf51d5e029164a62af8a97002bafaf91", - "fastp-seq-content-n-plot_Read_1_After_filtering.svg:md5,1cd1bb467239c3375c0670deb40910e4", - "fastp-seq-content-n-plot_Read_1_Before_filtering.svg:md5,58312bc31b5df1f981ddfaa464747d6a", - "fastp-seq-content-n-plot_Read_2_After_filtering.svg:md5,4b4d0bb5ee8e778e36d0b22b50e588ac", - "fastp-seq-content-n-plot_Read_2_Before_filtering.svg:md5,5a4346d963e57ef9dc93049473b299d4", - "fastp-seq-quality-plot_Read_1_After_filtering.svg:md5,8df1ad718fba86d1dc9100f686805969", - "fastp-seq-quality-plot_Read_1_Before_filtering.svg:md5,2ab2d86c525286641d2add385a2776b8", - "fastp-seq-quality-plot_Read_2_After_filtering.svg:md5,57fc98afa287a7efcb4cda584aaa1b03", - "fastp-seq-quality-plot_Read_2_Before_filtering.svg:md5,0255426c3f1eb52d8cc79e15becc30a2", - "fastp_filtered_reads_plot-cnt.svg:md5,e824977b86925e3f373258ecdd4043e3", - "fastp_filtered_reads_plot-pct.svg:md5,481a650cbb8337fd7324909c08782fbb", - "mosdepth-coverage-per-contig-single-cnt.svg:md5,54a9e9adab8aec8840883d8fbfd9a5d0", - "mosdepth-coverage-per-contig-single-pct.svg:md5,131d4cac8f19f0b95032c7233af5823e", - "mosdepth-cumcoverage-dist-id.svg:md5,179007d2d118f6a8e418e43aeaeb9c59", - "picard_alignment_readlength_plot.svg:md5,8251fdfdcf8d1cfcafa2c5e4274b5dd1", - "picard_alignment_summary_Aligned_Bases-cnt.svg:md5,fd201a6cf172881e6f665f3bf709e47d", - "picard_alignment_summary_Aligned_Bases-pct.svg:md5,000fee385374691cee56da73f6b1a6e3", - "picard_alignment_summary_Aligned_Reads-cnt.svg:md5,2dab47d583abe346da10f9cc7326afcf", - "picard_alignment_summary_Aligned_Reads-pct.svg:md5,d4a37067193df967815f12979b3af04c", - "picard_base_distribution_by_cycle__Adenine.svg:md5,218b08544c23a6efa4658d7f3752e104", - "picard_base_distribution_by_cycle__Cytosine.svg:md5,ab5e2bc1042bb94494552650de3f5572", - "picard_base_distribution_by_cycle__Guanine.svg:md5,b55b38dd248d4bb58d45727640b08bdb", - "picard_base_distribution_by_cycle__Thymine.svg:md5,3207e557593827437917773a6d7a3076", - "picard_base_distribution_by_cycle__Undetermined.svg:md5,ce646cb1a14cf74c5d07cd95ea3ea6fa", - "picard_quality_by_cycle.svg:md5,8d09b50d5323d7d08e78694e2b4f5783", - "picard_quality_score_distribution.svg:md5,252451413c9a1305642aeca9540fe95b", - "picard_wgs_metrics_bases.svg:md5,2433b911e40ebe4bf49fabfdd473f488", - "picard_wgs_metrics_histogram_Counts_Histogram.svg:md5,90789c6587b1924a203de3ea67051e1d", - "picard_wgs_metrics_histogram_Percentage_Drop-Off.svg:md5,57bf92e2f97b6698a78761e9133d696d", - "samtools-coverage-table.svg:md5,dc9a03bbcdc8e6c85ecdcbc473c284e5", - "samtools-coverage_BQ-cnt.svg:md5,3bf9dd0ff0afb7dac4e82c3cc0debee6", - "samtools-coverage_BQ-log.svg:md5,3503b4d291a6bc5f13321ea35367173c", - "samtools-coverage_Bases-cnt.svg:md5,1da43ab7b821f0950bc5fcd9d0ef4de6", - "samtools-coverage_Bases-log.svg:md5,5d6d1e30f71dc901bc854891f8a86c8b", - "samtools-coverage_Coverage-cnt.svg:md5,bd068ea990b4a9ab34f8ed7906ab4df7", - "samtools-coverage_Coverage-log.svg:md5,a84dbdcc47032a0802f0f4303fff79e5", - "samtools-coverage_MQ-cnt.svg:md5,a34d1b3ef3307b7f239f345c4c46417c", - "samtools-coverage_MQ-log.svg:md5,f0d92ed6064fe3857222add705200ebf", - "samtools-coverage_Mean_depth-cnt.svg:md5,beb5c52e77b588aff06211996b5c9c58", - "samtools-coverage_Mean_depth-log.svg:md5,bf0fe9b38385d501bfdc0eb8ae32dc0c", - "samtools-coverage_Reads-cnt.svg:md5,a0f29b2d300f8d441cf0444dfed15d2c", - "samtools-coverage_Reads-log.svg:md5,2b286ec78f439cc836c27b894355a649", - "samtools-flagstat-pct-table.svg:md5,a861423dc06a2c4343ac008da572cae6", - "samtools-flagstat-table.svg:md5,7e3929334dc02949b8a8624cee0b74f7", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-cnt.svg:md5,6beb4644520950ba9d88aa2fc76f97ca", - "samtools-idxstats-mapped-reads-plot_Normalised_Counts-log.svg:md5,bdd312d3b7078cf983b55365b073c8da", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-cnt.svg:md5,cacd164220e021555bfab9d77d1604d6", - "samtools-idxstats-mapped-reads-plot_Observed_over_Expected_Counts-log.svg:md5,a0afc475e749152c8a1f68348e126468", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-cnt.svg:md5,70ee0003a9ad53ef889f8b1e6ab29fbd", - "samtools-idxstats-mapped-reads-plot_Raw_Counts-log.svg:md5,10677c752400f74cb2d80b448a7ecb6e", - "samtools-stats-dp.svg:md5,7a82a092680d0a2f74bc6bd7ddaff3ff", - "samtools_alignment_plot-cnt.svg:md5,57bf2b3f8ae396795a58e41c6a13eaad", - "samtools_alignment_plot-pct.svg:md5,11319f379dfc395ae27e63e58911a7dc" - ] - ] + "multiqc_library_test_plots" ], "multiqc_library_report": [ - "multiqc_library_test.html:md5,39501e6d3e661aa5268cc7bc3013842e" + "multiqc_library_test.html" ], "multiqc_main_data": [ [ - [ - "llms-full.txt:md5,5c2ab84efb61df9527a502df6d502f6b", - "multiqc.log:md5,b1c042eb498add3a6e44b5b1198a11a3", - "multiqc.parquet:md5,38b4675edf61dc905c4e5001dc8dcde1", - "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", - "multiqc_data.json:md5,3372e515c6d7aee673f28f47c22507ba", - "multiqc_software_versions.txt:md5,b957e99d3c8616d8a0326be3f6114ced", - "multiqc_sources.txt:md5,d2a044df39ce3c6abe5cdc2d67473490" - ] + "multiqc_data" ] ], "multiqc_main_plots": [ @@ -1992,7 +1338,7 @@ ], "multiqc_main_report": [ [ - "multiqc.html:md5,62160777bc781484c4e2434e8c6009ff" + "multiqc.html" ] ], "panelcoverage": [ @@ -2242,6 +1588,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T19:51:58.967318" + "timestamp": "2025-12-04T20:39:54.655718" } } \ No newline at end of file From d0da19e7166bc78e875825aab9bd2c952e509a85 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 15:31:47 +0100 Subject: [PATCH 091/228] Update schema and test input with aligner: false --- assets/schema_input.json | 4 ++-- assets/schema_sampleinfo.json | 4 ++-- nextflow_schema.json | 4 ++-- tests/inputs/fastq.yml | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index deb42ab7..1e576bb7 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -35,9 +35,9 @@ }, "aligner": { "meta": ["aligner"], - "type": "string", + "type": ["string", "boolean"], "description": "Aligner to use to align sample to the reference genome", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star"] + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false] }, "tag": { "meta": ["tag"], diff --git a/assets/schema_sampleinfo.json b/assets/schema_sampleinfo.json index c5443971..daa63fc0 100644 --- a/assets/schema_sampleinfo.json +++ b/assets/schema_sampleinfo.json @@ -83,9 +83,9 @@ }, "aligner": { "meta": ["aligner"], - "type": "string", + "type": ["string", "boolean"], "description": "Aligner to use to align sample to the reference genome", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star"] + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false] } } }, diff --git a/nextflow_schema.json b/nextflow_schema.json index 1003fc1b..17c9bee5 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -52,10 +52,10 @@ "default": "", "properties": { "aligner": { - "type": "string", + "type": ["string", "boolean"], "default": "bowtie2", "description": "Which aligner to use", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star"] + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false] }, "markdup": { "type": "string", diff --git a/tests/inputs/fastq.yml b/tests/inputs/fastq.yml index 20a5ec56..87c8daf3 100644 --- a/tests/inputs/fastq.yml +++ b/tests/inputs/fastq.yml @@ -5,6 +5,7 @@ library: test_library organism: Homo sapiens tag: WES + aligner: bwamem fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz - id: sample1_L002 @@ -12,5 +13,22 @@ library: test_library organism: Homo sapiens tag: WES + aligner: bwamem + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz +- id: sample2_L001 + samplename: fastq_paired_unaligned + library: test_unaligned + organism: Homo sapiens + tag: WES + aligner: false + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz +- id: sample2_L002 + samplename: fastq_paired_unaligned + library: test_unaligned + organism: Homo sapiens + tag: WES + aligner: false fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz From e390159ed389f9dbc6d1a95214ef989c5625e0f8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:25:18 +0100 Subject: [PATCH 092/228] convert untrimmed fastq -> ucram --- workflows/preprocessing.nf | 65 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index c737d2b1..a51b5b09 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -166,6 +166,11 @@ workflow PREPROCESSING { if (aligner && !meta.aligner) { meta = meta + ["aligner": aligner] } + + // If the aligner is set to `false`, redirect sample to unaligned flow by dropping the genome_data key + if (meta.aligner == false || meta.aligner == "false") { + meta = meta - meta.subMap('genome_data') + } // set the ROI // // Special case for coPGT samples // // if there's no global ROI AND no sample speficic ROI @@ -188,12 +193,26 @@ workflow PREPROCESSING { .map { meta, fastq -> return [meta - meta.subMap('fcid', 'lane'), fastq] } + .branch { meta, _reads -> + supported: meta.genome_data instanceof Map && meta.genome_data.size() > 0 + other: true + } .set { ch_fastq_per_sample } - ch_fastq_per_sample.dump(tag: "FASTQ per sample", pretty: true) + ch_fastq_per_sample.supported.dump(tag: "Supported FASTQ per sample", pretty: true) + ch_fastq_per_sample.other.dump(tag: "Other FASTQ per sample", pretty: true) +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// STEP: FASTQ TO UNALIGNED CRAM CONVERSION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ - /* + FASTQ_TO_UCRAM(ch_fastq_per_sample.other) + ch_versions = ch_versions.mix(FASTQ_TO_UCRAM.out.versions) + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FASTQ TRIMMING AND QC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -223,44 +242,26 @@ workflow PREPROCESSING { reads, ] } - .branch { meta, _reads -> - supported: meta.genome_data instanceof Map && meta.genome_data.size() > 0 - other: true - } .set { ch_trimmed_reads } - ch_trimmed_reads.supported.dump(tag: "Supported trimmed reads per sample", pretty: true) - ch_trimmed_reads.other.dump(tag: "Other trimmed reads per sample", pretty: true) - - - /* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// STEP: FASTQ TO UNALIGNED CRAM CONVERSION -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - - FASTQ_TO_UCRAM(ch_trimmed_reads.other) - ch_versions = ch_versions.mix(FASTQ_TO_UCRAM.out.versions) - - /* + ch_trimmed_reads.dump(tag: "Supported trimmed reads per sample", pretty: true) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: FASTQ TO ALIGNED CRAM CONVERSION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_trimmed_reads.supported - .map { meta, reads -> - return [ - meta, - reads, - meta.aligner, - getGenomeAttribute(meta.genome_data, meta.aligner), - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "gtf"), - ] - } - .set { ch_meta_reads_aligner_index_fasta_gtf } + ch_trimmed_reads.map { meta, reads -> + return [ + meta, + reads, + meta.aligner, + getGenomeAttribute(meta.genome_data, meta.aligner), + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "gtf"), + ] + } + .set { ch_meta_reads_aligner_index_fasta_gtf } FASTQ_TO_CRAM( ch_meta_reads_aligner_index_fasta_gtf, From 52c3f8a4207a0267c22ff0a8321f5301186ee554 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:59:16 +0100 Subject: [PATCH 093/228] Drop support for unaligned cram --- CHANGELOG.md | 1 + main.nf | 5 - modules.json | 11 -- modules/nf-core/samtools/cat/environment.yml | 10 -- modules/nf-core/samtools/cat/main.nf | 50 --------- modules/nf-core/samtools/cat/meta.yml | 64 ----------- .../nf-core/samtools/cat/samtools-cat.diff | 23 ---- .../nf-core/samtools/cat/tests/main.nf.test | 61 ----------- .../samtools/cat/tests/main.nf.test.snap | 70 ------------ .../nf-core/samtools/import/environment.yml | 10 -- modules/nf-core/samtools/import/main.nf | 59 ---------- modules/nf-core/samtools/import/meta.yml | 77 ------------- .../samtools/import/tests/main.nf.test | 83 -------------- .../samtools/import/tests/main.nf.test.snap | 103 ------------------ .../local/fastq_to_unaligned_cram/main.nf | 67 ------------ .../local/fastq_to_unaligned_cram/meta.yml | 0 .../fastq_to_unaligned_cram/main.nf.test | 36 ------ .../fastq_to_unaligned_cram/main.nf.test.snap | 30 ----- workflows/preprocessing.nf | 20 +--- 19 files changed, 5 insertions(+), 775 deletions(-) delete mode 100644 modules/nf-core/samtools/cat/environment.yml delete mode 100644 modules/nf-core/samtools/cat/main.nf delete mode 100644 modules/nf-core/samtools/cat/meta.yml delete mode 100644 modules/nf-core/samtools/cat/samtools-cat.diff delete mode 100644 modules/nf-core/samtools/cat/tests/main.nf.test delete mode 100644 modules/nf-core/samtools/cat/tests/main.nf.test.snap delete mode 100644 modules/nf-core/samtools/import/environment.yml delete mode 100644 modules/nf-core/samtools/import/main.nf delete mode 100644 modules/nf-core/samtools/import/meta.yml delete mode 100644 modules/nf-core/samtools/import/tests/main.nf.test delete mode 100644 modules/nf-core/samtools/import/tests/main.nf.test.snap delete mode 100644 subworkflows/local/fastq_to_unaligned_cram/main.nf delete mode 100644 subworkflows/local/fastq_to_unaligned_cram/meta.yml delete mode 100644 tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test delete mode 100644 tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 69949def..a93a96cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update the output handling to use the new workflow output definitions. - Bump all modules to latest versions. - The workflow now outputs data in a subdirectory per `library`, including a library specific MultiQC report +- Drop support for unaligned cram outputs. ## v2.0.6 diff --git a/main.nf b/main.nf index 87371efa..5cae5882 100644 --- a/main.nf +++ b/main.nf @@ -70,7 +70,6 @@ workflow { demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) fastp_json = PREPROCESSING.out.fastp_json fastp_html = PREPROCESSING.out.fastp_html - ucrams = PREPROCESSING.out.ucrams crams = PREPROCESSING.out.crams align_reports = PREPROCESSING.out.align_reports sormadup_metrics = PREPROCESSING.out.sormadup_metrics @@ -124,10 +123,6 @@ output { def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" html >> out_path } } - ucrams { path { meta, cram -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.unaligned.cram" as String : "${meta.samplename}/${meta.samplename}.unaligned.cram" - cram >> out_path - } } crams { path { meta, cram, crai -> def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" diff --git a/modules.json b/modules.json index cbebbe1e..fe836420 100644 --- a/modules.json +++ b/modules.json @@ -86,12 +86,6 @@ "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, - "samtools/cat": { - "branch": "master", - "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"], - "patch": "modules/nf-core/samtools/cat/samtools-cat.diff" - }, "samtools/convert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", @@ -114,11 +108,6 @@ "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"] }, - "samtools/import": { - "branch": "master", - "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"] - }, "samtools/sormadup": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", diff --git a/modules/nf-core/samtools/cat/environment.yml b/modules/nf-core/samtools/cat/environment.yml deleted file mode 100644 index 89e12a64..00000000 --- a/modules/nf-core/samtools/cat/environment.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json -channels: - - conda-forge - - bioconda -dependencies: - # renovate: datasource=conda depName=bioconda/htslib - - bioconda::htslib=1.22.1 - # renovate: datasource=conda depName=bioconda/samtools - - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/cat/main.nf b/modules/nf-core/samtools/cat/main.nf deleted file mode 100644 index d200e501..00000000 --- a/modules/nf-core/samtools/cat/main.nf +++ /dev/null @@ -1,50 +0,0 @@ -process SAMTOOLS_CAT { - tag "$meta.id" - label 'process_low' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0' : - 'biocontainers/samtools:1.22.1--h96c455f_0' }" - - input: - tuple val(meta), path(input_files, stageAs: "?/*") - - output: - tuple val(meta), path("*.bam") , optional:true, emit: bam - tuple val(meta), path("*.cram"), optional:true, emit: cram - path "versions.yml" , emit: versions - - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - def file_type = input_files instanceof List ? input_files[0].getExtension() : input_files.getExtension() - """ - samtools \\ - cat \\ - $args \\ - -o ${prefix}.${file_type} \\ - $input_files - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS - """ - - stub: - prefix = task.ext.suffix ? "${meta.id}${task.ext.suffix}" : "${meta.id}" - def file_type = input_files instanceof List ? input_files[0].getExtension() : input_files.getExtension() - """ - touch ${prefix}.${file_type} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS - """ -} diff --git a/modules/nf-core/samtools/cat/meta.yml b/modules/nf-core/samtools/cat/meta.yml deleted file mode 100644 index a2ac0e21..00000000 --- a/modules/nf-core/samtools/cat/meta.yml +++ /dev/null @@ -1,64 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json -name: samtools_cat -description: Concatenate BAM or CRAM file -keywords: - - merge - - 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_files: - type: file - description: BAM/CRAM files - pattern: "*.{bam,cram}" - ontologies: [] -output: - bam: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - ${prefix}.bam: - type: file - description: Concatenated BAM file - pattern: "*.{bam}" - ontologies: [] - cram: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - ${prefix}.cram: - type: file - description: Concatenated CRAM file - pattern: "*.{cram}" - ontologies: [] - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -authors: - - "@matthdsm" -maintainers: - - "@matthdsm" diff --git a/modules/nf-core/samtools/cat/samtools-cat.diff b/modules/nf-core/samtools/cat/samtools-cat.diff deleted file mode 100644 index 5b6918b7..00000000 --- a/modules/nf-core/samtools/cat/samtools-cat.diff +++ /dev/null @@ -1,23 +0,0 @@ -Changes in component 'nf-core/samtools/cat' -'modules/nf-core/samtools/cat/environment.yml' is unchanged -'modules/nf-core/samtools/cat/meta.yml' is unchanged -Changes in 'samtools/cat/main.nf': ---- modules/nf-core/samtools/cat/main.nf -+++ modules/nf-core/samtools/cat/main.nf -@@ -11,9 +11,9 @@ - tuple val(meta), path(input_files, stageAs: "?/*") - - output: -- tuple val(meta), path("${prefix}.bam") , optional:true, emit: bam -- tuple val(meta), path("${prefix}.cram"), optional:true, emit: cram -- path "versions.yml" , emit: versions -+ tuple val(meta), path("*.bam") , optional:true, emit: bam -+ tuple val(meta), path("*.cram"), optional:true, emit: cram -+ path "versions.yml" , emit: versions - - - when: - -'modules/nf-core/samtools/cat/tests/main.nf.test.snap' is unchanged -'modules/nf-core/samtools/cat/tests/main.nf.test' is unchanged -************************************************************ diff --git a/modules/nf-core/samtools/cat/tests/main.nf.test b/modules/nf-core/samtools/cat/tests/main.nf.test deleted file mode 100644 index dad80b83..00000000 --- a/modules/nf-core/samtools/cat/tests/main.nf.test +++ /dev/null @@ -1,61 +0,0 @@ -nextflow_process { - - name "Test Process SAMTOOLS_CAT" - script "../main.nf" - process "SAMTOOLS_CAT" - - tag "modules" - tag "modules_nfcore" - tag "samtools" - tag "samtools/cat" - - test("bams") { - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ 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.unaligned.bam', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(file(process.out.bam[0][1]).name).match("bams_bam") }, - { assert snapshot(process.out.cram).match("bams_cram") }, - { assert snapshot(process.out.versions).match("bams_versions") } - ) - } - } - - test("bams_stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ 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.unaligned.bam', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(file(process.out.bam[0][1]).name).match("bams_stub_bam") }, - { assert snapshot(process.out.cram).match("bams_stub_cram") }, - { assert snapshot(process.out.versions).match("bams_stub_versions") } - ) - } - } -} diff --git a/modules/nf-core/samtools/cat/tests/main.nf.test.snap b/modules/nf-core/samtools/cat/tests/main.nf.test.snap deleted file mode 100644 index 2143309a..00000000 --- a/modules/nf-core/samtools/cat/tests/main.nf.test.snap +++ /dev/null @@ -1,70 +0,0 @@ -{ - "bams_stub_cram": { - "content": [ - [ - - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-02T16:45:42.587418" - }, - "bams_stub_versions": { - "content": [ - [ - "versions.yml:md5,99695cce7873f354da5dd8660522cb4f" - ] - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T13:02:09.79415" - }, - "bams_bam": { - "content": [ - "test.bam" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-02T16:45:37.965199" - }, - "bams_cram": { - "content": [ - [ - - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-02T16:45:37.96805" - }, - "bams_stub_bam": { - "content": [ - "test.bam" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" - }, - "timestamp": "2024-02-02T16:45:42.583881" - }, - "bams_versions": { - "content": [ - [ - "versions.yml:md5,99695cce7873f354da5dd8660522cb4f" - ] - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T13:02:05.668116" - } -} \ No newline at end of file diff --git a/modules/nf-core/samtools/import/environment.yml b/modules/nf-core/samtools/import/environment.yml deleted file mode 100644 index 89e12a64..00000000 --- a/modules/nf-core/samtools/import/environment.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json -channels: - - conda-forge - - bioconda -dependencies: - # renovate: datasource=conda depName=bioconda/htslib - - bioconda::htslib=1.22.1 - # renovate: datasource=conda depName=bioconda/samtools - - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/import/main.nf b/modules/nf-core/samtools/import/main.nf deleted file mode 100644 index 0efbc75a..00000000 --- a/modules/nf-core/samtools/import/main.nf +++ /dev/null @@ -1,59 +0,0 @@ -process SAMTOOLS_IMPORT { - tag "$meta.id" - label 'process_single' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.22.1--h96c455f_0': - 'biocontainers/samtools:1.22.1--h96c455f_0' }" - - input: - tuple val(meta), path(reads) - - output: - tuple val(meta), path("*.sam") , emit: sam, optional: true - tuple val(meta), path("*.bam") , emit: bam, optional: true - tuple val(meta), path("*.cram"), emit: cram, optional: true - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = args.contains("--output-fmt sam") ? "sam" : - args.contains("--output-fmt bam") ? "bam" : - args.contains("--output-fmt cram") ? "cram" : - "bam" - def input = reads instanceof List && meta.single_end ? reads.join(" -0") : // multiple single-end files - reads instanceof List && !meta.single_end ? "-1 ${reads[0]} -2 ${reads[1]}": // paired end file - meta.single_end ? "-0 $reads" : // single single-end file - !meta.single_end ? "-s $reads": // interleave paired-end file - reads // if all else fails, just add the reads without flags - """ - samtools \\ - import \\ - $input \\ - $args \\ - -@ $task.cpus \\ - -o ${prefix}.${suffix} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS - """ - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - - """ - touch ${prefix}.bam - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS - """ -} diff --git a/modules/nf-core/samtools/import/meta.yml b/modules/nf-core/samtools/import/meta.yml deleted file mode 100644 index 2b86ce79..00000000 --- a/modules/nf-core/samtools/import/meta.yml +++ /dev/null @@ -1,77 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json -name: "samtools_import" -description: converts FASTQ files to unmapped SAM/BAM/CRAM -keywords: - - import - - fastq - - 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 ]` - - reads: - type: file - description: fastq data to be converted to SAM/BAM/CRAM - pattern: "*.{fastq,fq,fastq.gz,fq.gz}" - ontologies: - - edam: http://edamontology.org/format_1930 # FASTQ -output: - sam: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*.sam": - type: file - description: SAM file - pattern: "*.sam" - ontologies: [] - bam: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*.bam": - type: file - description: Unaligned BAM file - pattern: "*.bam" - ontologies: [] - cram: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*.cram": - type: file - description: Unaligned CRAM file - pattern: "*.cram" - ontologies: [] - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -authors: - - "@matthdsm" -maintainers: - - "@matthdsm" diff --git a/modules/nf-core/samtools/import/tests/main.nf.test b/modules/nf-core/samtools/import/tests/main.nf.test deleted file mode 100644 index 9c7ce5d9..00000000 --- a/modules/nf-core/samtools/import/tests/main.nf.test +++ /dev/null @@ -1,83 +0,0 @@ -nextflow_process { - - name "Test Process SAMTOOLS_IMPORT" - script "../main.nf" - process "SAMTOOLS_IMPORT" - tag "modules" - tag "modules_nfcore" - tag "samtools" - tag "samtools/import" - - test("samtools_import_single ") { - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll( - {assert process.success}, - {assert snapshot(process.out.bam.collect { it.collect { it instanceof Map ? it : file(it).name } }).match()} - ) - } - } - - test("samtools_import_paired ") { - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [ 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(process.out.bam.collect { it.collect { it instanceof Map ? it : file(it).name } }).match()} - ) - } - } - - test("samtools_import_interleaved") { - - when { - params { - outdir = "$outputDir" - } - process { - """ - input[0] = Channel.of([ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll( - {assert process.success}, - {assert snapshot(process.out.bam.collect { it.collect { it instanceof Map ? it : file(it).name } }).match()} - ) - } - } -} diff --git a/modules/nf-core/samtools/import/tests/main.nf.test.snap b/modules/nf-core/samtools/import/tests/main.nf.test.snap deleted file mode 100644 index eb730a06..00000000 --- a/modules/nf-core/samtools/import/tests/main.nf.test.snap +++ /dev/null @@ -1,103 +0,0 @@ -{ - "samtools_import_single ": { - "content": [ - [ - [ - { - "id": "test", - "single_end": true - }, - "test.bam" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-31T11:38:44.388259606" - }, - "samtools_import_interleaved": { - "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-31T11:38:56.393371331" - }, - "samtools_import_paired ": { - "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam" - ] - ] - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-31T11:38:50.437197406" - }, - "samtools_import_interleaved ": { - "content": [ - { - "0": [ - - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,fad91b070f51c77d7abe22cd31243710" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,a529fc2aa6485db14986c95c53638b11" - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,fad91b070f51c77d7abe22cd31243710" - ] - ], - "cram": [ - - ], - "sam": [ - - ], - "versions": [ - "versions.yml:md5,a529fc2aa6485db14986c95c53638b11" - ] - } - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" - }, - "timestamp": "2024-05-30T12:12:43.491200967" - } -} \ No newline at end of file diff --git a/subworkflows/local/fastq_to_unaligned_cram/main.nf b/subworkflows/local/fastq_to_unaligned_cram/main.nf deleted file mode 100644 index f1137f26..00000000 --- a/subworkflows/local/fastq_to_unaligned_cram/main.nf +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env nextflow - -// -// Take fastq; convert to ubam and compress - -// MODULES -include { SAMTOOLS_CAT } from '../../../modules/nf-core/samtools/cat/main' -include { SAMTOOLS_IMPORT } from "../../../modules/nf-core/samtools/import/main" - -workflow FASTQ_TO_UCRAM { - take: - ch_fastq // channel: [mandatory] [meta, [fastq, ...]] - - main: - - ch_versions = channel.empty() - - /* - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // STEP: FASTQ TO BAM CONVERSION - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - - ch_fastq.dump(tag: "FASTQ_TO_UCRAM: reads to convert", pretty: true) - - // SAMTOOLS_IMPORT([meta, fastq]) - SAMTOOLS_IMPORT(ch_fastq) - ch_versions = ch_versions.mix(SAMTOOLS_IMPORT.out.versions.first()) - - SAMTOOLS_IMPORT.out.cram - .map { meta, files -> - def gk = (meta.chunks as Integer ?: 1) - return [ - groupKey( - meta - meta.subMap('id', 'readgroup', 'chunks') + [id: meta.samplename ? meta.samplename + ".unaligned" : meta.id + ".unaligned"], - gk, - ), - files, - ] - } - .groupTuple(by: [0]) - .dump(tag: "FASTQ_TO_UCRAM: unaligned cram per replicate", pretty: true) - .map { meta, files -> - def gk = (meta.count as Integer ?: 1) - return [ - groupKey( - meta - meta.subMap('count'), - gk, - ), - files, - ] - } - .groupTuple(by: [0]) - .map { meta, files -> - return [meta, files.flatten()] - } - .dump(tag: "FASTQ_TO_UCRAM: unaligned cram per sample", pretty: true) - .set { ch_ubam_per_sample } - - // Merge bam files per sample - SAMTOOLS_CAT(ch_ubam_per_sample) - ch_versions = ch_versions.mix(SAMTOOLS_CAT.out.versions.first()) - - emit: - cram = SAMTOOLS_CAT.out.cram // [meta, cram] - versions = ch_versions // versions -} diff --git a/subworkflows/local/fastq_to_unaligned_cram/meta.yml b/subworkflows/local/fastq_to_unaligned_cram/meta.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test deleted file mode 100644 index b3a3b185..00000000 --- a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test +++ /dev/null @@ -1,36 +0,0 @@ -nextflow_workflow { - - name "Test Workflow FASTQ_TO_UCRAM" - script "subworkflows/local/fastq_to_unaligned_cram/main.nf" - workflow "FASTQ_TO_UCRAM" - - tag "subworkflows" - tag "subworkflows/local" - tag "subworkflows/local/fastq_to_unaligned_cram" - - test("fastq to unaligned cram") { - - when { - workflow { - """ - input[0] = Channel.of([ - [ id:'test', samplename:'test', single_end:false ], // meta map - [ - file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), - file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz", checkIfExists: true) - ] - ]) - """ - } - } - - then { - assert workflow.success - assert snapshot( - sanitizeOutput(workflow.out, unstableKeys:["cram"]) - ).match() - } - - } - -} diff --git a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap deleted file mode 100644 index 39fd0d73..00000000 --- a/tests/subworkflows/local/fastq_to_unaligned_cram/main.nf.test.snap +++ /dev/null @@ -1,30 +0,0 @@ -{ - "fastq to unaligned cram": { - "content": [ - { - "cram": [ - [ - { - "groupSize": 1, - "groupTarget": { - "id": "test.unaligned", - "samplename": "test", - "single_end": false - } - }, - "test.unaligned.cram" - ] - ], - "versions": [ - "versions.yml:md5,7d0123b33defe52fceb94bd95f802978", - "versions.yml:md5,f253e859e7aa43e34481f5493c4e847b" - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-02T13:05:20.48603" - } -} \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index a51b5b09..86297aa5 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -15,11 +15,10 @@ include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' // Subworkflows -include { BAM_QC } from '../subworkflows/local/bam_qc/main' -include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' -include { COVERAGE } from '../subworkflows/local/coverage/main' -include { FASTQ_TO_UCRAM } from '../subworkflows/local/fastq_to_unaligned_cram/main' -include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' +include { BAM_QC } from '../subworkflows/local/bam_qc/main' +include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' +include { COVERAGE } from '../subworkflows/local/coverage/main' +include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' // Functions include { paramsSummaryMap } from 'plugin/nf-schema' @@ -202,16 +201,6 @@ workflow PREPROCESSING { ch_fastq_per_sample.supported.dump(tag: "Supported FASTQ per sample", pretty: true) ch_fastq_per_sample.other.dump(tag: "Other FASTQ per sample", pretty: true) -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// STEP: FASTQ TO UNALIGNED CRAM CONVERSION -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - - FASTQ_TO_UCRAM(ch_fastq_per_sample.other) - ch_versions = ch_versions.mix(FASTQ_TO_UCRAM.out.versions) - - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FASTQ TRIMMING AND QC @@ -502,7 +491,6 @@ workflow PREPROCESSING { demultiplex_logs = BCL_DEMULTIPLEX.out.logs fastp_json = FASTP.out.json fastp_html = FASTP.out.html - ucrams = FASTQ_TO_UCRAM.out.cram crams = FASTQ_TO_CRAM.out.cram_crai align_reports = FASTQ_TO_CRAM.out.align_reports sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics From 46368d86548b792e72378051ed31d4801077139b Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:51:38 +0100 Subject: [PATCH 094/228] redirect fastq to output when aligner is unset --- workflows/preprocessing.nf | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 86297aa5..07c8c439 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -161,10 +161,6 @@ workflow PREPROCESSING { else { meta = meta + ["genome_data": [:]] } - // set the aligner - if (aligner && !meta.aligner) { - meta = meta + ["aligner": aligner] - } // If the aligner is set to `false`, redirect sample to unaligned flow by dropping the genome_data key if (meta.aligner == false || meta.aligner == "false") { @@ -193,7 +189,7 @@ workflow PREPROCESSING { return [meta - meta.subMap('fcid', 'lane'), fastq] } .branch { meta, _reads -> - supported: meta.genome_data instanceof Map && meta.genome_data.size() > 0 + supported: meta.genome_data instanceof Map && meta.genome_data.size() > 0 && meta.aligner other: true } .set { ch_fastq_per_sample } From 0a094c1ee41c616df326de5332f0dc3c885997fd Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 21:24:49 +0100 Subject: [PATCH 095/228] update workflow output --- CHANGELOG.md | 1 + main.nf | 5 +++++ workflows/preprocessing.nf | 5 +++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a93a96cc..a6414d52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bump all modules to latest versions. - The workflow now outputs data in a subdirectory per `library`, including a library specific MultiQC report - Drop support for unaligned cram outputs. +- Add support for untrimmed fastq outputs for unsupported genomes or when aligner is set to `false`. ## v2.0.6 diff --git a/main.nf b/main.nf index 5cae5882..c45b7344 100644 --- a/main.nf +++ b/main.nf @@ -68,6 +68,7 @@ workflow { demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by:1) demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) + demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() fastp_json = PREPROCESSING.out.fastp_json fastp_html = PREPROCESSING.out.fastp_html crams = PREPROCESSING.out.crams @@ -115,6 +116,10 @@ output { def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" log >> out_path } } + demultiplex_fastq { path { meta, fastq -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" + fastq >> out_path + } } fastp_json { path { meta, json -> def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" json >> out_path diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 07c8c439..abb3a35b 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -205,8 +205,8 @@ workflow PREPROCESSING { // MODULE: fastp // Run QC, trimming and adapter removal - // FASTP([meta, fastq], adapter_fasta, save_trimmed, save_merged) - FASTP(ch_fastq_per_sample.map{ meta, fastq -> return [meta, fastq, []] }, false, false, false) + // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) + FASTP(ch_fastq_per_sample.supported.map{ meta, fastq -> return [meta, fastq, []] }, false, false, false) ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) ch_versions = ch_versions.mix(FASTP.out.versions.first()) @@ -485,6 +485,7 @@ workflow PREPROCESSING { demultiplex_interop = BCL_DEMULTIPLEX.out.interop demultiplex_reports = BCL_DEMULTIPLEX.out.reports demultiplex_logs = BCL_DEMULTIPLEX.out.logs + demultiplex_fastq = ch_fastq_per_sample.other fastp_json = FASTP.out.json fastp_html = FASTP.out.html crams = FASTQ_TO_CRAM.out.cram_crai From ae7e971d4600cb9ca07e1bdc87736a25a8d20a6a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 21:36:58 +0100 Subject: [PATCH 096/228] update docs --- README.md | 2 +- docs/parameters.md | 2 +- docs/usage.md | 44 ++++++++++++++++++++++---------------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 5bbc40e9..50e68f21 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) [![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) -[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1) +[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.1) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) diff --git a/docs/parameters.md b/docs/parameters.md index ba546b9b..f3b3df8e 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -17,7 +17,7 @@ Define where the pipeline should find input data and save output data. | Parameter | Description | Type | Default | Required | Hidden | | ------------------------ | ----------------------------------------------------------------------- | --------- | ----------- | -------- | ------ | -| `aligner` | Which aligner to use | `string` | bowtie2 | True | | +| `aligner` | Which aligner to use. Set to `false` to output fastq. | `string` | bowtie2 | True | | | `markdup` | Which alignment postprocessor to use | `string` | bamsormadup | | | | `run_coverage` | Run coverage analysis steps | `boolean` | True | | | | `skip_trimming` | Skip adapter trimming | `boolean` | False | | | diff --git a/docs/usage.md b/docs/usage.md index fe0779ab..1f1d72d2 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -39,17 +39,17 @@ TREATMENT_REP3,TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,,GRCh38,WES Following table shows the fields that are used by the `fastq` samplesheet: -| Column | Description | Required | -| ------------ | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | -| `fastq_1` | FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :heavy_check_mark: | -| `fastq_2` | FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :x: | -| `samplename` | The sample name corresponding to the sample in the Fastq file(s) | :heavy_check_mark: | -| `genome` | The genome build to use for the analysis. Currently supports GRCh38, GRCm39 and GRCz11 | :heavy_check_mark: (unless `organism` is given) | -| `organism` | Full name of the organism. Currently supports "Homo sapiens", "Mus musculus" and "Danio rerio" | :heavy_check_mark: (unless `genome` is given) | -| `library` | Sample library name | :x: | -| `tag` | The tag used by the sample. Can be one of WES, WGS or coPGT-M | :heavy_check_mark: | -| `roi` | The path to a BED file containing Regions Of Interest for coverage analysis | :x: | -| `aligner` | The aligner to use for this sample. Can be one of these: bowtie2, bwamem, bwamem2, dragmap and snap | :x: | +| Column | Description | Required | +| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | +| `fastq_1` | FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :heavy_check_mark: | +| `fastq_2` | FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :x: | +| `samplename` | The sample name corresponding to the sample in the Fastq file(s) | :heavy_check_mark: | +| `genome` | The genome build to use for the analysis. Currently supports GRCh38, GRCm39 and GRCz11 | :heavy_check_mark: (unless `organism` is given) | +| `organism` | Full name of the organism. Currently supports "Homo sapiens", "Mus musculus" and "Danio rerio" | :heavy_check_mark: (unless `genome` is given) | +| `library` | Sample library name | :x: | +| `tag` | The tag used by the sample. Can be one of WES, WGS or coPGT-M | :heavy_check_mark: | +| `roi` | The path to a BED file containing Regions Of Interest for coverage analysis | :x: | +| `aligner` | The aligner to use for this sample. Can be one of these: bowtie2, bwamem, bwamem2, dragmap, strobe and snap. set to `false` to output fastq. | :x: | An [example samplesheet](../tests/inputs/fastq.yml) has been provided with the pipeline. @@ -84,17 +84,17 @@ Sample1,test,Homo sapiens,WES Following table shows the fields that are used by the `flowcell` samplesheet: -| Column | Description | Required | -| --------------- | --------------------------------------------------------------------------------------------------- | ------------------ | -| `samplename` | The sample name | :heavy_check_mark: | -| `library` | The library name | :x: | -| `tag` | Sample tag. Has to be one of these: WES, WGS, coPGT-M | :heavy_check_mark: | -| `organism` | The organism of the sample. Has to be one of these: "Homo sapiens", "Mus musculus" or "Danio rerio" | :heavy_check_mark: | -| `vivar_project` | The vivar project name (currently not used by the pipeline) | :x: | -| `binsize` | The binsize for CNV analysis (currently not used by the pipeline) | :x: | -| `panels` | A list of panels for coverage analysis | :x: | -| `roi` | Region of interest BED file for coverage analysis | :x: | -| `aligner` | The aligner to use for this sample. Can be one of these: bowtie2, bwamem, bwamem2, dragmap and snap | :x: | +| Column | Description | Required | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | +| `samplename` | The sample name | :heavy_check_mark: | +| `library` | The library name | :x: | +| `tag` | Sample tag. Has to be one of these: WES, WGS, coPGT-M | :heavy_check_mark: | +| `organism` | The organism of the sample. Has to be one of these: "Homo sapiens", "Mus musculus" or "Danio rerio" | :heavy_check_mark: | +| `vivar_project` | The vivar project name (currently not used by the pipeline) | :x: | +| `binsize` | The binsize for CNV analysis (currently not used by the pipeline) | :x: | +| `panels` | A list of panels for coverage analysis | :x: | +| `roi` | Region of interest BED file for coverage analysis | :x: | +| `aligner` | The aligner to use for this sample. Can be one of these: bowtie2, bwamem, bwamem2, dragmap, strobe and snap. Set to `false` to output fastq. | :x: | ### Multiple runs of the same sample From efb3cf564b1c19909713a5c839dbbd6fc6cfbadb Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:12:39 +0100 Subject: [PATCH 097/228] output only fastq from demultiplexer, `aligner` param no longer mandatory --- nextflow.config | 2 +- nextflow_schema.json | 3 +-- tests/inputs/fastq.yml | 16 --------------- tests/workflows/preprocessing.nf.test.snap | 24 +++++++++++----------- workflows/preprocessing.nf | 15 +++++++++----- 5 files changed, 24 insertions(+), 36 deletions(-) diff --git a/nextflow.config b/nextflow.config index 6e2cfcae..fab6f6f3 100644 --- a/nextflow.config +++ b/nextflow.config @@ -18,7 +18,7 @@ params { igenomes_ignore = false // Analysis options - aligner = 'bowtie2' + aligner = null markdup = 'bamsormadup' umi_aware = false skip_trimming = false diff --git a/nextflow_schema.json b/nextflow_schema.json index 17c9bee5..67767d53 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -115,8 +115,7 @@ "format": "directory-path", "description": "Directory containing gene list bed files for granular coverage analysis" } - }, - "required": ["aligner"] + } }, "institutional_config_options": { "title": "Institutional config options", diff --git a/tests/inputs/fastq.yml b/tests/inputs/fastq.yml index 87c8daf3..52668235 100644 --- a/tests/inputs/fastq.yml +++ b/tests/inputs/fastq.yml @@ -16,19 +16,3 @@ aligner: bwamem fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz -- id: sample2_L001 - samplename: fastq_paired_unaligned - library: test_unaligned - organism: Homo sapiens - tag: WES - aligner: false - fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz - fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz -- id: sample2_L002 - samplename: fastq_paired_unaligned - library: test_unaligned - organism: Homo sapiens - tag: WES - aligner: false - fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz - fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 4a0b52f8..89d55ce7 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -32,6 +32,9 @@ "sample1.cram", "sample1.cram.crai" ] + ], + "demultiplex_fastq": [ + ], "demultiplex_interop": [ @@ -642,9 +645,6 @@ }, "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" ] - ], - "ucrams": [ - ], "versions": [ "versions.yml:md5,02acae00818ba01a01e2bdb03b574343", @@ -666,7 +666,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T20:36:50.85925" + "timestamp": "2025-12-04T22:06:58.57247" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -701,6 +701,9 @@ "sample1.cram", "sample1.cram.crai" ] + ], + "demultiplex_fastq": [ + ], "demultiplex_interop": [ @@ -989,9 +992,6 @@ }, "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" ] - ], - "ucrams": [ - ], "versions": [ "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", @@ -1009,7 +1009,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T20:42:53.576667" + "timestamp": "2025-12-04T22:11:37.660609" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1043,6 +1043,9 @@ "sample1.cram", "sample1.cram.crai" ] + ], + "demultiplex_fastq": [ + ], "demultiplex_interop": [ @@ -1564,9 +1567,6 @@ }, "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" ] - ], - "ucrams": [ - ], "versions": [ "versions.yml:md5,1d2a9b13790c70a69a1f62facc9b3a6c", @@ -1588,6 +1588,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T20:39:54.655718" + "timestamp": "2025-12-04T22:09:54.979336" } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index abb3a35b..29e8f295 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -107,6 +107,10 @@ workflow PREPROCESSING { .map { meta, fq -> return [meta, fq.flatten().unique()] } + .branch { meta, _fastq -> + to_align: meta.aligner && meta.aligner != "false" + other: true + } .set { ch_demultiplexed_fastq_with_sampleinfo } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -139,7 +143,7 @@ workflow PREPROCESSING { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_input_fastq - .mix(ch_demultiplexed_fastq_with_sampleinfo) + .mix(ch_demultiplexed_fastq_with_sampleinfo.to_align) .map { meta, reads -> if (meta.organism && !meta.genome) { if (meta.organism ==~ /(?i)Homo[\s_]sapiens/) { @@ -162,10 +166,11 @@ workflow PREPROCESSING { meta = meta + ["genome_data": [:]] } - // If the aligner is set to `false`, redirect sample to unaligned flow by dropping the genome_data key - if (meta.aligner == false || meta.aligner == "false") { - meta = meta - meta.subMap('genome_data') + // set the aligner + if (aligner && !meta.aligner) { + meta = meta + ["aligner": aligner] } + // set the ROI // // Special case for coPGT samples // // if there's no global ROI AND no sample speficic ROI @@ -485,7 +490,7 @@ workflow PREPROCESSING { demultiplex_interop = BCL_DEMULTIPLEX.out.interop demultiplex_reports = BCL_DEMULTIPLEX.out.reports demultiplex_logs = BCL_DEMULTIPLEX.out.logs - demultiplex_fastq = ch_fastq_per_sample.other + demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other fastp_json = FASTP.out.json fastp_html = FASTP.out.html crams = FASTQ_TO_CRAM.out.cram_crai From 7a23490990145da8347d3cf7b03d5bdda97b7248 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:34:44 +0100 Subject: [PATCH 098/228] drop `params.aligner` in favour of per sample `aligner` meta field --- README.md | 8 +++---- assets/schema_input.json | 4 ++-- assets/schema_sampleinfo.json | 9 +++++++- conf/profiles/WES.config | 1 - conf/profiles/WGS.config | 1 - conf/profiles/copgt.config | 1 - conf/profiles/sWGS.config | 1 - conf/test.config | 1 - docs/parameters.md | 1 - main.nf | 1 - nextflow.config | 1 - nextflow_schema.json | 6 ----- tests/default.nf.test | 2 -- tests/workflows/preprocessing.nf.test | 33 ++++++++++++--------------- workflows/preprocessing.nf | 6 ----- 15 files changed, 29 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 50e68f21..f867fbba 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,8 @@ First, prepare a samplesheet with your input data that looks as follows: `samplesheet.csv` for fastq inputs: ```csv -id,samplename,organism,library,fastq_1,fastq_2 -sample1,sample1,Homo sapiens,Library_Name,reads1.fq.gz,reads2.fq.gz +id,samplename,organism,library,aligner,fastq_1,fastq_2 +sample1,sample1,Homo sapiens,Library_Name,bwamem,reads1.fq.gz,reads2.fq.gz ``` `samplesheet.csv` for flowcell inputs: @@ -57,8 +57,8 @@ flowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/pa `sampleinfo.csv` for use with flowcell inputs: ```csv -samplename,library,organism,tag -fc_sample1,test,Homo sapiens,WES +samplename,library,organism,tag,aligner +fc_sample1,test,Homo sapiens,WES,bwamem ``` Now, you can run the pipeline using: diff --git a/assets/schema_input.json b/assets/schema_input.json index 1e576bb7..7eab645d 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -110,10 +110,10 @@ }, "anyOf": [ { - "required": ["id", "samplename", "organism", "tag", "fastq_1", "fastq_2"] + "required": ["id", "samplename", "organism", "aligner", "tag", "fastq_1", "fastq_2"] }, { - "required": ["id", "samplename", "genome", "tag", "fastq_1", "fastq_2"] + "required": ["id", "samplename", "genome", "aligner", "tag", "fastq_1", "fastq_2"] }, { "required": ["id", "samplesheet", "sample_info", "flowcell"] diff --git a/assets/schema_sampleinfo.json b/assets/schema_sampleinfo.json index daa63fc0..bac6789d 100644 --- a/assets/schema_sampleinfo.json +++ b/assets/schema_sampleinfo.json @@ -89,5 +89,12 @@ } } }, - "required": ["samplename", "tag", "organism"] + "anyOf": [ + { + "required": ["samplename", "organism", "aligner", "tag"] + }, + { + "required": ["samplename", "genome", "aligner", "tag"] + } + ] } diff --git a/conf/profiles/WES.config b/conf/profiles/WES.config index e7dd235b..2fd529a8 100644 --- a/conf/profiles/WES.config +++ b/conf/profiles/WES.config @@ -1,5 +1,4 @@ params { - aligner = "snap" run_coverage = true disable_picard_metrics = false roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v7.bed" diff --git a/conf/profiles/WGS.config b/conf/profiles/WGS.config index 2e1f2c11..657f8ec7 100644 --- a/conf/profiles/WGS.config +++ b/conf/profiles/WGS.config @@ -1,5 +1,4 @@ params { - aligner = "snap" markdup = "samtools" umi_aware = true run_coverage = true diff --git a/conf/profiles/copgt.config b/conf/profiles/copgt.config index 21a5bb45..67fd693b 100644 --- a/conf/profiles/copgt.config +++ b/conf/profiles/copgt.config @@ -1,5 +1,4 @@ params { - aligner = "snap" run_coverage = true disable_picard_metrics = true roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_coPGT-M_analyses_ROI_v1.bed" diff --git a/conf/profiles/sWGS.config b/conf/profiles/sWGS.config index 11be5b28..4497e094 100644 --- a/conf/profiles/sWGS.config +++ b/conf/profiles/sWGS.config @@ -1,5 +1,4 @@ params { - aligner = "bowtie2" run_coverage = false disable_picard_metrics = true } diff --git a/conf/test.config b/conf/test.config index 930c4538..f4ad2b2b 100644 --- a/conf/test.config +++ b/conf/test.config @@ -17,7 +17,6 @@ params { // Input data input = "${projectDir}/tests/inputs/fastq.yml" igenomes_base = "s3://reference-data/genomes" - aligner = "bwamem" } process { diff --git a/docs/parameters.md b/docs/parameters.md index f3b3df8e..914bd868 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -17,7 +17,6 @@ Define where the pipeline should find input data and save output data. | Parameter | Description | Type | Default | Required | Hidden | | ------------------------ | ----------------------------------------------------------------------- | --------- | ----------- | -------- | ------ | -| `aligner` | Which aligner to use. Set to `false` to output fastq. | `string` | bowtie2 | True | | | `markdup` | Which alignment postprocessor to use | `string` | bamsormadup | | | | `run_coverage` | Run coverage analysis steps | `boolean` | True | | | | `skip_trimming` | Skip adapter trimming | `boolean` | False | | | diff --git a/main.nf b/main.nf index c45b7344..9c2b4a22 100644 --- a/main.nf +++ b/main.nf @@ -45,7 +45,6 @@ workflow { PREPROCESSING( PIPELINE_INITIALISATION.out.samplesheet, params.genomes, - params.aligner, params.markdup, params.roi, params.genelists, diff --git a/nextflow.config b/nextflow.config index fab6f6f3..44d91929 100644 --- a/nextflow.config +++ b/nextflow.config @@ -18,7 +18,6 @@ params { igenomes_ignore = false // Analysis options - aligner = null markdup = 'bamsormadup' umi_aware = false skip_trimming = false diff --git a/nextflow_schema.json b/nextflow_schema.json index 67767d53..d7b52ec4 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -51,12 +51,6 @@ "description": "", "default": "", "properties": { - "aligner": { - "type": ["string", "boolean"], - "default": "bowtie2", - "description": "Which aligner to use", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false] - }, "markdup": { "type": "string", "default": "bamsormadup", diff --git a/tests/default.nf.test b/tests/default.nf.test index 6eb6875a..ba9b69e3 100644 --- a/tests/default.nf.test +++ b/tests/default.nf.test @@ -12,7 +12,6 @@ nextflow_pipeline { when { params { input = "${projectDir}/tests/inputs/fastq.yml" - aligner = "bwamem" igenomes_base = "s3://reference-data/genomes" outdir = "$outputDir" } @@ -29,7 +28,6 @@ nextflow_pipeline { when { params { input = "${projectDir}/tests/inputs/flowcell.yml" - aligner = "bwamem" igenomes_base = "s3://reference-data/genomes" outdir = "$outputDir" } diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index 54a187ec..6caacb09 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -21,7 +21,8 @@ nextflow_workflow { library: "test", organism: "Homo sapiens", tag: "WES", - sample_type: "DNA" + sample_type: "DNA", + aligner: "bwamem", ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -43,13 +44,11 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] - // aligner - input[2] = "bwamem" // markdup - input[3] = "bamsormadup" + input[2] = "bamsormadup" // roi - input[4] = "https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed" - input[5] = null + input[3] = "https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed" + input[4] = null """ } } @@ -90,7 +89,8 @@ nextflow_workflow { library: "test", organism: "Homo sapiens", tag: "WGS", - sample_type: "DNA" + sample_type: "DNA", + aligner: "bwamem", ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -112,13 +112,11 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] - // aligner - input[2] = "bwamem" // markdup - input[3] = "bamsormadup" + input[2] = "bamsormadup" // roi - input[4] = "" - input[5] = null + input[3] = "" + input[4] = null """ } } @@ -162,7 +160,8 @@ nextflow_workflow { library: "test", organism: "Homo sapiens", tag: "WES", - sample_type: "DNA" + sample_type: "DNA", + aligner: "bwamem", ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -184,13 +183,11 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] - // aligner - input[2] = "bwamem" // markdup - input[3] = "bamsormadup" + input[2] = "bamsormadup" // roi - input[4] = "https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed" - input[5] = null + input[3] = "https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed" + input[4] = null """ } } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 29e8f295..292b5b49 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -37,7 +37,6 @@ workflow PREPROCESSING { take: ch_samplesheet // channel: samplesheet read in from --input genomes // map: genome reference files - aligner // string: global aligner to use markdup // string: markdup method to use roi // file: regions of interest bed file to be applied to all samples genelists // file: directory containing genelist bed files for coverage analysis @@ -166,11 +165,6 @@ workflow PREPROCESSING { meta = meta + ["genome_data": [:]] } - // set the aligner - if (aligner && !meta.aligner) { - meta = meta + ["aligner": aligner] - } - // set the ROI // // Special case for coPGT samples // // if there's no global ROI AND no sample speficic ROI From 3907850fa3a78ce07c31f5e3f4cc7b796d89ab40 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:38:17 +0100 Subject: [PATCH 099/228] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6414d52..85b50d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The workflow now outputs data in a subdirectory per `library`, including a library specific MultiQC report - Drop support for unaligned cram outputs. - Add support for untrimmed fastq outputs for unsupported genomes or when aligner is set to `false`. +- Drop support for globle `aligner` parameter. The aligner must now be specified per sample in the sample sheet or sample info. ## v2.0.6 From eb69f58d7c6f6e8e7126393af405f5d8d0a6db01 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:38:36 +0100 Subject: [PATCH 100/228] typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85b50d0c..0d4b7bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The workflow now outputs data in a subdirectory per `library`, including a library specific MultiQC report - Drop support for unaligned cram outputs. - Add support for untrimmed fastq outputs for unsupported genomes or when aligner is set to `false`. -- Drop support for globle `aligner` parameter. The aligner must now be specified per sample in the sample sheet or sample info. +- Drop support for global `aligner` parameter. The aligner must now be specified per sample in the sample sheet or sample info. ## v2.0.6 From 10ca10007b30f3d659168b22b9c49343c1eee7a8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:56:08 +0100 Subject: [PATCH 101/228] update snapshot --- tests/workflows/preprocessing.nf.test.snap | 70 +++++++++++----------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 89d55ce7..6c072d58 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -87,6 +87,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "readgroup": { "CN": "CMGG", @@ -104,7 +105,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, @@ -148,6 +148,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -157,7 +158,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -175,6 +175,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -184,7 +185,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -202,6 +202,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -211,7 +212,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -232,6 +232,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -241,7 +242,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -259,6 +259,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -268,7 +269,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -286,6 +286,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -295,7 +296,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -313,6 +313,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -322,7 +323,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -340,6 +340,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -349,7 +350,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -367,6 +367,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -376,7 +377,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -521,6 +521,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -530,7 +531,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -548,6 +548,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -557,7 +558,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -575,6 +575,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -584,7 +585,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -602,6 +602,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -611,7 +612,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -629,6 +629,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -638,7 +639,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -666,7 +666,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T22:06:58.57247" + "timestamp": "2025-12-04T22:49:24.788115" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -756,6 +756,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "readgroup": { "CN": "CMGG", @@ -773,7 +774,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, @@ -895,6 +895,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -904,7 +905,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -922,6 +922,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -931,7 +932,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -949,6 +949,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -958,7 +959,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -976,6 +976,7 @@ "organism": "Homo sapiens", "tag": "WES", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -985,7 +986,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } @@ -1009,7 +1009,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T22:11:37.660609" + "timestamp": "2025-12-04T22:53:59.211177" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1097,6 +1097,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "readgroup": { "CN": "CMGG", @@ -1114,7 +1115,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "count": 1 }, "sample1.fastp.json:md5,caf903cc79784ceaa71d6ef743c02ff3" @@ -1156,6 +1156,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1165,7 +1166,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1182,6 +1182,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1191,7 +1192,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1208,6 +1208,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1217,7 +1218,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1237,6 +1237,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1246,7 +1247,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1263,6 +1263,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1272,7 +1273,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1298,6 +1298,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1307,7 +1308,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1448,6 +1448,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1457,7 +1458,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1474,6 +1474,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1483,7 +1484,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1500,6 +1500,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1509,7 +1510,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1526,6 +1526,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1535,7 +1536,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1552,6 +1552,7 @@ "organism": "Homo sapiens", "tag": "WGS", "sample_type": "DNA", + "aligner": "bwamem", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1561,7 +1562,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "aligner": "bwamem", "id": "sample1" } }, @@ -1588,6 +1588,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T22:09:54.979336" + "timestamp": "2025-12-04T22:52:15.051988" } } \ No newline at end of file From 9f433ebd1879d3c0711d7910d27ef44c3eb71cc0 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 5 Dec 2025 09:02:51 +0100 Subject: [PATCH 102/228] add GCP error codes to retry clause --- conf/base.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/base.config b/conf/base.config index 67db29f3..27606500 100644 --- a/conf/base.config +++ b/conf/base.config @@ -14,7 +14,7 @@ process { memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } maxRetries = 3 maxErrors = '-1' From 78655d03839c95be225b6882baba019b71b0287f Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Sun, 7 Dec 2025 08:00:14 +0100 Subject: [PATCH 103/228] improve MQC pool name --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index e1603297..0f975540 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -253,7 +253,7 @@ process { } withName: MULTIQC_LIBRARY { - ext.prefix = { meta.id ? "multiqc_library_${meta.id}" : "multiqc_library" } + ext.prefix = { meta.id ? "${meta.id}" : "multiqc_library" } ext.args = { meta.id ? "--title \"${meta.id} - Pool Summary\"" : '' } } } From 77c2139d278082201acd1648c3bec92451cbf2c9 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 8 Dec 2025 14:52:34 +0100 Subject: [PATCH 104/228] feat/improve_fq_shard --- CHANGELOG.md | 1 + conf/modules.config | 13 ++++++------- docs/parameters.md | 1 + nextflow.config | 1 + nextflow_schema.json | 15 +++++++++++++++ 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d4b7bef..2648d1d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Drop support for unaligned cram outputs. - Add support for untrimmed fastq outputs for unsupported genomes or when aligner is set to `false`. - Drop support for global `aligner` parameter. The aligner must now be specified per sample in the sample sheet or sample info. +- Simplify fastq sharding and make it user configurable via the `split_fastq` parameter. ## v2.0.6 diff --git a/conf/modules.config b/conf/modules.config index 0f975540..a001512a 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -32,13 +32,12 @@ process { withName: FASTP { ext.args = { [ - meta.single_end && reads.size() > 5000000000 ? "--split_by_lines 400000000" : "", - !meta.single_end && reads.any { f -> f.size() > 5000000000 } ? "--split_by_lines 400000000" : "", - params.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", - params.trim_front > 0 ? "--trim_front1 ${params.trim_front}" : "", - params.trim_tail > 0 ? "--trim_tail1 ${params.trim_tail}" : "", - params.adapter_R1 ? "--adapter_sequence ${params.adapter_R1}" : "", - params.adapter_R2 ? "--adapter_sequence_r2 ${params.adapter_R2}" : "", + params.split_fastq > 0 ? "--split_by_lines ${params.split_fastq * 4}" : '', + params.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", + params.trim_front > 0 ? "--trim_front1 ${params.trim_front}" : "", + params.trim_tail > 0 ? "--trim_tail1 ${params.trim_tail}" : "", + params.adapter_R1 ? "--adapter_sequence ${params.adapter_R1}" : "", + params.adapter_R2 ? "--adapter_sequence_r2 ${params.adapter_R2}" : "", "--compression 1", ].join(" ").trim() } diff --git a/docs/parameters.md b/docs/parameters.md index 914bd868..18c594f1 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -20,6 +20,7 @@ Define where the pipeline should find input data and save output data. | `markdup` | Which alignment postprocessor to use | `string` | bamsormadup | | | | `run_coverage` | Run coverage analysis steps | `boolean` | True | | | | `skip_trimming` | Skip adapter trimming | `boolean` | False | | | +| `split_fastq` | Number of reads per FastQ split (0 to disable splitting) | `integer` | 100000000 | | | | `trim_front` | Number of bases to trim from the front of the read | `integer` | 0 | | | | `trim_tail` | Number of bases to trim from the tail of the read | `integer` | 0 | | | | `adapter_R1` | Adapter sequence to be trimmed | `string` | None | | | diff --git a/nextflow.config b/nextflow.config index 44d91929..cd01f849 100644 --- a/nextflow.config +++ b/nextflow.config @@ -21,6 +21,7 @@ params { markdup = 'bamsormadup' umi_aware = false skip_trimming = false + split_fastq = 100000000 trim_front = 0 trim_tail = 0 adapter_R1 = null diff --git a/nextflow_schema.json b/nextflow_schema.json index d7b52ec4..efbaa2c0 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -72,6 +72,21 @@ "description": "Skip adapter trimming", "default": false }, + "split_fastq": { + "type": "integer", + "oneOf": [ + { + "minimum": 250 + }, + { + "const": 0 + } + ], + "default": 100000000, + "fa_icon": "fas fa-clock", + "description": "Specify how many reads each split of a FastQ file contains. Set 0 to turn off splitting at all.", + "help_text": "Use the the tool FastP to split FASTQ file by number of reads. This parallelizes across fastq file shards speeding up mapping. Note although the minimum value is 250 reads, if you have fewer than 250 reads a single FASTQ shard will still be created." + }, "trim_front": { "type": "integer", "default": 0, From aa5642bbb83a6d7841a5c2ffb9b07d831655c242 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:28:23 +0100 Subject: [PATCH 105/228] add optimized resources for WGS on GCP --- conf/modules.config | 14 +----- conf/profiles/gcp.config | 92 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 conf/profiles/gcp.config diff --git a/conf/modules.config b/conf/modules.config index a001512a..13de8a2f 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -14,11 +14,6 @@ process { // BCL convert withName: BCLCONVERT { - cpus = 32 - memory = 128.GB - disk = { 1.TB * task.attempt } - stageOutMode = 'copy' - ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", @@ -227,11 +222,6 @@ process { ext.prefix = { "${meta.id}.coverage" } } - //// CoverageQC (Multiqc) - // withName: ".*:COVERAGE:COVERAGEQC" { - // ext.args = { "--title \"Coverage ${meta.samplename ?: meta.id}\" } - // } - // QC withName: '.*BAM_QC.*' { @@ -240,8 +230,8 @@ process { //// Picard withName: '.*PICARD.*' { - memory = { 8.GB * task.attempt } - ext.args = "--MAX_RECORDS_IN_RAM 15000000" + memory = { 16.GB * task.attempt } + ext.args = "--MAX_RECORDS_IN_RAM 50000000" } diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config new file mode 100644 index 00000000..7460fe7d --- /dev/null +++ b/conf/profiles/gcp.config @@ -0,0 +1,92 @@ +// Tweaked resources for GCP + +process { + executor = 'google-batch' + disk = 100.GB + errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } + maxRetries = 5 + + // tentative fix for `cannot stat` error + // https://github.com/nextflow-io/nextflow/issues/6213#issuecomment-3173533808 + stageOutMode = 'copy' + + // BCL convert resources + withName: '.*PREPROCESSING:BCL_DEMULTIPLEX:BCLCONVERT' { + cpus = 32 + memory = { 64.GB * task.attempt } + disk = { 1.TB * task.attempt } + } + withName: '.*PREPROCESSING:BCL_DEMULTIPLEX:BCL2FASTQ' { + // Never used + } + + // Trimming resources + withName: '.*PREPROCESSING:FASTP' { + memory = { 4.GB * task.attempt } + } + + // Alignment resources + // DNA + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { + memory = 64.GB + } + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' { + memory = 64.GB + } + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' { + memory = 64.GB + } + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' { + memory = 64.GB + } + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { + memory = 64.GB + } + // RNA + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' { + memory = 64.GB + } + + // Alignment post-processing resources + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { + cpus = 16 + disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } + memory = 64.GB + time = 24.h + } + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORT' {} + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_CONVERT' {} + + // Coverage QC resources + withName: '.*PREPROCESSING:COVERAGE:MOSDEPTH' { + cpus = 4 + memory = 4.GB + } + withName: '.*PREPROCESSING:COVERAGE:SAMTOOLS_COVERAGE' { + cpus = 1 + memory = 1.GB + } + withName: '.*PREPROCESSING:COVERAGE:PANELCOVERAGE' {} + + // Bam QC resources + withName: '.*PREPROCESSING:BAM_QC:SAMTOOLS_.*$' { + cpus = 1 + memory = 1.GB + } + withName: '.*PREPROCESSING:BAM_QC:PICARD_.*$' { + cpus = 1 + memory = 16.GB + time = 24.h + } + + // Misc resources + withName: '.*PREPROCESSING:MD5SUM' { + cpus = 1 + memory = 128.MB + } + withName: '.*PREPROCESSING:MULTIQC_.*$' { + cpus = 1 + memory = 4.GB + } +} From 7b3fb476a66d1cfd9f5455d99f8647e8243c2cd0 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:31:55 +0100 Subject: [PATCH 106/228] add profile to config --- nextflow.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nextflow.config b/nextflow.config index cd01f849..f3ec3448 100644 --- a/nextflow.config +++ b/nextflow.config @@ -184,6 +184,8 @@ profiles { } test { includeConfig 'conf/test.config' } test_full { includeConfig 'conf/test_full.config' } + // resource profiles + gcp { includeConfig 'conf/profiles/gcp.config' } s3_ugent { includeConfig 'conf/profiles/s3_ugent.config' } // analysis profiles sWGS { includeConfig 'conf/profiles/sWGS.config' } From e47543786f498e7e79ec76f74523aa67df3c610d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 9 Dec 2025 10:59:22 +0100 Subject: [PATCH 107/228] apply cpu/mem as default, make module selectors more specific --- conf/modules.config | 87 +++++++++++++++++++++++++--------------- conf/profiles/gcp.config | 62 ++++++++-------------------- 2 files changed, 71 insertions(+), 78 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 13de8a2f..af8e1c73 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -13,7 +13,9 @@ process { // BCL convert - withName: BCLCONVERT { + withName: '.*PREPROCESSING:BCL_DEMULTIPLEX:BCLCONVERT' { + cpus = 16 + memory = { 64.GB * task.attempt } ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", @@ -24,7 +26,9 @@ process { } // FastP - withName: FASTP { + withName: '.*PREPROCESSING:FASTP' { + cpus = 4 + memory = { 4.GB * task.attempt } ext.args = { [ params.split_fastq > 0 ? "--split_by_lines ${params.split_fastq * 4}" : '', @@ -38,19 +42,6 @@ process { } } - // FASTQ_TO_UCRAM - //// Samtools Import - withName: '.*FASTQ_TO_UCRAM:SAMTOOLS_IMPORT' { - label = "process_medium" - ext.args = { - [ - meta.readgroup ? "--rg-line \"@RG\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\t") + "\"" : "", - "--output-fmt cram,version=3.0", - "--output-fmt-option archive", - ].join(" ").trim() - } - } - // FASTQ_TO_CRAM // Readgroup // Example: @@ -63,7 +54,9 @@ process { // SM : samplename //// Bowtie2 - withName: BOWTIE2_ALIGN { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { + cpus = 16 + memory = 32.GB ext.args = { [ "--local", @@ -76,7 +69,9 @@ process { } //// BWA mem/BWA mem2 - withName: 'BWAMEM.*_MEM' { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' { + cpus = 16 + memory = 32.GB ext.args = { [ "-K 100000000", @@ -91,7 +86,9 @@ process { } //// DRAGEN - withName: DRAGMAP_ALIGN { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' { + cpus = 16 + memory = 32.GB ext.args = { [ meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : "" @@ -109,7 +106,9 @@ process { // -xf 2 : expansion factor for reading compressed data //// SNAP - withName: SNAPALIGNER_ALIGN { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { + cpus = 16 + memory = 64.GB ext.args = { [ "-b-", @@ -125,7 +124,9 @@ process { } //// STROBEALIGN - withName: STROBEALIGN { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' { + cpus = 16 + memory = 32.GB ext.args = { [ meta.readgroup ? "--rg-id ${meta.readgroup.ID}" : "", @@ -136,7 +137,9 @@ process { } //// STAR - withName: STAR_ALIGN { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' { + cpus = 16 + memory = 64.GB ext.args = { [ "--readFilesCommand gunzip -c", @@ -153,7 +156,9 @@ process { //// Samtools sormadup - withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { + cpus = 16 + memory = 64.GB ext.prefix = { "${meta.id}.merged" } ext.args5 = { [ @@ -169,7 +174,9 @@ process { } //// Samtools multisort - withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORT' { + cpus = 16 + memory = 64.GB ext.prefix = { "${meta.id}.merged" } ext.args = { [ @@ -181,7 +188,9 @@ process { } //// BioBamBam Bamsormadup - withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' { + cpus = 8 + memory = 16.GB ext.prefix = { "${meta.id}.merged" } ext.args = { [ @@ -193,9 +202,9 @@ process { } //// Samtools convert - withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' { + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_CONVERT' { cpus = 8 - memory = 64.GB + memory = 8.GB ext.args = { [ "-C", @@ -207,7 +216,7 @@ process { // coverage //// Mosdepth - withName: '.*COVERAGE:MOSDEPTH' { + withName: '.*PREPROCESSING:COVERAGE:MOSDEPTH' { cpus = 4 memory = { 4.GB * task.attempt } ext.args = [ @@ -218,30 +227,44 @@ process { } //// Samtools coverage - withName: '.*:COVERAGE:SAMTOOLS_COVERAGE' { + withName: '.*PREPROCESSING:COVERAGE:SAMTOOLS_COVERAGE' { + cpus = 1 + memory = 1.GB ext.prefix = { "${meta.id}.coverage" } } // QC - withName: '.*BAM_QC.*' { + withName: '.*PREPROCESSING:BAM_QC:SAMTOOLS_.*$' { cpus = 1 + memory = 1.GB } //// Picard - withName: '.*PICARD.*' { + withName: '.*PREPROCESSING:BAM_QC:PICARD_.*$' { + cpus = 1 memory = { 16.GB * task.attempt } ext.args = "--MAX_RECORDS_IN_RAM 50000000" } + withName: '.*PREPROCESSING:MD5SUM' { + cpus = 1 + memory = 128.MB + } // MultiQC - withName: MULTIQC_MAIN { + withName: '.*PREPROCESSING:MULTIQC_.*$' { + cpus = 1 + memory = 4.GB + } + withName: '.*PREPROCESSING:MULTIQC_MAIN' { ext.prefix = { params.multiqc_title ? params.multiqc_title : "multiqc" } ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } } - withName: MULTIQC_LIBRARY { + withName: '.*PREPROCESSING:MULTIQC_LIBRARY' { + cpus = 1 + memory = 4.GB ext.prefix = { meta.id ? "${meta.id}" : "multiqc_library" } ext.args = { meta.id ? "--title \"${meta.id} - Pool Summary\"" : '' } } diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config index 7460fe7d..6ab54a96 100644 --- a/conf/profiles/gcp.config +++ b/conf/profiles/gcp.config @@ -21,72 +21,42 @@ process { } // Trimming resources - withName: '.*PREPROCESSING:FASTP' { - memory = { 4.GB * task.attempt } - } + withName: '.*PREPROCESSING:FASTP' {} // Alignment resources // DNA - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { - memory = 64.GB - } - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' { - memory = 64.GB - } - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' { - memory = 64.GB - } - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' { - memory = 64.GB - } - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { - memory = 64.GB - } + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' {} + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' {} + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' {} + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' {} + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' {} // RNA - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' { - memory = 64.GB - } + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' {} // Alignment post-processing resources withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { - cpus = 16 disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } - memory = 64.GB time = 24.h } - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORT' {} + withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORT' { + disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } + time = 24.h + } withName: '.*PREPROCESSING:FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_CONVERT' {} // Coverage QC resources - withName: '.*PREPROCESSING:COVERAGE:MOSDEPTH' { - cpus = 4 - memory = 4.GB - } - withName: '.*PREPROCESSING:COVERAGE:SAMTOOLS_COVERAGE' { - cpus = 1 - memory = 1.GB - } + withName: '.*PREPROCESSING:COVERAGE:MOSDEPTH' {} + withName: '.*PREPROCESSING:COVERAGE:SAMTOOLS_COVERAGE' {} withName: '.*PREPROCESSING:COVERAGE:PANELCOVERAGE' {} // Bam QC resources - withName: '.*PREPROCESSING:BAM_QC:SAMTOOLS_.*$' { - cpus = 1 - memory = 1.GB - } + withName: '.*PREPROCESSING:BAM_QC:SAMTOOLS_.*$' {} withName: '.*PREPROCESSING:BAM_QC:PICARD_.*$' { - cpus = 1 - memory = 16.GB time = 24.h } // Misc resources - withName: '.*PREPROCESSING:MD5SUM' { - cpus = 1 - memory = 128.MB - } - withName: '.*PREPROCESSING:MULTIQC_.*$' { - cpus = 1 - memory = 4.GB - } + withName: '.*PREPROCESSING:MD5SUM' {} + withName: '.*PREPROCESSING:MULTIQC_.*$' {} } From ef81280f397dd3f85de292adbe20cd3d9be4f7b1 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:11:27 +0100 Subject: [PATCH 108/228] update snapshot --- tests/workflows/preprocessing.nf.test.snap | 74 +++++++++++----------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 6c072d58..82cf9c36 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -108,7 +108,7 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, - "sample1.fastp.json:md5,caf903cc79784ceaa71d6ef743c02ff3" + "sample1.fastp.json:md5,2edca71b00e4804eb7b39ff72f1c304a" ] ], "md5sums": [ @@ -189,7 +189,7 @@ "id": "sample1" } }, - "sample1.per-base.bed.gz:md5,46115d39863826ae9199340c2eb888a6" + "sample1.per-base.bed.gz:md5,e5c10c94f3870f6ed2c75a904e9ade7f" ] ], "mosdepth_per_base_csi": [ @@ -216,7 +216,7 @@ "id": "sample1" } }, - "sample1.per-base.bed.gz.csi:md5,12fdbaf668bda28541b869adecc15dc7" + "sample1.per-base.bed.gz.csi:md5,b9223463b0f024768ebbbb3e42ace8da" ] ], "mosdepth_per_base_d4": [ @@ -327,7 +327,7 @@ "id": "sample1" } }, - "sample1.regions.bed.gz:md5,63a7fee57ae572a661fba2d14c6db1b4" + "sample1.regions.bed.gz:md5,6b7cc84380695011ffd0681dc79cefaa" ] ], "mosdepth_regions_csi": [ @@ -354,7 +354,7 @@ "id": "sample1" } }, - "sample1.regions.bed.gz.csi:md5,531956423eb6b53186ae4adc39e0e61e" + "sample1.regions.bed.gz.csi:md5,45cbd8c0f3d231c114a2d79d7dd21a80" ] ], "mosdepth_summary": [ @@ -381,7 +381,7 @@ "id": "sample1" } }, - "sample1.mosdepth.summary.txt:md5,cfd81f854b864f9630e8831b48cfc9a0" + "sample1.mosdepth.summary.txt:md5,f1f18d9bd23783bedb7f9e246e192a7e" ] ], "mosdepth_thresholds_bed": [ @@ -391,13 +391,13 @@ ], "multiqc_library_data": [ - "multiqc_library_test_data" + "test_data" ], "multiqc_library_plots": [ - "multiqc_library_test_plots" + "test_plots" ], "multiqc_library_report": [ - "multiqc_library_test.html" + "test.html" ], "multiqc_main_data": [ [ @@ -535,7 +535,7 @@ "id": "sample1" } }, - "sample1.coverage.txt:md5,82e6e6b4163459aeca0b9dd40ef67d13" + "sample1.coverage.txt:md5,656b7371132475783094d80b7d2292b5" ] ], "samtools_flagstat": [ @@ -562,7 +562,7 @@ "id": "sample1" } }, - "sample1.flagstat:md5,da197e74ff53116dd9b8b1241f468aac" + "sample1.flagstat:md5,cd826b1749737d52499cf543d101ecd2" ] ], "samtools_idxstats": [ @@ -589,7 +589,7 @@ "id": "sample1" } }, - "sample1.idxstats:md5,4e1b204d3bb59e42022c5d84be705ed8" + "sample1.idxstats:md5,ecc89a474dced28b0610f17a82785007" ] ], "samtools_stats": [ @@ -616,7 +616,7 @@ "id": "sample1" } }, - "sample1.stats:md5,33a10d02ce404301e012f07841815f59" + "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" ] ], "sormadup_metrics": [ @@ -643,7 +643,7 @@ "id": "sample1" } }, - "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" + "sample1.merged.metrics.txt:md5,01b7286134f5cb6530c3bab2c86fd169" ] ], "versions": [ @@ -666,7 +666,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T22:49:24.788115" + "timestamp": "2025-12-09T11:03:22.986076" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -777,7 +777,7 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, - "sample1.fastp.json:md5,caf903cc79784ceaa71d6ef743c02ff3" + "sample1.fastp.json:md5,2edca71b00e4804eb7b39ff72f1c304a" ] ], "md5sums": [ @@ -844,13 +844,13 @@ ], "multiqc_library_data": [ - "multiqc_library_test_data" + "test_data" ], "multiqc_library_plots": [ - "multiqc_library_test_plots" + "test_plots" ], "multiqc_library_report": [ - "multiqc_library_test.html" + "test.html" ], "multiqc_main_data": [ [ @@ -909,7 +909,7 @@ "id": "sample1" } }, - "sample1.flagstat:md5,da197e74ff53116dd9b8b1241f468aac" + "sample1.flagstat:md5,cd826b1749737d52499cf543d101ecd2" ] ], "samtools_idxstats": [ @@ -936,7 +936,7 @@ "id": "sample1" } }, - "sample1.idxstats:md5,4e1b204d3bb59e42022c5d84be705ed8" + "sample1.idxstats:md5,ecc89a474dced28b0610f17a82785007" ] ], "samtools_stats": [ @@ -963,7 +963,7 @@ "id": "sample1" } }, - "sample1.stats:md5,33a10d02ce404301e012f07841815f59" + "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" ] ], "sormadup_metrics": [ @@ -990,7 +990,7 @@ "id": "sample1" } }, - "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" + "sample1.merged.metrics.txt:md5,01b7286134f5cb6530c3bab2c86fd169" ] ], "versions": [ @@ -1009,7 +1009,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T22:53:59.211177" + "timestamp": "2025-12-09T11:09:14.114309" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1117,7 +1117,7 @@ }, "count": 1 }, - "sample1.fastp.json:md5,caf903cc79784ceaa71d6ef743c02ff3" + "sample1.fastp.json:md5,2edca71b00e4804eb7b39ff72f1c304a" ] ], "md5sums": [ @@ -1195,7 +1195,7 @@ "id": "sample1" } }, - "sample1.per-base.bed.gz:md5,46115d39863826ae9199340c2eb888a6" + "sample1.per-base.bed.gz:md5,e5c10c94f3870f6ed2c75a904e9ade7f" ] ], "mosdepth_per_base_csi": [ @@ -1221,7 +1221,7 @@ "id": "sample1" } }, - "sample1.per-base.bed.gz.csi:md5,12fdbaf668bda28541b869adecc15dc7" + "sample1.per-base.bed.gz.csi:md5,b9223463b0f024768ebbbb3e42ace8da" ] ], "mosdepth_per_base_d4": [ @@ -1311,7 +1311,7 @@ "id": "sample1" } }, - "sample1.mosdepth.summary.txt:md5,9799b90b7db86a6eab36f33b04a67ae0" + "sample1.mosdepth.summary.txt:md5,699b955719b06ff290edbe0692492213" ] ], "mosdepth_thresholds_bed": [ @@ -1321,13 +1321,13 @@ ], "multiqc_library_data": [ - "multiqc_library_test_data" + "test_data" ], "multiqc_library_plots": [ - "multiqc_library_test_plots" + "test_plots" ], "multiqc_library_report": [ - "multiqc_library_test.html" + "test.html" ], "multiqc_main_data": [ [ @@ -1461,7 +1461,7 @@ "id": "sample1" } }, - "sample1.coverage.txt:md5,82e6e6b4163459aeca0b9dd40ef67d13" + "sample1.coverage.txt:md5,656b7371132475783094d80b7d2292b5" ] ], "samtools_flagstat": [ @@ -1487,7 +1487,7 @@ "id": "sample1" } }, - "sample1.flagstat:md5,da197e74ff53116dd9b8b1241f468aac" + "sample1.flagstat:md5,cd826b1749737d52499cf543d101ecd2" ] ], "samtools_idxstats": [ @@ -1513,7 +1513,7 @@ "id": "sample1" } }, - "sample1.idxstats:md5,4e1b204d3bb59e42022c5d84be705ed8" + "sample1.idxstats:md5,ecc89a474dced28b0610f17a82785007" ] ], "samtools_stats": [ @@ -1539,7 +1539,7 @@ "id": "sample1" } }, - "sample1.stats:md5,33a10d02ce404301e012f07841815f59" + "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" ] ], "sormadup_metrics": [ @@ -1565,7 +1565,7 @@ "id": "sample1" } }, - "sample1.merged.metrics.txt:md5,ba50ddef3f0147526ed1f01a98c47ed6" + "sample1.merged.metrics.txt:md5,01b7286134f5cb6530c3bab2c86fd169" ] ], "versions": [ @@ -1588,6 +1588,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-04T22:52:15.051988" + "timestamp": "2025-12-09T11:06:50.62591" } } \ No newline at end of file From bac9ba626cad01d486829a746a2201830a388dcc Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:09:18 +0100 Subject: [PATCH 109/228] fix process selectors --- conf/modules.config | 40 ++++++++++++++++++++-------------------- conf/profiles/gcp.config | 40 ++++++++++++++++++++-------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index af8e1c73..b895b341 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -13,7 +13,7 @@ process { // BCL convert - withName: '.*PREPROCESSING:BCL_DEMULTIPLEX:BCLCONVERT' { + withName: '.*BCL_DEMULTIPLEX:BCLCONVERT' { cpus = 16 memory = { 64.GB * task.attempt } ext.args = { @@ -26,7 +26,7 @@ process { } // FastP - withName: '.*PREPROCESSING:FASTP' { + withName: '.*FASTP' { cpus = 4 memory = { 4.GB * task.attempt } ext.args = { @@ -54,7 +54,7 @@ process { // SM : samplename //// Bowtie2 - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { cpus = 16 memory = 32.GB ext.args = { @@ -69,7 +69,7 @@ process { } //// BWA mem/BWA mem2 - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' { + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' { cpus = 16 memory = 32.GB ext.args = { @@ -86,7 +86,7 @@ process { } //// DRAGEN - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' { + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' { cpus = 16 memory = 32.GB ext.args = { @@ -106,7 +106,7 @@ process { // -xf 2 : expansion factor for reading compressed data //// SNAP - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { cpus = 16 memory = 64.GB ext.args = { @@ -124,7 +124,7 @@ process { } //// STROBEALIGN - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' { + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' { cpus = 16 memory = 32.GB ext.args = { @@ -137,7 +137,7 @@ process { } //// STAR - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' { + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' { cpus = 16 memory = 64.GB ext.args = { @@ -156,7 +156,7 @@ process { //// Samtools sormadup - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { cpus = 16 memory = 64.GB ext.prefix = { "${meta.id}.merged" } @@ -174,7 +174,7 @@ process { } //// Samtools multisort - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORT' { + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { cpus = 16 memory = 64.GB ext.prefix = { "${meta.id}.merged" } @@ -188,7 +188,7 @@ process { } //// BioBamBam Bamsormadup - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' { + withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' { cpus = 8 memory = 16.GB ext.prefix = { "${meta.id}.merged" } @@ -202,7 +202,7 @@ process { } //// Samtools convert - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_CONVERT' { + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' { cpus = 8 memory = 8.GB ext.args = { @@ -216,7 +216,7 @@ process { // coverage //// Mosdepth - withName: '.*PREPROCESSING:COVERAGE:MOSDEPTH' { + withName: '.*COVERAGE:MOSDEPTH' { cpus = 4 memory = { 4.GB * task.attempt } ext.args = [ @@ -227,7 +227,7 @@ process { } //// Samtools coverage - withName: '.*PREPROCESSING:COVERAGE:SAMTOOLS_COVERAGE' { + withName: '.*COVERAGE:SAMTOOLS_COVERAGE' { cpus = 1 memory = 1.GB ext.prefix = { "${meta.id}.coverage" } @@ -235,34 +235,34 @@ process { // QC - withName: '.*PREPROCESSING:BAM_QC:SAMTOOLS_.*$' { + withName: '.*BAM_QC:SAMTOOLS_.*$' { cpus = 1 memory = 1.GB } //// Picard - withName: '.*PREPROCESSING:BAM_QC:PICARD_.*$' { + withName: '.*BAM_QC:PICARD_.*$' { cpus = 1 memory = { 16.GB * task.attempt } ext.args = "--MAX_RECORDS_IN_RAM 50000000" } - withName: '.*PREPROCESSING:MD5SUM' { + withName: '.*MD5SUM' { cpus = 1 memory = 128.MB } // MultiQC - withName: '.*PREPROCESSING:MULTIQC_.*$' { + withName: '.*MULTIQC_.*$' { cpus = 1 memory = 4.GB } - withName: '.*PREPROCESSING:MULTIQC_MAIN' { + withName: '.*MULTIQC_MAIN' { ext.prefix = { params.multiqc_title ? params.multiqc_title : "multiqc" } ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } } - withName: '.*PREPROCESSING:MULTIQC_LIBRARY' { + withName: '.*MULTIQC_LIBRARY' { cpus = 1 memory = 4.GB ext.prefix = { meta.id ? "${meta.id}" : "multiqc_library" } diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config index 6ab54a96..2662a4b8 100644 --- a/conf/profiles/gcp.config +++ b/conf/profiles/gcp.config @@ -11,52 +11,52 @@ process { stageOutMode = 'copy' // BCL convert resources - withName: '.*PREPROCESSING:BCL_DEMULTIPLEX:BCLCONVERT' { + withName: '.*BCL_DEMULTIPLEX:BCLCONVERT' { cpus = 32 memory = { 64.GB * task.attempt } disk = { 1.TB * task.attempt } } - withName: '.*PREPROCESSING:BCL_DEMULTIPLEX:BCL2FASTQ' { + withName: '.*BCL_DEMULTIPLEX:BCL2FASTQ' { // Never used } // Trimming resources - withName: '.*PREPROCESSING:FASTP' {} + withName: '.*FASTP' {} // Alignment resources // DNA - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' {} - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' {} - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' {} - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' {} - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' {} + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' {} + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' {} + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' {} + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' {} + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' {} // RNA - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' {} + withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' {} // Alignment post-processing resources - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } time = 24.h } - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_SORT' { + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } time = 24.h } - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} - withName: '.*PREPROCESSING:FASTQ_TO_CRAM:SAMTOOLS_CONVERT' {} + withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} + withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' {} // Coverage QC resources - withName: '.*PREPROCESSING:COVERAGE:MOSDEPTH' {} - withName: '.*PREPROCESSING:COVERAGE:SAMTOOLS_COVERAGE' {} - withName: '.*PREPROCESSING:COVERAGE:PANELCOVERAGE' {} + withName: '.*COVERAGE:MOSDEPTH' {} + withName: '.*COVERAGE:SAMTOOLS_COVERAGE' {} + withName: '.*COVERAGE:PANELCOVERAGE' {} // Bam QC resources - withName: '.*PREPROCESSING:BAM_QC:SAMTOOLS_.*$' {} - withName: '.*PREPROCESSING:BAM_QC:PICARD_.*$' { + withName: '.*BAM_QC:SAMTOOLS_.*$' {} + withName: '.*BAM_QC:PICARD_.*$' { time = 24.h } // Misc resources - withName: '.*PREPROCESSING:MD5SUM' {} - withName: '.*PREPROCESSING:MULTIQC_.*$' {} + withName: '.*MD5SUM' {} + withName: '.*MULTIQC_.*$' {} } From 02b268cb5500a799baa0b61bf15d1ceb5e9093a8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:13:19 +0100 Subject: [PATCH 110/228] update snapshots --- tests/subworkflows/local/coverage/main.nf.test.snap | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 2891b942..4df77336 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -35,7 +35,7 @@ "single_end": false, "tag": "WES" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.coverage.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] ], "13": [ @@ -242,7 +242,7 @@ "single_end": false, "tag": "WES" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.coverage.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] ], "versions": [ @@ -256,7 +256,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T12:34:24.897893" + "timestamp": "2025-12-09T12:02:48.263146" }, "Coverage - seqcap": { "content": [ @@ -294,7 +294,7 @@ "single_end": false, "tag": "seqcap" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.coverage.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] ], "13": [ @@ -486,7 +486,7 @@ "single_end": false, "tag": "seqcap" }, - "test.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" + "test.coverage.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] ], "versions": [ @@ -499,6 +499,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T12:34:05.200571" + "timestamp": "2025-12-09T12:02:26.604953" } } \ No newline at end of file From 419f66ef1aaa0b90fb608ee804676233ae2d1115 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:41:02 +0100 Subject: [PATCH 111/228] fix process selectors even more --- conf/modules.config | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index b895b341..7cd68402 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -54,7 +54,7 @@ process { // SM : samplename //// Bowtie2 - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { + withName: '.*FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { cpus = 16 memory = 32.GB ext.args = { @@ -69,7 +69,7 @@ process { } //// BWA mem/BWA mem2 - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' { + withName: '.*FASTQ_ALIGN_DNA:BWAMEM.*_MEM' { cpus = 16 memory = 32.GB ext.args = { @@ -86,7 +86,7 @@ process { } //// DRAGEN - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' { + withName: '.*FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' { cpus = 16 memory = 32.GB ext.args = { @@ -106,7 +106,7 @@ process { // -xf 2 : expansion factor for reading compressed data //// SNAP - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { + withName: '.*FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { cpus = 16 memory = 64.GB ext.args = { @@ -124,7 +124,7 @@ process { } //// STROBEALIGN - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' { + withName: '.*FASTQ_ALIGN_DNA:STROBEALIGN' { cpus = 16 memory = 32.GB ext.args = { @@ -137,7 +137,7 @@ process { } //// STAR - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' { + withName: '.*FASTQ_ALIGN_RNA:STAR_ALIGN' { cpus = 16 memory = 64.GB ext.args = { From 6b648ddc387bde7cb4130e349aefa51eeabe7078 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:41:03 +0100 Subject: [PATCH 112/228] gcp: comment unused selectors --- conf/profiles/gcp.config | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config index 2662a4b8..47cc2481 100644 --- a/conf/profiles/gcp.config +++ b/conf/profiles/gcp.config @@ -16,22 +16,19 @@ process { memory = { 64.GB * task.attempt } disk = { 1.TB * task.attempt } } - withName: '.*BCL_DEMULTIPLEX:BCL2FASTQ' { - // Never used - } // Trimming resources - withName: '.*FASTP' {} + // withName: '.*FASTP' {} // Alignment resources // DNA - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' {} - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' {} - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' {} - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' {} - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' {} + // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' {} + // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' {} + // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' {} + // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' {} + // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' {} // RNA - withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' {} + // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' {} // Alignment post-processing resources withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { @@ -42,21 +39,21 @@ process { disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } time = 24.h } - withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} - withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' {} + // withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} + // withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' {} // Coverage QC resources - withName: '.*COVERAGE:MOSDEPTH' {} - withName: '.*COVERAGE:SAMTOOLS_COVERAGE' {} - withName: '.*COVERAGE:PANELCOVERAGE' {} + // withName: '.*COVERAGE:MOSDEPTH' {} + // withName: '.*COVERAGE:SAMTOOLS_COVERAGE' {} + // withName: '.*COVERAGE:PANELCOVERAGE' {} // Bam QC resources - withName: '.*BAM_QC:SAMTOOLS_.*$' {} + // withName: '.*BAM_QC:SAMTOOLS_.*$' {} withName: '.*BAM_QC:PICARD_.*$' { time = 24.h } // Misc resources - withName: '.*MD5SUM' {} - withName: '.*MULTIQC_.*$' {} + // withName: '.*MD5SUM' {} + // withName: '.*MULTIQC_.*$' {} } From 6ae79743761abbfeabeba672d0f914068a21e76e Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:29:34 +0100 Subject: [PATCH 113/228] update gcp profile --- conf/profiles/gcp.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config index 47cc2481..1d3b072d 100644 --- a/conf/profiles/gcp.config +++ b/conf/profiles/gcp.config @@ -32,11 +32,11 @@ process { // Alignment post-processing resources withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { - disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } + disk = { input instanceof List ? input.size().sum() * 3 * task.attempt : input.size() * 3 * task.attempt } time = 24.h } withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { - disk = { input instanceof List ? input.size().sum() * 2 * task.attempt : input.size() * 2 * task.attempt } + disk = { input instanceof List ? input.size().sum() * 3 * task.attempt : input.size() * 3 * task.attempt } time = 24.h } // withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} From ae5956e9c9d3d636522c1f19946f6d376834eaf2 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 10 Dec 2025 15:35:15 +0100 Subject: [PATCH 114/228] bump multiqc --- modules.json | 2 +- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 8 ++--- modules/nf-core/multiqc/meta.yml | 26 +++++----------- modules/nf-core/multiqc/multiqc.diff | 11 +------ .../nf-core/multiqc/tests/main.nf.test.snap | 30 +++++++++---------- 6 files changed, 30 insertions(+), 49 deletions(-) diff --git a/modules.json b/modules.json index fe836420..3b24ee17 100644 --- a/modules.json +++ b/modules.json @@ -64,7 +64,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", + "git_sha": "9656d955b700a8707c4a67821ab056f8c1095675", "installed_by": ["modules"], "patch": "modules/nf-core/multiqc/multiqc.diff" }, diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index d02016a0..009874d4 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::multiqc=1.32 + - bioconda::multiqc=1.33 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 1d691b15..25c2a503 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -4,8 +4,8 @@ process MULTIQC { 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/8c/8c6c120d559d7ee04c7442b61ad7cf5a9e8970be5feefb37d68eeaa60c1034eb/data' : - 'community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf' }" + '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(multiqc_files, stageAs: "?/*") @@ -19,7 +19,8 @@ process MULTIQC { 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"'), emit: versions_multiqc + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), 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 @@ -51,6 +52,5 @@ process MULTIQC { touch multiqc_data/.stub mkdir multiqc_plots touch multiqc_report.html - """ } diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index 4a908611..e4b8f94d 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,6 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples - into a single report +description: Aggregate results from bioinformatics analyses across many samples into + a single report keywords: - QC - bioinformatics tools @@ -28,8 +28,8 @@ input: - 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. + 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 @@ -73,17 +73,6 @@ output: description: Plots created by MultiQC pattern: "*_data" ontologies: [] - versions_multiqc: - - - ${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: string - description: The command used to generate the version of the tool -topics: versions: - - ${task.process}: type: string @@ -91,9 +80,10 @@ topics: - multiqc: type: string description: The tool name - - multiqc --version | sed "s/.* //g: - type: string - description: The command used to generate the version of the tool + - multiqc --version | sed "s/.* //g": + type: eval + description: The expression to obtain the version of the tool + authors: - "@abhi18av" - "@bunop" diff --git a/modules/nf-core/multiqc/multiqc.diff b/modules/nf-core/multiqc/multiqc.diff index 73a5eb45..f0991afe 100644 --- a/modules/nf-core/multiqc/multiqc.diff +++ b/modules/nf-core/multiqc/multiqc.diff @@ -11,7 +11,7 @@ Changes in 'multiqc/main.nf': conda "${moduleDir}/environment.yml" @@ -7,7 +8,7 @@ - 'community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf' }" + 'community.wave.seqera.io/library/multiqc:1.33--ee7739d47738383b' }" input: - path multiqc_files, stageAs: "?/*" @@ -19,15 +19,6 @@ Changes in 'multiqc/main.nf': path(multiqc_config) path(extra_multiqc_config) path(multiqc_logo) -@@ -18,7 +19,7 @@ - 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"'), topic: versions, emit: versions_multiqc -+ tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions_multiqc - - when: - task.ext.when == null || task.ext.when 'modules/nf-core/multiqc/tests/main.nf.test.snap' is unchanged 'modules/nf-core/multiqc/tests/nextflow.config' is unchanged diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index f76049d3..d72d35b7 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -2,20 +2,20 @@ "sarscov2 single-end [fastqc]": { "content": [ { - "versions_multiqc": [ + "versions": [ [ "MULTIQC", "multiqc", - "1.32" + "1.33" ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-10-28T15:27:59.813370216" + "timestamp": "2025-12-09T10:10:43.020315838" }, "sarscov2 single-end [fastqc] - stub": { "content": [ @@ -24,38 +24,38 @@ "multiqc_data", "multiqc_plots", { - "versions_multiqc": [ + "versions": [ [ "MULTIQC", "multiqc", - "1.32" + "1.33" ] ] } ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-10-28T15:30:48.963962021" + "timestamp": "2025-12-09T10:11:14.131950776" }, "sarscov2 single-end [fastqc] [config]": { "content": [ { - "versions_multiqc": [ + "versions": [ [ "MULTIQC", "multiqc", - "1.32" + "1.33" ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-10-28T15:29:30.664969334" + "timestamp": "2025-12-09T10:11:07.15692209" } } \ No newline at end of file From f9104c13b62c84734abd56f6597a5fe3dc1f7ecd Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 11 Dec 2025 13:12:58 +0100 Subject: [PATCH 115/228] gcp: set default time to 24h --- conf/profiles/gcp.config | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config index 1d3b072d..577dd18d 100644 --- a/conf/profiles/gcp.config +++ b/conf/profiles/gcp.config @@ -3,6 +3,7 @@ process { executor = 'google-batch' disk = 100.GB + time = 24.h errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } maxRetries = 5 From 45df61cce3d3864d46ec653d09af074764bd332f Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 12 Dec 2025 16:36:53 +0100 Subject: [PATCH 116/228] increase samtools verbosity --- conf/modules.config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 7cd68402..2fc9ba9e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -160,8 +160,13 @@ process { cpus = 16 memory = 64.GB ext.prefix = { "${meta.id}.merged" } + ext.args = "--verbosity 5" + ext.args2 = "--verbosity 5" + ext.args3 = "--verbosity 5" + ext.args4 = "--verbosity 5" ext.args5 = { [ + "--verbosity 5", "-s", "--json", "-d 2500", From b0fa8989ea9aec02fd6f883271d074a93154e9c8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 12 Dec 2025 16:38:03 +0100 Subject: [PATCH 117/228] patch sormadup --- modules/nf-core/samtools/sormadup/main.nf | 1 - modules/nf-core/samtools/sormadup/samtools-sormadup.diff | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/nf-core/samtools/sormadup/main.nf b/modules/nf-core/samtools/sormadup/main.nf index 25541ed8..9bc8a43b 100644 --- a/modules/nf-core/samtools/sormadup/main.nf +++ b/modules/nf-core/samtools/sormadup/main.nf @@ -63,7 +63,6 @@ process SAMTOOLS_SORMADUP { -u \\ -T ${prefix}.sort \\ --threads $task.cpus \\ - -m ${sort_memory}M \\ - \\ | \\ samtools markdup \\ diff --git a/modules/nf-core/samtools/sormadup/samtools-sormadup.diff b/modules/nf-core/samtools/sormadup/samtools-sormadup.diff index f614f937..1e13bac8 100644 --- a/modules/nf-core/samtools/sormadup/samtools-sormadup.diff +++ b/modules/nf-core/samtools/sormadup/samtools-sormadup.diff @@ -14,6 +14,14 @@ Changes in 'samtools/sormadup/main.nf': output: tuple val(meta), path("*.bam") , emit: bam, optional: true +@@ -64,7 +63,6 @@ + -u \\ + -T ${prefix}.sort \\ + --threads $task.cpus \\ +- -m ${sort_memory}M \\ + - \\ + | \\ + samtools markdup \\ 'modules/nf-core/samtools/sormadup/tests/main.nf.test.snap' is unchanged 'modules/nf-core/samtools/sormadup/tests/bam.config' is unchanged From 44b94211b03010b3c357ad11c4a1c2d457ef61dd Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:53:38 +0100 Subject: [PATCH 118/228] rna: make sure the correct index is used --- subworkflows/local/fastq_to_aligned_cram/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index c00f4d75..09c4cec8 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -38,7 +38,7 @@ workflow FASTQ_TO_CRAM { ch_meta_reads_aligner_index_fasta_gtf .branch { meta, reads, aligner, index, fasta, gtf -> rna: meta.sample_type == "RNA" - return [meta, reads, "star", index, gtf] + return [meta, reads, "star", getGenomeAttribute(meta.genome_data, 'star'), gtf] dna: meta.sample_type == "DNA" || meta.sample_type == "Tissue" return [meta, reads, aligner, index, fasta] } From adfc3f08651106abec3c5f9177195b60a6246835 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 17 Dec 2025 13:33:48 +0100 Subject: [PATCH 119/228] add splice junctions and junctions to rna output --- conf/modules.config | 17 ++ main.nf | 10 + modules.json | 10 + modules/nf-core/cat/cat/environment.yml | 7 + modules/nf-core/cat/cat/main.nf | 78 +++++ modules/nf-core/cat/cat/meta.yml | 63 ++++ modules/nf-core/cat/cat/tests/main.nf.test | 192 ++++++++++++ .../nf-core/cat/cat/tests/main.nf.test.snap | 283 ++++++++++++++++++ modules/nf-core/cat/cat/tests/nextflow.config | 6 + modules/nf-core/gnu/sort/environment.yml | 7 + modules/nf-core/gnu/sort/main.nf | 48 +++ modules/nf-core/gnu/sort/meta.yml | 55 ++++ modules/nf-core/gnu/sort/tests/main.nf.test | 120 ++++++++ .../nf-core/gnu/sort/tests/main.nf.test.snap | 164 ++++++++++ .../gnu/sort/tests/sort_complex.config | 6 + .../gnu/sort/tests/sort_simple_bed.config | 6 + .../gnu/sort/tests/sort_simple_genome.config | 6 + subworkflows/local/fastq_align_rna/main.nf | 56 +++- .../local/fastq_to_aligned_cram/main.nf | 10 +- tests/default.nf.test | 16 + tests/inputs/fastq_rna.yml | 20 ++ workflows/preprocessing.nf | 2 + 22 files changed, 1174 insertions(+), 8 deletions(-) create mode 100644 modules/nf-core/cat/cat/environment.yml create mode 100644 modules/nf-core/cat/cat/main.nf create mode 100644 modules/nf-core/cat/cat/meta.yml create mode 100644 modules/nf-core/cat/cat/tests/main.nf.test create mode 100644 modules/nf-core/cat/cat/tests/main.nf.test.snap create mode 100644 modules/nf-core/cat/cat/tests/nextflow.config create mode 100644 modules/nf-core/gnu/sort/environment.yml create mode 100644 modules/nf-core/gnu/sort/main.nf create mode 100644 modules/nf-core/gnu/sort/meta.yml create mode 100644 modules/nf-core/gnu/sort/tests/main.nf.test create mode 100644 modules/nf-core/gnu/sort/tests/main.nf.test.snap create mode 100644 modules/nf-core/gnu/sort/tests/sort_complex.config create mode 100644 modules/nf-core/gnu/sort/tests/sort_simple_bed.config create mode 100644 modules/nf-core/gnu/sort/tests/sort_simple_genome.config create mode 100644 tests/inputs/fastq_rna.yml diff --git a/conf/modules.config b/conf/modules.config index 2fc9ba9e..d5364955 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -154,6 +154,23 @@ process { } } + withName: '.*FASTQ_ALIGN_RNA:CAT_SPLICE_JUNCTIONS' { + ext.prefix = { "${meta.id}.unsorted.Sj.out.tab" } + } + + withName: '.*FASTQ_ALIGN_RNA:CAT_JUNCTIONS' { + ext.prefix = { "${meta.id}.unsorted.Chimeric.out.junction" } + } + + withName: '.*FASTQ_ALIGN_RNA:SORT_SPLICE_JUNCTIONS' { + ext.prefix = { "${meta.id}.Sj.out" } + ext.args = '-k1,1n -k2,2n -k3,3n' + } + + withName: '.*FASTQ_ALIGN_RNA:SORT_JUNCTIONS' { + ext.prefix = { "${meta.id}.Chimeric.out" } + ext.args = '-k1,1n -k2,2n -k4,4n -k5,5n' + } //// Samtools sormadup withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { diff --git a/main.nf b/main.nf index 9c2b4a22..03dfac1a 100644 --- a/main.nf +++ b/main.nf @@ -71,6 +71,8 @@ workflow { fastp_json = PREPROCESSING.out.fastp_json fastp_html = PREPROCESSING.out.fastp_html crams = PREPROCESSING.out.crams + rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions + rna_junctions = PREPROCESSING.out.rna_junctions align_reports = PREPROCESSING.out.align_reports sormadup_metrics = PREPROCESSING.out.sormadup_metrics mosdepth_global = PREPROCESSING.out.mosdepth_global @@ -133,6 +135,14 @@ output { cram >> out_cram crai >> out_crai } } + rna_splice_junctions { path { meta, sjt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" + sjt >> out_path + } } + rna_junctions { path { meta, junctions -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" + junctions >> out_path + } } align_reports { path { meta, log -> def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" log >> out_path diff --git a/modules.json b/modules.json index 3b24ee17..8e111c49 100644 --- a/modules.json +++ b/modules.json @@ -40,6 +40,11 @@ "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, + "cat/cat": { + "branch": "master", + "git_sha": "69614d4579a6bd9b8a2ecffb35959809d9c36559", + "installed_by": ["modules"] + }, "dragmap/align": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", @@ -51,6 +56,11 @@ "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", "installed_by": ["modules"] }, + "gnu/sort": { + "branch": "master", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "installed_by": ["modules"] + }, "md5sum": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", diff --git a/modules/nf-core/cat/cat/environment.yml b/modules/nf-core/cat/cat/environment.yml new file mode 100644 index 00000000..98511769 --- /dev/null +++ b/modules/nf-core/cat/cat/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: + - conda-forge::pigz=2.8 diff --git a/modules/nf-core/cat/cat/main.nf b/modules/nf-core/cat/cat/main.nf new file mode 100644 index 00000000..aa72fc4d --- /dev/null +++ b/modules/nf-core/cat/cat/main.nf @@ -0,0 +1,78 @@ +process CAT_CAT { + tag "$meta.id" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/pigz:2.8' : + 'biocontainers/pigz:2.8' }" + + input: + tuple val(meta), path(files_in) + + output: + tuple val(meta), path("${prefix}"), emit: file_out + tuple val("${task.process}"), val("pigz"), eval("pigz --version 2>&1 | sed 's/pigz //g'"), topic: versions, emit: versions_cat + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def args2 = task.ext.args2 ?: '' + def file_list = files_in.collect { it.toString() } + + // choose appropriate concatenation tool depending on input and output format + + // | input | output | command1 | command2 | + // |-----------|------------|----------|----------| + // | gzipped | gzipped | cat | | + // | ungzipped | ungzipped | cat | | + // | gzipped | ungzipped | zcat | | + // | ungzipped | gzipped | cat | pigz | + + // Use input file ending as default + prefix = task.ext.prefix ?: "${meta.id}${getFileSuffix(file_list[0])}" + out_zip = prefix.endsWith('.gz') + in_zip = file_list[0].endsWith('.gz') + command1 = (in_zip && !out_zip) ? 'zcat' : 'cat' + command2 = (!in_zip && out_zip) ? "| pigz -c -p $task.cpus $args2" : '' + if(file_list.contains(prefix.trim())) { + error "The name of the input file can't be the same as for the output prefix in the " + + "module CAT_CAT (currently `$prefix`). Please choose a different one." + } + """ + $command1 \\ + $args \\ + ${file_list.join(' ')} \\ + $command2 \\ + > ${prefix} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) + END_VERSIONS + """ + + stub: + def file_list = files_in.collect { it.toString() } + prefix = task.ext.prefix ?: "${meta.id}${file_list[0].substring(file_list[0].lastIndexOf('.'))}" + if(file_list.contains(prefix.trim())) { + error "The name of the input file can't be the same as for the output prefix in the " + + "module CAT_CAT (currently `$prefix`). Please choose a different one." + } + """ + touch $prefix + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) + END_VERSIONS + """ +} + +// for .gz files also include the second to last extension if it is present. E.g., .fasta.gz +def getFileSuffix(filename) { + def match = filename =~ /^.*?((\.\w{1,5})?(\.\w{1,5}\.gz$))/ + return match ? match[0][1] : filename.substring(filename.lastIndexOf('.')) +} diff --git a/modules/nf-core/cat/cat/meta.yml b/modules/nf-core/cat/cat/meta.yml new file mode 100644 index 00000000..36a7359b --- /dev/null +++ b/modules/nf-core/cat/cat/meta.yml @@ -0,0 +1,63 @@ +name: cat_cat +description: A module for concatenation of gzipped or uncompressed files +keywords: + - concatenate + - gzip + - cat +tools: + - cat: + description: Just concatenation + documentation: https://man7.org/linux/man-pages/man1/cat.1.html + licence: ["GPL-3.0-or-later"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - files_in: + type: file + description: List of compressed / uncompressed files + pattern: "*" + ontologies: [] +output: + file_out: + - - meta: + type: map + description: Groovy Map containing sample information + - ${prefix}: + type: file + description: Concatenated file. Will be gzipped if file_out ends with + ".gz" + pattern: "${file_out}" + ontologies: [] + versions_cat: + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - "pigz --version 2>&1 | sed 's/pigz //g'": + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - "pigz --version 2>&1 | sed 's/pigz //g'": + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@erikrikarddaniel" + - "@FriederikeHanssen" +maintainers: + - "@erikrikarddaniel" + - "@FriederikeHanssen" diff --git a/modules/nf-core/cat/cat/tests/main.nf.test b/modules/nf-core/cat/cat/tests/main.nf.test new file mode 100644 index 00000000..030c6649 --- /dev/null +++ b/modules/nf-core/cat/cat/tests/main.nf.test @@ -0,0 +1,192 @@ +nextflow_process { + + name "Test Process CAT_CAT" + script "../main.nf" + process "CAT_CAT" + + tag "modules" + tag "modules_nfcore" + tag "cat" + tag "cat/cat" + + test("sarscov2 - genome - error: name conflict") { + when { + process { + """ + input[0] = + [ + [ id:'genome', single_end:true ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) + ] + ] + """ + } + } + then { + assertAll( + { assert !process.success }, + { assert process.stdout.toString().contains("The name of the input file can't be the same as for the output prefix") }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 - [ fasta, sizes ] - unzipped") { + when { + process { + """ + input[0] = + [ + [ id:'test', single_end:true ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) + ] + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + + test("sarscov2 - [ gff3_gz, maf_gz ] - zipped") { + when { + process { + """ + input[0] = + [ + [ id:'test', single_end:true ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gff3.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/alignment/last/contigs.genome.maf.gz', checkIfExists: true) + ] + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() + } + ) + } + } + + test("sarscov2 - [ gff3_gz, maf_gz ] - unzipped") { + config './nextflow.config' + + when { + params { + cat_prefix = "cat.txt" + } + process { + """ + input[0] = + [ + [ id:'test', single_end:true ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gff3.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/alignment/last/contigs.genome.maf.gz', checkIfExists: true) + ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("sarscov2 - [ fasta, sizes ] - zipped") { + config './nextflow.config' + + when { + params { + cat_prefix = "cat.txt.gz" + } + process { + """ + input[0] = + [ + [ id:'test', single_end:true ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) + ] + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 - fasta - zipped") { + config './nextflow.config' + + when { + params { + cat_prefix = "cat.txt.gz" + } + process { + """ + input[0] = + [ + [ id:'test', single_end:true ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 - fasta - unzipped - stub") { + options "-stub" + + when { + process { + """ + input[0] = + [ + [ id:'test', single_end:true ], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/cat/cat/tests/main.nf.test.snap b/modules/nf-core/cat/cat/tests/main.nf.test.snap new file mode 100644 index 00000000..5b4e4cc3 --- /dev/null +++ b/modules/nf-core/cat/cat/tests/main.nf.test.snap @@ -0,0 +1,283 @@ +{ + "sarscov2 - [ gff3_gz, maf_gz ] - unzipped": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "cat.txt:md5,c439d3b60e7bc03e8802a451a0d9a5d9" + ] + ], + "1": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ], + "file_out": [ + [ + { + "id": "test", + "single_end": true + }, + "cat.txt:md5,c439d3b60e7bc03e8802a451a0d9a5d9" + ] + ], + "versions_cat": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T09:08:31.479828" + }, + "sarscov2 - fasta - unzipped - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.fasta:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ], + "file_out": [ + [ + { + "id": "test", + "single_end": true + }, + "test.fasta:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_cat": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T16:16:28.118094" + }, + "sarscov2 - [ fasta, sizes ] - zipped": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "cat.txt.gz:md5,f44b33a0e441ad58b2d3700270e2dbe2" + ] + ], + "1": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ], + "file_out": [ + [ + { + "id": "test", + "single_end": true + }, + "cat.txt.gz:md5,f44b33a0e441ad58b2d3700270e2dbe2" + ] + ], + "versions_cat": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T16:15:56.529595" + }, + "sarscov2 - genome - error: name conflict": { + "content": [ + { + "0": [ + + ], + "1": [ + + ], + "file_out": [ + + ], + "versions_cat": [ + + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T16:14:54.496538" + }, + "sarscov2 - [ fasta, sizes ] - unzipped": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.fasta:md5,f44b33a0e441ad58b2d3700270e2dbe2" + ] + ], + "1": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ], + "file_out": [ + [ + { + "id": "test", + "single_end": true + }, + "test.fasta:md5,f44b33a0e441ad58b2d3700270e2dbe2" + ] + ], + "versions_cat": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T11:26:29.942203" + }, + "sarscov2 - [ gff3_gz, maf_gz ] - zipped": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.gff3.gz:md5,c439d3b60e7bc03e8802a451a0d9a5d9" + ] + ], + "1": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ], + "file_out": [ + [ + { + "id": "test", + "single_end": true + }, + "test.gff3.gz:md5,c439d3b60e7bc03e8802a451a0d9a5d9" + ] + ], + "versions_cat": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T11:26:45.679401" + }, + "sarscov2 - fasta - zipped": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "cat.txt.gz:md5,6e9fe4042a72f2345f644f239272b7e6" + ] + ], + "1": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ], + "file_out": [ + [ + { + "id": "test", + "single_end": true + }, + "cat.txt.gz:md5,6e9fe4042a72f2345f644f239272b7e6" + ] + ], + "versions_cat": [ + [ + "CAT_CAT", + "pigz", + "2.8" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T16:16:12.439911" + } +} \ No newline at end of file diff --git a/modules/nf-core/cat/cat/tests/nextflow.config b/modules/nf-core/cat/cat/tests/nextflow.config new file mode 100644 index 00000000..5bc9bf50 --- /dev/null +++ b/modules/nf-core/cat/cat/tests/nextflow.config @@ -0,0 +1,6 @@ + +process { + withName: CAT_CAT { + ext.prefix = "${params.cat_prefix}" + } +} diff --git a/modules/nf-core/gnu/sort/environment.yml b/modules/nf-core/gnu/sort/environment.yml new file mode 100644 index 00000000..0c4cd942 --- /dev/null +++ b/modules/nf-core/gnu/sort/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: + - conda-forge::coreutils=9.5 diff --git a/modules/nf-core/gnu/sort/main.nf b/modules/nf-core/gnu/sort/main.nf new file mode 100644 index 00000000..6190210d --- /dev/null +++ b/modules/nf-core/gnu/sort/main.nf @@ -0,0 +1,48 @@ +process GNU_SORT { + tag "$meta.id" + label "process_low" + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/coreutils:9.5': + 'biocontainers/coreutils:9.5' }" + + input: + tuple val(meta), path(input) + + output: + tuple val(meta), path( "${output_file}" ) , emit: sorted + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + suffix = task.ext.suffix ?: "${input.extension}" + output_file = "${prefix}.${suffix}" + if ("$input" == "$output_file") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + """ + sort ${args} ${input} > ${output_file} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + coreutils: \$(sort --version |& sed '1!d ; s/sort (GNU coreutils) //') + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + suffix = task.ext.suffix ?: "${input.extension}" + output_file = "${prefix}.${suffix}" + if ("$input" == "$output_file") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" + """ + touch ${output_file} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + coreutils: \$(sort --version |& sed '1!d ; s/sort (GNU coreutils) //') + END_VERSIONS + """ +} diff --git a/modules/nf-core/gnu/sort/meta.yml b/modules/nf-core/gnu/sort/meta.yml new file mode 100644 index 00000000..feba2c1f --- /dev/null +++ b/modules/nf-core/gnu/sort/meta.yml @@ -0,0 +1,55 @@ +name: "gnu_sort" +description: | + Writes a sorted concatenation of file/s +keywords: + - GNU + - coreutils + - sort + - merge compare +tools: + - gnu: + description: "The GNU Core Utilities are the basic file, shell and text manipulation + utilities of the GNU operating system. These are the core utilities which are + expected to exist on every operating system." + homepage: "https://www.gnu.org/software/coreutils/" + documentation: "https://www.gnu.org/software/coreutils/manual/html_node/index.html" + tool_dev_url: "https://git.savannah.gnu.org/cgit/coreutils.git" + doi: "10.5281/zenodo.581670" + licence: ["GPL"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: Draft assembly file + pattern: "*.{txt,bed,interval,genome,bins}" + ontologies: [] +output: + sorted: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + pattern: "${output_file}" + - "${output_file}": + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + pattern: "${output_file}" + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@DLBPointon" +maintainers: + - "@DLBPointon" diff --git a/modules/nf-core/gnu/sort/tests/main.nf.test b/modules/nf-core/gnu/sort/tests/main.nf.test new file mode 100644 index 00000000..e4030187 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/main.nf.test @@ -0,0 +1,120 @@ +nextflow_process { + + name "Test Process GNU_SORT" + script "modules/nf-core/gnu/sort/main.nf" + process "GNU_SORT" + + tag "modules" + tag "modules_nfcore" + tag "gnu" + tag "gnu/sort" + + test("unsorted_genome_sort") { + config "./sort_simple_bed.config" + + when { + process { + """ + input[0] = [ + [id:'genome_test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['genome_file'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + { assert snapshot( + file(process.out.sorted[0][1]).name + ).match("genome_sort") + } + ) + } + + } + + test("unsorted_intervals_sort") { + config "./sort_simple_bed.config" + when { + process { + """ + input[0] = [ + [id:'test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['intervals'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + { assert snapshot( + file(process.out.sorted[0][1]).name + ).match("interval_sort") + } + ) + } + + } + + test("unsorted_csv_sort") { + config "./sort_complex.config" + + when { + process { + """ + input[0] = [ + [id:'test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['numbers_csv'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + { assert snapshot( + file(process.out.sorted[0][1]).name + ).match("csv_sort") + } + ) + } + + } + + test("unsorted_csv_sort_stub") { + config "./sort_complex.config" + options "-stub" + + when { + process { + """ + input[0] = [ + [id:'test'], + file(params.test_data['generic']['unsorted_data']['unsorted_text']['numbers_csv'], + checkIfExists: true) + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() }, + ) + } + + } + +} diff --git a/modules/nf-core/gnu/sort/tests/main.nf.test.snap b/modules/nf-core/gnu/sort/tests/main.nf.test.snap new file mode 100644 index 00000000..20e17080 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/main.nf.test.snap @@ -0,0 +1,164 @@ +{ + "unsorted_csv_sort": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,0b52d1b4c4a0c6e972c6f94aafd75a1d" + ] + ], + "1": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,0b52d1b4c4a0c6e972c6f94aafd75a1d" + ] + ], + "versions": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-04-30T14:27:50.564838" + }, + "interval_sort": { + "content": [ + "test.bed.sorted" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-04-30T14:27:34.740893" + }, + "unsorted_csv_sort_stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test.csv.sorted:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-04-30T14:28:06.468116" + }, + "csv_sort": { + "content": [ + "test.csv.sorted" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-04-30T14:27:50.596931" + }, + "unsorted_genome_sort": { + "content": [ + { + "0": [ + [ + { + "id": "genome_test" + }, + "genome_test.bed.sorted:md5,fd97f7efafdbbfa71d9b560f10b4b048" + ] + ], + "1": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ], + "sorted": [ + [ + { + "id": "genome_test" + }, + "genome_test.bed.sorted:md5,fd97f7efafdbbfa71d9b560f10b4b048" + ] + ], + "versions": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-04-30T14:27:19.192354" + }, + "genome_sort": { + "content": [ + "genome_test.bed.sorted" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-04-30T14:27:19.234221" + }, + "unsorted_intervals_sort": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bed.sorted:md5,abbce903ef263d38b2f71856387799ab" + ] + ], + "1": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ], + "sorted": [ + [ + { + "id": "test" + }, + "test.bed.sorted:md5,abbce903ef263d38b2f71856387799ab" + ] + ], + "versions": [ + "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-04-30T14:27:34.711885" + } +} \ No newline at end of file diff --git a/modules/nf-core/gnu/sort/tests/sort_complex.config b/modules/nf-core/gnu/sort/tests/sort_complex.config new file mode 100644 index 00000000..ce4f1518 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/sort_complex.config @@ -0,0 +1,6 @@ +process { + withName: GNU_SORT { + ext.args = { "-t ';' -g -k 1,1 -k 2,2" } + ext.suffix = { "csv.sorted" } + } +} diff --git a/modules/nf-core/gnu/sort/tests/sort_simple_bed.config b/modules/nf-core/gnu/sort/tests/sort_simple_bed.config new file mode 100644 index 00000000..8496c8d7 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/sort_simple_bed.config @@ -0,0 +1,6 @@ +process { + withName: GNU_SORT { + ext.args = { "-k1,1 -k2,2n" } + ext.suffix = { "bed.sorted" } + } +} diff --git a/modules/nf-core/gnu/sort/tests/sort_simple_genome.config b/modules/nf-core/gnu/sort/tests/sort_simple_genome.config new file mode 100644 index 00000000..c408ece1 --- /dev/null +++ b/modules/nf-core/gnu/sort/tests/sort_simple_genome.config @@ -0,0 +1,6 @@ +process { + withName: GNU_SORT { + ext.args = { "-k1,1 -k2,2n" } + ext.suffix = { "genome.sorted" } + } +} diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index 03b9c585..ed99fa48 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -5,7 +5,11 @@ // -include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" +include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" +include { CAT_CAT as CAT_JUNCTIONS } from "../../../modules/nf-core/cat/cat/main.nf" +include { CAT_CAT as CAT_SPLICE_JUNCTIONS } from "../../../modules/nf-core/cat/cat/main.nf" +include { GNU_SORT as SORT_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" +include { GNU_SORT as SORT_SPLICE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" workflow FASTQ_ALIGN_RNA { take: @@ -40,8 +44,52 @@ workflow FASTQ_ALIGN_RNA { ) ch_versions = ch_versions.mix(STAR_ALIGN.out.versions.first()) + // Concatenate splice junction files + def ch_splice_junctions_to_merge = group_junctions(STAR_ALIGN.out.spl_junc_tab) + + CAT_SPLICE_JUNCTIONS(ch_splice_junctions_to_merge) + SORT_SPLICE_JUNCTIONS(CAT_SPLICE_JUNCTIONS.out.file_out) + ch_versions = ch_versions.mix(SORT_SPLICE_JUNCTIONS.out.versions.first()) + + // Concatenate junction files + def ch_junctions_to_merge = group_junctions(STAR_ALIGN.out.junction) + + CAT_JUNCTIONS(ch_junctions_to_merge) + SORT_JUNCTIONS(CAT_JUNCTIONS.out.file_out) + ch_versions = ch_versions.mix(SORT_JUNCTIONS.out.versions.first()) + emit: - bam = ch_bam // channel: [ [meta], bam ] - reports = ch_reports // channel: [ [meta], log ] - versions = ch_versions // channel: [ versions.yml ] + bam = ch_bam // channel: [ [meta], bam ] + splice_junctions = SORT_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] + junctions = SORT_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] + reports = ch_reports // channel: [ [meta], log ] + versions = ch_versions // channel: [ versions.yml ] +} + +def group_junctions(ch) { + return ch.map { meta, files -> + def gk = (meta.chunks as Integer ?: 1) + return [ + groupKey( + meta - meta.subMap('readgroup', 'chunks') + [id: meta.id ==~ /^\d{4}\..*$/ ? meta.id[5..-1] : meta.id], + gk, + ), + files, + ] + } + .groupTuple() + .map { meta, files -> + def gk = (meta.count as Integer ?: 1) + return [ + groupKey( + meta - meta.subMap('count') + [id: meta.samplename ?: meta.id], + gk, + ), + files, + ] + } + .groupTuple() + .map { meta, files -> + return [meta, files.flatten()] + } } diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index c00f4d75..8c0cf445 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -151,8 +151,10 @@ workflow FASTQ_TO_CRAM { ch_cram_crai.dump(tag: "FASTQ_TO_CRAM: cram and crai", pretty: true) emit: - cram_crai = ch_cram_crai - sormadup_metrics = ch_sormadup_metrics - align_reports = FASTQ_ALIGN_DNA.out.reports - versions = ch_versions + cram_crai = ch_cram_crai + rna_splice_junctions = FASTQ_ALIGN_RNA.out.splice_junctions + rna_junctions = FASTQ_ALIGN_RNA.out.junctions + sormadup_metrics = ch_sormadup_metrics + align_reports = FASTQ_ALIGN_DNA.out.reports + versions = ch_versions } diff --git a/tests/default.nf.test b/tests/default.nf.test index ba9b69e3..66a790d4 100644 --- a/tests/default.nf.test +++ b/tests/default.nf.test @@ -39,4 +39,20 @@ nextflow_pipeline { } + test("main - fastq RNA input") { + + when { + params { + input = "${projectDir}/tests/inputs/fastq_rna.yml" + igenomes_base = "s3://reference-data/genomes" + outdir = "$outputDir" + } + } + + then { + assert workflow.success + } + + } + } diff --git a/tests/inputs/fastq_rna.yml b/tests/inputs/fastq_rna.yml new file mode 100644 index 00000000..878dab22 --- /dev/null +++ b/tests/inputs/fastq_rna.yml @@ -0,0 +1,20 @@ +--- +# fastq inputs +- id: sample1_L001 + samplename: fastq_paired1 + library: test_library + organism: Homo sapiens + tag: WES + sample_type: RNA + aligner: star + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz +- id: sample1_L002 + samplename: fastq_paired1 + library: test_library + organism: Homo sapiens + tag: WES + sample_type: RNA + aligner: star + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 292b5b49..9149e445 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -488,6 +488,8 @@ workflow PREPROCESSING { fastp_json = FASTP.out.json fastp_html = FASTP.out.html crams = FASTQ_TO_CRAM.out.cram_crai + rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions + rna_junctions = FASTQ_TO_CRAM.out.rna_junctions align_reports = FASTQ_TO_CRAM.out.align_reports sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics mosdepth_global = mosdepth_global_out From cf107cf1f34e9f6bb0c939f146ebdfb47b20dbf3 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 17 Dec 2025 13:35:09 +0100 Subject: [PATCH 120/228] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2648d1d9..def4121f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add support for untrimmed fastq outputs for unsupported genomes or when aligner is set to `false`. - Drop support for global `aligner` parameter. The aligner must now be specified per sample in the sample sheet or sample info. - Simplify fastq sharding and make it user configurable via the `split_fastq` parameter. +- Added splice junctions and junctions outputs for RNA-seq alignments using STAR. ## v2.0.6 From 4bf8735b9ce7ad108397eb66c84861d3e47a72b2 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 17 Dec 2025 14:11:18 +0100 Subject: [PATCH 121/228] merge with the sort module --- conf/modules.config | 18 +- modules.json | 131 +++++--- modules/nf-core/cat/cat/environment.yml | 7 - modules/nf-core/cat/cat/main.nf | 78 ----- modules/nf-core/cat/cat/meta.yml | 63 ---- modules/nf-core/cat/cat/tests/main.nf.test | 192 ------------ .../nf-core/cat/cat/tests/main.nf.test.snap | 283 ------------------ modules/nf-core/cat/cat/tests/nextflow.config | 6 - subworkflows/local/fastq_align_rna/main.nf | 22 +- 9 files changed, 110 insertions(+), 690 deletions(-) delete mode 100644 modules/nf-core/cat/cat/environment.yml delete mode 100644 modules/nf-core/cat/cat/main.nf delete mode 100644 modules/nf-core/cat/cat/meta.yml delete mode 100644 modules/nf-core/cat/cat/tests/main.nf.test delete mode 100644 modules/nf-core/cat/cat/tests/main.nf.test.snap delete mode 100644 modules/nf-core/cat/cat/tests/nextflow.config diff --git a/conf/modules.config b/conf/modules.config index d5364955..9aa74e0e 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -154,22 +154,16 @@ process { } } - withName: '.*FASTQ_ALIGN_RNA:CAT_SPLICE_JUNCTIONS' { - ext.prefix = { "${meta.id}.unsorted.Sj.out.tab" } - } - - withName: '.*FASTQ_ALIGN_RNA:CAT_JUNCTIONS' { - ext.prefix = { "${meta.id}.unsorted.Chimeric.out.junction" } - } - - withName: '.*FASTQ_ALIGN_RNA:SORT_SPLICE_JUNCTIONS' { + withName: '.*FASTQ_ALIGN_RNA:SORT_MERGE_SPLICE_JUNCTIONS' { ext.prefix = { "${meta.id}.Sj.out" } - ext.args = '-k1,1n -k2,2n -k3,3n' + ext.suffix = "tab" + ext.args = '-k1,1n -k2,2n -k3,3n --merge' } - withName: '.*FASTQ_ALIGN_RNA:SORT_JUNCTIONS' { + withName: '.*FASTQ_ALIGN_RNA:SORT_MERGE_JUNCTIONS' { ext.prefix = { "${meta.id}.Chimeric.out" } - ext.args = '-k1,1n -k2,2n -k4,4n -k5,5n' + ext.suffix = "junction" + ext.args = '-k1,1n -k2,2n -k4,4n -k5,5n --merge' } //// Samtools sormadup diff --git a/modules.json b/modules.json index 8e111c49..c83142f7 100644 --- a/modules.json +++ b/modules.json @@ -8,150 +8,199 @@ "bcl2fastq": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["bcl_demultiplex"] + "installed_by": [ + "bcl_demultiplex" + ] }, "bclconvert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["bcl_demultiplex", "modules"], + "installed_by": [ + "bcl_demultiplex", + "modules" + ], "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, "biobambam/bamsormadup": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, "bowtie2/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", "git_sha": "d86336f3e7ae0d5f76c67b0859409769cfeb2af2", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, - "cat/cat": { - "branch": "master", - "git_sha": "69614d4579a6bd9b8a2ecffb35959809d9c36559", - "installed_by": ["modules"] - }, "dragmap/align": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": ["fastq_align_dna"], + "installed_by": [ + "fastq_align_dna" + ], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, "fastp": { "branch": "master", "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "gnu/sort": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "md5sum": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "mosdepth": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, "multiqc": { "branch": "master", "git_sha": "9656d955b700a8707c4a67821ab056f8c1095675", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/multiqc/multiqc.diff" }, "picard/collecthsmetrics": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, "samtools/convert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, "samtools/flagstat": { "branch": "master", "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/idxstats": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"] + "installed_by": [ + "modules" + ] }, "samtools/sormadup": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, "samtools/sort": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "samtools/stats": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, "snapaligner/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, "star/align": { "branch": "master", "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", - "installed_by": ["modules"], + "installed_by": [ + "modules" + ], "patch": "modules/nf-core/star/align/star-align.diff" }, "strobealign": { "branch": "master", "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", - "installed_by": ["fastq_align_dna", "modules"], + "installed_by": [ + "fastq_align_dna", + "modules" + ], "patch": "modules/nf-core/strobealign/strobealign.diff" } } @@ -161,30 +210,40 @@ "bcl_demultiplex": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "fastq_align_dna": { "branch": "master", "git_sha": "070ddae7fb59384d3d85bf69eb9a1d71ab33ada9", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "df4d1c8cdee98a1bbbed8fc51e82296568e0f9c1", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] }, "utils_nfschema_plugin": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["subworkflows"] + "installed_by": [ + "subworkflows" + ] } } } } } -} +} \ No newline at end of file diff --git a/modules/nf-core/cat/cat/environment.yml b/modules/nf-core/cat/cat/environment.yml deleted file mode 100644 index 98511769..00000000 --- a/modules/nf-core/cat/cat/environment.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json -channels: - - conda-forge - - bioconda -dependencies: - - conda-forge::pigz=2.8 diff --git a/modules/nf-core/cat/cat/main.nf b/modules/nf-core/cat/cat/main.nf deleted file mode 100644 index aa72fc4d..00000000 --- a/modules/nf-core/cat/cat/main.nf +++ /dev/null @@ -1,78 +0,0 @@ -process CAT_CAT { - tag "$meta.id" - label 'process_low' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/pigz:2.8' : - 'biocontainers/pigz:2.8' }" - - input: - tuple val(meta), path(files_in) - - output: - tuple val(meta), path("${prefix}"), emit: file_out - tuple val("${task.process}"), val("pigz"), eval("pigz --version 2>&1 | sed 's/pigz //g'"), topic: versions, emit: versions_cat - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - def args2 = task.ext.args2 ?: '' - def file_list = files_in.collect { it.toString() } - - // choose appropriate concatenation tool depending on input and output format - - // | input | output | command1 | command2 | - // |-----------|------------|----------|----------| - // | gzipped | gzipped | cat | | - // | ungzipped | ungzipped | cat | | - // | gzipped | ungzipped | zcat | | - // | ungzipped | gzipped | cat | pigz | - - // Use input file ending as default - prefix = task.ext.prefix ?: "${meta.id}${getFileSuffix(file_list[0])}" - out_zip = prefix.endsWith('.gz') - in_zip = file_list[0].endsWith('.gz') - command1 = (in_zip && !out_zip) ? 'zcat' : 'cat' - command2 = (!in_zip && out_zip) ? "| pigz -c -p $task.cpus $args2" : '' - if(file_list.contains(prefix.trim())) { - error "The name of the input file can't be the same as for the output prefix in the " + - "module CAT_CAT (currently `$prefix`). Please choose a different one." - } - """ - $command1 \\ - $args \\ - ${file_list.join(' ')} \\ - $command2 \\ - > ${prefix} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS - """ - - stub: - def file_list = files_in.collect { it.toString() } - prefix = task.ext.prefix ?: "${meta.id}${file_list[0].substring(file_list[0].lastIndexOf('.'))}" - if(file_list.contains(prefix.trim())) { - error "The name of the input file can't be the same as for the output prefix in the " + - "module CAT_CAT (currently `$prefix`). Please choose a different one." - } - """ - touch $prefix - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS - """ -} - -// for .gz files also include the second to last extension if it is present. E.g., .fasta.gz -def getFileSuffix(filename) { - def match = filename =~ /^.*?((\.\w{1,5})?(\.\w{1,5}\.gz$))/ - return match ? match[0][1] : filename.substring(filename.lastIndexOf('.')) -} diff --git a/modules/nf-core/cat/cat/meta.yml b/modules/nf-core/cat/cat/meta.yml deleted file mode 100644 index 36a7359b..00000000 --- a/modules/nf-core/cat/cat/meta.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: cat_cat -description: A module for concatenation of gzipped or uncompressed files -keywords: - - concatenate - - gzip - - cat -tools: - - cat: - description: Just concatenation - documentation: https://man7.org/linux/man-pages/man1/cat.1.html - licence: ["GPL-3.0-or-later"] - identifier: "" -input: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - files_in: - type: file - description: List of compressed / uncompressed files - pattern: "*" - ontologies: [] -output: - file_out: - - - meta: - type: map - description: Groovy Map containing sample information - - ${prefix}: - type: file - description: Concatenated file. Will be gzipped if file_out ends with - ".gz" - pattern: "${file_out}" - ontologies: [] - versions_cat: - - - ${task.process}: - type: string - description: The name of the process - - pigz: - type: string - description: The name of the tool - - "pigz --version 2>&1 | sed 's/pigz //g'": - type: eval - description: The expression to obtain the version of the tool - -topics: - versions: - - - ${task.process}: - type: string - description: The name of the process - - pigz: - type: string - description: The name of the tool - - "pigz --version 2>&1 | sed 's/pigz //g'": - type: eval - description: The expression to obtain the version of the tool - -authors: - - "@erikrikarddaniel" - - "@FriederikeHanssen" -maintainers: - - "@erikrikarddaniel" - - "@FriederikeHanssen" diff --git a/modules/nf-core/cat/cat/tests/main.nf.test b/modules/nf-core/cat/cat/tests/main.nf.test deleted file mode 100644 index 030c6649..00000000 --- a/modules/nf-core/cat/cat/tests/main.nf.test +++ /dev/null @@ -1,192 +0,0 @@ -nextflow_process { - - name "Test Process CAT_CAT" - script "../main.nf" - process "CAT_CAT" - - tag "modules" - tag "modules_nfcore" - tag "cat" - tag "cat/cat" - - test("sarscov2 - genome - error: name conflict") { - when { - process { - """ - input[0] = - [ - [ id:'genome', single_end:true ], - [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) - ] - ] - """ - } - } - then { - assertAll( - { assert !process.success }, - { assert process.stdout.toString().contains("The name of the input file can't be the same as for the output prefix") }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 - [ fasta, sizes ] - unzipped") { - when { - process { - """ - input[0] = - [ - [ id:'test', single_end:true ], - [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) - ] - ] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - - test("sarscov2 - [ gff3_gz, maf_gz ] - zipped") { - when { - process { - """ - input[0] = - [ - [ id:'test', single_end:true ], - [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gff3.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/alignment/last/contigs.genome.maf.gz', checkIfExists: true) - ] - ] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() - } - ) - } - } - - test("sarscov2 - [ gff3_gz, maf_gz ] - unzipped") { - config './nextflow.config' - - when { - params { - cat_prefix = "cat.txt" - } - process { - """ - input[0] = - [ - [ id:'test', single_end:true ], - [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.gff3.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/alignment/last/contigs.genome.maf.gz', checkIfExists: true) - ] - ] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - - } - - test("sarscov2 - [ fasta, sizes ] - zipped") { - config './nextflow.config' - - when { - params { - cat_prefix = "cat.txt.gz" - } - process { - """ - input[0] = - [ - [ id:'test', single_end:true ], - [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.sizes', checkIfExists: true) - ] - ] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 - fasta - zipped") { - config './nextflow.config' - - when { - params { - cat_prefix = "cat.txt.gz" - } - process { - """ - input[0] = - [ - [ id:'test', single_end:true ], - [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - ] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 - fasta - unzipped - stub") { - options "-stub" - - when { - process { - """ - input[0] = - [ - [ id:'test', single_end:true ], - [ - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - ] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } -} diff --git a/modules/nf-core/cat/cat/tests/main.nf.test.snap b/modules/nf-core/cat/cat/tests/main.nf.test.snap deleted file mode 100644 index 5b4e4cc3..00000000 --- a/modules/nf-core/cat/cat/tests/main.nf.test.snap +++ /dev/null @@ -1,283 +0,0 @@ -{ - "sarscov2 - [ gff3_gz, maf_gz ] - unzipped": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "cat.txt:md5,c439d3b60e7bc03e8802a451a0d9a5d9" - ] - ], - "1": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ], - "file_out": [ - [ - { - "id": "test", - "single_end": true - }, - "cat.txt:md5,c439d3b60e7bc03e8802a451a0d9a5d9" - ] - ], - "versions_cat": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-10T09:08:31.479828" - }, - "sarscov2 - fasta - unzipped - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fasta:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ], - "file_out": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fasta:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions_cat": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-10T16:16:28.118094" - }, - "sarscov2 - [ fasta, sizes ] - zipped": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "cat.txt.gz:md5,f44b33a0e441ad58b2d3700270e2dbe2" - ] - ], - "1": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ], - "file_out": [ - [ - { - "id": "test", - "single_end": true - }, - "cat.txt.gz:md5,f44b33a0e441ad58b2d3700270e2dbe2" - ] - ], - "versions_cat": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-10T16:15:56.529595" - }, - "sarscov2 - genome - error: name conflict": { - "content": [ - { - "0": [ - - ], - "1": [ - - ], - "file_out": [ - - ], - "versions_cat": [ - - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-10T16:14:54.496538" - }, - "sarscov2 - [ fasta, sizes ] - unzipped": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fasta:md5,f44b33a0e441ad58b2d3700270e2dbe2" - ] - ], - "1": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ], - "file_out": [ - [ - { - "id": "test", - "single_end": true - }, - "test.fasta:md5,f44b33a0e441ad58b2d3700270e2dbe2" - ] - ], - "versions_cat": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-10T11:26:29.942203" - }, - "sarscov2 - [ gff3_gz, maf_gz ] - zipped": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.gff3.gz:md5,c439d3b60e7bc03e8802a451a0d9a5d9" - ] - ], - "1": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ], - "file_out": [ - [ - { - "id": "test", - "single_end": true - }, - "test.gff3.gz:md5,c439d3b60e7bc03e8802a451a0d9a5d9" - ] - ], - "versions_cat": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-10T11:26:45.679401" - }, - "sarscov2 - fasta - zipped": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "cat.txt.gz:md5,6e9fe4042a72f2345f644f239272b7e6" - ] - ], - "1": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ], - "file_out": [ - [ - { - "id": "test", - "single_end": true - }, - "cat.txt.gz:md5,6e9fe4042a72f2345f644f239272b7e6" - ] - ], - "versions_cat": [ - [ - "CAT_CAT", - "pigz", - "2.8" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2025-12-10T16:16:12.439911" - } -} \ No newline at end of file diff --git a/modules/nf-core/cat/cat/tests/nextflow.config b/modules/nf-core/cat/cat/tests/nextflow.config deleted file mode 100644 index 5bc9bf50..00000000 --- a/modules/nf-core/cat/cat/tests/nextflow.config +++ /dev/null @@ -1,6 +0,0 @@ - -process { - withName: CAT_CAT { - ext.prefix = "${params.cat_prefix}" - } -} diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index ed99fa48..ce0d6862 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -5,11 +5,9 @@ // -include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" -include { CAT_CAT as CAT_JUNCTIONS } from "../../../modules/nf-core/cat/cat/main.nf" -include { CAT_CAT as CAT_SPLICE_JUNCTIONS } from "../../../modules/nf-core/cat/cat/main.nf" -include { GNU_SORT as SORT_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" -include { GNU_SORT as SORT_SPLICE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" +include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" +include { GNU_SORT as SORT_MERGE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" +include { GNU_SORT as SORT_MERGE_SPLICE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" workflow FASTQ_ALIGN_RNA { take: @@ -47,21 +45,19 @@ workflow FASTQ_ALIGN_RNA { // Concatenate splice junction files def ch_splice_junctions_to_merge = group_junctions(STAR_ALIGN.out.spl_junc_tab) - CAT_SPLICE_JUNCTIONS(ch_splice_junctions_to_merge) - SORT_SPLICE_JUNCTIONS(CAT_SPLICE_JUNCTIONS.out.file_out) - ch_versions = ch_versions.mix(SORT_SPLICE_JUNCTIONS.out.versions.first()) + SORT_MERGE_SPLICE_JUNCTIONS(ch_splice_junctions_to_merge) + ch_versions = ch_versions.mix(SORT_MERGE_SPLICE_JUNCTIONS.out.versions.first()) // Concatenate junction files def ch_junctions_to_merge = group_junctions(STAR_ALIGN.out.junction) - CAT_JUNCTIONS(ch_junctions_to_merge) - SORT_JUNCTIONS(CAT_JUNCTIONS.out.file_out) - ch_versions = ch_versions.mix(SORT_JUNCTIONS.out.versions.first()) + SORT_MERGE_JUNCTIONS(ch_junctions_to_merge) + ch_versions = ch_versions.mix(SORT_MERGE_JUNCTIONS.out.versions.first()) emit: bam = ch_bam // channel: [ [meta], bam ] - splice_junctions = SORT_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] - junctions = SORT_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] + splice_junctions = SORT_MERGE_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] + junctions = SORT_MERGE_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] reports = ch_reports // channel: [ [meta], log ] versions = ch_versions // channel: [ versions.yml ] } From 9453c195183460e64b95044ad3304b38a9b45e47 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 17 Dec 2025 14:26:05 +0100 Subject: [PATCH 122/228] prettier --- modules.json | 126 +++++++++++++-------------------------------------- 1 file changed, 31 insertions(+), 95 deletions(-) diff --git a/modules.json b/modules.json index c83142f7..d1d3d5eb 100644 --- a/modules.json +++ b/modules.json @@ -8,199 +8,145 @@ "bcl2fastq": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "bcl_demultiplex" - ] + "installed_by": ["bcl_demultiplex"] }, "bclconvert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "bcl_demultiplex", - "modules" - ], + "installed_by": ["bcl_demultiplex", "modules"], "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, "biobambam/bamsormadup": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, "bowtie2/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", "git_sha": "d86336f3e7ae0d5f76c67b0859409769cfeb2af2", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, "dragmap/align": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", - "installed_by": [ - "fastq_align_dna" - ], + "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, "fastp": { "branch": "master", "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "gnu/sort": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "md5sum": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "mosdepth": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, "multiqc": { "branch": "master", "git_sha": "9656d955b700a8707c4a67821ab056f8c1095675", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/multiqc/multiqc.diff" }, "picard/collecthsmetrics": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, "samtools/convert": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, "samtools/flagstat": { "branch": "master", "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/idxstats": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": [ - "modules" - ] + "installed_by": ["modules"] }, "samtools/sormadup": { "branch": "master", "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, "samtools/sort": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, "samtools/stats": { "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, "snapaligner/align": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, "star/align": { "branch": "master", "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", - "installed_by": [ - "modules" - ], + "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" }, "strobealign": { "branch": "master", "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", - "installed_by": [ - "fastq_align_dna", - "modules" - ], + "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/strobealign/strobealign.diff" } } @@ -210,40 +156,30 @@ "bcl_demultiplex": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "fastq_align_dna": { "branch": "master", "git_sha": "070ddae7fb59384d3d85bf69eb9a1d71ab33ada9", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nextflow_pipeline": { "branch": "master", "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", "git_sha": "df4d1c8cdee98a1bbbed8fc51e82296568e0f9c1", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": [ - "subworkflows" - ] + "installed_by": ["subworkflows"] } } } } } -} \ No newline at end of file +} From 6a7d91d6511fa573f34b1912cc52a6601091aca5 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 17 Dec 2025 14:52:29 +0100 Subject: [PATCH 123/228] fix tests --- conf/modules.config | 1 + .../local/fastq_align_rna/main.nf.test.snap | 52 ++++++++++-- .../fastq_to_aligned_cram/main.nf.test.snap | 82 ++++++++++++++++--- tests/workflows/preprocessing.nf.test.snap | 34 ++++++-- 4 files changed, 143 insertions(+), 26 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 9aa74e0e..db240008 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -138,6 +138,7 @@ process { //// STAR withName: '.*FASTQ_ALIGN_RNA:STAR_ALIGN' { + ext.prefix = { "${meta.id}.star" } cpus = 16 memory = 64.GB ext.args = { diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index bd1553c9..3c8c8522 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -14,7 +14,25 @@ "samplename": "test", "single_end": false }, - "test.Aligned.out.bam" + "test.star.Aligned.out.bam" + ] + ], + "junctions": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test", + "samplename": "test", + "single_end": false, + "sample_type": "RNA", + "genome": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + } + } + }, + "test.Chimeric.out.junction:md5,b560229eb850489cf0cc6f60baee57b5" ] ], "reports": [ @@ -29,7 +47,7 @@ "samplename": "test", "single_end": false }, - "test.Log.final.out" + "test.star.Log.final.out" ], [ { @@ -42,7 +60,7 @@ "samplename": "test", "single_end": false }, - "test.Log.out" + "test.star.Log.out" ], [ { @@ -55,19 +73,39 @@ "samplename": "test", "single_end": false }, - "test.Log.progress.out" + "test.star.Log.progress.out" + ] + ], + "splice_junctions": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test", + "samplename": "test", + "single_end": false, + "sample_type": "RNA", + "genome": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + } + } + }, + "test.Sj.out.tab:md5,15852c5678c04e86dcb66793b7e02bb9" ] ], "versions": [ - "versions.yml:md5,a08c174f2d393f0b39c2cfe003ffafb9" + "versions.yml:md5,a08c174f2d393f0b39c2cfe003ffafb9", + "versions.yml:md5,e0beb4fb46280de51c432ed766a0cdb2", + "versions.yml:md5,e1135512a195d12c4b6aaadd8e84dcf6" ] } ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.10.0" + "nextflow": "25.10.2" }, - "timestamp": "2025-11-04T14:22:48.650056385" + "timestamp": "2025-12-17T14:44:53.335659555" }, "fastq align rna - unknown aligner": { "content": [ diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index d1459def..a4ee2182 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -23,6 +23,12 @@ "test.merged.cram", "test.merged.cram.crai" ] + ], + "rna_junctions": [ + + ], + "rna_splice_junctions": [ + ], "sormadup_metrics": [ @@ -34,10 +40,10 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T13:40:29.319628" + "timestamp": "2025-12-17T14:52:18.252297311" }, "fastq to cram - bwa - bamsormadup": { "content": [ @@ -63,6 +69,12 @@ "test.cram", "test.cram.crai" ] + ], + "rna_junctions": [ + + ], + "rna_splice_junctions": [ + ], "sormadup_metrics": [ [ @@ -91,10 +103,10 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T12:52:20.737608" + "timestamp": "2025-12-17T14:46:54.525880067" }, "fastq to cram - bwa - samtools sormadup": { "content": [ @@ -120,6 +132,12 @@ "test.merged.cram", "test.merged.cram.crai" ] + ], + "rna_junctions": [ + + ], + "rna_splice_junctions": [ + ], "sormadup_metrics": [ [ @@ -136,7 +154,7 @@ } } }, - "test.merged.metrics:md5,a4129081c3f2f10e6f6ecdf8b1c44852" + "test.merged.metrics:md5,795c73aa836eb480e418f52db98e37cc" ] ], "versions": [ @@ -147,10 +165,10 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T13:04:47.356008" + "timestamp": "2025-12-17T14:50:28.614932101" }, "fastq to cram - star - bamsormadup": { "content": [ @@ -177,6 +195,42 @@ "test.cram.crai" ] ], + "rna_junctions": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test", + "samplename": "test", + "single_end": false, + "sample_type": "RNA", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + } + } + }, + "test.Chimeric.out.junction:md5,b560229eb850489cf0cc6f60baee57b5" + ] + ], + "rna_splice_junctions": [ + [ + { + "groupSize": 1, + "groupTarget": { + "id": "test", + "samplename": "test", + "single_end": false, + "sample_type": "RNA", + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + } + } + }, + "test.Sj.out.tab:md5,15852c5678c04e86dcb66793b7e02bb9" + ] + ], "sormadup_metrics": [ [ { @@ -202,10 +256,10 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T13:04:21.082358" + "timestamp": "2025-12-17T14:49:33.159222222" }, "fastq to cram - bwa - samtools sort": { "content": [ @@ -231,6 +285,12 @@ "test.merged.cram", "test.merged.cram.crai" ] + ], + "rna_junctions": [ + + ], + "rna_splice_junctions": [ + ], "sormadup_metrics": [ @@ -242,9 +302,9 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-02T13:40:06.599667" + "timestamp": "2025-12-17T14:51:22.925873858" } } \ No newline at end of file diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 82cf9c36..79b6910d 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -510,6 +510,12 @@ ], "picard_wgsmetrics": [ + ], + "rna_junctions": [ + + ], + "rna_splice_junctions": [ + ], "samtools_coverage": [ [ @@ -535,7 +541,7 @@ "id": "sample1" } }, - "sample1.coverage.txt:md5,656b7371132475783094d80b7d2292b5" + "sample1.coverage.txt:md5,2273df8af027c91ad1a51ab62ff39f13" ] ], "samtools_flagstat": [ @@ -616,7 +622,7 @@ "id": "sample1" } }, - "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" + "sample1.stats:md5,48c3d9d21314717edf49cfd80014be2a" ] ], "sormadup_metrics": [ @@ -663,10 +669,10 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-09T11:03:22.986076" + "timestamp": "2025-12-17T14:17:54.029873192" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -881,6 +887,12 @@ ], "picard_wgsmetrics": [ + ], + "rna_junctions": [ + + ], + "rna_splice_junctions": [ + ], "samtools_coverage": [ @@ -1006,10 +1018,10 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-09T11:09:14.114309" + "timestamp": "2025-12-17T14:25:25.520000109" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1437,6 +1449,12 @@ }, "sample1.CollectWgsMetrics.coverage_metrics" ] + ], + "rna_junctions": [ + + ], + "rna_splice_junctions": [ + ], "samtools_coverage": [ [ @@ -1585,9 +1603,9 @@ } ], "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-09T11:06:50.62591" + "timestamp": "2025-12-17T14:22:40.972493649" } } \ No newline at end of file From b077cf6a2b1b62dc27a5d01ce86f8c6e4dbc1117 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 17 Dec 2025 15:30:28 +0100 Subject: [PATCH 124/228] fix unstable stat files in snapshot --- tests/workflows/preprocessing.nf.test | 4 +- tests/workflows/preprocessing.nf.test.snap | 48 +++++++++++----------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index 6caacb09..e7c17760 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -69,7 +69,9 @@ nextflow_workflow { "picard_wgsmetrics", "picard_multiplemetrics_pdf", "picard_multiplemetrics", - "picard_hsmetrics" + "picard_hsmetrics", + "samtools_flagstat", + "samtools_coverage" ]) ).match() } diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 79b6910d..d0d59981 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -522,26 +522,26 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WES", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", - "id": "sample1" + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" } }, - "sample1.coverage.txt:md5,2273df8af027c91ad1a51ab62ff39f13" + "sample1.coverage.txt" ] ], "samtools_flagstat": [ @@ -549,26 +549,26 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WES", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", - "id": "sample1" + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" } }, - "sample1.flagstat:md5,cd826b1749737d52499cf543d101ecd2" + "sample1.flagstat" ] ], "samtools_idxstats": [ @@ -622,7 +622,7 @@ "id": "sample1" } }, - "sample1.stats:md5,48c3d9d21314717edf49cfd80014be2a" + "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" ] ], "sormadup_metrics": [ @@ -672,7 +672,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T14:17:54.029873192" + "timestamp": "2025-12-17T15:25:16.549534093" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ From a0bbefba0143862c9cbeb9bc69e7c579b1f77a6a Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 17 Dec 2025 16:03:17 +0100 Subject: [PATCH 125/228] fix unstable stat files in snapshot --- tests/workflows/preprocessing.nf.test | 8 ++- tests/workflows/preprocessing.nf.test.snap | 70 +++++++++++----------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index e7c17760..50e25c9e 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -139,7 +139,9 @@ nextflow_workflow { "picard_wgsmetrics", "picard_multiplemetrics_pdf", "picard_multiplemetrics", - "picard_hsmetrics" + "picard_hsmetrics", + "samtools_flagstat", + "samtools_coverage" ]) ).match() } @@ -210,7 +212,9 @@ nextflow_workflow { "picard_wgsmetrics", "picard_multiplemetrics_pdf", "picard_multiplemetrics", - "picard_hsmetrics" + "picard_hsmetrics", + "samtools_flagstat", + "samtools_coverage" ]) ).match() } diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index d0d59981..f072b009 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -902,26 +902,26 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WES", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", - "id": "sample1" + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" } }, - "sample1.flagstat:md5,cd826b1749737d52499cf543d101ecd2" + "sample1.flagstat" ] ], "samtools_idxstats": [ @@ -1021,7 +1021,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T14:25:25.520000109" + "timestamp": "2025-12-17T15:54:33.813455843" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1461,25 +1461,25 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WGS", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "id": "sample1" + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" } }, - "sample1.coverage.txt:md5,656b7371132475783094d80b7d2292b5" + "sample1.coverage.txt" ] ], "samtools_flagstat": [ @@ -1487,25 +1487,25 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WGS", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "id": "sample1" + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" } }, - "sample1.flagstat:md5,cd826b1749737d52499cf543d101ecd2" + "sample1.flagstat" ] ], "samtools_idxstats": [ @@ -1606,6 +1606,6 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T14:22:40.972493649" + "timestamp": "2025-12-17T15:51:53.194202966" } } \ No newline at end of file From 68c3b7727c9bd54e2252600c01eebe15765251b5 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Wed, 17 Dec 2025 16:45:28 +0100 Subject: [PATCH 126/228] fixing tests took waaaaaaay too long --- .../local/fastq_align_rna/main.nf.test | 2 +- .../local/fastq_align_rna/main.nf.test.snap | 16 ++--- .../local/fastq_to_aligned_cram/main.nf.test | 3 +- .../fastq_to_aligned_cram/main.nf.test.snap | 14 ++-- tests/workflows/preprocessing.nf.test | 9 ++- tests/workflows/preprocessing.nf.test.snap | 72 +++++++++---------- 6 files changed, 62 insertions(+), 54 deletions(-) diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test b/tests/subworkflows/local/fastq_align_rna/main.nf.test index caf71651..c8319d20 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test @@ -39,7 +39,7 @@ nextflow_workflow { then { assert workflow.success assert snapshot( - sanitizeOutput(workflow.out, unstableKeys:["bam", "reports"]) + sanitizeOutput(workflow.out, unstableKeys:["bam", "reports", "junctions"]) ).match() } diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index 3c8c8522..cf2552d1 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -22,17 +22,17 @@ { "groupSize": 1, "groupTarget": { + "genome": { + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + }, "id": "test", - "samplename": "test", - "single_end": false, "sample_type": "RNA", - "genome": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - } + "samplename": "test", + "single_end": false } }, - "test.Chimeric.out.junction:md5,b560229eb850489cf0cc6f60baee57b5" + "test.Chimeric.out.junction" ] ], "reports": [ @@ -105,7 +105,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T14:44:53.335659555" + "timestamp": "2025-12-17T16:44:58.048883426" }, "fastq align rna - unknown aligner": { "content": [ diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test index 6ee92e5e..9a7a9eb3 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test @@ -64,7 +64,8 @@ nextflow_workflow { sample_type:'RNA', genome_data: [ fasta: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + star: "s3://test-data/genomics/homo_sapiens/genome/star/" ] ], // meta map [ diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index a4ee2182..dd208219 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -183,7 +183,8 @@ "groupTarget": { "genome_data": { "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "star": "s3://test-data/genomics/homo_sapiens/genome/star/" }, "id": "test", "sample_type": "RNA", @@ -206,7 +207,8 @@ "sample_type": "RNA", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "star": "s3://test-data/genomics/homo_sapiens/genome/star/" } } }, @@ -224,7 +226,8 @@ "sample_type": "RNA", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "star": "s3://test-data/genomics/homo_sapiens/genome/star/" } } }, @@ -242,7 +245,8 @@ "sample_type": "RNA", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "star": "s3://test-data/genomics/homo_sapiens/genome/star/" } } }, @@ -259,7 +263,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T14:49:33.159222222" + "timestamp": "2025-12-17T16:27:53.162318921" }, "fastq to cram - bwa - samtools sort": { "content": [ diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index 50e25c9e..45c0fba2 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -71,7 +71,8 @@ nextflow_workflow { "picard_multiplemetrics", "picard_hsmetrics", "samtools_flagstat", - "samtools_coverage" + "samtools_coverage", + "samtools_stats" ]) ).match() } @@ -141,7 +142,8 @@ nextflow_workflow { "picard_multiplemetrics", "picard_hsmetrics", "samtools_flagstat", - "samtools_coverage" + "samtools_coverage", + "samtools_stats" ]) ).match() } @@ -214,7 +216,8 @@ nextflow_workflow { "picard_multiplemetrics", "picard_hsmetrics", "samtools_flagstat", - "samtools_coverage" + "samtools_coverage", + "samtools_stats" ]) ).match() } diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index f072b009..20333b5b 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -603,26 +603,26 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WES", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", - "id": "sample1" + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" } }, - "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" + "sample1.stats" ] ], "sormadup_metrics": [ @@ -672,7 +672,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T15:25:16.549534093" + "timestamp": "2025-12-17T16:32:55.414537131" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -956,26 +956,26 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WES", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", - "id": "sample1" + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WES" } }, - "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" + "sample1.stats" ] ], "sormadup_metrics": [ @@ -1021,7 +1021,7 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T15:54:33.813455843" + "timestamp": "2025-12-17T16:40:10.119231711" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1539,25 +1539,25 @@ { "groupSize": 1, "groupTarget": { - "samplename": "sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WGS", - "sample_type": "DNA", "aligner": "bwamem", - "single_end": false, "genome": "GRCh38", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", - "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", - "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "id": "sample1" + "id": "sample1", + "library": "test", + "organism": "Homo sapiens", + "sample_type": "DNA", + "samplename": "sample1", + "single_end": false, + "tag": "WGS" } }, - "sample1.stats:md5,bbe2999c6baf17c96d4f00370c6b9501" + "sample1.stats" ] ], "sormadup_metrics": [ @@ -1606,6 +1606,6 @@ "nf-test": "0.9.2", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T15:51:53.194202966" + "timestamp": "2025-12-17T16:37:31.272800991" } } \ No newline at end of file From ddc9928a4c57cae00c7c2fef12f505c3f31cf290 Mon Sep 17 00:00:00 2001 From: Nicolas Vannieuwkerke Date: Fri, 19 Dec 2025 10:01:17 +0100 Subject: [PATCH 127/228] fix splice junctions file name --- conf/modules.config | 2 +- .../local/fastq_align_rna/main.nf.test.snap | 4 +-- .../fastq_to_aligned_cram/main.nf.test.snap | 34 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index db240008..f35f76e7 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -156,7 +156,7 @@ process { } withName: '.*FASTQ_ALIGN_RNA:SORT_MERGE_SPLICE_JUNCTIONS' { - ext.prefix = { "${meta.id}.Sj.out" } + ext.prefix = { "${meta.id}.SJ.out" } ext.suffix = "tab" ext.args = '-k1,1n -k2,2n -k3,3n --merge' } diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index cf2552d1..2cd3d63c 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -91,7 +91,7 @@ } } }, - "test.Sj.out.tab:md5,15852c5678c04e86dcb66793b7e02bb9" + "test.SJ.out.tab:md5,15852c5678c04e86dcb66793b7e02bb9" ] ], "versions": [ @@ -119,4 +119,4 @@ }, "timestamp": "2024-05-28T16:17:08.089796673" } -} \ No newline at end of file +} diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index dd208219..aabf04cd 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -3,7 +3,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -25,13 +25,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ], "versions": [ "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", @@ -49,7 +49,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -71,10 +71,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -112,7 +112,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -134,10 +134,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -174,7 +174,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -231,7 +231,7 @@ } } }, - "test.Sj.out.tab:md5,15852c5678c04e86dcb66793b7e02bb9" + "test.SJ.out.tab:md5,15852c5678c04e86dcb66793b7e02bb9" ] ], "sormadup_metrics": [ @@ -269,7 +269,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -291,13 +291,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ], "versions": [ "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", @@ -311,4 +311,4 @@ }, "timestamp": "2025-12-17T14:51:22.925873858" } -} \ No newline at end of file +} From b4181518839604e5cfda9f84c61242fb88bec3f5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Sun, 21 Dec 2025 14:47:48 +0100 Subject: [PATCH 128/228] fix conditional config for samtools_sormadup --- conf/modules.config | 2 ++ conf/profiles/gcp.config | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index f35f76e7..480d1c75 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -156,12 +156,14 @@ process { } withName: '.*FASTQ_ALIGN_RNA:SORT_MERGE_SPLICE_JUNCTIONS' { + cpus = 1 ext.prefix = { "${meta.id}.SJ.out" } ext.suffix = "tab" ext.args = '-k1,1n -k2,2n -k3,3n --merge' } withName: '.*FASTQ_ALIGN_RNA:SORT_MERGE_JUNCTIONS' { + cpus = 1 ext.prefix = { "${meta.id}.Chimeric.out" } ext.suffix = "junction" ext.args = '-k1,1n -k2,2n -k4,4n -k5,5n --merge' diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config index 577dd18d..2bab1b6d 100644 --- a/conf/profiles/gcp.config +++ b/conf/profiles/gcp.config @@ -33,11 +33,11 @@ process { // Alignment post-processing resources withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { - disk = { input instanceof List ? input.size().sum() * 3 * task.attempt : input.size() * 3 * task.attempt } + disk = { input instanceof List ? input.sum { it.size() } * 3 * task.attempt : input.size() * 3 * task.attempt } time = 24.h } withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { - disk = { input instanceof List ? input.size().sum() * 3 * task.attempt : input.size() * 3 * task.attempt } + disk = { input instanceof List ? input.sum { it.size() } * 3 * task.attempt : input.size() * 3 * task.attempt } time = 24.h } // withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} From 082a73685b7943316b321f12bfe449c83025a3da Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 23 Dec 2025 13:42:13 +0100 Subject: [PATCH 129/228] bump fastp module --- modules.json | 2 +- modules/nf-core/fastp/main.nf | 18 +-- modules/nf-core/fastp/tests/main.nf.test.snap | 108 +++++++++--------- workflows/preprocessing.nf | 2 +- 4 files changed, 65 insertions(+), 65 deletions(-) diff --git a/modules.json b/modules.json index d1d3d5eb..0b710f92 100644 --- a/modules.json +++ b/modules.json @@ -48,7 +48,7 @@ }, "fastp": { "branch": "master", - "git_sha": "d9ec4ef289ad39b8a662a7a12be50409b11df84b", + "git_sha": "b8f1de0ac853ae5b56c63450d47438f899c553d0", "installed_by": ["modules"] }, "gnu/sort": { diff --git a/modules/nf-core/fastp/main.nf b/modules/nf-core/fastp/main.nf index 85013f5d..7538fc3a 100644 --- a/modules/nf-core/fastp/main.nf +++ b/modules/nf-core/fastp/main.nf @@ -29,9 +29,9 @@ process FASTP { def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" def adapter_list = adapter_fasta ? "--adapter_fasta ${adapter_fasta}" : "" - def fail_fastq = save_trimmed_fail && meta.single_end ? "--failed_out ${prefix}.fail.fastq.gz" : save_trimmed_fail && !meta.single_end ? "--failed_out ${prefix}.paired.fail.fastq.gz --unpaired1 ${prefix}_1.fail.fastq.gz --unpaired2 ${prefix}_2.fail.fastq.gz" : '' - def out_fq1 = discard_trimmed_pass ?: ( meta.single_end ? "--out1 ${prefix}.fastp.fastq.gz" : "--out1 ${prefix}_1.fastp.fastq.gz" ) - def out_fq2 = discard_trimmed_pass ?: "--out2 ${prefix}_2.fastp.fastq.gz" + def fail_fastq = save_trimmed_fail && meta.single_end ? "--failed_out ${prefix}.fail.fastq.gz" : save_trimmed_fail && !meta.single_end ? "--failed_out ${prefix}.paired.fail.fastq.gz --unpaired1 ${prefix}_R1.fail.fastq.gz --unpaired2 ${prefix}_R2.fail.fastq.gz" : '' + def out_fq1 = discard_trimmed_pass ?: ( meta.single_end ? "--out1 ${prefix}.fastp.fastq.gz" : "--out1 ${prefix}_R1.fastp.fastq.gz" ) + def out_fq2 = discard_trimmed_pass ?: "--out2 ${prefix}_R2.fastp.fastq.gz" // Added soft-links to original fastqs for consistent naming in MultiQC // Use single ended for interleaved. Add --interleaved_in in config. if ( task.ext.args?.contains('--interleaved_in') ) { @@ -78,11 +78,11 @@ process FASTP { } else { def merge_fastq = save_merged ? "-m --merged_out ${prefix}.merged.fastq.gz" : '' """ - [ ! -f ${prefix}_1.fastq.gz ] && ln -sf ${reads[0]} ${prefix}_1.fastq.gz - [ ! -f ${prefix}_2.fastq.gz ] && ln -sf ${reads[1]} ${prefix}_2.fastq.gz + [ ! -f ${prefix}_R1.fastq.gz ] && ln -sf ${reads[0]} ${prefix}_R1.fastq.gz + [ ! -f ${prefix}_R2.fastq.gz ] && ln -sf ${reads[1]} ${prefix}_R2.fastq.gz fastp \\ - --in1 ${prefix}_1.fastq.gz \\ - --in2 ${prefix}_2.fastq.gz \\ + --in1 ${prefix}_R1.fastq.gz \\ + --in2 ${prefix}_R2.fastq.gz \\ $out_fq1 \\ $out_fq2 \\ --json ${prefix}.fastp.json \\ @@ -105,9 +105,9 @@ process FASTP { stub: def prefix = task.ext.prefix ?: "${meta.id}" def is_single_output = task.ext.args?.contains('--interleaved_in') || meta.single_end - def touch_reads = (discard_trimmed_pass) ? "" : (is_single_output) ? "echo '' | gzip > ${prefix}.fastp.fastq.gz" : "echo '' | gzip > ${prefix}_1.fastp.fastq.gz ; echo '' | gzip > ${prefix}_2.fastp.fastq.gz" + def touch_reads = (discard_trimmed_pass) ? "" : (is_single_output) ? "echo '' | gzip > ${prefix}.fastp.fastq.gz" : "echo '' | gzip > ${prefix}_R1.fastp.fastq.gz ; echo '' | gzip > ${prefix}_R2.fastp.fastq.gz" def touch_merged = (!is_single_output && save_merged) ? "echo '' | gzip > ${prefix}.merged.fastq.gz" : "" - def touch_fail_fastq = (!save_trimmed_fail) ? "" : meta.single_end ? "echo '' | gzip > ${prefix}.fail.fastq.gz" : "echo '' | gzip > ${prefix}.paired.fail.fastq.gz ; echo '' | gzip > ${prefix}_1.fail.fastq.gz ; echo '' | gzip > ${prefix}_2.fail.fastq.gz" + def touch_fail_fastq = (!save_trimmed_fail) ? "" : meta.single_end ? "echo '' | gzip > ${prefix}.fail.fastq.gz" : "echo '' | gzip > ${prefix}.paired.fail.fastq.gz ; echo '' | gzip > ${prefix}_R1.fail.fastq.gz ; echo '' | gzip > ${prefix}_R2.fail.fastq.gz" """ $touch_reads $touch_fail_fastq diff --git a/modules/nf-core/fastp/tests/main.nf.test.snap b/modules/nf-core/fastp/tests/main.nf.test.snap index a30c680d..2276fc08 100644 --- a/modules/nf-core/fastp/tests/main.nf.test.snap +++ b/modules/nf-core/fastp/tests/main.nf.test.snap @@ -97,8 +97,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,67b2bbae47f073e05a97a9c2edce23c7", - "test_2.fastp.fastq.gz:md5,25cbdca08e2083dbd4f0502de6b62f39" + "test_R1.fastp.fastq.gz:md5,67b2bbae47f073e05a97a9c2edce23c7", + "test_R2.fastp.fastq.gz:md5,25cbdca08e2083dbd4f0502de6b62f39" ] ] ], @@ -113,10 +113,10 @@ ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-19T16:23:12.436191" + "timestamp": "2025-12-22T14:32:22.887952042" }, "test_fastp_paired_end_merged_adapterlist": { "content": [ @@ -127,8 +127,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,54b726a55e992a869fd3fa778afe1672", - "test_2.fastp.fastq.gz:md5,29d3b33b869f7b63417b8ff07bb128ba" + "test_R1.fastp.fastq.gz:md5,54b726a55e992a869fd3fa778afe1672", + "test_R2.fastp.fastq.gz:md5,29d3b33b869f7b63417b8ff07bb128ba" ] ] ], @@ -149,10 +149,10 @@ ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-19T16:23:32.267735" + "timestamp": "2025-12-22T14:32:53.752975682" }, "test_fastp_single_end_qc_only": { "content": [ @@ -193,8 +193,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,6ff32a64c5188b9a9192be1398c262c7", - "test_2.fastp.fastq.gz:md5,db0cb7c9977e94ac2b4b446ebd017a8a" + "test_R1.fastp.fastq.gz:md5,6ff32a64c5188b9a9192be1398c262c7", + "test_R2.fastp.fastq.gz:md5,db0cb7c9977e94ac2b4b446ebd017a8a" ] ] ], @@ -206,8 +206,8 @@ }, [ "test.paired.fail.fastq.gz:md5,409b687c734cedd7a1fec14d316e1366", - "test_1.fail.fastq.gz:md5,4f273cf3159c13f79e8ffae12f5661f6", - "test_2.fail.fastq.gz:md5,f97b9edefb5649aab661fbc9e71fc995" + "test_R1.fail.fastq.gz:md5,4f273cf3159c13f79e8ffae12f5661f6", + "test_R2.fail.fastq.gz:md5,f97b9edefb5649aab661fbc9e71fc995" ] ] ], @@ -219,10 +219,10 @@ ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-19T16:23:24.23891" + "timestamp": "2025-12-22T14:32:41.270456637" }, "fastp - stub test_fastp_interleaved": { "content": [ @@ -436,8 +436,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -517,8 +517,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -540,10 +540,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-11T09:55:37.413738" + "timestamp": "2025-12-22T14:33:44.204950729" }, "test_fastp_paired_end_merged - stub": { "content": [ @@ -555,8 +555,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -636,8 +636,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -659,10 +659,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-11T09:55:32.965652" + "timestamp": "2025-12-22T14:33:38.518882433" }, "test_fastp_paired_end_merged": { "content": [ @@ -673,8 +673,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,54b726a55e992a869fd3fa778afe1672", - "test_2.fastp.fastq.gz:md5,29d3b33b869f7b63417b8ff07bb128ba" + "test_R1.fastp.fastq.gz:md5,54b726a55e992a869fd3fa778afe1672", + "test_R2.fastp.fastq.gz:md5,29d3b33b869f7b63417b8ff07bb128ba" ] ] ], @@ -695,10 +695,10 @@ ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-19T16:23:28.074624" + "timestamp": "2025-12-22T14:32:47.366974895" }, "test_fastp_paired_end - stub": { "content": [ @@ -710,8 +710,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -785,8 +785,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -802,10 +802,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-11T09:55:14.414258" + "timestamp": "2025-12-22T14:33:16.494574544" }, "test_fastp_single_end": { "content": [ @@ -957,8 +957,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -997,8 +997,8 @@ }, [ "test.paired.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_1.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -1042,8 +1042,8 @@ "single_end": false }, [ - "test_1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fastp.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -1055,8 +1055,8 @@ }, [ "test.paired.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_1.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test_2.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "test_R1.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_R2.fail.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ] ], @@ -1069,10 +1069,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-09-11T09:55:28.399328" + "timestamp": "2025-12-22T14:33:32.863505882" }, "fastp test_fastp_interleaved": { "content": [ diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 9149e445..6d2802eb 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -220,7 +220,7 @@ workflow PREPROCESSING { } .transpose() .map { meta, reads -> - def new_id = reads instanceof List ? reads[0].getName() - ~/_1.fastp.*/ : reads.getName() - ~/.fastp.*/ + def new_id = reads instanceof List ? reads[0].getName() - ~/_R1.fastp.*/ : reads.getName() - ~/.fastp.*/ return [ meta - meta.subMap('id') + [id: new_id], reads, From 6ee5e9d9b3b8cb982fb3726580be29659029479c Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:30:07 +0100 Subject: [PATCH 130/228] fix snapshots --- tests/workflows/preprocessing.nf.test.snap | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 20333b5b..15d55f4e 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -108,7 +108,7 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, - "sample1.fastp.json:md5,2edca71b00e4804eb7b39ff72f1c304a" + "sample1.fastp.json:md5,5a65f5141251ac26b8f0a0d0a618b524" ] ], "md5sums": [ @@ -669,10 +669,10 @@ } ], "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T16:32:55.414537131" + "timestamp": "2025-12-23T13:59:59.404732" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -783,7 +783,7 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, - "sample1.fastp.json:md5,2edca71b00e4804eb7b39ff72f1c304a" + "sample1.fastp.json:md5,5a65f5141251ac26b8f0a0d0a618b524" ] ], "md5sums": [ @@ -1018,10 +1018,10 @@ } ], "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T16:40:10.119231711" + "timestamp": "2025-12-23T14:06:35.503463" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1129,7 +1129,7 @@ }, "count": 1 }, - "sample1.fastp.json:md5,2edca71b00e4804eb7b39ff72f1c304a" + "sample1.fastp.json:md5,5a65f5141251ac26b8f0a0d0a618b524" ] ], "md5sums": [ @@ -1603,9 +1603,9 @@ } ], "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.3", "nextflow": "25.10.2" }, - "timestamp": "2025-12-17T16:37:31.272800991" + "timestamp": "2025-12-23T14:04:00.643521" } } \ No newline at end of file From aa029ef91a6927e76999248deef22d44798efd14 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Sat, 24 Jan 2026 07:43:58 +0100 Subject: [PATCH 131/228] Change export_plots setting from true to false takes too long --- assets/multiqc_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 755c9880..cc354c76 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -8,7 +8,7 @@ report_section_order: order: -1001 "nf-cmgg-preprocessing-summary": order: -1002 -export_plots: true +export_plots: false disable_version_detection: true bclconvert: create_undetermined_barcode_barplots: true From 605c622c984c76df8fcc20a17f548e2c5b238e61 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:34:29 +0100 Subject: [PATCH 132/228] use custom multiqc --- conf/modules.config | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 480d1c75..794ca8e8 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -273,19 +273,28 @@ process { // MultiQC withName: '.*MULTIQC_.*$' { + container = "cmgg/multiqc_cmgg:0.0.2-multiqc-v1.33" cpus = 1 memory = 4.GB } withName: '.*MULTIQC_MAIN' { ext.prefix = { params.multiqc_title ? params.multiqc_title : "multiqc" } - ext.args = { params.multiqc_title ? "--title \"${params.multiqc_title}\"" : '' } + ext.args = { + [ + "--template \"cmgg\"", + params.multiqc_title ? "--title \"${params.multiqc_title}\"" : "", + ].join(" ").trim() + } } withName: '.*MULTIQC_LIBRARY' { - cpus = 1 - memory = 4.GB ext.prefix = { meta.id ? "${meta.id}" : "multiqc_library" } - ext.args = { meta.id ? "--title \"${meta.id} - Pool Summary\"" : '' } + ext.args = { + [ + "--template \"cmgg\"", + meta.id ? "--title \"${meta.id} - Pool Summary\"" : "", + ].join(" ").trim() + } } } From 2c0dcc8a655119a508f8005202cc3377859c1d04 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:48:48 +0100 Subject: [PATCH 133/228] disable AI in reports --- conf/modules.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/modules.config b/conf/modules.config index 794ca8e8..36734a8a 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -282,6 +282,7 @@ process { ext.args = { [ "--template \"cmgg\"", + "--no-ai", params.multiqc_title ? "--title \"${params.multiqc_title}\"" : "", ].join(" ").trim() } @@ -292,6 +293,7 @@ process { ext.args = { [ "--template \"cmgg\"", + "--no-ai", meta.id ? "--title \"${meta.id} - Pool Summary\"" : "", ].join(" ").trim() } From 29c77e626198281095b0bd10d1d83a18fe9af367 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 4 Feb 2026 14:04:59 +0100 Subject: [PATCH 134/228] fix linting --- .nf-core.yml | 5 ++--- ro-crate-metadata.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.nf-core.yml b/.nf-core.yml index 2b4bcc77..a9c2a6ae 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -19,15 +19,14 @@ lint: - LICENSE merge_markers: - bin/cmgg_genelists - multiqc_config: - - report_comment + multiqc_config: false nextflow_config: - manifest.name - manifest.homePage template_strings: - bin/cmgg_genelists nf_test_content: false -nf_core_version: 3.5.1 +nf_core_version: 3.5.2 repository_type: pipeline template: author: Matthias De Smet, Nicolas Vannieuwkerke diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 632da7c3..55c3e77d 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -23,7 +23,7 @@ "@type": "Dataset", "creativeWorkStatus": "InProgress", "datePublished": "2025-11-13T15:11:21+00:00", - "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag\nfc_sample1,test,Homo sapiens,WES\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,aligner,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,bwamem,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag,aligner\nfc_sample1,test,Homo sapiens,WES,bwamem\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" From f32013180f1c8b00a5ab4e352207ef91b63c400e Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:30:23 +0100 Subject: [PATCH 135/228] gcp config: add instance templates --- conf/base.config | 22 ++++++++++++---------- conf/profiles/gcp.config | 3 +++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/conf/base.config b/conf/base.config index 27606500..60cf57dd 100644 --- a/conf/base.config +++ b/conf/base.config @@ -11,8 +11,9 @@ process { cpus = { 1 * task.attempt } - memory = { 6.GB * task.attempt } + memory = { 8.GB * task.attempt } time = { 4.h * task.attempt } + machineType = 'template://gen-nfbatch-dev-small' // e2-standard-4 errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } maxRetries = 3 @@ -20,31 +21,32 @@ process { // Process-specific resource requirements withLabel:process_single { + machineType = 'template://gen-nfbatch-dev-small' // e2-standard-4 cpus = { 1 } - memory = { 6.GB * task.attempt } + memory = { 8.GB * task.attempt } time = { 4.h * task.attempt } } withLabel:process_low { + machineType = 'template://gen-nfbatch-dev-small' // e2-standard-4 cpus = { 2 * task.attempt } - memory = { 12.GB * task.attempt } + memory = { 16.GB * task.attempt } time = { 4.h * task.attempt } } withLabel:process_medium { - cpus = { 6 * task.attempt } - memory = { 36.GB * task.attempt } + machineType = 'template://gen-nfbatch-dev-medium' // n2-highmem-8 + cpus = { 8 * task.attempt } + memory = { 64.GB * task.attempt } time = { 8.h * task.attempt } } withLabel:process_high { - cpus = { 12 * task.attempt } - memory = { 72.GB * task.attempt } + machineType = 'template://gen-nfbatch-dev-large' // n2-highmem-16 + cpus = { 16 * task.attempt } + memory = { 128.GB * task.attempt } time = { 16.h * task.attempt } } withLabel:process_long { time = { 20.h * task.attempt } } - withLabel:process_high_memory { - memory = { 200.GB * task.attempt } - } withLabel:error_ignore { errorStrategy = 'ignore' } diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config index 2bab1b6d..cd2ebcba 100644 --- a/conf/profiles/gcp.config +++ b/conf/profiles/gcp.config @@ -13,6 +13,7 @@ process { // BCL convert resources withName: '.*BCL_DEMULTIPLEX:BCLCONVERT' { + machineType = 'template://gen-nfbatch-dev-xlarge' // n2-highmem-32, 1TB disk cpus = 32 memory = { 64.GB * task.attempt } disk = { 1.TB * task.attempt } @@ -33,10 +34,12 @@ process { // Alignment post-processing resources withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { + machineType = 'template://gen-nfbatch-dev-medium' // n2-highmem-8, 100GB disk disk = { input instanceof List ? input.sum { it.size() } * 3 * task.attempt : input.size() * 3 * task.attempt } time = 24.h } withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { + machineType = 'template://gen-nfbatch-dev-medium' // n2-highmem-8, 100GB disk disk = { input instanceof List ? input.sum { it.size() } * 3 * task.attempt : input.size() * 3 * task.attempt } time = 24.h } From 3c107281bf1cc7fd07a55428143cbaaa606ae9de Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:56:32 +0100 Subject: [PATCH 136/228] remove analysis profiles and migrate to exernal repo --- conf/base.config | 6 ---- conf/profiles/WES.config | 6 ---- conf/profiles/WGS.config | 6 ---- conf/profiles/copgt.config | 13 -------- conf/profiles/gcp.config | 63 ----------------------------------- conf/profiles/s3_ugent.config | 9 ----- conf/profiles/sWGS.config | 4 --- nextflow.config | 19 +++-------- 8 files changed, 5 insertions(+), 121 deletions(-) delete mode 100644 conf/profiles/WES.config delete mode 100644 conf/profiles/WGS.config delete mode 100644 conf/profiles/copgt.config delete mode 100644 conf/profiles/gcp.config delete mode 100644 conf/profiles/s3_ugent.config delete mode 100644 conf/profiles/sWGS.config diff --git a/conf/base.config b/conf/base.config index 60cf57dd..ff798214 100644 --- a/conf/base.config +++ b/conf/base.config @@ -13,33 +13,27 @@ process { cpus = { 1 * task.attempt } memory = { 8.GB * task.attempt } time = { 4.h * task.attempt } - machineType = 'template://gen-nfbatch-dev-small' // e2-standard-4 - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } maxRetries = 3 maxErrors = '-1' // Process-specific resource requirements withLabel:process_single { - machineType = 'template://gen-nfbatch-dev-small' // e2-standard-4 cpus = { 1 } memory = { 8.GB * task.attempt } time = { 4.h * task.attempt } } withLabel:process_low { - machineType = 'template://gen-nfbatch-dev-small' // e2-standard-4 cpus = { 2 * task.attempt } memory = { 16.GB * task.attempt } time = { 4.h * task.attempt } } withLabel:process_medium { - machineType = 'template://gen-nfbatch-dev-medium' // n2-highmem-8 cpus = { 8 * task.attempt } memory = { 64.GB * task.attempt } time = { 8.h * task.attempt } } withLabel:process_high { - machineType = 'template://gen-nfbatch-dev-large' // n2-highmem-16 cpus = { 16 * task.attempt } memory = { 128.GB * task.attempt } time = { 16.h * task.attempt } diff --git a/conf/profiles/WES.config b/conf/profiles/WES.config deleted file mode 100644 index 2fd529a8..00000000 --- a/conf/profiles/WES.config +++ /dev/null @@ -1,6 +0,0 @@ -params { - run_coverage = true - disable_picard_metrics = false - roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_WES_analysis_ROI_v7.bed" - genelists = "${params.igenomes_base}/Hsapiens/GRCh38/regions/genelists" -} diff --git a/conf/profiles/WGS.config b/conf/profiles/WGS.config deleted file mode 100644 index 657f8ec7..00000000 --- a/conf/profiles/WGS.config +++ /dev/null @@ -1,6 +0,0 @@ -params { - markdup = "samtools" - umi_aware = true - run_coverage = true - disable_picard_metrics = false -} diff --git a/conf/profiles/copgt.config b/conf/profiles/copgt.config deleted file mode 100644 index 67fd693b..00000000 --- a/conf/profiles/copgt.config +++ /dev/null @@ -1,13 +0,0 @@ -params { - run_coverage = true - disable_picard_metrics = true - roi = "${params.igenomes_base}/Hsapiens/GRCh38/regions/CMGG_coPGT-M_analyses_ROI_v1.bed" - - // trimming options - skip_trimming = false - trim_front = 6 - adapter_R1 = "CAGATC" - - // markduplicates options - markdup = false -} diff --git a/conf/profiles/gcp.config b/conf/profiles/gcp.config deleted file mode 100644 index cd2ebcba..00000000 --- a/conf/profiles/gcp.config +++ /dev/null @@ -1,63 +0,0 @@ -// Tweaked resources for GCP - -process { - executor = 'google-batch' - disk = 100.GB - time = 24.h - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } - maxRetries = 5 - - // tentative fix for `cannot stat` error - // https://github.com/nextflow-io/nextflow/issues/6213#issuecomment-3173533808 - stageOutMode = 'copy' - - // BCL convert resources - withName: '.*BCL_DEMULTIPLEX:BCLCONVERT' { - machineType = 'template://gen-nfbatch-dev-xlarge' // n2-highmem-32, 1TB disk - cpus = 32 - memory = { 64.GB * task.attempt } - disk = { 1.TB * task.attempt } - } - - // Trimming resources - // withName: '.*FASTP' {} - - // Alignment resources - // DNA - // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' {} - // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:BWAMEM.*_MEM' {} - // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:DRAGMAP_ALIGN' {} - // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:STROBEALIGN' {} - // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' {} - // RNA - // withName: '.*FASTQ_TO_CRAM:FASTQ_ALIGN_RNA:STAR_ALIGN' {} - - // Alignment post-processing resources - withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORMADUP' { - machineType = 'template://gen-nfbatch-dev-medium' // n2-highmem-8, 100GB disk - disk = { input instanceof List ? input.sum { it.size() } * 3 * task.attempt : input.size() * 3 * task.attempt } - time = 24.h - } - withName: '.*FASTQ_TO_CRAM:SAMTOOLS_SORT' { - machineType = 'template://gen-nfbatch-dev-medium' // n2-highmem-8, 100GB disk - disk = { input instanceof List ? input.sum { it.size() } * 3 * task.attempt : input.size() * 3 * task.attempt } - time = 24.h - } - // withName: '.*FASTQ_TO_CRAM:BIOBAMBAM_BAMSORMADUP' {} - // withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' {} - - // Coverage QC resources - // withName: '.*COVERAGE:MOSDEPTH' {} - // withName: '.*COVERAGE:SAMTOOLS_COVERAGE' {} - // withName: '.*COVERAGE:PANELCOVERAGE' {} - - // Bam QC resources - // withName: '.*BAM_QC:SAMTOOLS_.*$' {} - withName: '.*BAM_QC:PICARD_.*$' { - time = 24.h - } - - // Misc resources - // withName: '.*MD5SUM' {} - // withName: '.*MULTIQC_.*$' {} -} diff --git a/conf/profiles/s3_ugent.config b/conf/profiles/s3_ugent.config deleted file mode 100644 index 7e2fe67a..00000000 --- a/conf/profiles/s3_ugent.config +++ /dev/null @@ -1,9 +0,0 @@ -aws { - profile = "ugent" - client { - endpoint = "https://s3.ugent.be" - protocol = "https" - s3PathStyleAccess = true - connectionTimeout = 60000 - } -} diff --git a/conf/profiles/sWGS.config b/conf/profiles/sWGS.config deleted file mode 100644 index 4497e094..00000000 --- a/conf/profiles/sWGS.config +++ /dev/null @@ -1,4 +0,0 @@ -params { - run_coverage = false - disable_picard_metrics = true -} diff --git a/nextflow.config b/nextflow.config index f3ec3448..2787bdd6 100644 --- a/nextflow.config +++ b/nextflow.config @@ -57,8 +57,8 @@ params { config_profile_name = null config_profile_description = null - custom_config_version = 'master' - custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + custom_config_version = 'main' + custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null @@ -184,26 +184,17 @@ profiles { } test { includeConfig 'conf/test.config' } test_full { includeConfig 'conf/test_full.config' } - // resource profiles - gcp { includeConfig 'conf/profiles/gcp.config' } - s3_ugent { includeConfig 'conf/profiles/s3_ugent.config' } - // analysis profiles - sWGS { includeConfig 'conf/profiles/sWGS.config' } - WGS { includeConfig 'conf/profiles/WGS.config' } - WES { includeConfig 'conf/profiles/WES.config' } - copgt { includeConfig 'conf/profiles/copgt.config' } } // Load nf-core custom profiles from different institutions // If params.custom_config_base is set AND either the NXF_OFFLINE environment variable is not set or params.custom_config_base is a local path, the nfcore_custom.config file from the specified base path is included. // Load nf-cmgg/preprocessing custom profiles from different institutions. -includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" +// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" -// Load nf-cmgg/preprocessing custom profiles from different institutions. -// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs -// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" +// Load nf-cmgg/preprocessing custom profiles. +includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled From 8cfdd7865553e4b2ea99a16050782e8ba3e39bcf Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:40:12 +0100 Subject: [PATCH 137/228] fix linting --- .nf-core.yml | 4 +--- nextflow_schema.json | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.nf-core.yml b/.nf-core.yml index a9c2a6ae..b17c6d97 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -20,9 +20,7 @@ lint: merge_markers: - bin/cmgg_genelists multiqc_config: false - nextflow_config: - - manifest.name - - manifest.homePage + nextflow_config: false template_strings: - bin/cmgg_genelists nf_test_content: false diff --git a/nextflow_schema.json b/nextflow_schema.json index efbaa2c0..19a00a3f 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -136,16 +136,16 @@ "custom_config_version": { "type": "string", "description": "Git commit id for Institutional configs.", - "default": "master", + "default": "main", "hidden": true, "fa_icon": "fas fa-users-cog" }, "custom_config_base": { "type": "string", - "description": "Base directory for Institutional configs.", - "default": "https://raw.githubusercontent.com/nf-core/configs/master", + "description": "Base directory for custom configs.", + "default": "https://raw.githubusercontent.com/nf-cmgg/configs/main", "hidden": true, - "help_text": "If you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.", + "help_text": "If you're running offline, Nextflow will not be able to fetch the custom config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.", "fa_icon": "fas fa-users-cog" }, "config_profile_name": { From 2b0370b736ac9de3e7e250b6724a3eeaa22c89e5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:53:58 +0100 Subject: [PATCH 138/228] fix snaps --- tests/workflows/preprocessing.nf.test.snap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 15d55f4e..0bdfd83c 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -394,7 +394,7 @@ "test_data" ], "multiqc_library_plots": [ - "test_plots" + ], "multiqc_library_report": [ "test.html" @@ -853,7 +853,7 @@ "test_data" ], "multiqc_library_plots": [ - "test_plots" + ], "multiqc_library_report": [ "test.html" @@ -1336,7 +1336,7 @@ "test_data" ], "multiqc_library_plots": [ - "test_plots" + ], "multiqc_library_report": [ "test.html" From 2b03d68f379b257954bbb8fd436a1106040cce1b Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 9 Feb 2026 13:50:29 +0100 Subject: [PATCH 139/228] nf-cmgg/configs fix --- nextflow.config | 23 +++++++++++++++----- nextflow_schema.json | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/nextflow.config b/nextflow.config index 2787bdd6..6a275948 100644 --- a/nextflow.config +++ b/nextflow.config @@ -57,11 +57,20 @@ params { config_profile_name = null config_profile_description = null - custom_config_version = 'main' - custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.custom_config_version}" + custom_config_version = 'master' + custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null + // CMGG Config options + cmgg_config_profile_name = null + cmgg_config_profile_description = null + + cmgg_custom_config_version = 'main' + cmgg_custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.cmgg_custom_config_version}" + cmgg_config_profile_contact = null + cmgg_config_profile_url = null + // Schema validation default options validate_params = true } @@ -190,11 +199,15 @@ profiles { // If params.custom_config_base is set AND either the NXF_OFFLINE environment variable is not set or params.custom_config_base is a local path, the nfcore_custom.config file from the specified base path is included. // Load nf-cmgg/preprocessing custom profiles from different institutions. -// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" +includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" -// Load nf-cmgg/preprocessing custom profiles. -includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" +// Load nf-cmgg/preprocessing custom profiles from different institutions. +// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs +// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" + +// Load nf-cmgg/preprocessing custom profiles from nf-cmgg/configs. +includeConfig params.cmgg_custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.cmgg_custom_config_base.startsWith('http')) ? "${params.cmgg_custom_config_base}/pipeline/preprocessing.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled diff --git a/nextflow_schema.json b/nextflow_schema.json index 19a00a3f..63d39f34 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -174,6 +174,54 @@ } } }, + "cmgg_institutional_config_options": { + "title": "nf-cmgg config options", + "type": "object", + "fa_icon": "fas fa-university", + "description": "Parameters used to describe centralised config profiles. These should not be edited.", + "help_text": "The centralised nf-cmgg configuration profiles use a handful of pipeline parameters to describe themselves. This information is then printed to the Nextflow log when you run a pipeline. You should not need to change these values when you run a pipeline.", + "properties": { + "cmgg_custom_config_version": { + "type": "string", + "description": "Git commit id for nf-cmgg configs.", + "default": "master", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "cmgg_custom_config_base": { + "type": "string", + "description": "Base directory for nf-cmgg configs.", + "default": "https://raw.githubusercontent.com/nf-cmgg/configs/master", + "hidden": true, + "help_text": "If you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.", + "fa_icon": "fas fa-users-cog" + }, + "cmgg_config_profile_name": { + "type": "string", + "description": "nf-cmgg config name.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "cmgg_config_profile_description": { + "type": "string", + "description": "nf-cmgg config description.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "cmgg_config_profile_contact": { + "type": "string", + "description": "nf-cmgg config contact information.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + }, + "cmgg_config_profile_url": { + "type": "string", + "description": "nf-cmgg config URL link.", + "hidden": true, + "fa_icon": "fas fa-users-cog" + } + } + }, "generic_options": { "title": "Generic options", "type": "object", @@ -315,6 +363,9 @@ { "$ref": "#/$defs/institutional_config_options" }, + { + "$ref": "#/$defs/cmgg_institutional_config_options" + }, { "$ref": "#/$defs/generic_options" } From 926ab4988da1a40bb7b09b7cf75b5524638c0523 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 9 Feb 2026 14:21:32 +0100 Subject: [PATCH 140/228] bump version to 3.0.0dev --- .nf-core.yml | 5 ++- CHANGELOG.md | 2 +- nextflow.config | 2 +- ro-crate-metadata.json | 79 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/.nf-core.yml b/.nf-core.yml index b17c6d97..e1b35ad2 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -28,12 +28,11 @@ nf_core_version: 3.5.2 repository_type: pipeline template: author: Matthias De Smet, Nicolas Vannieuwkerke - description: Demultiplexing, adapter trimming, alignment, and coverage calculation - for NGS data. + description: Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data. force: false is_nfcore: false name: preprocessing org: nf-cmgg outdir: . skip_features: ["fastqc"] - version: 2.1.0dev + version: 3.0.0dev diff --git a/CHANGELOG.md b/CHANGELOG.md index def4121f..4963ab44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.1.0dev +## 3.0.0dev - Update the output handling to use the new workflow output definitions. - Bump all modules to latest versions. diff --git a/nextflow.config b/nextflow.config index 6a275948..2beb9d9e 100644 --- a/nextflow.config +++ b/nextflow.config @@ -288,7 +288,7 @@ manifest { mainScript = 'main.nf' defaultBranch = 'main' nextflowVersion = '!>=25.10.0' - version = '2.1.0dev' + version = '3.0.0dev' doi = '' } diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 55c3e77d..1d3d46af 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -22,24 +22,36 @@ "@id": "./", "@type": "Dataset", "creativeWorkStatus": "InProgress", - "datePublished": "2025-11-13T15:11:21+00:00", + "datePublished": "2026-02-09T13:16:20+00:00", "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,aligner,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,bwamem,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag,aligner\nfc_sample1,test,Homo sapiens,WES,bwamem\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" }, + { + "@id": "docs/images/metro_map.png" + }, { "@id": "assets/" }, + { + "@id": "bin/" + }, { "@id": "conf/" }, { "@id": "docs/" }, + { + "@id": "docs/images/" + }, { "@id": "modules/" }, + { + "@id": "modules/local/" + }, { "@id": "modules/nf-core/" }, @@ -93,7 +105,7 @@ }, "mentions": [ { - "@id": "#3be06551-eaa0-4c8e-8ad8-cf70f05fb90c" + "@id": "#e939b96d-700d-40a2-9ff8-added4e0ade4" } ], "name": "nf-cmgg/preprocessing" @@ -120,9 +132,20 @@ "SoftwareSourceCode", "ComputationalWorkflow" ], + "creator": [ + { + "@id": "https://orcid.org/0000-0003-2555-3114" + }, + { + "@id": "https://orcid.org/0009-0003-5619-1555" + } + ], "dateCreated": "", - "dateModified": "2025-11-13T16:11:21Z", + "dateModified": "2026-02-09T14:16:20Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", + "image": { + "@id": "docs/images/metro_map.png" + }, "keywords": [ "nf-core", "nextflow" @@ -130,6 +153,11 @@ "license": [ "MIT" ], + "maintainer": [ + { + "@id": "https://orcid.org/0000-0003-2555-3114" + } + ], "name": [ "nf-cmgg/preprocessing" ], @@ -144,7 +172,7 @@ "https://nf-co.re/nf-cmgg/preprocessing/dev/" ], "version": [ - "2.1.0dev" + "3.0.0dev" ] }, { @@ -157,14 +185,22 @@ "url": { "@id": "https://www.nextflow.io/" }, - "version": "!>=25.04.0" + "version": "!>=25.10.0" }, { - "@id": "#3be06551-eaa0-4c8e-8ad8-cf70f05fb90c", + "@id": "docs/images/metro_map.png", + "@type": [ + "File", + "ImageObject" + ], + "name": "Workflow diagram" + }, + { + "@id": "#e939b96d-700d-40a2-9ff8-added4e0ade4", "@type": "TestSuite", "instance": [ { - "@id": "#4d67a865-3114-4fc8-94e4-c36091fb7276" + "@id": "#a6c6a5a5-b7e8-4825-8dce-3f467dbc2c91" } ], "mainEntity": { @@ -173,7 +209,7 @@ "name": "Test suite for nf-cmgg/preprocessing" }, { - "@id": "#4d67a865-3114-4fc8-94e4-c36091fb7276", + "@id": "#a6c6a5a5-b7e8-4825-8dce-3f467dbc2c91", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-cmgg/preprocessing", "resource": "repos/nf-cmgg/preprocessing/actions/workflows/nf-test.yml", @@ -195,6 +231,11 @@ "@type": "Dataset", "description": "Additional files" }, + { + "@id": "bin/", + "@type": "Dataset", + "description": "Scripts that must be callable from a pipeline process" + }, { "@id": "conf/", "@type": "Dataset", @@ -205,11 +246,21 @@ "@type": "Dataset", "description": "Markdown files for documenting the pipeline" }, + { + "@id": "docs/images/", + "@type": "Dataset", + "description": "Images for the documentation files" + }, { "@id": "modules/", "@type": "Dataset", "description": "Modules used by the pipeline" }, + { + "@id": "modules/local/", + "@type": "Dataset", + "description": "Pipeline-specific modules" + }, { "@id": "modules/nf-core/", "@type": "Dataset", @@ -290,6 +341,18 @@ "@type": "Organization", "name": "nf-core", "url": "https://nf-co.re/" + }, + { + "@id": "https://orcid.org/0000-0003-2555-3114", + "@type": "Person", + "email": "11850640+matthdsm@users.noreply.github.com", + "name": "Matthias De Smet" + }, + { + "@id": "https://orcid.org/0009-0003-5619-1555", + "@type": "Person", + "email": "101190534+nvnieuwk@users.noreply.github.com", + "name": "Nicolas Vannieuwkerke" } ] } \ No newline at end of file From f1d78fe1e2a404a5e2f7d6e4ff8a8cbe89f98f36 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:20:21 +0100 Subject: [PATCH 141/228] deprecate global analysis params in favor of per sample settings --- CHANGELOG.md | 4 + assets/schema_input.json | 80 ++++++-- assets/schema_sampleinfo.json | 70 ++++++- main.nf | 2 - .../picard/collectmultiplemetrics/main.nf | 4 +- nextflow.config | 10 - nextflow_schema.json | 51 ----- subworkflows/local/bam_qc/main.nf | 70 +++---- .../local/fastq_to_aligned_cram/main.nf | 79 ++++---- workflows/preprocessing.nf | 191 +++++------------- 10 files changed, 260 insertions(+), 301 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4963ab44..aeda298e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Drop support for unaligned cram outputs. - Add support for untrimmed fastq outputs for unsupported genomes or when aligner is set to `false`. - Drop support for global `aligner` parameter. The aligner must now be specified per sample in the sample sheet or sample info. +- Drop support for global `markdup` and `umi_aware` parameters. Marking duplicates must now be specified per sample in the sample sheet or sample info. +- Drop support for global `run_coverage` and `disable_picard_metrics` parameters. Running coverage analysis must now be specified per sample in the sample sheet or sample info. +- Drop support for global `skip_trimming`, `trim_front`, `trim_tail`, `adapter_R1` and `adapter_R2` parameters. Trimming must now be specified per sample in the sample sheet or sample info. +- Drop support for global `roi` parameter. Regions of interest must now be specified per sample in the sample sheet or sample info. - Simplify fastq sharding and make it user configurable via the `split_fastq` parameter. - Added splice junctions and junctions outputs for RNA-seq alignments using STAR. diff --git a/assets/schema_input.json b/assets/schema_input.json index 7eab645d..59ee5046 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -37,7 +37,71 @@ "meta": ["aligner"], "type": ["string", "boolean"], "description": "Aligner to use to align sample to the reference genome", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false] + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false], + "default": "false" + }, + "markdup": { + "meta": ["markdup"], + "type": ["string", "boolean"], + "description": "Mark duplicates tool to use", + "enum": ["bamsormadup", "samtools", "false", false], + "default": "bamsormadup" + }, + "umi_aware": { + "meta": ["umi_aware"], + "type": "boolean", + "description": "Run markdup in UMI-aware mode. This applies to Samtools only and requires the UMI to be in the read name.", + "default": false + }, + "skip_trimming": { + "meta": ["skip_trimming"], + "type": "boolean", + "description": "Skip adapter trimming", + "default": false + }, + "trim_front": { + "meta": ["trim_front"], + "type": "integer", + "description": "Number of bases to trim from the front of each read", + "default": 0 + }, + "trim_tail": { + "meta": ["trim_tail"], + "type": "integer", + "description": "Number of bases to trim from the tail of each read", + "default": 0 + }, + "adapter_R1": { + "meta": ["adapter_R1"], + "type": "string", + "description": "Adapter sequence to trim from read 1", + "default": null + }, + "adapter_R2": { + "meta": ["adapter_R2"], + "type": "string", + "description": "Adapter sequence to trim from read 2", + "default": null + }, + "run_coverage": { + "meta": ["run_coverage"], + "type": "boolean", + "description": "Whether to run coverage analysis for the sample", + "default": false + }, + "disable_picard_metrics": { + "meta": ["disable_picard_metrics"], + "type": "boolean", + "description": "Whether to disable Picard metrics calculation. This can be used to speed up processing if Picard is not needed.", + "default": true + }, + "roi": { + "meta": ["roi"], + "type": "string", + "format": "file-path", + "description": "Region of interest BED file for coverage analysis", + "pattern": "^\\S+\\.bed$", + "default": null }, "tag": { "meta": ["tag"], @@ -45,12 +109,6 @@ "description": "Sample tag", "pattern": "^[a-zA-Z0-9_-]+$" }, - "purpose": { - "meta": ["purpose"], - "type": "string", - "description": "Sample purpose, can be either 'research' or 'diagnostic'", - "enum": ["research", "diagnostic"] - }, "sample_type": { "meta": ["sample_type"], "type": "string", @@ -64,14 +122,6 @@ "pattern": "^[a-zA-Z0-9_-]+$", "description": "Sample library name" }, - "roi": { - "meta": ["roi"], - "type": "string", - "format": "file-path", - "description": "Region of interest BED file for coverage analysis", - "pattern": "^\\S+\\.bed$", - "default": null - }, "lane": { "type": "integer", "meta": ["lane"], diff --git a/assets/schema_sampleinfo.json b/assets/schema_sampleinfo.json index bac6789d..26bb486a 100644 --- a/assets/schema_sampleinfo.json +++ b/assets/schema_sampleinfo.json @@ -73,19 +73,75 @@ "type": "string" } }, + "aligner": { + "meta": ["aligner"], + "type": ["string", "boolean"], + "description": "Aligner to use to align sample to the reference genome", + "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false], + "default": "false" + }, + "markdup": { + "meta": ["markdup"], + "type": ["string", "boolean"], + "description": "Mark duplicates tool to use", + "enum": ["bamsormadup", "samtools", "false", false], + "default": "bamsormadup" + }, + "umi_aware": { + "meta": ["umi_aware"], + "type": "boolean", + "description": "Run markdup in UMI-aware mode. This applies to Samtools only and requires the UMI to be in the read name.", + "default": false + }, + "skip_trimming": { + "meta": ["skip_trimming"], + "type": "boolean", + "description": "Skip adapter trimming", + "default": false + }, + "trim_front": { + "meta": ["trim_front"], + "type": "integer", + "description": "Number of bases to trim from the front of each read", + "default": 0 + }, + "trim_tail": { + "meta": ["trim_tail"], + "type": "integer", + "description": "Number of bases to trim from the tail of each read", + "default": 0 + }, + "adapter_R1": { + "meta": ["adapter_R1"], + "type": "string", + "description": "Adapter sequence to trim from read 1", + "default": null + }, + "adapter_R2": { + "meta": ["adapter_R2"], + "type": "string", + "description": "Adapter sequence to trim from read 2", + "default": null + }, + "run_coverage": { + "meta": ["run_coverage"], + "type": "boolean", + "description": "Whether to run coverage analysis for the sample", + "default": false + }, + "disable_picard_metrics": { + "meta": ["disable_picard_metrics"], + "type": "boolean", + "description": "Whether to disable Picard metrics calculation. This can be used to speed up processing if Picard is not needed.", + "default": true + }, "roi": { "meta": ["roi"], "type": "string", "format": "file-path", "description": "Region of interest BED file for coverage analysis", - "pattern": "^[a-zA-Z0-9_]+.bed$", + "pattern": "^\\S+\\.bed$", "default": null - }, - "aligner": { - "meta": ["aligner"], - "type": ["string", "boolean"], - "description": "Aligner to use to align sample to the reference genome", - "enum": ["bowtie2", "bwamem", "bwamem2", "dragmap", "snap", "strobe", "star", "false", false] } } }, diff --git a/main.nf b/main.nf index 03dfac1a..305e0e6b 100644 --- a/main.nf +++ b/main.nf @@ -45,8 +45,6 @@ workflow { PREPROCESSING( PIPELINE_INITIALISATION.out.samplesheet, params.genomes, - params.markdup, - params.roi, params.genelists, ) diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index e4d74998..765d2ce9 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -8,7 +8,7 @@ process PICARD_COLLECTMULTIPLEMETRICS { 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: - tuple val(meta) , path(bam), path(bai) ,path(fasta) ,path(fai) + tuple val(meta) , path(bam), path(bai), path(intervals), path(fasta) ,path(fai), path(dict) output: tuple val(meta), path("*_metrics"), emit: metrics @@ -21,6 +21,7 @@ process PICARD_COLLECTMULTIPLEMETRICS { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + def intervals = intervals ? "--INTERVALS ${intervals.join(',')}" : "" def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" def avail_mem = 3072 if (!task.memory) { @@ -35,6 +36,7 @@ process PICARD_COLLECTMULTIPLEMETRICS { $args \\ --INPUT $bam \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ + $intervals \\ $reference cat <<-END_VERSIONS > versions.yml diff --git a/nextflow.config b/nextflow.config index 2beb9d9e..30835d39 100644 --- a/nextflow.config +++ b/nextflow.config @@ -18,17 +18,7 @@ params { igenomes_ignore = false // Analysis options - markdup = 'bamsormadup' - umi_aware = false - skip_trimming = false split_fastq = 100000000 - trim_front = 0 - trim_tail = 0 - adapter_R1 = null - adapter_R2 = null - run_coverage = true - disable_picard_metrics = false - roi = null genelists = null // MultiQC options diff --git a/nextflow_schema.json b/nextflow_schema.json index 63d39f34..722c57ce 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -51,27 +51,6 @@ "description": "", "default": "", "properties": { - "markdup": { - "type": "string", - "default": "bamsormadup", - "description": "Which alignment postprocessor to use", - "enum": ["bamsormadup", "samtools", "false"] - }, - "umi_aware": { - "type": "boolean", - "default": "false", - "description": "Run markdup in UMI-aware mode. This applies to Samtools only and requires the UMI to be in the read name." - }, - "run_coverage": { - "type": "boolean", - "description": "Run coverage analysis steps", - "default": true - }, - "skip_trimming": { - "type": "boolean", - "description": "Skip adapter trimming", - "default": false - }, "split_fastq": { "type": "integer", "oneOf": [ @@ -87,36 +66,6 @@ "description": "Specify how many reads each split of a FastQ file contains. Set 0 to turn off splitting at all.", "help_text": "Use the the tool FastP to split FASTQ file by number of reads. This parallelizes across fastq file shards speeding up mapping. Note although the minimum value is 250 reads, if you have fewer than 250 reads a single FASTQ shard will still be created." }, - "trim_front": { - "type": "integer", - "default": 0, - "description": "Number of bases to trim from the front of the read" - }, - "trim_tail": { - "type": "integer", - "default": 0, - "description": "Number of bases to trim from the tail of the read" - }, - "adapter_R1": { - "type": "string", - "default": null, - "description": "Adapter sequence to be trimmed" - }, - "adapter_R2": { - "type": "string", - "default": null, - "description": "Adapter sequence to be trimmed" - }, - "disable_picard_metrics": { - "type": "boolean", - "default": false, - "description": "Disable the calculation of (slow) Picard metrics" - }, - "roi": { - "type": "string", - "default": null, - "description": "Region of interest for coverage analysis to be applied to all samples" - }, "genelists": { "type": "string", "default": null, diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index e35555a8..4978c5dd 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -11,65 +11,57 @@ include { PICARD_COLLECTWGSMETRICS } from '../../../modules/nf-core/picard/ workflow BAM_QC { take: ch_bam_bai_roi_fasta_fai_dict // channel: [ val(meta), path(bam), path(bai), path(roi), path(fasta), path(fai), path(dict)] - disable_picard // boolean main: ch_versions = channel.empty() ch_bam_bai_roi_fasta_fai_dict - .map { meta, bam, bai, _roi, fasta, _fai, _dict -> - return [meta, bam, bai, fasta] - } - .set { ch_bam_bai_fasta } - - SAMTOOLS_STATS(ch_bam_bai_fasta) + .map { meta, bam, bai, _roi, fasta, _fai, _dict -> + return [meta, bam, bai, fasta, fai] + } + .set { ch_bam_bai_fasta_fai } - ch_bam_bai_fasta - .map { meta, bam, bai, _fasta -> - return [meta, bam, bai] - } - .set { ch_bam_bai } + SAMTOOLS_STATS(ch_bam_bai_fasta_fai) + ch_versions = ch_versions.mix(SAMTOOLS_STATS.out.versions.first()) - SAMTOOLS_FLAGSTAT(ch_bam_bai) + SAMTOOLS_FLAGSTAT(ch_bam_bai_fasta_fai) ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions.first()) - SAMTOOLS_IDXSTATS(ch_bam_bai) + SAMTOOLS_IDXSTATS(ch_bam_bai_fasta_fai) ch_versions = ch_versions.mix(SAMTOOLS_IDXSTATS.out.versions.first()) ch_picard_hsmetrics = channel.empty() ch_picard_multiplemetrics = channel.empty() ch_picard_multiplemetrics_pdf = channel.empty() ch_picard_wgsmetrics = channel.empty() - if (!disable_picard) { - ch_bam_bai_roi_fasta_fai_dict - .map { meta, bam, bai, _roi, fasta, fai, _dict -> - return [meta, bam, bai, fasta, fai] - } - .set { ch_bam_bai_fasta_fai } + ch_bam_bai_roi_fasta_fai_dict + .filter { meta, _bam, _bai, _roi, _fasta, _fai, _dict -> + meta.disable_picard_metrics != true + } + .set { ch_picard } + + PICARD_COLLECTMULTIPLEMETRICS(ch_picard) + ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions.first()) + ch_picard_multiplemetrics = PICARD_COLLECTMULTIPLEMETRICS.out.metrics + ch_picard_multiplemetrics_pdf = PICARD_COLLECTMULTIPLEMETRICS.out.pdf - PICARD_COLLECTMULTIPLEMETRICS(ch_bam_bai_fasta_fai) - ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions.first()) - ch_picard_multiplemetrics = PICARD_COLLECTMULTIPLEMETRICS.out.metrics - ch_picard_multiplemetrics_pdf = PICARD_COLLECTMULTIPLEMETRICS.out.pdf + ch_picard + .branch { meta, bam, bai, roi, fasta, fai, dict -> + hsmetrics: roi != [] + return [meta, bam, bai, roi, fasta, fai, dict] + wgsmetrics: roi == [] + return [meta, bam, bai, fasta, fai, dict] + .set { ch_picard_coverage } } - ch_bam_bai_roi_fasta_fai_dict - .branch { meta, bam, bai, roi, fasta, fai, dict -> - hsmetrics: roi != [] - return [meta, bam, bai, roi, roi, fasta, fai, dict] - wgsmetrics: roi == [] - return [meta, bam, bai, fasta, fai] - } - .set { ch_picard } + PICARD_COLLECTWGSMETRICS(ch_picard_coverage.wgsmetrics, []) + ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) + ch_picard_wgsmetrics = PICARD_COLLECTWGSMETRICS.out.metrics - PICARD_COLLECTWGSMETRICS(ch_picard.wgsmetrics, []) - ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) - ch_picard_wgsmetrics = PICARD_COLLECTWGSMETRICS.out.metrics + PICARD_COLLECTHSMETRICS(ch_picard_coverage.hsmetrics) + ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions.first()) + ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics - PICARD_COLLECTHSMETRICS(ch_picard.hsmetrics) - ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions.first()) - ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics - } emit: samtools_stats = SAMTOOLS_STATS.out.stats diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 1460d083..9d30ea92 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -20,7 +20,6 @@ include { getGenomeAttribute } from '../../local/utils_nfcore_preprocessing_p workflow FASTQ_TO_CRAM { take: ch_meta_reads_aligner_index_fasta_gtf // channel: [mandatory] [meta, [fastq, ...], aligner [bowtie2, bwamem, bwamem2, dragmap, snap, star], aligner_index, fasta, gtf] - markdup // string: [optional ] markdup [bamsormadup, samtools, false] main: @@ -28,10 +27,10 @@ workflow FASTQ_TO_CRAM { ch_sormadup_metrics = channel.empty() /* - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // STEP: ALIGNMENT - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // STEP: ALIGNMENT + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ ch_meta_reads_aligner_index_fasta_gtf.dump(tag: "FASTQ_TO_CRAM: reads to align", pretty: true) @@ -39,7 +38,8 @@ workflow FASTQ_TO_CRAM { .branch { meta, reads, aligner, index, fasta, gtf -> rna: meta.sample_type == "RNA" return [meta, reads, "star", getGenomeAttribute(meta.genome_data, 'star'), gtf] - dna: meta.sample_type == "DNA" || meta.sample_type == "Tissue" + dna: true // catch all non-RNA samples as DNA, as some may be missing sample_type or have other sample types (e.g. tissue, cell line, etc.) that should be aligned with the DNA aligner + //dna: meta.sample_type == "DNA" || meta.sample_type == "Tissue" return [meta, reads, aligner, index, fasta] } .set { ch_meta_reads_aligner_index_fasta_datatype } @@ -58,10 +58,10 @@ workflow FASTQ_TO_CRAM { ch_versions = ch_versions.mix(FASTQ_ALIGN_DNA.out.versions) /* - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // STEP: MARK DUPLICATES - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // STEP: MARK DUPLICATES + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ FASTQ_ALIGN_DNA.out.bam .mix(FASTQ_ALIGN_RNA.out.bam) @@ -90,40 +90,45 @@ workflow FASTQ_TO_CRAM { .map { meta, files -> return [meta, files.flatten(), getGenomeAttribute(meta.genome_data, 'fasta')] } + .dump(tag: "FASTQ_TO_CRAM: aligned bam per sample", pretty: true) + .branch { meta, files, fasta -> + bamsormadup: meta.markdup == "bamsormadup" + return [meta, files, fasta] + samtools: meta.markdup == "samtools" + return [meta, files, fasta] + sort: meta.markdup == "false" || meta.markdup == false + return [meta, files, fasta] + unknown: true + error("markdup option ${meta.markdup} not supported") + } .set { ch_bam_fasta } - ch_bam_fasta.dump(tag: "FASTQ_TO_CRAM: aligned bam per sample", pretty: true) ch_markdup_index = channel.empty() - if (markdup == "bamsormadup") { - // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) - BIOBAMBAM_BAMSORMADUP(ch_bam_fasta) - ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch: true, failOnDuplicate: true)) - ch_sormadup_metrics = ch_sormadup_metrics.mix(BIOBAMBAM_BAMSORMADUP.out.metrics) - ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions.first()) - } - else if (markdup == "samtools") { - SAMTOOLS_SORMADUP(ch_bam_fasta) - ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch: true, failOnDuplicate: true)) - ch_sormadup_metrics = ch_sormadup_metrics.mix(SAMTOOLS_SORMADUP.out.metrics) - ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions.first()) - } - else if (markdup == "false" || markdup == false) { - // Merge bam files and compress - // SAMTOOLS_SORT([meta, [bam, bam], fasta],index_format) - SAMTOOLS_SORT(ch_bam_fasta, "crai") - ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORT.out.cram.join(SAMTOOLS_SORT.out.crai, failOnMismatch: true, failOnDuplicate: true)) - } - else { - error("markdup: ${markdup} not supported") - } + // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) + BIOBAMBAM_BAMSORMADUP(ch_bam_fasta.bamsormadup) + ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch: true, failOnDuplicate: true)) + ch_sormadup_metrics = ch_sormadup_metrics.mix(BIOBAMBAM_BAMSORMADUP.out.metrics) + ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions.first()) + + // SAMTOOLS_SORMADUP([meta, [bam, bam]], fasta) + SAMTOOLS_SORMADUP(ch_bam_fasta.samtools) + ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch: true, failOnDuplicate: true)) + ch_sormadup_metrics = ch_sormadup_metrics.mix(SAMTOOLS_SORMADUP.out.metrics) + ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions.first()) + + // Merge bam files and compress + // SAMTOOLS_SORT([meta, [bam, bam], fasta],index_format) + SAMTOOLS_SORT(ch_bam_fasta.sort, "crai") + ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORT.out.cram.join(SAMTOOLS_SORT.out.crai, failOnMismatch: true, failOnDuplicate: true)) + ch_markdup_index.dump(tag: "FASTQ_TO_CRAM: postprocessed bam", pretty: true) /* - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // COMPRESSION - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // COMPRESSION + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ ch_markdup_index .branch { meta, reads, index -> diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 6d2802eb..3b22a329 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -37,8 +37,6 @@ workflow PREPROCESSING { take: ch_samplesheet // channel: samplesheet read in from --input genomes // map: genome reference files - markdup // string: markdup method to use - roi // file: regions of interest bed file to be applied to all samples genelists // file: directory containing genelist bed files for coverage analysis main: @@ -55,9 +53,6 @@ workflow PREPROCESSING { error("Unable to determine input type, please check inputs") } .set { ch_inputs_from_samplesheet } - - roi = roi ? file(roi, checkIfExists: true) : null - genelists = genelists ? channel.value(file(genelists + "/*.bed", checkIfExists: true)) : channel.empty() /* @@ -164,19 +159,6 @@ workflow PREPROCESSING { else { meta = meta + ["genome_data": [:]] } - - // set the ROI - // // Special case for coPGT samples - // // if there's no global ROI AND no sample speficic ROI - // // AND the sample tag is "coPGT-M", set the sample ROI to "roi_copgt" - if (!roi && !meta.roi && meta.tag == "coPGT-M") { - meta = meta + ["roi": getGenomeAttribute(meta.genome_data, "roi_copgt")] - } - // // if there's a global ROI AND no sample specific ROI - // // set the global ROI to the sample - if (roi && !meta.roi) { - meta = meta + ["roi": roi] - } return [meta, reads] } .map { meta, reads -> [meta.samplename, [meta, reads]] } @@ -248,130 +230,61 @@ workflow PREPROCESSING { .set { ch_meta_reads_aligner_index_fasta_gtf } FASTQ_TO_CRAM( - ch_meta_reads_aligner_index_fasta_gtf, - markdup, + ch_meta_reads_aligner_index_fasta_gtf ) ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics) ch_versions = ch_versions.mix(FASTQ_TO_CRAM.out.versions) - - /* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// STEP: FILTER SAMPLES WITH 'SNP' TAG -// samples with SNP tag contain only data for sample tracking -// and as such don't need all the QC steps -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - - FASTQ_TO_CRAM.out.cram_crai - .filter { meta, _cram, _crai -> - meta.tag != "SNP" - } - .set { ch_no_snp_samples } - - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: COVERAGE ANALYSIS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_no_snp_samples - .map { meta, cram, crai -> - if (meta.roi) { - return [ - meta, - cram, - crai, - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - file(meta.roi, checkIfExists: true), - ] - } - else { - return [ - meta, - cram, - crai, - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - [], - ] - } - } - .set { ch_cram_crai_fasta_fai_roi } - - def mosdepth_global_out = channel.empty() - def mosdepth_summary_out = channel.empty() - def mosdepth_regions_out = channel.empty() - def mosdepth_per_base_d4_out = channel.empty() - def mosdepth_per_base_bed_out = channel.empty() - def mosdepth_per_base_csi_out = channel.empty() - def mosdepth_regions_bed_out = channel.empty() - def mosdepth_regions_csi_out = channel.empty() - def mosdepth_quantized_bed_out = channel.empty() - def mosdepth_quantized_csi_out = channel.empty() - def mosdepth_thresholds_bed_out = channel.empty() - def mosdepth_thresholds_csi_out = channel.empty() - def samtools_coverage_out = channel.empty() - def panelcoverage_out = channel.empty() - if (params.run_coverage) { - COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) - ch_multiqc_files = ch_multiqc_files.mix( - COVERAGE.out.mosdepth_summary, - COVERAGE.out.mosdepth_global, - COVERAGE.out.mosdepth_regions, - COVERAGE.out.samtools_coverage, - ) - mosdepth_global_out = COVERAGE.out.mosdepth_global - mosdepth_summary_out = COVERAGE.out.mosdepth_summary - mosdepth_regions_out = COVERAGE.out.mosdepth_regions - mosdepth_per_base_d4_out = COVERAGE.out.mosdepth_per_base_d4 - mosdepth_per_base_bed_out = COVERAGE.out.mosdepth_per_base_bed - mosdepth_per_base_csi_out = COVERAGE.out.mosdepth_per_base_csi - mosdepth_regions_bed_out = COVERAGE.out.mosdepth_regions_bed - mosdepth_regions_csi_out = COVERAGE.out.mosdepth_regions_csi - mosdepth_quantized_bed_out = COVERAGE.out.mosdepth_quantized_bed - mosdepth_quantized_csi_out = COVERAGE.out.mosdepth_quantized_csi - mosdepth_thresholds_bed_out = COVERAGE.out.mosdepth_thresholds_bed - mosdepth_thresholds_csi_out = COVERAGE.out.mosdepth_thresholds_csi - samtools_coverage_out = COVERAGE.out.samtools_coverage - panelcoverage_out = COVERAGE.out.panelcoverage - ch_versions = ch_versions.mix(COVERAGE.out.versions) + FASTQ_TO_CRAM.out.cram_crai + .filter { meta, _cram, _crai -> + meta.run_coverage.toBoolean() == true + } + .map { meta, cram, crai -> + return [ + meta, + cram, + crai, + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + meta.roi ? file(meta.roi, checkIfExists: true) : [], + ] } + .set { ch_cram_crai_fasta_fai_roi } + + COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) + ch_multiqc_files = ch_multiqc_files.mix( + COVERAGE.out.mosdepth_summary, + COVERAGE.out.mosdepth_global, + COVERAGE.out.mosdepth_regions, + COVERAGE.out.samtools_coverage, + ) + ch_versions = ch_versions.mix(COVERAGE.out.versions) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: QC FOR ALIGNMENTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_no_snp_samples - .map { meta, cram, crai -> - if (meta.roi) { - return [ - meta, - cram, - crai, - file(meta.roi, checkIfExists: true), - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - getGenomeAttribute(meta.genome_data, "dict"), - ] - } - else { - return [ - meta, - cram, - crai, - [], - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - getGenomeAttribute(meta.genome_data, "dict"), - ] - } - } - .set { ch_cram_crai_roi_fasta_fai_dict } + FASTQ_TO_CRAM.out.cram_crai + .map { meta, cram, crai -> + return [ + meta, + cram, + crai, + meta.roi ? file(meta.roi, checkIfExists: true) : [], + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + getGenomeAttribute(meta.genome_data, "dict"), + ] + } + .set { ch_cram_crai_roi_fasta_fai_dict } - BAM_QC(ch_cram_crai_roi_fasta_fai_dict, params.disable_picard_metrics) + BAM_QC(ch_cram_crai_roi_fasta_fai_dict) ch_multiqc_files = ch_multiqc_files.mix( BAM_QC.out.samtools_stats, BAM_QC.out.samtools_flagstat, @@ -492,20 +405,20 @@ workflow PREPROCESSING { rna_junctions = FASTQ_TO_CRAM.out.rna_junctions align_reports = FASTQ_TO_CRAM.out.align_reports sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics - mosdepth_global = mosdepth_global_out - mosdepth_summary = mosdepth_summary_out - mosdepth_regions = mosdepth_regions_out - mosdepth_per_base_d4 = mosdepth_per_base_d4_out - mosdepth_per_base_bed = mosdepth_per_base_bed_out - mosdepth_per_base_csi = mosdepth_per_base_csi_out - mosdepth_regions_bed = mosdepth_regions_bed_out - mosdepth_regions_csi = mosdepth_regions_csi_out - mosdepth_quantized_bed = mosdepth_quantized_bed_out - mosdepth_quantized_csi = mosdepth_quantized_csi_out - mosdepth_thresholds_bed = mosdepth_thresholds_bed_out - mosdepth_thresholds_csi = mosdepth_thresholds_csi_out - samtools_coverage = samtools_coverage_out - panelcoverage = panelcoverage_out + mosdepth_global = COVERAGE.out.mosdepth_global + mosdepth_summary = COVERAGE.out.mosdepth_summary + mosdepth_regions = COVERAGE.out.mosdepth_regions + mosdepth_per_base_d4 = COVERAGE.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = COVERAGE.out.mosdepth_per_base_bed + mosdepth_per_base_csi = COVERAGE.out.mosdepth_per_base_csi + mosdepth_regions_bed = COVERAGE.out.mosdepth_regions_bed + mosdepth_regions_csi = COVERAGE.out.mosdepth_regions_csi + mosdepth_quantized_bed = COVERAGE.out.mosdepth_quantized_bed + mosdepth_quantized_csi = COVERAGE.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = COVERAGE.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = COVERAGE.out.mosdepth_thresholds_csi + samtools_coverage = COVERAGE.out.samtools_coverage + panelcoverage = COVERAGE.out.panelcoverage samtools_stats = BAM_QC.out.samtools_stats samtools_flagstat = BAM_QC.out.samtools_flagstat samtools_idxstats = BAM_QC.out.samtools_idxstats From dcb2a6e1cf1f974021d49d73cebe32e54e9084b5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:51:55 +0100 Subject: [PATCH 142/228] nextflow lint --- .../picard/collectmultiplemetrics/main.nf | 8 +- modules/nf-core/samtools/sormadup/main.nf | 3 - subworkflows/local/bam_qc/main.nf | 5 +- .../nf-core/utils_nfcore_pipeline/main.nf | 2 +- workflows/preprocessing.nf | 248 +++++++++--------- 5 files changed, 137 insertions(+), 129 deletions(-) diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index 765d2ce9..2dc6679d 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -21,8 +21,8 @@ process PICARD_COLLECTMULTIPLEMETRICS { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def intervals = intervals ? "--INTERVALS ${intervals.join(',')}" : "" - def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" + def intervals_cmd = intervals ? "--INTERVALS ${intervals.join(',')}" : "" + def reference_cmd = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" def avail_mem = 3072 if (!task.memory) { log.info '[Picard CollectMultipleMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.' @@ -36,8 +36,8 @@ process PICARD_COLLECTMULTIPLEMETRICS { $args \\ --INPUT $bam \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ - $intervals \\ - $reference + $intervals_cmd \\ + $reference_cmd cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/sormadup/main.nf b/modules/nf-core/samtools/sormadup/main.nf index 9bc8a43b..86afb479 100644 --- a/modules/nf-core/samtools/sormadup/main.nf +++ b/modules/nf-core/samtools/sormadup/main.nf @@ -32,9 +32,6 @@ process SAMTOOLS_SORMADUP { args5.contains("--output-fmt cram") ? "cram" : "bam" def reference = fasta ? "--reference ${fasta}" : "" - // memory per thread for samtools sort - // set to 50% of the memory per thread, but at least 768M (samtools default) - def sort_memory = Math.max(768,(task.memory.mega/task.cpus*0.50).intValue()) """ samtools cat \\ diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index 4978c5dd..37ef16a7 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -16,7 +16,7 @@ workflow BAM_QC { ch_versions = channel.empty() ch_bam_bai_roi_fasta_fai_dict - .map { meta, bam, bai, _roi, fasta, _fai, _dict -> + .map { meta, bam, bai, _roi, fasta, fai, _dict -> return [meta, bam, bai, fasta, fai] } .set { ch_bam_bai_fasta_fai } @@ -52,7 +52,8 @@ workflow BAM_QC { return [meta, bam, bai, roi, fasta, fai, dict] wgsmetrics: roi == [] return [meta, bam, bai, fasta, fai, dict] - .set { ch_picard_coverage } } + } + .set { ch_picard_coverage } PICARD_COLLECTWGSMETRICS(ch_picard_coverage.wgsmetrics, []) ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index bfd25876..2f30e9a4 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -98,7 +98,7 @@ def workflowVersionToYAML() { // Get channel of software versions used in pipeline in YAML format // def softwareVersionsToYAML(ch_versions) { - return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) + return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(channel.of(workflowVersionToYAML())) } // diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 3b22a329..33c0930b 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -1,4 +1,4 @@ -include { samplesheetToList } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -7,25 +7,25 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules -include { FASTP } from '../modules/nf-core/fastp/main' -include { MD5SUM } from '../modules/nf-core/md5sum/main' -include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' -include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' -include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' -include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' +include { FASTP } from '../modules/nf-core/fastp/main' +include { MD5SUM } from '../modules/nf-core/md5sum/main' +include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' +include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' +include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' +include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' // Subworkflows -include { BAM_QC } from '../subworkflows/local/bam_qc/main' -include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' -include { COVERAGE } from '../subworkflows/local/coverage/main' -include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' +include { BAM_QC } from '../subworkflows/local/bam_qc/main' +include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' +include { COVERAGE } from '../subworkflows/local/coverage/main' +include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' // Functions -include { paramsSummaryMap } from 'plugin/nf-schema' -include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' -include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -36,8 +36,8 @@ include { getGenomeAttribute } from '../subworkflows/local/utils_nfco workflow PREPROCESSING { take: ch_samplesheet // channel: samplesheet read in from --input - genomes // map: genome reference files - genelists // file: directory containing genelist bed files for coverage analysis + genomes // map: genome reference files + genelists // file: directory containing genelist bed files for coverage analysis main: ch_versions = channel.empty() @@ -73,7 +73,7 @@ workflow PREPROCESSING { BCL_DEMULTIPLEX.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) ch_multiqc_files = ch_multiqc_files.mix( BCL_DEMULTIPLEX.out.reports, - BCL_DEMULTIPLEX.out.stats + BCL_DEMULTIPLEX.out.stats, ) ch_versions = ch_versions.mix(BCL_DEMULTIPLEX.out.versions) @@ -178,7 +178,7 @@ workflow PREPROCESSING { ch_fastq_per_sample.supported.dump(tag: "Supported FASTQ per sample", pretty: true) ch_fastq_per_sample.other.dump(tag: "Other FASTQ per sample", pretty: true) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FASTQ TRIMMING AND QC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -187,7 +187,14 @@ workflow PREPROCESSING { // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) - FASTP(ch_fastq_per_sample.supported.map{ meta, fastq -> return [meta, fastq, []] }, false, false, false) + FASTP( + ch_fastq_per_sample.supported.map { meta, fastq -> + return [meta, fastq, []] + }, + false, + false, + false, + ) ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) ch_versions = ch_versions.mix(FASTP.out.versions.first()) @@ -212,22 +219,23 @@ workflow PREPROCESSING { ch_trimmed_reads.dump(tag: "Supported trimmed reads per sample", pretty: true) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: FASTQ TO ALIGNED CRAM CONVERSION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_trimmed_reads.map { meta, reads -> - return [ - meta, - reads, - meta.aligner, - getGenomeAttribute(meta.genome_data, meta.aligner), - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "gtf"), - ] - } - .set { ch_meta_reads_aligner_index_fasta_gtf } + ch_trimmed_reads + .map { meta, reads -> + return [ + meta, + reads, + meta.aligner, + getGenomeAttribute(meta.genome_data, meta.aligner), + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "gtf"), + ] + } + .set { ch_meta_reads_aligner_index_fasta_gtf } FASTQ_TO_CRAM( ch_meta_reads_aligner_index_fasta_gtf @@ -236,25 +244,26 @@ workflow PREPROCESSING { ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics) ch_versions = ch_versions.mix(FASTQ_TO_CRAM.out.versions) + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: COVERAGE ANALYSIS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ FASTQ_TO_CRAM.out.cram_crai - .filter { meta, _cram, _crai -> - meta.run_coverage.toBoolean() == true - } - .map { meta, cram, crai -> - return [ - meta, - cram, - crai, - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - meta.roi ? file(meta.roi, checkIfExists: true) : [], - ] - } - .set { ch_cram_crai_fasta_fai_roi } + .filter { meta, _cram, _crai -> + meta.run_coverage.toBoolean() + } + .map { meta, cram, crai -> + return [ + meta, + cram, + crai, + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + meta.roi ? file(meta.roi, checkIfExists: true) : [], + ] + } + .set { ch_cram_crai_fasta_fai_roi } COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) ch_multiqc_files = ch_multiqc_files.mix( @@ -271,18 +280,18 @@ workflow PREPROCESSING { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ FASTQ_TO_CRAM.out.cram_crai - .map { meta, cram, crai -> - return [ - meta, - cram, - crai, - meta.roi ? file(meta.roi, checkIfExists: true) : [], - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "fai"), - getGenomeAttribute(meta.genome_data, "dict"), - ] - } - .set { ch_cram_crai_roi_fasta_fai_dict } + .map { meta, cram, crai -> + return [ + meta, + cram, + crai, + meta.roi ? file(meta.roi, checkIfExists: true) : [], + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "fai"), + getGenomeAttribute(meta.genome_data, "dict"), + ] + } + .set { ch_cram_crai_roi_fasta_fai_dict } BAM_QC(ch_cram_crai_roi_fasta_fai_dict) ch_multiqc_files = ch_multiqc_files.mix( @@ -318,7 +327,7 @@ workflow PREPROCESSING { // // Collate and save software versions // - def topic_versions = Channel.topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path @@ -327,9 +336,9 @@ workflow PREPROCESSING { def topic_versions_string = topic_versions.versions_tuple .map { process, tool, version -> - [ process[process.lastIndexOf(':')+1..-1], " ${tool}: ${version}" ] + [process[process.lastIndexOf(':') + 1..-1], " ${tool}: ${version}"] } - .groupTuple(by:0) + .groupTuple(by: 0) .map { process, tool_versions -> tool_versions.unique().sort() "${process}:\n${tool_versions.join('\n')}" @@ -341,42 +350,43 @@ workflow PREPROCESSING { storeDir: "${params.outdir}/pipeline_info", name: 'nf_cmgg_preprocessing_software_mqc_versions.yml', sort: true, - newLine: true + newLine: true, ) - .map { file -> [[id: 'main'], file] } // add meta for multiqc + .map { file -> [[id: 'main'], file] } .set { ch_collated_versions } // // MODULE: MultiQC // - ch_multiqc_config = channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_config = channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) ch_multiqc_custom_config = params.multiqc_config ? channel.fromPath(params.multiqc_config, checkIfExists: true) : channel.empty() - ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() + ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") ch_workflow_summary = channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml').map{ file -> [[id: 'main'], file] }) + ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml').map { file -> [[id: 'main'], file] }) - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true).map{ file -> [[id: 'main'], file] }) + ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true).map { file -> [[id: 'main'], file] }) - ch_multiqc_files = ch_multiqc_files.map { meta, files -> - return [meta.library ? [id: meta.library] : [id: 'main'], files] - } - .branch { meta, files -> - main: meta.id == 'main' + ch_multiqc_files = ch_multiqc_files + .map { meta, files -> + return [meta.library ? [id: meta.library] : [id: 'main'], files] + } + .branch { meta, files -> + main: meta.id == 'main' return files - library: meta.id != 'main' + library: meta.id != 'main' return [meta, files instanceof List ? files : [files]] - } + } ch_multiqc_files.main.dump(tag: "MULTIQC files - main", pretty: true) ch_multiqc_files.library.dump(tag: "MULTIQC files - library", pretty: true) MULTIQC_MAIN( - ch_multiqc_files.main.collect().map{ files -> [[id: 'main'], files] }, + ch_multiqc_files.main.collect().map { files -> [[id: 'main'], files] }, ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), @@ -385,7 +395,7 @@ workflow PREPROCESSING { ) MULTIQC_LIBRARY( - ch_multiqc_files.library.transpose(by:1).groupTuple(), + ch_multiqc_files.library.transpose(by: 1).groupTuple(), ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), @@ -394,46 +404,46 @@ workflow PREPROCESSING { ) emit: - demultiplex_interop = BCL_DEMULTIPLEX.out.interop - demultiplex_reports = BCL_DEMULTIPLEX.out.reports - demultiplex_logs = BCL_DEMULTIPLEX.out.logs - demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other - fastp_json = FASTP.out.json - fastp_html = FASTP.out.html - crams = FASTQ_TO_CRAM.out.cram_crai - rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions - rna_junctions = FASTQ_TO_CRAM.out.rna_junctions - align_reports = FASTQ_TO_CRAM.out.align_reports - sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics - mosdepth_global = COVERAGE.out.mosdepth_global - mosdepth_summary = COVERAGE.out.mosdepth_summary - mosdepth_regions = COVERAGE.out.mosdepth_regions - mosdepth_per_base_d4 = COVERAGE.out.mosdepth_per_base_d4 - mosdepth_per_base_bed = COVERAGE.out.mosdepth_per_base_bed - mosdepth_per_base_csi = COVERAGE.out.mosdepth_per_base_csi - mosdepth_regions_bed = COVERAGE.out.mosdepth_regions_bed - mosdepth_regions_csi = COVERAGE.out.mosdepth_regions_csi - mosdepth_quantized_bed = COVERAGE.out.mosdepth_quantized_bed - mosdepth_quantized_csi = COVERAGE.out.mosdepth_quantized_csi - mosdepth_thresholds_bed = COVERAGE.out.mosdepth_thresholds_bed - mosdepth_thresholds_csi = COVERAGE.out.mosdepth_thresholds_csi - samtools_coverage = COVERAGE.out.samtools_coverage - panelcoverage = COVERAGE.out.panelcoverage - samtools_stats = BAM_QC.out.samtools_stats - samtools_flagstat = BAM_QC.out.samtools_flagstat - samtools_idxstats = BAM_QC.out.samtools_idxstats - picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics - picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf - picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics - picard_hsmetrics = BAM_QC.out.picard_hsmetrics - md5sums = MD5SUM.out.checksum - multiqc_main_report = MULTIQC_MAIN.out.report.toList() - multiqc_main_data = MULTIQC_MAIN.out.data.toList() - multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() - multiqc_library_report = MULTIQC_LIBRARY.out.report - multiqc_library_data = MULTIQC_LIBRARY.out.data - multiqc_library_plots = MULTIQC_LIBRARY.out.plots - versions = ch_versions + demultiplex_interop = BCL_DEMULTIPLEX.out.interop + demultiplex_reports = BCL_DEMULTIPLEX.out.reports + demultiplex_logs = BCL_DEMULTIPLEX.out.logs + demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other + fastp_json = FASTP.out.json + fastp_html = FASTP.out.html + crams = FASTQ_TO_CRAM.out.cram_crai + rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions + rna_junctions = FASTQ_TO_CRAM.out.rna_junctions + align_reports = FASTQ_TO_CRAM.out.align_reports + sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics + mosdepth_global = COVERAGE.out.mosdepth_global + mosdepth_summary = COVERAGE.out.mosdepth_summary + mosdepth_regions = COVERAGE.out.mosdepth_regions + mosdepth_per_base_d4 = COVERAGE.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = COVERAGE.out.mosdepth_per_base_bed + mosdepth_per_base_csi = COVERAGE.out.mosdepth_per_base_csi + mosdepth_regions_bed = COVERAGE.out.mosdepth_regions_bed + mosdepth_regions_csi = COVERAGE.out.mosdepth_regions_csi + mosdepth_quantized_bed = COVERAGE.out.mosdepth_quantized_bed + mosdepth_quantized_csi = COVERAGE.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = COVERAGE.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = COVERAGE.out.mosdepth_thresholds_csi + samtools_coverage = COVERAGE.out.samtools_coverage + panelcoverage = COVERAGE.out.panelcoverage + samtools_stats = BAM_QC.out.samtools_stats + samtools_flagstat = BAM_QC.out.samtools_flagstat + samtools_idxstats = BAM_QC.out.samtools_idxstats + picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics + picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf + picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics + picard_hsmetrics = BAM_QC.out.picard_hsmetrics + md5sums = MD5SUM.out.checksum + multiqc_main_report = MULTIQC_MAIN.out.report.toList() + multiqc_main_data = MULTIQC_MAIN.out.data.toList() + multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() + multiqc_library_report = MULTIQC_LIBRARY.out.report + multiqc_library_data = MULTIQC_LIBRARY.out.data + multiqc_library_plots = MULTIQC_LIBRARY.out.plots + versions = ch_versions } /* From c672154501ebb44ec9d37c806c94fb11a9a12837 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 9 Feb 2026 19:00:53 +0100 Subject: [PATCH 143/228] fix tests --- conf/modules.config | 12 ++++++------ subworkflows/local/bam_qc/main.nf | 2 -- tests/subworkflows/local/bam_qc/main.nf.test | 6 ------ tests/workflows/preprocessing.nf.test | 18 +++--------------- 4 files changed, 9 insertions(+), 29 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 36734a8a..d0ac2fe6 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -32,11 +32,11 @@ process { ext.args = { [ params.split_fastq > 0 ? "--split_by_lines ${params.split_fastq * 4}" : '', - params.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", - params.trim_front > 0 ? "--trim_front1 ${params.trim_front}" : "", - params.trim_tail > 0 ? "--trim_tail1 ${params.trim_tail}" : "", - params.adapter_R1 ? "--adapter_sequence ${params.adapter_R1}" : "", - params.adapter_R2 ? "--adapter_sequence_r2 ${params.adapter_R2}" : "", + meta.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", + meta.trim_front > 0 ? "--trim_front1 ${meta.trim_front}" : "", + meta.trim_tail > 0 ? "--trim_tail1 ${meta.trim_tail}" : "", + meta.adapter_R1 ? "--adapter_sequence ${meta.adapter_R1}" : "", + meta.adapter_R2 ? "--adapter_sequence_r2 ${meta.adapter_R2}" : "", "--compression 1", ].join(" ").trim() } @@ -184,7 +184,7 @@ process { "-s", "--json", "-d 2500", - params.umi_aware ? "--barcode-name" : "", + meta.umi_aware ? "--barcode-name" : "", "--write-index", "--output-fmt cram,version=3.0", "--output-fmt-option archive", diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index 37ef16a7..6eb6a0ea 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -22,8 +22,6 @@ workflow BAM_QC { .set { ch_bam_bai_fasta_fai } SAMTOOLS_STATS(ch_bam_bai_fasta_fai) - ch_versions = ch_versions.mix(SAMTOOLS_STATS.out.versions.first()) - SAMTOOLS_FLAGSTAT(ch_bam_bai_fasta_fai) ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions.first()) diff --git a/tests/subworkflows/local/bam_qc/main.nf.test b/tests/subworkflows/local/bam_qc/main.nf.test index 90e3c564..8cd0106b 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test +++ b/tests/subworkflows/local/bam_qc/main.nf.test @@ -23,8 +23,6 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", checkIfExists: true), ]) - // boolean - input[1] = false """ } } @@ -57,8 +55,6 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", checkIfExists: true), ]) - // boolean - input[1] = false """ } } @@ -90,8 +86,6 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", checkIfExists: true), ]) - // boolean - input[1] = true """ } } diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index 45c0fba2..fdcd70ec 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -44,11 +44,7 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] - // markdup - input[2] = "bamsormadup" - // roi - input[3] = "https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed" - input[4] = null + input[2] = null """ } } @@ -115,11 +111,7 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] - // markdup - input[2] = "bamsormadup" - // roi - input[3] = "" - input[4] = null + input[2] = null """ } } @@ -189,11 +181,7 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] - // markdup - input[2] = "bamsormadup" - // roi - input[3] = "https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed" - input[4] = null + input[2] = null """ } } From f723b97b4cb1de477b2e9fa415e945b602587af7 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 07:17:05 +0100 Subject: [PATCH 144/228] fix linting --- modules.json | 4 ++-- .../nf-core/samtools/sormadup/samtools-sormadup.diff | 12 +++++++++++- subworkflows/nf-core/utils_nfschema_plugin/main.nf | 2 +- .../utils_nfschema_plugin/tests/nextflow.config | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/modules.json b/modules.json index 0b710f92..037ebfe4 100644 --- a/modules.json +++ b/modules.json @@ -170,12 +170,12 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "df4d1c8cdee98a1bbbed8fc51e82296568e0f9c1", + "git_sha": "65f5e638d901a51534c68fd5c1c19e8112fb4df1", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": ["subworkflows"] } } diff --git a/modules/nf-core/samtools/sormadup/samtools-sormadup.diff b/modules/nf-core/samtools/sormadup/samtools-sormadup.diff index 1e13bac8..e5a640be 100644 --- a/modules/nf-core/samtools/sormadup/samtools-sormadup.diff +++ b/modules/nf-core/samtools/sormadup/samtools-sormadup.diff @@ -14,7 +14,17 @@ Changes in 'samtools/sormadup/main.nf': output: tuple val(meta), path("*.bam") , emit: bam, optional: true -@@ -64,7 +63,6 @@ +@@ -33,9 +32,6 @@ + args5.contains("--output-fmt cram") ? "cram" : + "bam" + def reference = fasta ? "--reference ${fasta}" : "" +- // memory per thread for samtools sort +- // set to 50% of the memory per thread, but at least 768M (samtools default) +- def sort_memory = Math.max(768,(task.memory.mega/task.cpus*0.50).intValue()) + + """ + samtools cat \\ +@@ -64,7 +60,6 @@ -u \\ -T ${prefix}.sort \\ --threads $task.cpus \\ diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf index acb39724..1df8b76f 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -38,7 +38,7 @@ workflow UTILS_NFSCHEMA_PLUGIN { } log.info paramsHelp( help_options, - params.help instanceof String ? params.help : "", + (params.help instanceof String && params.help != "true") ? params.help : "", ) exit 0 } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 8d8c7371..f6537cc3 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,5 +1,5 @@ plugins { - id "nf-schema@2.5.1" + id "nf-schema@2.6.1" } validation { From e479866d171034926da16c7abda822068b48c644 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 07:26:46 +0100 Subject: [PATCH 145/228] fix fq_to_aligned cram test --- .../local/fastq_to_aligned_cram/main.nf.test | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test index 9a7a9eb3..549854ff 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test @@ -19,6 +19,7 @@ nextflow_workflow { samplename:'test', single_end:false, sample_type:'DNA', + markdup: "bamsormadup", genome_data: [ fasta: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" @@ -33,8 +34,6 @@ nextflow_workflow { file("s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna"), [] ]) - // markdup - input[1] = "bamsormadup" """ } } @@ -62,6 +61,7 @@ nextflow_workflow { samplename:'test', single_end:false, sample_type:'RNA', + markdup: "bamsormadup", genome_data: [ fasta: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", @@ -77,8 +77,6 @@ nextflow_workflow { file("s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna"), [] ]) - // markdup - input[1] = "bamsormadup" """ } } @@ -102,10 +100,11 @@ nextflow_workflow { // [meta, [fq_1,fq_2], aligner, index, fasta] input[0] = Channel.of([ [ - id:'test', - samplename:'test', - single_end:false, - sample_type:'DNA', + id: "test", + samplename: "test", + single_end: false, + sample_type: "DNA", + markdup: "samtools", genome_data: [ fasta: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" @@ -120,8 +119,6 @@ nextflow_workflow { file("s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna"), [] ]) - // markdup - input[1] = "samtools" """ } } @@ -145,10 +142,11 @@ nextflow_workflow { // [meta, [fq_1,fq_2], aligner, index, fasta] input[0] = Channel.of([ [ - id:'test', - samplename:'test', - single_end:false, - sample_type:'DNA', + id: "test", + samplename: "test", + single_end: false, + sample_type: "DNA", + markdup: "false", genome_data: [ fasta: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" @@ -163,8 +161,6 @@ nextflow_workflow { file("s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna"), [] ]) - // markdup - input[1] = "false" """ } } @@ -189,10 +185,11 @@ nextflow_workflow { // [meta, [fq_1,fq_2], aligner, index, fasta] input[0] = Channel.of([ [ - id:'test', - samplename:'test', - single_end:false, - sample_type:'DNA', + id: "test", + samplename: "test", + single_end: false, + sample_type: "DNA", + markdup: "false", genome_data: [ fasta: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" @@ -207,8 +204,6 @@ nextflow_workflow { file("s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna"), [] ]) - // markdup - input[1] = "false" """ } } From 1472bc59105f17c27746d38b2d59934743b36911 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 07:34:25 +0100 Subject: [PATCH 146/228] fix preprocessing test inputs --- tests/workflows/preprocessing.nf.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index fdcd70ec..f31029f4 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -23,6 +23,7 @@ nextflow_workflow { tag: "WES", sample_type: "DNA", aligner: "bwamem", + markdup: "bamsormadup" ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -90,6 +91,7 @@ nextflow_workflow { tag: "WGS", sample_type: "DNA", aligner: "bwamem", + markdup: "bamsormadup" ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -160,6 +162,7 @@ nextflow_workflow { tag: "WES", sample_type: "DNA", aligner: "bwamem", + markdup: "bamsormadup" ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), From bdd54c17b56e0bf76149c6a290899f8d098f8925 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:37:45 +0100 Subject: [PATCH 147/228] update snapshot --- .../fastq_to_aligned_cram/main.nf.test.snap | 72 +++++++++++-------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index aabf04cd..5db51b5f 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -3,7 +3,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -15,6 +15,7 @@ "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" }, "id": "test", + "markdup": "false", "sample_type": "DNA", "samplename": "test", "single_end": false @@ -25,13 +26,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ], "versions": [ "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", @@ -40,16 +41,16 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-12-17T14:52:18.252297311" + "timestamp": "2026-02-10T09:29:24.149695" }, "fastq to cram - bwa - bamsormadup": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -61,6 +62,7 @@ "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" }, "id": "test", + "markdup": "bamsormadup", "sample_type": "DNA", "samplename": "test", "single_end": false @@ -71,10 +73,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -85,6 +87,7 @@ "samplename": "test", "single_end": false, "sample_type": "DNA", + "markdup": "bamsormadup", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" @@ -103,16 +106,16 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-12-17T14:46:54.525880067" + "timestamp": "2026-02-10T09:24:26.615795" }, "fastq to cram - bwa - samtools sormadup": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -124,6 +127,7 @@ "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" }, "id": "test", + "markdup": "samtools", "sample_type": "DNA", "samplename": "test", "single_end": false @@ -134,10 +138,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -148,6 +152,7 @@ "samplename": "test", "single_end": false, "sample_type": "DNA", + "markdup": "samtools", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" @@ -165,16 +170,16 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-12-17T14:50:28.614932101" + "timestamp": "2026-02-10T09:27:45.908866" }, "fastq to cram - star - bamsormadup": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -187,6 +192,7 @@ "star": "s3://test-data/genomics/homo_sapiens/genome/star/" }, "id": "test", + "markdup": "bamsormadup", "sample_type": "RNA", "samplename": "test", "single_end": false @@ -205,6 +211,7 @@ "samplename": "test", "single_end": false, "sample_type": "RNA", + "markdup": "bamsormadup", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", @@ -224,6 +231,7 @@ "samplename": "test", "single_end": false, "sample_type": "RNA", + "markdup": "bamsormadup", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", @@ -243,6 +251,7 @@ "samplename": "test", "single_end": false, "sample_type": "RNA", + "markdup": "bamsormadup", "genome_data": { "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", @@ -260,16 +269,16 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-12-17T16:27:53.162318921" + "timestamp": "2026-02-10T09:26:55.879993" }, "fastq to cram - bwa - samtools sort": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -281,6 +290,7 @@ "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" }, "id": "test", + "markdup": "false", "sample_type": "DNA", "samplename": "test", "single_end": false @@ -291,13 +301,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ], "versions": [ "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", @@ -306,9 +316,9 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-12-17T14:51:22.925873858" + "timestamp": "2026-02-10T09:28:34.042629" } -} +} \ No newline at end of file From 3ded077caa9e110d7f67de6c838b26e7be3ccc14 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:49:21 +0100 Subject: [PATCH 148/228] update snapshot --- tests/subworkflows/local/fastq_align_rna/main.nf.test.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index 2cd3d63c..cf11ffe9 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -119,4 +119,4 @@ }, "timestamp": "2024-05-28T16:17:08.089796673" } -} +} \ No newline at end of file From 71c8972a0061936c08e76169a737acfa77bf19b5 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:57:01 +0100 Subject: [PATCH 149/228] fix roi default --- assets/schema_input.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index 59ee5046..f656f58f 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -101,7 +101,7 @@ "format": "file-path", "description": "Region of interest BED file for coverage analysis", "pattern": "^\\S+\\.bed$", - "default": null + "default": "[]" }, "tag": { "meta": ["tag"], From 0b4e4bd735dd75174b08c87d6e254867ae44171b Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:24:01 +0100 Subject: [PATCH 150/228] nextflow lint entire pipeline --- assets/schema_input.json | 2 +- conf/base.config | 38 +- conf/modules.config | 60 +-- conf/test_full.config | 4 +- main.nf | 432 +++++++++++------- nextflow.config | 252 +++++----- nf-test.config | 12 +- subworkflows/local/bam_qc/main.nf | 43 +- subworkflows/local/coverage/main.nf | 32 +- subworkflows/local/fastq_align_rna/main.nf | 19 +- .../local/fastq_to_aligned_cram/main.nf | 23 +- .../main.nf | 91 ++-- tests/inputs/fastq.yml | 2 + tests/inputs/fastq_rna.yml | 2 + workflows/preprocessing.nf | 4 +- 15 files changed, 550 insertions(+), 466 deletions(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index f656f58f..59ee5046 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -101,7 +101,7 @@ "format": "file-path", "description": "Region of interest BED file for coverage analysis", "pattern": "^\\S+\\.bed$", - "default": "[]" + "default": null }, "tag": { "meta": ["tag"], diff --git a/conf/base.config b/conf/base.config index ff798214..ac353851 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,41 +10,41 @@ process { - cpus = { 1 * task.attempt } - memory = { 8.GB * task.attempt } - time = { 4.h * task.attempt } + cpus = { 1 * task.attempt } + memory = { 8.GB * task.attempt } + time = { 4.h * task.attempt } errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } maxRetries = 3 maxErrors = '-1' // Process-specific resource requirements - withLabel:process_single { - cpus = { 1 } + withLabel: process_single { + cpus = { 1 } memory = { 8.GB * task.attempt } - time = { 4.h * task.attempt } + time = { 4.h * task.attempt } } - withLabel:process_low { - cpus = { 2 * task.attempt } + withLabel: process_low { + cpus = { 2 * task.attempt } memory = { 16.GB * task.attempt } - time = { 4.h * task.attempt } + time = { 4.h * task.attempt } } - withLabel:process_medium { - cpus = { 8 * task.attempt } + withLabel: process_medium { + cpus = { 8 * task.attempt } memory = { 64.GB * task.attempt } - time = { 8.h * task.attempt } + time = { 8.h * task.attempt } } - withLabel:process_high { - cpus = { 16 * task.attempt } + withLabel: process_high { + cpus = { 16 * task.attempt } memory = { 128.GB * task.attempt } - time = { 16.h * task.attempt } + time = { 16.h * task.attempt } } - withLabel:process_long { - time = { 20.h * task.attempt } + withLabel: process_long { + time = { 20.h * task.attempt } } - withLabel:error_ignore { + withLabel: error_ignore { errorStrategy = 'ignore' } - withLabel:error_retry { + withLabel: error_retry { errorStrategy = 'retry' maxRetries = 2 } diff --git a/conf/modules.config b/conf/modules.config index d0ac2fe6..16f7338f 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -14,9 +14,9 @@ process { // BCL convert withName: '.*BCL_DEMULTIPLEX:BCLCONVERT' { - cpus = 16 - memory = { 64.GB * task.attempt } - ext.args = { + cpus = 16 + memory = { 64.GB * task.attempt } + ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", "--force", @@ -27,16 +27,16 @@ process { // FastP withName: '.*FASTP' { - cpus = 4 - memory = { 4.GB * task.attempt } - ext.args = { + cpus = 4 + memory = { 4.GB * task.attempt } + ext.args = { [ - params.split_fastq > 0 ? "--split_by_lines ${params.split_fastq * 4}" : '', - meta.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", - meta.trim_front > 0 ? "--trim_front1 ${meta.trim_front}" : "", - meta.trim_tail > 0 ? "--trim_tail1 ${meta.trim_tail}" : "", - meta.adapter_R1 ? "--adapter_sequence ${meta.adapter_R1}" : "", - meta.adapter_R2 ? "--adapter_sequence_r2 ${meta.adapter_R2}" : "", + params.split_fastq > 0 ? "--split_by_lines ${params.split_fastq * 4}" : '', + meta.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", + meta.trim_front > 0 ? "--trim_front1 ${meta.trim_front}" : "", + meta.trim_tail > 0 ? "--trim_tail1 ${meta.trim_tail}" : "", + meta.adapter_R1 ? "--adapter_sequence ${meta.adapter_R1}" : "", + meta.adapter_R2 ? "--adapter_sequence_r2 ${meta.adapter_R2}" : "", "--compression 1", ].join(" ").trim() } @@ -57,7 +57,7 @@ process { withName: '.*FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { cpus = 16 memory = 32.GB - ext.args = { + ext.args = { [ "--local", "--fast-local", @@ -65,7 +65,7 @@ process { meta.readgroup ? "--rg " + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join(" --rg ") : "", ].join(" ").trim() } - ext.args2 = "--fast" + ext.args2 = "--fast" } //// BWA mem/BWA mem2 @@ -107,8 +107,8 @@ process { //// SNAP withName: '.*FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { - cpus = 16 - memory = 64.GB + cpus = 16 + memory = 64.GB ext.args = { [ "-b-", @@ -125,8 +125,8 @@ process { //// STROBEALIGN withName: '.*FASTQ_ALIGN_DNA:STROBEALIGN' { - cpus = 16 - memory = 32.GB + cpus = 16 + memory = 32.GB ext.args = { [ meta.readgroup ? "--rg-id ${meta.readgroup.ID}" : "", @@ -139,9 +139,9 @@ process { //// STAR withName: '.*FASTQ_ALIGN_RNA:STAR_ALIGN' { ext.prefix = { "${meta.id}.star" } - cpus = 16 - memory = 64.GB - ext.args = { + cpus = 16 + memory = 64.GB + ext.args = { [ "--readFilesCommand gunzip -c", "--twopassMode Basic", @@ -222,9 +222,9 @@ process { //// Samtools convert withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' { - cpus = 8 - memory = 8.GB - ext.args = { + cpus = 8 + memory = 8.GB + ext.args = { [ "-C", "--output-fmt cram,version=3.0", @@ -247,15 +247,15 @@ process { //// Samtools coverage withName: '.*COVERAGE:SAMTOOLS_COVERAGE' { - cpus = 1 - memory = 1.GB + cpus = 1 + memory = 1.GB ext.prefix = { "${meta.id}.coverage" } } // QC withName: '.*BAM_QC:SAMTOOLS_.*$' { - cpus = 1 + cpus = 1 memory = 1.GB } @@ -267,15 +267,15 @@ process { } withName: '.*MD5SUM' { - cpus = 1 + cpus = 1 memory = 128.MB } // MultiQC withName: '.*MULTIQC_.*$' { container = "cmgg/multiqc_cmgg:0.0.2-multiqc-v1.33" - cpus = 1 - memory = 4.GB + cpus = 1 + memory = 4.GB } withName: '.*MULTIQC_MAIN' { ext.prefix = { params.multiqc_title ? params.multiqc_title : "multiqc" } diff --git a/conf/test_full.config b/conf/test_full.config index 6225119a..bad1c6f1 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -17,8 +17,8 @@ params { // Input data for full size test // TODO nf-core: Specify the paths to your full test data ( on nf-core/test-datasets or directly in repositories, e.g. SRA) // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' // Genome references - genome = 'R64-1-1' + genome = 'R64-1-1' } diff --git a/main.nf b/main.nf index 305e0e6b..f9ce7868 100644 --- a/main.nf +++ b/main.nf @@ -62,185 +62,263 @@ workflow { ) publish: - demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) - demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by:1) - demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) - demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() - fastp_json = PREPROCESSING.out.fastp_json - fastp_html = PREPROCESSING.out.fastp_html - crams = PREPROCESSING.out.crams - rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions - rna_junctions = PREPROCESSING.out.rna_junctions - align_reports = PREPROCESSING.out.align_reports - sormadup_metrics = PREPROCESSING.out.sormadup_metrics - mosdepth_global = PREPROCESSING.out.mosdepth_global - mosdepth_summary = PREPROCESSING.out.mosdepth_summary - mosdepth_regions = PREPROCESSING.out.mosdepth_regions - mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 - mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed - mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi - mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed - mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi - mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed - mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi - mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed - mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi - samtools_coverage = PREPROCESSING.out.samtools_coverage - panelcoverage = PREPROCESSING.out.panelcoverage - samtools_stats = PREPROCESSING.out.samtools_stats - samtools_flagstat = PREPROCESSING.out.samtools_flagstat - samtools_idxstats = PREPROCESSING.out.samtools_idxstats - picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics + demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by: 1) + demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by: 1) + demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by: 1) + demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() + fastp_json = PREPROCESSING.out.fastp_json + fastp_html = PREPROCESSING.out.fastp_html + crams = PREPROCESSING.out.crams + rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions + rna_junctions = PREPROCESSING.out.rna_junctions + align_reports = PREPROCESSING.out.align_reports + sormadup_metrics = PREPROCESSING.out.sormadup_metrics + mosdepth_global = PREPROCESSING.out.mosdepth_global + mosdepth_summary = PREPROCESSING.out.mosdepth_summary + mosdepth_regions = PREPROCESSING.out.mosdepth_regions + mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed + mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi + mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed + mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi + mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed + mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi + samtools_coverage = PREPROCESSING.out.samtools_coverage + panelcoverage = PREPROCESSING.out.panelcoverage + samtools_stats = PREPROCESSING.out.samtools_stats + samtools_flagstat = PREPROCESSING.out.samtools_flagstat + samtools_idxstats = PREPROCESSING.out.samtools_idxstats + picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics picard_multiplemetrics_pdf = PREPROCESSING.out.picard_multiplemetrics_pdf - picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics - picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics - md5sums = PREPROCESSING.out.md5sums - multiqc_main_report = PREPROCESSING.out.multiqc_main_report - multiqc_main_data = PREPROCESSING.out.multiqc_main_data - multiqc_main_plots = PREPROCESSING.out.multiqc_main_plots - multiqc_library_report = PREPROCESSING.out.multiqc_library_report - multiqc_library_data = PREPROCESSING.out.multiqc_library_data - multiqc_library_plots = PREPROCESSING.out.multiqc_library_plots + picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics + picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics + md5sums = PREPROCESSING.out.md5sums + multiqc_main_report = PREPROCESSING.out.multiqc_main_report + multiqc_main_data = PREPROCESSING.out.multiqc_main_data + multiqc_main_plots = PREPROCESSING.out.multiqc_main_plots + multiqc_library_report = PREPROCESSING.out.multiqc_library_report + multiqc_library_data = PREPROCESSING.out.multiqc_library_data + multiqc_library_plots = PREPROCESSING.out.multiqc_library_plots } output { - demultiplex_interop { path { _meta, bin -> - bin >> "Interop/${bin.name}" - } } - demultiplex_reports { path { meta, report -> - def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" - report >> out_path - } } - demultiplex_logs { path { meta, log -> - def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" - log >> out_path - } } - demultiplex_fastq { path { meta, fastq -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" - fastq >> out_path - } } - fastp_json { path { meta, json -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" - json >> out_path - } } - fastp_html { path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path - } } - crams { path { meta, cram, crai -> - def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" - def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" - cram >> out_cram - crai >> out_crai - } } - rna_splice_junctions { path { meta, sjt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" - sjt >> out_path - } } - rna_junctions { path { meta, junctions -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" - junctions >> out_path - } } - align_reports { path { meta, log -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" - log >> out_path - } } - sormadup_metrics { path { meta, metrics -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" - metrics >> out_path - } } - mosdepth_global { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_summary { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_d4 { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_quantized_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_quantized_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_thresholds_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_thresholds_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_coverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - panelcoverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_stats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_flagstat { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_idxstats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_multiplemetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_multiplemetrics_pdf { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_wgsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_hsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - md5sums { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - multiqc_main_report { path "multiqc/" } - multiqc_main_data { path "multiqc/" } - multiqc_main_plots { path "multiqc/" } - multiqc_library_report { path "multiqc/" } - multiqc_library_data { path "multiqc/" } - multiqc_library_plots { path "multiqc/" } + demultiplex_interop { + path { _meta, bin -> + bin >> "Interop/${bin.name}" + } + } + demultiplex_reports { + path { meta, report -> + def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" + report >> out_path + } + } + demultiplex_logs { + path { meta, log -> + def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" + log >> out_path + } + } + demultiplex_fastq { + path { meta, fastq -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" + fastq >> out_path + } + } + fastp_json { + path { meta, json -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" + json >> out_path + } + } + fastp_html { + path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } + } + crams { + path { meta, cram, crai -> + def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" + def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" + cram >> out_cram + crai >> out_crai + } + } + rna_splice_junctions { + path { meta, sjt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" + sjt >> out_path + } + } + rna_junctions { + path { meta, junctions -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" + junctions >> out_path + } + } + align_reports { + path { meta, log -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" + log >> out_path + } + } + sormadup_metrics { + path { meta, metrics -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" + metrics >> out_path + } + } + mosdepth_global { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_summary { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_d4 { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_quantized_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_quantized_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_thresholds_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_thresholds_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_coverage { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + panelcoverage { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_stats { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_flagstat { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_idxstats { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_multiplemetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_multiplemetrics_pdf { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_wgsmetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_hsmetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + md5sums { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + multiqc_main_report { + path "multiqc/" + } + multiqc_main_data { + path "multiqc/" + } + multiqc_main_plots { + path "multiqc/" + } + multiqc_library_report { + path "multiqc/" + } + multiqc_library_data { + path "multiqc/" + } + multiqc_library_plots { + path "multiqc/" + } } diff --git a/nextflow.config b/nextflow.config index 30835d39..05719293 100644 --- a/nextflow.config +++ b/nextflow.config @@ -10,47 +10,47 @@ params { // Input options - input = null + input = null // References - genome = null - igenomes_base = '/references/' - igenomes_ignore = false + genome = null + igenomes_base = '/references/' + igenomes_ignore = false // Analysis options - split_fastq = 100000000 - genelists = null + split_fastq = 100000000 + genelists = null // MultiQC options - multiqc_config = null - multiqc_title = null - multiqc_logo = null - max_multiqc_email_size = '25.MB' - multiqc_methods_description = null + multiqc_config = null + multiqc_title = null + multiqc_logo = null + max_multiqc_email_size = '25.MB' + multiqc_methods_description = null // Boilerplate options - outdir = null - publish_dir_mode = 'copy' - email = null - email_on_fail = null - plaintext_email = false - monochrome_logs = false - hook_url = System.getenv('HOOK_URL') - help = false - help_full = false - show_hidden = false - version = false - pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' - trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') + outdir = null + publish_dir_mode = 'copy' + email = null + email_on_fail = null + plaintext_email = false + monochrome_logs = false + hook_url = System.getenv('HOOK_URL') + help = false + help_full = false + show_hidden = false + version = false + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' + trace_report_suffix = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') // Config options - config_profile_name = null - config_profile_description = null + config_profile_name = null + config_profile_description = null - custom_config_version = 'master' - custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" - config_profile_contact = null - config_profile_url = null + custom_config_version = 'master' + custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + config_profile_contact = null + config_profile_url = null // CMGG Config options cmgg_config_profile_name = null @@ -62,7 +62,7 @@ params { cmgg_config_profile_url = null // Schema validation default options - validate_params = true + validate_params = true } // Load base.config by default for all pipelines @@ -73,40 +73,40 @@ includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ profiles { debug { - dumpHashes = true - process.beforeScript = 'echo $HOSTNAME' - cleanup = false + dumpHashes = true + process.beforeScript = 'echo $HOSTNAME' + cleanup = false nextflow.enable.configProcessNamesValidation = true } conda { - conda.enabled = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - conda.channels = ['conda-forge', 'bioconda'] - apptainer.enabled = false + conda.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + conda.channels = ['conda-forge', 'bioconda'] + apptainer.enabled = false } mamba { - conda.enabled = true - conda.useMamba = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + conda.enabled = true + conda.useMamba = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } docker { - docker.enabled = true - conda.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false - docker.runOptions = '-u $(id -u):$(id -g)' + docker.enabled = true + conda.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + docker.runOptions = '-u $(id -u):$(id -g)' } arm64 { process.arch = 'arm64' @@ -120,54 +120,54 @@ profiles { wave.strategy = 'conda,container' } emulate_amd64 { - docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' } singularity { - singularity.enabled = true - singularity.autoMounts = true - conda.enabled = false - docker.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + singularity.enabled = true + singularity.autoMounts = true + conda.enabled = false + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } podman { - podman.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + podman.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } shifter { - shifter.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + shifter.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } charliecloud { - charliecloud.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - apptainer.enabled = false + charliecloud.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + apptainer.enabled = false } apptainer { - apptainer.enabled = true - apptainer.autoMounts = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false + apptainer.enabled = true + apptainer.autoMounts = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false } wave { apptainer.ociAutoPull = true @@ -177,12 +177,16 @@ profiles { wave.strategy = 'conda,container' } gpu { - docker.runOptions = '-u $(id -u):$(id -g) --gpus all' - apptainer.runOptions = '--nv' - singularity.runOptions = '--nv' + docker.runOptions = '-u $(id -u):$(id -g) --gpus all' + apptainer.runOptions = '--nv' + singularity.runOptions = '--nv' + } + test { + includeConfig 'conf/test.config' + } + test_full { + includeConfig 'conf/test_full.config' } - test { includeConfig 'conf/test.config' } - test_full { includeConfig 'conf/test_full.config' } } // Load nf-core custom profiles from different institutions @@ -202,10 +206,10 @@ includeConfig params.cmgg_custom_config_base && (!System.getenv('NXF_OFFLINE') | // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled // Set to your registry if you have a mirror of containers -apptainer.registry = 'quay.io' -docker.registry = 'quay.io' -podman.registry = 'quay.io' -singularity.registry = 'quay.io' +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' charliecloud.registry = 'quay.io' // Export these variables to prevent local Python/R libraries from conflicting with those in the container @@ -222,35 +226,35 @@ env { // Set bash options process.shell = [ "bash", - "-C", // No clobber - prevent output redirection from overwriting files. - "-e", // Exit if a tool returns a non-zero status/exit code - "-u", // Treat unset variables and parameters as an error - "-o", // Returns the status of the last command to exit.. - "pipefail" // ..with a non-zero status or zero if all successfully execute + "-C", + "-e", + "-u", + "-o", + "pipefail", ] // Disable process selector warnings by default. Use debug profile to enable warnings. nextflow.enable.configProcessNamesValidation = false timeline { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/execution_timeline_${params.trace_report_suffix}.html" + file = "${params.outdir}/pipeline_info/execution_timeline_${params.trace_report_suffix}.html" } report { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/execution_report_${params.trace_report_suffix}.html" + file = "${params.outdir}/pipeline_info/execution_report_${params.trace_report_suffix}.html" } trace { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt" + file = "${params.outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt" } dag { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" } manifest { @@ -261,16 +265,16 @@ manifest { affiliation: 'Center for Medical Genetics Ghent, Ghent University, Belgium', email: 'matthias.desmet@ugent.be', github: '@matthdsm', - contribution: ["author","maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: 'https://orcid.org/0000-0003-2555-3114' + contribution: ["author", "maintainer"], + orcid: 'https://orcid.org/0000-0003-2555-3114', ], [ name: ' Nicolas Vannieuwkerke', affiliation: 'Center for Medical Genetics Ghent, Ghent University Hospital, Belgium', email: 'nicolas.vannieuwkerke@ugent.be', github: '@nvnieuwk', - contribution: ["maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: 'https://orcid.org/0009-0003-5619-1555' + contribution: ["maintainer"], + orcid: 'https://orcid.org/0009-0003-5619-1555', ], ] homePage = 'https://github.com/nf-cmgg/preprocessing' @@ -284,12 +288,12 @@ manifest { // Nextflow plugins plugins { - id 'nf-schema@2.6.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.6.1' } validation { defaultIgnoreParams = ["genomes"] - monochromeLogs = params.monochrome_logs + monochromeLogs = params.monochrome_logs } // Load modules.config for DSL2 module specific options diff --git a/nf-test.config b/nf-test.config index fa368ccb..c5d343b4 100644 --- a/nf-test.config +++ b/nf-test.config @@ -1,21 +1,21 @@ config { // location for all nf-test tests - testsDir "." + testsDir = "." // nf-test directory including temporary files for each test - workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + workDir = System.getenv("NFT_WORKDIR") ?: ".nf-test" // location of an optional nextflow.config file specific for executing tests - configFile "tests/nextflow.config" + configFile = "tests/nextflow.config" // ignore tests coming from the nf-core/modules repo - ignore 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*' + ignore = ['modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*'] // run all test with defined profile(s) from the main nextflow.config - profile "test" + profile = "test" // list of filenames or patterns that should be trigger a full test run - triggers 'nextflow.config', 'nf-test.config', 'conf/test.config', 'tests/nextflow.config', 'tests/.nftignore' + triggers = ['nextflow.config', 'nf-test.config', 'conf/test.config', 'tests/nextflow.config', 'tests/.nftignore'] // load the necessary plugins plugins { diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index 6eb6a0ea..ba8f4b5f 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -16,10 +16,10 @@ workflow BAM_QC { ch_versions = channel.empty() ch_bam_bai_roi_fasta_fai_dict - .map { meta, bam, bai, _roi, fasta, fai, _dict -> - return [meta, bam, bai, fasta, fai] - } - .set { ch_bam_bai_fasta_fai } + .map { meta, bam, bai, _roi, fasta, fai, _dict -> + return [meta, bam, bai, fasta, fai] + } + .set { ch_bam_bai_fasta_fai } SAMTOOLS_STATS(ch_bam_bai_fasta_fai) SAMTOOLS_FLAGSTAT(ch_bam_bai_fasta_fai) @@ -34,10 +34,10 @@ workflow BAM_QC { ch_picard_wgsmetrics = channel.empty() ch_bam_bai_roi_fasta_fai_dict - .filter { meta, _bam, _bai, _roi, _fasta, _fai, _dict -> - meta.disable_picard_metrics != true - } - .set { ch_picard } + .filter { meta, _bam, _bai, _roi, _fasta, _fai, _dict -> + meta.disable_picard_metrics != true + } + .set { ch_picard } PICARD_COLLECTMULTIPLEMETRICS(ch_picard) ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions.first()) @@ -45,13 +45,13 @@ workflow BAM_QC { ch_picard_multiplemetrics_pdf = PICARD_COLLECTMULTIPLEMETRICS.out.pdf ch_picard - .branch { meta, bam, bai, roi, fasta, fai, dict -> - hsmetrics: roi != [] + .branch { meta, bam, bai, roi, fasta, fai, dict -> + hsmetrics: roi != [] return [meta, bam, bai, roi, fasta, fai, dict] - wgsmetrics: roi == [] + wgsmetrics: roi == [] return [meta, bam, bai, fasta, fai, dict] - } - .set { ch_picard_coverage } + } + .set { ch_picard_coverage } PICARD_COLLECTWGSMETRICS(ch_picard_coverage.wgsmetrics, []) ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) @@ -61,14 +61,13 @@ workflow BAM_QC { ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions.first()) ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics - emit: - samtools_stats = SAMTOOLS_STATS.out.stats - samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat - samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats - picard_multiplemetrics = ch_picard_multiplemetrics - picard_multiplemetrics_pdf = ch_picard_multiplemetrics_pdf - picard_wgsmetrics = ch_picard_wgsmetrics - picard_hsmetrics = ch_picard_hsmetrics - versions = ch_versions + samtools_stats = SAMTOOLS_STATS.out.stats + samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat + samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats + picard_multiplemetrics = ch_picard_multiplemetrics + picard_multiplemetrics_pdf = ch_picard_multiplemetrics_pdf + picard_wgsmetrics = ch_picard_wgsmetrics + picard_hsmetrics = ch_picard_hsmetrics + versions = ch_versions } diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 27a19c43..501b0773 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -8,7 +8,7 @@ include { PANELCOVERAGE } from "../../../modules/local/panelcoverage/main" workflow COVERAGE { take: ch_meta_cram_crai_fasta_fai_roi // channel: [mandatory] [meta, cram, crai, fasta, fai, roi] - ch_genelists // channel: [optional] [genelists] + ch_genelists // channel: [optional] [genelists] main: @@ -56,19 +56,19 @@ workflow COVERAGE { ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) emit: - mosdepth_global = MOSDEPTH.out.global_txt - mosdepth_summary = MOSDEPTH.out.summary_txt - mosdepth_regions = MOSDEPTH.out.regions_txt - mosdepth_per_base_d4 = MOSDEPTH.out.per_base_d4 - mosdepth_per_base_bed = MOSDEPTH.out.per_base_bed - mosdepth_per_base_csi = MOSDEPTH.out.per_base_csi - mosdepth_regions_bed = MOSDEPTH.out.regions_bed - mosdepth_regions_csi = MOSDEPTH.out.regions_csi - mosdepth_quantized_bed = MOSDEPTH.out.quantized_bed - mosdepth_quantized_csi = MOSDEPTH.out.quantized_csi - mosdepth_thresholds_bed = MOSDEPTH.out.thresholds_bed - mosdepth_thresholds_csi = MOSDEPTH.out.thresholds_csi - samtools_coverage = SAMTOOLS_COVERAGE.out.coverage - panelcoverage = PANELCOVERAGE.out.regiondist - versions = ch_versions + mosdepth_global = MOSDEPTH.out.global_txt + mosdepth_summary = MOSDEPTH.out.summary_txt + mosdepth_regions = MOSDEPTH.out.regions_txt + mosdepth_per_base_d4 = MOSDEPTH.out.per_base_d4 + mosdepth_per_base_bed = MOSDEPTH.out.per_base_bed + mosdepth_per_base_csi = MOSDEPTH.out.per_base_csi + mosdepth_regions_bed = MOSDEPTH.out.regions_bed + mosdepth_regions_csi = MOSDEPTH.out.regions_csi + mosdepth_quantized_bed = MOSDEPTH.out.quantized_bed + mosdepth_quantized_csi = MOSDEPTH.out.quantized_csi + mosdepth_thresholds_bed = MOSDEPTH.out.thresholds_bed + mosdepth_thresholds_csi = MOSDEPTH.out.thresholds_csi + samtools_coverage = SAMTOOLS_COVERAGE.out.coverage + panelcoverage = PANELCOVERAGE.out.regiondist + versions = ch_versions } diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index ce0d6862..1ca27833 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -5,9 +5,9 @@ // -include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" -include { GNU_SORT as SORT_MERGE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" -include { GNU_SORT as SORT_MERGE_SPLICE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" +include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" +include { GNU_SORT as SORT_MERGE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" +include { GNU_SORT as SORT_MERGE_SPLICE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" workflow FASTQ_ALIGN_RNA { take: @@ -55,15 +55,16 @@ workflow FASTQ_ALIGN_RNA { ch_versions = ch_versions.mix(SORT_MERGE_JUNCTIONS.out.versions.first()) emit: - bam = ch_bam // channel: [ [meta], bam ] - splice_junctions = SORT_MERGE_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] - junctions = SORT_MERGE_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] - reports = ch_reports // channel: [ [meta], log ] - versions = ch_versions // channel: [ versions.yml ] + bam = ch_bam // channel: [ [meta], bam ] + splice_junctions = SORT_MERGE_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] + junctions = SORT_MERGE_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] + reports = ch_reports // channel: [ [meta], log ] + versions = ch_versions // channel: [ versions.yml ] } def group_junctions(ch) { - return ch.map { meta, files -> + return ch + .map { meta, files -> def gk = (meta.chunks as Integer ?: 1) return [ groupKey( diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 9d30ea92..226e97b9 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -38,7 +38,8 @@ workflow FASTQ_TO_CRAM { .branch { meta, reads, aligner, index, fasta, gtf -> rna: meta.sample_type == "RNA" return [meta, reads, "star", getGenomeAttribute(meta.genome_data, 'star'), gtf] - dna: true // catch all non-RNA samples as DNA, as some may be missing sample_type or have other sample types (e.g. tissue, cell line, etc.) that should be aligned with the DNA aligner + dna: true + // catch all non-RNA samples as DNA, as some may be missing sample_type or have other sample types (e.g. tissue, cell line, etc.) that should be aligned with the DNA aligner //dna: meta.sample_type == "DNA" || meta.sample_type == "Tissue" return [meta, reads, aligner, index, fasta] } @@ -93,13 +94,13 @@ workflow FASTQ_TO_CRAM { .dump(tag: "FASTQ_TO_CRAM: aligned bam per sample", pretty: true) .branch { meta, files, fasta -> bamsormadup: meta.markdup == "bamsormadup" - return [meta, files, fasta] + return [meta, files, fasta] samtools: meta.markdup == "samtools" - return [meta, files, fasta] + return [meta, files, fasta] sort: meta.markdup == "false" || meta.markdup == false - return [meta, files, fasta] + return [meta, files, fasta] unknown: true - error("markdup option ${meta.markdup} not supported") + error("markdup option ${meta.markdup} not supported") } .set { ch_bam_fasta } @@ -156,10 +157,10 @@ workflow FASTQ_TO_CRAM { ch_cram_crai.dump(tag: "FASTQ_TO_CRAM: cram and crai", pretty: true) emit: - cram_crai = ch_cram_crai - rna_splice_junctions = FASTQ_ALIGN_RNA.out.splice_junctions - rna_junctions = FASTQ_ALIGN_RNA.out.junctions - sormadup_metrics = ch_sormadup_metrics - align_reports = FASTQ_ALIGN_DNA.out.reports - versions = ch_versions + cram_crai = ch_cram_crai + rna_splice_junctions = FASTQ_ALIGN_RNA.out.splice_junctions + rna_junctions = FASTQ_ALIGN_RNA.out.junctions + sormadup_metrics = ch_sormadup_metrics + align_reports = FASTQ_ALIGN_DNA.out.reports + versions = ch_versions } diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf index c66aaf01..4c65f558 100644 --- a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -8,15 +8,15 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { samplesheetToList } from 'plugin/nf-schema' -include { paramsHelp } from 'plugin/nf-schema' -include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' -include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' +include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { imNotification } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -25,16 +25,15 @@ include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipelin */ workflow PIPELINE_INITIALISATION { - take: - version // boolean: Display version and exit - validate_params // boolean: Boolean whether to validate parameters against the schema at runtime + version // boolean: Display version and exit + validate_params // boolean: Boolean whether to validate parameters against the schema at runtime nextflow_cli_args // array: List of positional nextflow CLI args - outdir // string: The output directory where the results will be saved - input // string: Path to input samplesheet - help // boolean: Display help message and exit - help_full // boolean: Show the full help message - show_hidden // boolean: Show hidden parameters in the help message + outdir // string: The output directory where the results will be saved + input // string: Path to input samplesheet + help // boolean: Display help message and exit + help_full // boolean: Show the full help message + show_hidden // boolean: Show hidden parameters in the help message main: @@ -43,11 +42,11 @@ workflow PIPELINE_INITIALISATION { // // Print version and exit if required and dump pipeline parameters to JSON file // - UTILS_NEXTFLOW_PIPELINE ( + UTILS_NEXTFLOW_PIPELINE( version, true, outdir, - workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 + workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1, ) // @@ -55,7 +54,7 @@ workflow PIPELINE_INITIALISATION { // command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir " - UTILS_NFSCHEMA_PLUGIN ( + UTILS_NFSCHEMA_PLUGIN( workflow, validate_params, null, @@ -64,13 +63,13 @@ workflow PIPELINE_INITIALISATION { show_hidden, "", "", - command + command, ) // // Check config provided to the pipeline // - UTILS_NFCORE_PIPELINE ( + UTILS_NFCORE_PIPELINE( nextflow_cli_args ) @@ -97,15 +96,14 @@ workflow PIPELINE_INITIALISATION { */ workflow PIPELINE_COMPLETION { - take: - email // string: email address - email_on_fail // string: email address sent on pipeline failure + email // string: email address + email_on_fail // string: email address sent on pipeline failure plaintext_email // boolean: Send plain-text email instead of HTML - outdir // path: Path to output directory where results will be published + outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output - hook_url // string: hook URL for notifications - multiqc_report // string: Path to MultiQC report + hook_url // string: hook URL for notifications + multiqc_report // string: Path to MultiQC report main: summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") @@ -134,7 +132,7 @@ workflow PIPELINE_COMPLETION { } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error("Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting") } } @@ -157,19 +155,19 @@ def validateInputSamplesheet(input) { def (metas, fastqs) = input[1..2] // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end - def endedness_ok = metas.collect{ meta -> meta.single_end }.unique().size == 1 + def endedness_ok = metas.collect { meta -> meta.single_end }.unique().size == 1 if (!endedness_ok) { error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") } - return [ metas[0], fastqs ] + return [metas[0], fastqs] } // // Get attribute from genome config file e.g. fasta // def getGenomeAttribute(genomes, attribute) { if (genomes && genomes.containsKey(attribute)) { - return genomes[ attribute ] + return genomes[attribute] } return null } @@ -179,11 +177,7 @@ def getGenomeAttribute(genomes, attribute) { // def genomeExistsError() { if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + - " Currently, the available genome keys are:\n" + - " ${params.genomes.keySet().join(", ")}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + " Currently, the available genome keys are:\n" + " ${params.genomes.keySet().join(", ")}\n" + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" error(error_string) } } @@ -195,11 +189,11 @@ def toolCitationText() { // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", // Uncomment function in methodsDescriptionText to render in MultiQC report def citation_text = [ - "Tools used in the workflow included:", - "FastQC (Andrews 2010),", - "MultiQC (Ewels et al. 2016)", - "." - ].join(' ').trim() + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + ".", + ].join(' ').trim() return citation_text } @@ -209,9 +203,9 @@ def toolBibliographyText() { // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", // Uncomment function in methodsDescriptionText to render in MultiQC report def reference_text = [ - "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", - "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " - ].join(' ').trim() + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • ", + ].join(' ').trim() return reference_text } @@ -233,7 +227,10 @@ def methodsDescriptionText(mqc_methods_yaml) { temp_doi_ref += "(doi: ${doi_ref.replace("https://doi.org/", "").replace(" ", "")}), " } meta["doi_text"] = temp_doi_ref.substring(0, temp_doi_ref.length() - 2) - } else meta["doi_text"] = "" + } + else { + meta["doi_text"] = "" + } meta["nodoi_text"] = meta.manifest_map.doi ? "" : "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " // Tool references @@ -247,7 +244,7 @@ def methodsDescriptionText(mqc_methods_yaml) { def methods_text = mqc_methods_yaml.text - def engine = new groovy.text.SimpleTemplateEngine() + def engine = new groovy.text.SimpleTemplateEngine() def description_html = engine.createTemplate(methods_text).make(meta) return description_html.toString() diff --git a/tests/inputs/fastq.yml b/tests/inputs/fastq.yml index 52668235..a0033b21 100644 --- a/tests/inputs/fastq.yml +++ b/tests/inputs/fastq.yml @@ -6,6 +6,7 @@ organism: Homo sapiens tag: WES aligner: bwamem + markdup: bamsormadup fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz - id: sample1_L002 @@ -14,5 +15,6 @@ organism: Homo sapiens tag: WES aligner: bwamem + markdup: bamsormadup fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/tests/inputs/fastq_rna.yml b/tests/inputs/fastq_rna.yml index 878dab22..998af6b5 100644 --- a/tests/inputs/fastq_rna.yml +++ b/tests/inputs/fastq_rna.yml @@ -7,6 +7,7 @@ tag: WES sample_type: RNA aligner: star + markdup: bamsormadup fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz - id: sample1_L002 @@ -16,5 +17,6 @@ tag: WES sample_type: RNA aligner: star + markdup: bamsormadup fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 33c0930b..bfe1a63d 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -260,7 +260,7 @@ workflow PREPROCESSING { crai, getGenomeAttribute(meta.genome_data, "fasta"), getGenomeAttribute(meta.genome_data, "fai"), - meta.roi ? file(meta.roi, checkIfExists: true) : [], + meta.roi && meta.roi != [] ? file(meta.roi, checkIfExists: true) : [], ] } .set { ch_cram_crai_fasta_fai_roi } @@ -285,7 +285,7 @@ workflow PREPROCESSING { meta, cram, crai, - meta.roi ? file(meta.roi, checkIfExists: true) : [], + meta.roi && meta.roi != [] ? file(meta.roi, checkIfExists: true) : [], getGenomeAttribute(meta.genome_data, "fasta"), getGenomeAttribute(meta.genome_data, "fai"), getGenomeAttribute(meta.genome_data, "dict"), From efb99f01c064e56a97474e776e0cddfb3bcc8260 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:57:19 +0100 Subject: [PATCH 151/228] meta fixes --- assets/schema_input.json | 2 +- assets/schema_sampleinfo.json | 2 +- tests/inputs/fastq.yml | 2 ++ tests/inputs/fastq_rna.yml | 2 ++ tests/workflows/preprocessing.nf.test | 9 ++++++--- workflows/preprocessing.nf | 2 +- 6 files changed, 13 insertions(+), 6 deletions(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index 59ee5046..a6cd4941 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -87,7 +87,7 @@ "meta": ["run_coverage"], "type": "boolean", "description": "Whether to run coverage analysis for the sample", - "default": false + "default": true }, "disable_picard_metrics": { "meta": ["disable_picard_metrics"], diff --git a/assets/schema_sampleinfo.json b/assets/schema_sampleinfo.json index 26bb486a..dee4c572 100644 --- a/assets/schema_sampleinfo.json +++ b/assets/schema_sampleinfo.json @@ -127,7 +127,7 @@ "meta": ["run_coverage"], "type": "boolean", "description": "Whether to run coverage analysis for the sample", - "default": false + "default": true }, "disable_picard_metrics": { "meta": ["disable_picard_metrics"], diff --git a/tests/inputs/fastq.yml b/tests/inputs/fastq.yml index a0033b21..8195b58b 100644 --- a/tests/inputs/fastq.yml +++ b/tests/inputs/fastq.yml @@ -7,6 +7,7 @@ tag: WES aligner: bwamem markdup: bamsormadup + run_coverage: true fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz - id: sample1_L002 @@ -16,5 +17,6 @@ tag: WES aligner: bwamem markdup: bamsormadup + run_coverage: true fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/tests/inputs/fastq_rna.yml b/tests/inputs/fastq_rna.yml index 998af6b5..3945eb53 100644 --- a/tests/inputs/fastq_rna.yml +++ b/tests/inputs/fastq_rna.yml @@ -8,6 +8,7 @@ sample_type: RNA aligner: star markdup: bamsormadup + run_coverage: true fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz - id: sample1_L002 @@ -18,5 +19,6 @@ sample_type: RNA aligner: star markdup: bamsormadup + run_coverage: true fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index f31029f4..dfc856d0 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -23,7 +23,8 @@ nextflow_workflow { tag: "WES", sample_type: "DNA", aligner: "bwamem", - markdup: "bamsormadup" + markdup: "bamsormadup", + run_coverage: true ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -91,7 +92,8 @@ nextflow_workflow { tag: "WGS", sample_type: "DNA", aligner: "bwamem", - markdup: "bamsormadup" + markdup: "bamsormadup", + run_coverage: true ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -162,7 +164,8 @@ nextflow_workflow { tag: "WES", sample_type: "DNA", aligner: "bwamem", - markdup: "bamsormadup" + markdup: "bamsormadup", + run_coverage: true ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index bfe1a63d..16618c2e 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -251,7 +251,7 @@ workflow PREPROCESSING { */ FASTQ_TO_CRAM.out.cram_crai .filter { meta, _cram, _crai -> - meta.run_coverage.toBoolean() + meta.run_coverage && meta.run_coverage.toBoolean() } .map { meta, cram, crai -> return [ From 6614d338d2c15ae4ab22d4c86f138a81e4f4396d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:36:06 +0100 Subject: [PATCH 152/228] bump picard/collectmultiplemetrics module --- modules.json | 2 +- .../picard/collectmultiplemetrics/main.nf | 12 +- .../picard/collectmultiplemetrics/meta.yml | 28 ++++- .../picard-collectmultiplemetrics.diff | 30 ++++- .../collectmultiplemetrics/tests/main.nf.test | 6 +- .../tests/main.nf.test.snap | 54 ++++++--- subworkflows/local/bam_qc/main.nf | 2 +- tests/subworkflows/local/bam_qc/main.nf.test | 6 +- .../local/bam_qc/main.nf.test.snap | 106 ++++-------------- 9 files changed, 120 insertions(+), 126 deletions(-) diff --git a/modules.json b/modules.json index 037ebfe4..5b76e3b7 100644 --- a/modules.json +++ b/modules.json @@ -81,7 +81,7 @@ }, "picard/collectmultiplemetrics": { "branch": "master", - "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", + "git_sha": "74ec93d00bef147da3fb1f2262e8d31c14108f88", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index 2dc6679d..158a746f 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -13,7 +13,7 @@ process PICARD_COLLECTMULTIPLEMETRICS { output: tuple val(meta), path("*_metrics"), emit: metrics tuple val(meta), path("*.pdf") , emit: pdf, optional: true - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('picard'), eval("picard CollectMultipleMetrics --version 2>&1 | sed -n 's/^Version:*//p'"), topic: versions, emit: versions_picard when: task.ext.when == null || task.ext.when @@ -38,11 +38,6 @@ process PICARD_COLLECTMULTIPLEMETRICS { --OUTPUT ${prefix}.CollectMultipleMetrics \\ $intervals_cmd \\ $reference_cmd - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - picard: \$(picard CollectMultipleMetrics --version 2>&1 | grep -o 'Version.*' | cut -f2- -d:) - END_VERSIONS """ stub: @@ -58,10 +53,5 @@ process PICARD_COLLECTMULTIPLEMETRICS { touch ${prefix}.CollectMultipleMetrics.quality_by_cycle.pdf touch ${prefix}.CollectMultipleMetrics.insert_size_histogram.pdf touch ${prefix}.CollectMultipleMetrics.quality_distribution_metrics - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - picard: \$(echo \$(picard CollectMultipleMetrics --version 2>&1) | grep -o 'Version:.*' | cut -f2- -d:) - END_VERSIONS """ } diff --git a/modules/nf-core/picard/collectmultiplemetrics/meta.yml b/modules/nf-core/picard/collectmultiplemetrics/meta.yml index 3f0bf610..1ea47244 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/meta.yml +++ b/modules/nf-core/picard/collectmultiplemetrics/meta.yml @@ -74,13 +74,29 @@ output: description: PDF plots of metrics pattern: "*.{pdf}" ontologies: [] + versions_picard: + - - ${task.process}: + type: string + description: The process the versions were collected from + - picard: + type: string + description: The tool name + - "picard CollectMultipleMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + type: string + description: The command used to generate the version of the tool + +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The process the versions were collected from + - picard: + type: string + description: The tool name + - "picard CollectMultipleMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + type: string + description: The command used to generate the version of the tool + authors: - "@drpatelh" maintainers: diff --git a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff index 489076fb..c3cd8e55 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff +++ b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff @@ -11,10 +11,38 @@ Changes in 'picard/collectmultiplemetrics/main.nf': - tuple val(meta) , path(bam), path(bai) - tuple val(meta2), path(fasta) - tuple val(meta3), path(fai) -+ tuple val(meta) , path(bam), path(bai) ,path(fasta) ,path(fai) ++ tuple val(meta) , path(bam), path(bai), path(intervals), path(fasta) ,path(fai), path(dict) output: tuple val(meta), path("*_metrics"), emit: metrics +@@ -23,7 +21,8 @@ + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" +- def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" ++ def intervals_cmd = intervals ? "--INTERVALS ${intervals.join(',')}" : "" ++ def reference_cmd = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" + def avail_mem = 3072 + if (!task.memory) { + log.info '[Picard CollectMultipleMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.' +@@ -37,8 +36,8 @@ + $args \\ + --INPUT $bam \\ + --OUTPUT ${prefix}.CollectMultipleMetrics \\ +- $reference +- ++ $intervals_cmd \\ ++ $reference_cmd + """ + + stub: +@@ -54,6 +53,5 @@ + touch ${prefix}.CollectMultipleMetrics.quality_by_cycle.pdf + touch ${prefix}.CollectMultipleMetrics.insert_size_histogram.pdf + touch ${prefix}.CollectMultipleMetrics.quality_distribution_metrics +- + """ + } 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test index 5b67774f..08456941 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test +++ b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test @@ -36,7 +36,7 @@ nextflow_process { { assert snapshot( process.out.metrics[0][1].collect { file(it).name }.toSorted(), process.out.pdf[0][1].collect { file(it).name }.toSorted(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -66,7 +66,7 @@ nextflow_process { { assert snapshot( process.out.metrics[0][1].collect { file(it).name }.toSorted(), process.out.pdf[0][1].collect { file(it).name }.toSorted(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -102,7 +102,7 @@ nextflow_process { { assert snapshot( process.out.metrics[0][1].collect { file(it).name }.toSorted(), process.out.pdf[0][1].collect { file(it).name }.toSorted(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) diff --git a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap index 5a1de114..1acf3776 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap @@ -15,15 +15,21 @@ "test.CollectMultipleMetrics.quality_distribution.pdf", "test.CollectMultipleMetrics.read_length_histogram.pdf" ], - [ - "versions.yml:md5,aca7ca0dc0012ee97698236828ba242a" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTMULTIPLEMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:41:26.126816186" + "timestamp": "2026-02-02T10:22:21.230301646" }, "test-picard-collectmultiplemetrics-cram": { "content": [ @@ -41,15 +47,21 @@ "test.CollectMultipleMetrics.quality_distribution.pdf", "test.CollectMultipleMetrics.read_length_histogram.pdf" ], - [ - "versions.yml:md5,aca7ca0dc0012ee97698236828ba242a" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTMULTIPLEMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:41:50.933556225" + "timestamp": "2026-02-02T10:23:52.23446844" }, "test-picard-collectmultiplemetrics-nofasta": { "content": [ @@ -67,14 +79,20 @@ "test.CollectMultipleMetrics.quality_distribution.pdf", "test.CollectMultipleMetrics.read_length_histogram.pdf" ], - [ - "versions.yml:md5,aca7ca0dc0012ee97698236828ba242a" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTMULTIPLEMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:41:38.213084333" + "timestamp": "2026-02-02T10:23:27.387621193" } } \ No newline at end of file diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index ba8f4b5f..ebea484d 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -35,7 +35,7 @@ workflow BAM_QC { ch_bam_bai_roi_fasta_fai_dict .filter { meta, _bam, _bai, _roi, _fasta, _fai, _dict -> - meta.disable_picard_metrics != true + !meta.disable_picard_metrics } .set { ch_picard } diff --git a/tests/subworkflows/local/bam_qc/main.nf.test b/tests/subworkflows/local/bam_qc/main.nf.test index 8cd0106b..acb2f53a 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test +++ b/tests/subworkflows/local/bam_qc/main.nf.test @@ -15,7 +15,7 @@ nextflow_workflow { """ // [meta, bam, bai, roi, fasta, fai, dict] input[0] = Channel.of([ - [ id:'test', single_end:false ], + [ id:'test', single_end:false, disable_picard_metrics:false ], file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram.crai", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), @@ -47,7 +47,7 @@ nextflow_workflow { """ // [meta, bam, bai, roi, fasta, fai, dict] input[0] = Channel.of([ - [ id:'test', single_end:false ], + [ id:'test', single_end:false, disable_picard_metrics:false ], file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram.crai", checkIfExists: true), [], @@ -78,7 +78,7 @@ nextflow_workflow { """ // [meta, bam, bai, roi, fasta, fai, dict] input[0] = Channel.of([ - [ id:'test', single_end:false ], + [ id:'test', single_end:false, disable_picard_metrics:true ], file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/cram/sample1.sorted.cram.crai", checkIfExists: true), file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), diff --git a/tests/subworkflows/local/bam_qc/main.nf.test.snap b/tests/subworkflows/local/bam_qc/main.nf.test.snap index 2403cda0..3392b3dd 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test.snap +++ b/tests/subworkflows/local/bam_qc/main.nf.test.snap @@ -3,43 +3,13 @@ "content": [ { "picard_hsmetrics": [ - [ - { - "id": "test", - "single_end": false - }, - "test.CollectHsMetrics.coverage_metrics" - ] + ], "picard_multiplemetrics": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.CollectMultipleMetrics.alignment_summary_metrics", - "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics", - "test.CollectMultipleMetrics.insert_size_metrics", - "test.CollectMultipleMetrics.quality_by_cycle_metrics", - "test.CollectMultipleMetrics.quality_distribution_metrics" - ] - ] + ], "picard_multiplemetrics_pdf": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf", - "test.CollectMultipleMetrics.insert_size_histogram.pdf", - "test.CollectMultipleMetrics.quality_by_cycle.pdf", - "test.CollectMultipleMetrics.quality_distribution.pdf", - "test.CollectMultipleMetrics.read_length_histogram.pdf" - ] - ] + ], "picard_wgsmetrics": [ @@ -48,7 +18,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": false }, "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" ] @@ -57,7 +28,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": false }, "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" ] @@ -66,24 +38,23 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": false }, "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] ], "versions": [ "versions.yml:md5,15389a9f97668f320b9628da1903a93b", - "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5", - "versions.yml:md5,593804078c060457d011f7f6b650e500", - "versions.yml:md5,f5507938ec419f55239e3faa9f99376f" + "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.3" }, - "timestamp": "2025-12-02T12:48:55.096074" + "timestamp": "2026-02-10T19:21:23.498543" }, "Bam QC - Samtools": { "content": [ @@ -146,49 +117,20 @@ ], "picard_multiplemetrics": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.CollectMultipleMetrics.alignment_summary_metrics", - "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics", - "test.CollectMultipleMetrics.insert_size_metrics", - "test.CollectMultipleMetrics.quality_by_cycle_metrics", - "test.CollectMultipleMetrics.quality_distribution_metrics" - ] - ] + ], "picard_multiplemetrics_pdf": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf", - "test.CollectMultipleMetrics.insert_size_histogram.pdf", - "test.CollectMultipleMetrics.quality_by_cycle.pdf", - "test.CollectMultipleMetrics.quality_distribution.pdf", - "test.CollectMultipleMetrics.read_length_histogram.pdf" - ] - ] + ], "picard_wgsmetrics": [ - [ - { - "id": "test", - "single_end": false - }, - "test.CollectWgsMetrics.coverage_metrics" - ] + ], "samtools_flagstat": [ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": false }, "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" ] @@ -197,7 +139,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": false }, "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" ] @@ -206,23 +149,22 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": false }, "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] ], "versions": [ "versions.yml:md5,15389a9f97668f320b9628da1903a93b", - "versions.yml:md5,3d2d9acb75406ea94b547be23a45601b", - "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5", - "versions.yml:md5,f5507938ec419f55239e3faa9f99376f" + "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.3" }, - "timestamp": "2025-12-02T12:49:52.298773" + "timestamp": "2026-02-10T19:25:10.626677" } } \ No newline at end of file From f4fc5c7b1a419c9eca79611b2f88543eb80bd06d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:37:37 +0100 Subject: [PATCH 153/228] bump picard/collecthsmetrics module --- modules.json | 2 +- .../nf-core/picard/collecthsmetrics/main.nf | 12 +- .../nf-core/picard/collecthsmetrics/meta.yml | 27 +++- .../collecthsmetrics/tests/main.nf.test | 12 +- .../collecthsmetrics/tests/main.nf.test.snap | 145 +++++++++++++----- 5 files changed, 132 insertions(+), 66 deletions(-) diff --git a/modules.json b/modules.json index 5b76e3b7..d8bc7b60 100644 --- a/modules.json +++ b/modules.json @@ -75,7 +75,7 @@ }, "picard/collecthsmetrics": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "976ed20e328a92cb24ab6c63a8983ed31bf48469", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, diff --git a/modules/nf-core/picard/collecthsmetrics/main.nf b/modules/nf-core/picard/collecthsmetrics/main.nf index a1dc56d8..63b3479c 100644 --- a/modules/nf-core/picard/collecthsmetrics/main.nf +++ b/modules/nf-core/picard/collecthsmetrics/main.nf @@ -12,7 +12,7 @@ process PICARD_COLLECTHSMETRICS { output: tuple val(meta), path("*_metrics") , emit: metrics - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('picard'), eval("picard CollectHsMetrics --version 2>&1 | sed -n 's/^Version:*//p'"), topic: versions, emit: versions_picard when: task.ext.when == null || task.ext.when @@ -59,21 +59,11 @@ process PICARD_COLLECTHSMETRICS { --INPUT $bam \\ --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - picard: \$(echo \$(picard CollectHsMetrics --version 2>&1) | grep -o 'Version:.*' | cut -f2- -d:) - END_VERSIONS """ stub: def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.CollectHsMetrics.coverage_metrics - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - picard: \$(echo \$(picard CollectHsMetrics --version 2>&1) | grep -o 'Version:.*' | cut -f2- -d:) - END_VERSIONS """ } diff --git a/modules/nf-core/picard/collecthsmetrics/meta.yml b/modules/nf-core/picard/collecthsmetrics/meta.yml index 511ae959..a21aa6ec 100644 --- a/modules/nf-core/picard/collecthsmetrics/meta.yml +++ b/modules/nf-core/picard/collecthsmetrics/meta.yml @@ -99,13 +99,28 @@ output: description: Alignment metrics files generated by picard pattern: "*_{metrics}" ontologies: [] + versions_picard: + - - ${task.process}: + type: string + description: The process the versions were collected from + - picard: + type: string + description: The tool name + - "picard CollectHsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + type: string + description: The command used to generate the version of the tool + +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The process the versions were collected from + - picard: + type: string + description: The tool name + - "picard CollectHsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + type: string + description: The command used to generate the version of the tool authors: - "@projectoriented" - "@matthdsm" diff --git a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test index fe40e7b0..07a9ccf4 100644 --- a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test +++ b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test @@ -39,7 +39,7 @@ nextflow_process { file(process.out.metrics[0][1]).name, size, lines, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -77,7 +77,7 @@ nextflow_process { file(process.out.metrics[0][1]).name, size, lines, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -110,7 +110,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out).match() } ) } @@ -146,7 +146,7 @@ nextflow_process { file(process.out.metrics[0][1]).name, size, lines, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -185,7 +185,7 @@ nextflow_process { file(process.out.metrics[0][1]).name, size, lines, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -224,7 +224,7 @@ nextflow_process { file(process.out.metrics[0][1]).name, size, lines, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) diff --git a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap index 11b0f7c5..74d9441f 100644 --- a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap @@ -105,15 +105,64 @@ "88\t0\t0", "89\t0\t0" ], - [ - "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTHSMETRICS", + "picard", + "3.4.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-05T17:03:29.566021877" + }, + "sarscov2 - bam - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.CollectHsMetrics.coverage_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "PICARD_COLLECTHSMETRICS", + "picard", + "3.4.0" + ] + ], + "metrics": [ + [ + { + "id": "test", + "single_end": false + }, + "test.CollectHsMetrics.coverage_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_picard": [ + [ + "PICARD_COLLECTHSMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:37:59.62099935" + "timestamp": "2026-01-05T17:03:13.333276975" }, "sarscov2 - bam - gzippedfa": { "content": [ @@ -221,27 +270,21 @@ "88\t0\t0", "89\t0\t0" ], - [ - "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" - ] - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-15T10:37:32.831030701" - }, - "versions": { - "content": [ - [ - "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTHSMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:37:42.492104283" + "timestamp": "2026-01-05T17:03:04.382110367" }, "sarscov2 - bam - samebed": { "content": [ @@ -349,15 +392,21 @@ "88\t0\t0", "89\t0\t0" ], - [ - "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTHSMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:38:39.302597954" + "timestamp": "2026-01-05T17:13:22.872920293" }, "sarscov2 - bam": { "content": [ @@ -465,15 +514,21 @@ "88\t0\t0", "89\t0\t0" ], - [ - "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTHSMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:37:15.861292725" + "timestamp": "2026-01-05T17:02:47.615784738" }, "sarscov2 - bam - bed": { "content": [ @@ -581,14 +636,20 @@ "88\t0\t0", "89\t0\t0" ], - [ - "versions.yml:md5,533cf1e35d36fdacbb762f5df2e1b322" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTHSMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:38:18.912909604" + "timestamp": "2026-01-05T17:13:02.812282052" } } \ No newline at end of file From 60deb6a75c48d613d75a15b039fb8e43fe0f113a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:38:35 +0100 Subject: [PATCH 154/228] bump picard/collectwgsmetrics module --- modules.json | 2 +- .../nf-core/picard/collectwgsmetrics/main.nf | 11 +----- .../nf-core/picard/collectwgsmetrics/meta.yml | 27 ++++++++++---- .../collectwgsmetrics/tests/main.nf.test | 4 +-- .../collectwgsmetrics/tests/main.nf.test.snap | 36 ++++++++++++------- 5 files changed, 49 insertions(+), 31 deletions(-) diff --git a/modules.json b/modules.json index d8bc7b60..a18151a1 100644 --- a/modules.json +++ b/modules.json @@ -87,7 +87,7 @@ }, "picard/collectwgsmetrics": { "branch": "master", - "git_sha": "df124e87c74d8b40285199f8cc20151f5aa57255", + "git_sha": "66d5808eaaabd9de8997c4c31a9e8cdd3b56c080", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, diff --git a/modules/nf-core/picard/collectwgsmetrics/main.nf b/modules/nf-core/picard/collectwgsmetrics/main.nf index cd4a7711..63330d22 100644 --- a/modules/nf-core/picard/collectwgsmetrics/main.nf +++ b/modules/nf-core/picard/collectwgsmetrics/main.nf @@ -13,7 +13,7 @@ process PICARD_COLLECTWGSMETRICS { output: tuple val(meta), path("*_metrics"), emit: metrics - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('picard'), eval("picard CollectWgsMetrics --version 2>&1 | sed -n 's/^Version:*//p'"), topic: versions, emit: versions_picard when: task.ext.when == null || task.ext.when @@ -38,11 +38,6 @@ process PICARD_COLLECTWGSMETRICS { --REFERENCE_SEQUENCE ${fasta} \\ $interval - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - picard: \$(picard CollectWgsMetrics --version 2>&1 | grep -o 'Version.*' | cut -f2- -d:) - END_VERSIONS """ stub: @@ -50,9 +45,5 @@ process PICARD_COLLECTWGSMETRICS { """ touch ${prefix}.CollectWgsMetrics.coverage_metrics - cat <<-END_VERSIONS > versions.yml - "${task.process}": - picard: \$(picard CollectWgsMetrics --version 2>&1 | grep -o 'Version.*' | cut -f2- -d:) - END_VERSIONS """ } diff --git a/modules/nf-core/picard/collectwgsmetrics/meta.yml b/modules/nf-core/picard/collectwgsmetrics/meta.yml index a27e0a88..c59811d5 100644 --- a/modules/nf-core/picard/collectwgsmetrics/meta.yml +++ b/modules/nf-core/picard/collectwgsmetrics/meta.yml @@ -69,13 +69,28 @@ output: description: Alignment metrics files generated by picard pattern: "*_{metrics}" ontologies: [] + versions_picard: + - - ${task.process}: + type: string + description: The process the versions were collected from + - picard: + type: string + description: The tool name + - "picard CollectWgsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + type: string + description: The command used to generate the version of the tool + +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The process the versions were collected from + - picard: + type: string + description: The tool name + - "picard CollectWgsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + type: string + description: The command used to generate the version of the tool authors: - "@drpatelh" - "@flowuenne" diff --git a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test index a3984566..d6a60e6b 100644 --- a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test +++ b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test @@ -38,7 +38,7 @@ nextflow_process { { assert process.success }, { assert snapshot( file(process.out.metrics[0][1]).text.contains('coverage high_quality_coverage_count'), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -73,7 +73,7 @@ nextflow_process { { assert process.success }, { assert snapshot( file(process.out.metrics[0][1]).text.contains('coverage high_quality_coverage_count'), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) diff --git a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap index d944d96b..375c2ef9 100644 --- a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap @@ -2,27 +2,39 @@ "test-picard-collectwgsmetrics-with-interval": { "content": [ true, - [ - "versions.yml:md5,0fa1034c5831e54d4534e6052a8d6b61" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTWGSMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:45:19.40801445" + "timestamp": "2026-02-02T14:52:55.091876466" }, "test-picard-collectwgsmetrics": { "content": [ true, - [ - "versions.yml:md5,0fa1034c5831e54d4534e6052a8d6b61" - ] + { + "versions_picard": [ + [ + "PICARD_COLLECTWGSMETRICS", + "picard", + "3.4.0" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-15T10:44:57.689335695" + "timestamp": "2026-02-02T14:52:11.334274481" } } \ No newline at end of file From d66d99c7fc81ff54824efb2c971c68348b4b0674 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:43:04 +0100 Subject: [PATCH 155/228] bam_qc -> topic --- modules.json | 6 +- modules/nf-core/samtools/flagstat/main.nf | 12 +-- modules/nf-core/samtools/flagstat/meta.yml | 33 +++++--- .../samtools/flagstat/tests/main.nf.test.snap | 40 +++++++--- modules/nf-core/samtools/idxstats/main.nf | 12 +-- modules/nf-core/samtools/idxstats/meta.yml | 29 +++++-- .../samtools/idxstats/tests/main.nf.test | 10 ++- .../samtools/idxstats/tests/main.nf.test.snap | 80 ++++++++----------- modules/nf-core/samtools/stats/main.nf | 4 +- modules/nf-core/samtools/stats/meta.yml | 17 ++-- subworkflows/local/bam_qc/main.nf | 10 +-- workflows/preprocessing.nf | 1 - 12 files changed, 132 insertions(+), 122 deletions(-) diff --git a/modules.json b/modules.json index a18151a1..744675f8 100644 --- a/modules.json +++ b/modules.json @@ -105,12 +105,12 @@ }, "samtools/flagstat": { "branch": "master", - "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", + "git_sha": "1d2fbdcbca677bbe8da0f9d0d2bb7c02f2cab1c9", "installed_by": ["modules"] }, "samtools/idxstats": { "branch": "master", - "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", + "git_sha": "1d2fbdcbca677bbe8da0f9d0d2bb7c02f2cab1c9", "installed_by": ["modules"] }, "samtools/sormadup": { @@ -127,7 +127,7 @@ }, "samtools/stats": { "branch": "master", - "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", + "git_sha": "fe93fde0845f907fc91ad7cc7d797930408824df", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/stats/samtools-stats.diff" }, diff --git a/modules/nf-core/samtools/flagstat/main.nf b/modules/nf-core/samtools/flagstat/main.nf index f148f56b..0cfb7e87 100644 --- a/modules/nf-core/samtools/flagstat/main.nf +++ b/modules/nf-core/samtools/flagstat/main.nf @@ -12,7 +12,7 @@ process SAMTOOLS_FLAGSTAT { output: tuple val(meta), path("*.flagstat"), emit: flagstat - path "versions.yml" , emit: versions + 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 @@ -25,11 +25,6 @@ process SAMTOOLS_FLAGSTAT { --threads ${task.cpus} \\ $bam \\ > ${prefix}.flagstat - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -48,10 +43,5 @@ process SAMTOOLS_FLAGSTAT { 850000 + 0 with mate mapped to a different chr 50000 + 0 with mate mapped to a different chr (mapQ>=5) END_FLAGSTAT - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/samtools/flagstat/meta.yml b/modules/nf-core/samtools/flagstat/meta.yml index ebbc15f2..8caa1bcc 100644 --- a/modules/nf-core/samtools/flagstat/meta.yml +++ b/modules/nf-core/samtools/flagstat/meta.yml @@ -1,6 +1,6 @@ name: samtools_flagstat -description: Counts the number of alignments in a BAM/CRAM/SAM file for each FLAG - type +description: Counts the number of alignments in a BAM/CRAM/SAM file for each + FLAG type keywords: - stats - mapping @@ -17,7 +17,8 @@ tools: homepage: http://www.htslib.org/ documentation: http://www.htslib.org/doc/samtools.html doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] + licence: + - "MIT" identifier: biotools:samtools input: - - meta: @@ -47,13 +48,27 @@ output: description: File containing samtools flagstat output pattern: "*.{flagstat}" ontologies: [] + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool authors: - "@drpatelh" maintainers: diff --git a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap index 0a0a9b15..f5c882da 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -12,7 +12,11 @@ ] ], "1": [ - "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" + [ + "SAMTOOLS_FLAGSTAT", + "samtools", + "1.22.1" + ] ], "flagstat": [ [ @@ -23,16 +27,20 @@ "test.flagstat:md5,67394650dbae96d1a4fcc70484822159" ] ], - "versions": [ - "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" + "versions_samtools": [ + [ + "SAMTOOLS_FLAGSTAT", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-15T15:02:00.813612" + "timestamp": "2026-02-03T11:14:30.820969684" }, "BAM": { "content": [ @@ -47,7 +55,11 @@ ] ], "1": [ - "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" + [ + "SAMTOOLS_FLAGSTAT", + "samtools", + "1.22.1" + ] ], "flagstat": [ [ @@ -58,15 +70,19 @@ "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" ] ], - "versions": [ - "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" + "versions_samtools": [ + [ + "SAMTOOLS_FLAGSTAT", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-15T15:01:55.232954" + "timestamp": "2026-02-03T11:14:25.581619424" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/idxstats/main.nf b/modules/nf-core/samtools/idxstats/main.nf index 9181a1a5..d5b70a7f 100644 --- a/modules/nf-core/samtools/idxstats/main.nf +++ b/modules/nf-core/samtools/idxstats/main.nf @@ -12,7 +12,7 @@ process SAMTOOLS_IDXSTATS { output: tuple val(meta), path("*.idxstats"), emit: idxstats - path "versions.yml" , emit: versions + 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 @@ -27,11 +27,6 @@ process SAMTOOLS_IDXSTATS { --threads ${task.cpus-1} \\ $bam \\ > ${prefix}.idxstats - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -39,10 +34,5 @@ process SAMTOOLS_IDXSTATS { """ touch ${prefix}.idxstats - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/samtools/idxstats/meta.yml b/modules/nf-core/samtools/idxstats/meta.yml index 96d42746..fd153841 100644 --- a/modules/nf-core/samtools/idxstats/meta.yml +++ b/modules/nf-core/samtools/idxstats/meta.yml @@ -17,7 +17,8 @@ tools: homepage: http://www.htslib.org/ documentation: http://www.htslib.org/doc/samtools.html doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] + licence: + - "MIT" identifier: biotools:samtools input: - - meta: @@ -47,13 +48,27 @@ output: description: File containing samtools idxstats output pattern: "*.{idxstats}" ontologies: [] + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool authors: - "@drpatelh" maintainers: diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test b/modules/nf-core/samtools/idxstats/tests/main.nf.test index 5fd1fc78..c990cd55 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test @@ -25,7 +25,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.idxstats, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -47,7 +50,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.idxstats, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } }} diff --git a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap index d3e785e0..19a54c7c 100644 --- a/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/idxstats/tests/main.nf.test.snap @@ -1,72 +1,56 @@ { "bam - stub": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,6da44e5235401559cea62052bdc0197b" - ], - "idxstats": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_IDXSTATS", + "samtools", + "1.22.1" ] - ], - "versions": [ - "versions.yml:md5,6da44e5235401559cea62052bdc0197b" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-10T13:47:35.796569" + "timestamp": "2026-02-02T16:21:46.333090477" }, "bam": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + ] + ], { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" - ] - ], - "1": [ - "versions.yml:md5,6da44e5235401559cea62052bdc0197b" - ], - "idxstats": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.idxstats:md5,df60a8c8d6621100d05178c93fb053a2" + "SAMTOOLS_IDXSTATS", + "samtools", + "1.22.1" ] - ], - "versions": [ - "versions.yml:md5,6da44e5235401559cea62052bdc0197b" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-10T13:47:31.86415" + "timestamp": "2026-02-02T16:21:41.063422521" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/stats/main.nf b/modules/nf-core/samtools/stats/main.nf index 7b070ac3..f9032148 100644 --- a/modules/nf-core/samtools/stats/main.nf +++ b/modules/nf-core/samtools/stats/main.nf @@ -18,11 +18,13 @@ process SAMTOOLS_STATS { task.ext.when == null || task.ext.when script: - def prefix = task.ext.prefix ?: "${meta.id}" + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" def reference = fasta ? "--reference ${fasta}" : "" """ samtools \\ stats \\ + ${args} \\ --threads ${task.cpus} \\ ${reference} \\ ${input} \\ diff --git a/modules/nf-core/samtools/stats/meta.yml b/modules/nf-core/samtools/stats/meta.yml index a20509ae..5c59cce4 100644 --- a/modules/nf-core/samtools/stats/meta.yml +++ b/modules/nf-core/samtools/stats/meta.yml @@ -62,21 +62,22 @@ output: - samtools: type: string description: Name of the tool - - samtools version | sed "1!d;s/.* //: - type: string - description: The command used to generate the version 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: The process the versions were collected from + description: Name of the process - samtools: type: string - description: The tool name - - samtools version | sed "1!d;s/.* //: - type: string - description: The command used to generate the version of the tool + description: Name of the tool + - samtools version | sed "1!d;s/.* //": + type: eval + description: The expression to obtain the version of the tool + authors: - "@drpatelh" - "@FriederikeHanssen" diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index ebea484d..d6e1c8bd 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -13,8 +13,6 @@ workflow BAM_QC { ch_bam_bai_roi_fasta_fai_dict // channel: [ val(meta), path(bam), path(bai), path(roi), path(fasta), path(fai), path(dict)] main: - ch_versions = channel.empty() - ch_bam_bai_roi_fasta_fai_dict .map { meta, bam, bai, _roi, fasta, fai, _dict -> return [meta, bam, bai, fasta, fai] @@ -23,10 +21,7 @@ workflow BAM_QC { SAMTOOLS_STATS(ch_bam_bai_fasta_fai) SAMTOOLS_FLAGSTAT(ch_bam_bai_fasta_fai) - ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions.first()) - SAMTOOLS_IDXSTATS(ch_bam_bai_fasta_fai) - ch_versions = ch_versions.mix(SAMTOOLS_IDXSTATS.out.versions.first()) ch_picard_hsmetrics = channel.empty() ch_picard_multiplemetrics = channel.empty() @@ -40,7 +35,6 @@ workflow BAM_QC { .set { ch_picard } PICARD_COLLECTMULTIPLEMETRICS(ch_picard) - ch_versions = ch_versions.mix(PICARD_COLLECTMULTIPLEMETRICS.out.versions.first()) ch_picard_multiplemetrics = PICARD_COLLECTMULTIPLEMETRICS.out.metrics ch_picard_multiplemetrics_pdf = PICARD_COLLECTMULTIPLEMETRICS.out.pdf @@ -54,11 +48,10 @@ workflow BAM_QC { .set { ch_picard_coverage } PICARD_COLLECTWGSMETRICS(ch_picard_coverage.wgsmetrics, []) - ch_versions = ch_versions.mix(PICARD_COLLECTWGSMETRICS.out.versions.first()) ch_picard_wgsmetrics = PICARD_COLLECTWGSMETRICS.out.metrics PICARD_COLLECTHSMETRICS(ch_picard_coverage.hsmetrics) - ch_versions = ch_versions.mix(PICARD_COLLECTHSMETRICS.out.versions.first()) + ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics emit: @@ -69,5 +62,4 @@ workflow BAM_QC { picard_multiplemetrics_pdf = ch_picard_multiplemetrics_pdf picard_wgsmetrics = ch_picard_wgsmetrics picard_hsmetrics = ch_picard_hsmetrics - versions = ch_versions } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 16618c2e..e7af9c5d 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -303,7 +303,6 @@ workflow PREPROCESSING { BAM_QC.out.picard_wgsmetrics, BAM_QC.out.picard_hsmetrics, ) - ch_versions = ch_versions.mix(BAM_QC.out.versions) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 39a4884cfb3bf4d643bbf0a99a37826f7569b39b Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:48:03 +0100 Subject: [PATCH 156/228] bump mqc module --- modules.json | 2 +- modules/nf-core/multiqc/meta.yml | 27 +++++++++++++++++++++++++-- workflows/preprocessing.nf | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/modules.json b/modules.json index 744675f8..2ac331be 100644 --- a/modules.json +++ b/modules.json @@ -69,7 +69,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "9656d955b700a8707c4a67821ab056f8c1095675", + "git_sha": "575e1a4b51a9bad7a8cd1316a88fb85684ef7c7b", "installed_by": ["modules"], "patch": "modules/nf-core/multiqc/multiqc.diff" }, diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index e4b8f94d..9fd34f37 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -71,7 +71,7 @@ output: - "*_plots": type: file description: Plots created by MultiQC - pattern: "*_data" + pattern: "*_plots" ontologies: [] versions: - - ${task.process}: @@ -83,7 +83,6 @@ output: - multiqc --version | sed "s/.* //g": type: eval description: The expression to obtain the version of the tool - authors: - "@abhi18av" - "@bunop" @@ -94,3 +93,27 @@ maintainers: - "@bunop" - "@drpatelh" - "@jfy133" +containers: + conda: + linux/amd64: + lock_file: https://wave.seqera.io/v1alpha1/builds/bd-ee7739d47738383b_1/condalock + linux/arm64: + lock_file: https://wave.seqera.io/v1alpha1/builds/bd-58d7dee710ab3aa8_1/condalock + docker: + linux/amd64: + build_id: bd-ee7739d47738383b_1 + name: community.wave.seqera.io/library/multiqc:1.33--ee7739d47738383b + scanId: sc-6ddec592dcadd583_4 + linux/arm64: + build_id: bd-58d7dee710ab3aa8_1 + name: community.wave.seqera.io/library/multiqc:1.33--58d7dee710ab3aa8 + scanId: sc-a04c42273e34c55c_2 + singularity: + linux/amd64: + build_id: bd-e3576ddf588fa00d_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/34/34e733a9ae16a27e80fe00f863ea1479c96416017f24a907996126283e7ecd4d/data + name: oras://community.wave.seqera.io/library/multiqc:1.33--e3576ddf588fa00d + linux/arm64: + build_id: bd-2537ca5f8445e3c2_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/78/78b89e91d89e9cc99ad5ade5be311f347838cb2acbfb4f13bc343b170be09ce4/data + name: oras://community.wave.seqera.io/library/multiqc:1.33--2537ca5f8445e3c2 diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index e7af9c5d..365327af 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -285,7 +285,7 @@ workflow PREPROCESSING { meta, cram, crai, - meta.roi && meta.roi != [] ? file(meta.roi, checkIfExists: true) : [], + (meta.roi && meta.roi) != [] ? file(meta.roi, checkIfExists: true) : [], getGenomeAttribute(meta.genome_data, "fasta"), getGenomeAttribute(meta.genome_data, "fai"), getGenomeAttribute(meta.genome_data, "dict"), From 6e56545a364de08884152240aa8934a6368f6b9d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:50:01 +0100 Subject: [PATCH 157/228] bump star/align module --- modules.json | 2 +- modules/nf-core/star/align/main.nf | 18 +- modules/nf-core/star/align/meta.yml | 68 +- modules/nf-core/star/align/star-align.diff | 2 +- modules/nf-core/star/align/tests/main.nf.test | 10 +- .../star/align/tests/main.nf.test.snap | 670 +++++++++++++----- subworkflows/local/fastq_align_rna/main.nf | 1 - 7 files changed, 546 insertions(+), 225 deletions(-) diff --git a/modules.json b/modules.json index 2ac331be..aa368218 100644 --- a/modules.json +++ b/modules.json @@ -139,7 +139,7 @@ }, "star/align": { "branch": "master", - "git_sha": "ce9e10540a1555145ddd1ddd8b15f7443cbe1449", + "git_sha": "d6419d592de78e193625b209c1d0a5cc09206df3", "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" }, diff --git a/modules/nf-core/star/align/main.nf b/modules/nf-core/star/align/main.nf index 034f91df..653996ad 100644 --- a/modules/nf-core/star/align/main.nf +++ b/modules/nf-core/star/align/main.nf @@ -16,7 +16,9 @@ process STAR_ALIGN { tuple val(meta), path('*Log.final.out') , emit: log_final tuple val(meta), path('*Log.out') , emit: log_out tuple val(meta), path('*Log.progress.out'), emit: log_progress - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('star'), eval('STAR --version | sed "s/STAR_//"'), emit: versions_star, topic: versions + tuple val("${task.process}"), val('samtools'), eval("samtools --version | sed -n '1s/samtools //p'"), emit: versions_samtools, topic: versions + tuple val("${task.process}"), val('gawk'), eval("gawk --version | sed -n '1s/GNU Awk \\([0-9.]*\\).*/\\1/p'"), emit: versions_gawk, topic: versions tuple val(meta), path('*d.out.bam') , optional:true, emit: bam tuple val(meta), path("${prefix}.sortedByCoord.out.bam") , optional:true, emit: bam_sorted @@ -68,13 +70,6 @@ process STAR_ALIGN { mv ${prefix}.Unmapped.out.mate2 ${prefix}.unmapped_2.fastq gzip ${prefix}.unmapped_2.fastq fi - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - star: \$(STAR --version | sed -e "s/STAR_//g") - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - gawk: \$(echo \$(gawk --version 2>&1) | sed 's/^.*GNU Awk //; s/, .*\$//') - END_VERSIONS """ stub: @@ -97,12 +92,5 @@ process STAR_ALIGN { touch ${prefix}.out.sam touch ${prefix}.Signal.UniqueMultiple.str1.out.wig touch ${prefix}.Signal.UniqueMultiple.str1.out.bg - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - star: \$(STAR --version | sed -e "s/STAR_//g") - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - gawk: \$(echo \$(gawk --version 2>&1) | sed 's/^.*GNU Awk //; s/, .*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/star/align/meta.yml b/modules/nf-core/star/align/meta.yml index 1ee46905..d1441570 100644 --- a/modules/nf-core/star/align/meta.yml +++ b/modules/nf-core/star/align/meta.yml @@ -89,13 +89,37 @@ output: description: STAR log progress file pattern: "*Log.progress.out" ontologies: [] - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + versions_star: + - - ${task.process}: + type: string + description: The name of the process + - star: + type: string + description: The name of the tool + - STAR --version | sed "s/STAR_//": + type: eval + description: The expression to obtain the version of the tool + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools --version | sed -n '1s/samtools //p': + type: eval + description: The expression to obtain the version of the tool + versions_gawk: + - - ${task.process}: + type: string + description: The name of the process + - gawk: + type: string + description: The name of the tool + - gawk --version | sed -n '1s/GNU Awk \([0-9.]*\).*/\1/p': + type: eval + description: The expression to obtain the version of the tool + bam: - - meta: type: map @@ -243,6 +267,36 @@ output: description: STAR output bedGraph format file(s) (optional) pattern: "*.bg" ontologies: [] +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - star: + type: string + description: The name of the tool + - STAR --version | sed "s/STAR_//": + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools --version | sed -n '1s/samtools //p': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - gawk: + type: string + description: The name of the tool + - gawk --version | sed -n '1s/GNU Awk \([0-9.]*\).*/\1/p': + type: eval + description: The expression to obtain the version of the tool + authors: - "@kevinmenden" - "@drpatelh" diff --git a/modules/nf-core/star/align/star-align.diff b/modules/nf-core/star/align/star-align.diff index 398da009..0c9c6621 100644 --- a/modules/nf-core/star/align/star-align.diff +++ b/modules/nf-core/star/align/star-align.diff @@ -16,7 +16,7 @@ Changes in 'star/align/main.nf': val seq_platform val seq_center -@@ -44,7 +41,7 @@ +@@ -46,7 +43,7 @@ def reads1 = [] def reads2 = [] meta.single_end ? [reads].flatten().each{ read -> reads1 << read} : reads.eachWithIndex{ v, ix -> ( ix & 1 ? reads2 : reads1) << v } diff --git a/modules/nf-core/star/align/tests/main.nf.test b/modules/nf-core/star/align/tests/main.nf.test index a62c17db..da0cc07e 100644 --- a/modules/nf-core/star/align/tests/main.nf.test +++ b/modules/nf-core/star/align/tests/main.nf.test @@ -65,7 +65,7 @@ nextflow_process { process.out.spl_junc_tab, process.out.tab, process.out.wig, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -130,7 +130,7 @@ nextflow_process { process.out.spl_junc_tab, process.out.tab, process.out.wig, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -194,7 +194,7 @@ nextflow_process { process.out.spl_junc_tab, process.out.tab, process.out.wig, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -259,7 +259,7 @@ nextflow_process { process.out.spl_junc_tab, process.out.tab, process.out.wig, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -326,7 +326,7 @@ nextflow_process { process.out.spl_junc_tab, process.out.tab, process.out.wig, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } diff --git a/modules/nf-core/star/align/tests/main.nf.test.snap b/modules/nf-core/star/align/tests/main.nf.test.snap index a1ec3a3d..2b5755db 100644 --- a/modules/nf-core/star/align/tests/main.nf.test.snap +++ b/modules/nf-core/star/align/tests/main.nf.test.snap @@ -21,6 +21,27 @@ ] ], "10": [ + [ + { + "id": "test", + "single_end": true + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "12": [ [ { "id": "test", @@ -33,7 +54,7 @@ ] ] ], - "11": [ + "13": [ [ { "id": "test", @@ -42,7 +63,7 @@ "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "12": [ + "14": [ [ { "id": "test", @@ -51,7 +72,7 @@ "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "13": [ + "15": [ [ { "id": "test", @@ -60,7 +81,7 @@ "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "14": [ + "16": [ [ { "id": "test", @@ -69,7 +90,7 @@ "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "15": [ + "17": [ [ { "id": "test", @@ -78,7 +99,7 @@ "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "16": [ + "18": [ [ { "id": "test", @@ -97,28 +118,24 @@ ] ], "3": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "4": [ [ - { - "id": "test", - "single_end": true - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "STAR_ALIGN", + "samtools", + "1.21" ] ], "5": [ [ - { - "id": "test", - "single_end": true - }, - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "STAR_ALIGN", + "gawk", + "5.1.0" ] ], "6": [ @@ -127,7 +144,11 @@ "id": "test", "single_end": true }, - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "7": [ @@ -136,7 +157,7 @@ "id": "test", "single_end": true }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "8": [ @@ -145,7 +166,7 @@ "id": "test", "single_end": true }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "9": [ @@ -154,10 +175,7 @@ "id": "test", "single_end": true }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "bam": [ @@ -306,8 +324,26 @@ ] ] ], - "versions": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "wig": [ [ @@ -321,10 +357,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:28:39.242074494" + "timestamp": "2026-02-03T09:28:25.802437191" }, "homo_sapiens - paired_end - arriba - stub": { "content": [ @@ -348,6 +384,27 @@ ] ], "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "12": [ [ { "id": "test", @@ -360,7 +417,7 @@ ] ] ], - "11": [ + "13": [ [ { "id": "test", @@ -369,7 +426,7 @@ "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "12": [ + "14": [ [ { "id": "test", @@ -378,7 +435,7 @@ "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "13": [ + "15": [ [ { "id": "test", @@ -387,7 +444,7 @@ "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "14": [ + "16": [ [ { "id": "test", @@ -396,7 +453,7 @@ "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "15": [ + "17": [ [ { "id": "test", @@ -405,7 +462,7 @@ "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "16": [ + "18": [ [ { "id": "test", @@ -424,28 +481,24 @@ ] ], "3": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "4": [ [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "STAR_ALIGN", + "samtools", + "1.21" ] ], "5": [ [ - { - "id": "test", - "single_end": false - }, - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "STAR_ALIGN", + "gawk", + "5.1.0" ] ], "6": [ @@ -454,7 +507,11 @@ "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "7": [ @@ -463,7 +520,7 @@ "id": "test", "single_end": false }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "8": [ @@ -472,7 +529,7 @@ "id": "test", "single_end": false }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "9": [ @@ -481,10 +538,7 @@ "id": "test", "single_end": false }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "bam": [ @@ -633,8 +687,26 @@ ] ] ], - "versions": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "wig": [ [ @@ -648,10 +720,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:29:08.392620556" + "timestamp": "2026-02-03T09:28:38.483306917" }, "homo_sapiens - single_end": { "content": [ @@ -702,15 +774,35 @@ [ ], - [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" - ] + { + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2024-12-11T16:21:34.549483887" + "timestamp": "2026-02-02T23:44:45.378997" }, "homo_sapiens - paired_end": { "content": [ @@ -761,15 +853,35 @@ [ ], - [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" - ] + { + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2024-12-11T16:22:17.011253146" + "timestamp": "2026-02-02T23:50:50.657212" }, "homo_sapiens - paired_end - multiple - stub": { "content": [ @@ -793,6 +905,27 @@ ] ], "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "12": [ [ { "id": "test", @@ -805,7 +938,7 @@ ] ] ], - "11": [ + "13": [ [ { "id": "test", @@ -814,7 +947,7 @@ "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "12": [ + "14": [ [ { "id": "test", @@ -823,7 +956,7 @@ "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "13": [ + "15": [ [ { "id": "test", @@ -832,7 +965,7 @@ "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "14": [ + "16": [ [ { "id": "test", @@ -841,7 +974,7 @@ "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "15": [ + "17": [ [ { "id": "test", @@ -850,7 +983,7 @@ "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "16": [ + "18": [ [ { "id": "test", @@ -869,28 +1002,24 @@ ] ], "3": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "4": [ [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "STAR_ALIGN", + "samtools", + "1.21" ] ], "5": [ [ - { - "id": "test", - "single_end": false - }, - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "STAR_ALIGN", + "gawk", + "5.1.0" ] ], "6": [ @@ -899,7 +1028,11 @@ "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "7": [ @@ -908,7 +1041,7 @@ "id": "test", "single_end": false }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "8": [ @@ -917,7 +1050,7 @@ "id": "test", "single_end": false }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "9": [ @@ -926,10 +1059,7 @@ "id": "test", "single_end": false }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "bam": [ @@ -1078,8 +1208,26 @@ ] ] ], - "versions": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "wig": [ [ @@ -1093,10 +1241,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:29:31.072104862" + "timestamp": "2026-02-03T09:28:51.288466085" }, "homo_sapiens - paired_end - multiple": { "content": [ @@ -1147,15 +1295,35 @@ [ ], - [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" - ] + { + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:28:26.645008336" + "timestamp": "2026-02-03T09:28:19.516063466" }, "homo_sapiens - paired_end - stub": { "content": [ @@ -1179,6 +1347,27 @@ ] ], "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "12": [ [ { "id": "test", @@ -1191,7 +1380,7 @@ ] ] ], - "11": [ + "13": [ [ { "id": "test", @@ -1200,7 +1389,7 @@ "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "12": [ + "14": [ [ { "id": "test", @@ -1209,7 +1398,7 @@ "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "13": [ + "15": [ [ { "id": "test", @@ -1218,7 +1407,7 @@ "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "14": [ + "16": [ [ { "id": "test", @@ -1227,7 +1416,7 @@ "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "15": [ + "17": [ [ { "id": "test", @@ -1236,7 +1425,7 @@ "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "16": [ + "18": [ [ { "id": "test", @@ -1255,28 +1444,24 @@ ] ], "3": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "4": [ [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "STAR_ALIGN", + "samtools", + "1.21" ] ], "5": [ [ - { - "id": "test", - "single_end": false - }, - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "STAR_ALIGN", + "gawk", + "5.1.0" ] ], "6": [ @@ -1285,7 +1470,11 @@ "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "7": [ @@ -1294,7 +1483,7 @@ "id": "test", "single_end": false }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "8": [ @@ -1303,7 +1492,7 @@ "id": "test", "single_end": false }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "9": [ @@ -1312,10 +1501,7 @@ "id": "test", "single_end": false }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "bam": [ @@ -1464,8 +1650,26 @@ ] ] ], - "versions": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "wig": [ [ @@ -1479,10 +1683,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:28:53.816280805" + "timestamp": "2026-02-03T09:28:32.099657738" }, "homo_sapiens - paired_end - starfusion": { "content": [ @@ -1524,15 +1728,35 @@ [ ], - [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" - ] + { + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:27:14.136111964" + "timestamp": "2026-02-03T09:26:46.244829386" }, "homo_sapiens - paired_end - arriba": { "content": [ @@ -1573,15 +1797,35 @@ [ ], - [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" - ] + { + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:24:00.829462526" + "timestamp": "2026-02-03T09:22:41.580434639" }, "homo_sapiens - paired_end - starfusion - stub": { "content": [ @@ -1605,6 +1849,27 @@ ] ], "10": [ + [ + { + "id": "test", + "single_end": false + }, + "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "11": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "12": [ [ { "id": "test", @@ -1617,7 +1882,7 @@ ] ] ], - "11": [ + "13": [ [ { "id": "test", @@ -1626,7 +1891,7 @@ "test.SJ.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "12": [ + "14": [ [ { "id": "test", @@ -1635,7 +1900,7 @@ "test.ReadsPerGene.out.tab:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "13": [ + "15": [ [ { "id": "test", @@ -1644,7 +1909,7 @@ "test.Chimeric.out.junction:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "14": [ + "16": [ [ { "id": "test", @@ -1653,7 +1918,7 @@ "test.out.sam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "15": [ + "17": [ [ { "id": "test", @@ -1662,7 +1927,7 @@ "test.Signal.UniqueMultiple.str1.out.wig:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "16": [ + "18": [ [ { "id": "test", @@ -1681,28 +1946,24 @@ ] ], "3": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "4": [ [ - { - "id": "test", - "single_end": false - }, - [ - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", - "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] + "STAR_ALIGN", + "samtools", + "1.21" ] ], "5": [ [ - { - "id": "test", - "single_end": false - }, - "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "STAR_ALIGN", + "gawk", + "5.1.0" ] ], "6": [ @@ -1711,7 +1972,11 @@ "id": "test", "single_end": false }, - "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + [ + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e", + "testXd.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "7": [ @@ -1720,7 +1985,7 @@ "id": "test", "single_end": false }, - "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "8": [ @@ -1729,7 +1994,7 @@ "id": "test", "single_end": false }, - "test.Aligned.unsort.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.Aligned.sortedByCoord.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "9": [ @@ -1738,10 +2003,7 @@ "id": "test", "single_end": false }, - [ - "test.unmapped_1.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", - "test.unmapped_2.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" - ] + "test.toTranscriptome.out.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "bam": [ @@ -1890,8 +2152,26 @@ ] ] ], - "versions": [ - "versions.yml:md5,b416145d7b5b8a080e832a7f7cde4c44" + "versions_gawk": [ + [ + "STAR_ALIGN", + "gawk", + "5.1.0" + ] + ], + "versions_samtools": [ + [ + "STAR_ALIGN", + "samtools", + "1.21" + ] + ], + "versions_star": [ + [ + "STAR_ALIGN", + "star", + "2.7.11b" + ] ], "wig": [ [ @@ -1905,9 +2185,9 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-12-11T16:29:20.015372487" + "timestamp": "2026-02-03T09:28:44.836246776" } } \ No newline at end of file diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index 1ca27833..5e86bff2 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -40,7 +40,6 @@ workflow FASTQ_ALIGN_RNA { STAR_ALIGN.out.log_progress, STAR_ALIGN.out.log_out, ) - ch_versions = ch_versions.mix(STAR_ALIGN.out.versions.first()) // Concatenate splice junction files def ch_splice_junctions_to_merge = group_junctions(STAR_ALIGN.out.spl_junc_tab) From 1dfaee82bd16a7f7a79b1af032332295d75a6d70 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:51:52 +0100 Subject: [PATCH 158/228] bump samtools/sormadup module --- modules.json | 2 +- modules/nf-core/samtools/sormadup/main.nf | 13 +-- modules/nf-core/samtools/sormadup/meta.yml | 47 +++++++--- .../samtools/sormadup/tests/main.nf.test | 52 ++++++----- .../samtools/sormadup/tests/main.nf.test.snap | 88 +++++++++++-------- 5 files changed, 118 insertions(+), 84 deletions(-) diff --git a/modules.json b/modules.json index aa368218..8332985d 100644 --- a/modules.json +++ b/modules.json @@ -115,7 +115,7 @@ }, "samtools/sormadup": { "branch": "master", - "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", + "git_sha": "0043d7ccd6b7278cd566db278c2f6ceb937e04ba", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sormadup/samtools-sormadup.diff" }, diff --git a/modules/nf-core/samtools/sormadup/main.nf b/modules/nf-core/samtools/sormadup/main.nf index 86afb479..15bcf5ff 100644 --- a/modules/nf-core/samtools/sormadup/main.nf +++ b/modules/nf-core/samtools/sormadup/main.nf @@ -8,7 +8,7 @@ process SAMTOOLS_SORMADUP { 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(fasta) + tuple val(meta), path(input), path(fasta), path(fai) output: tuple val(meta), path("*.bam") , emit: bam, optional: true @@ -16,7 +16,7 @@ process SAMTOOLS_SORMADUP { tuple val(meta), path("*.csi") , emit: csi, optional: true tuple val(meta), path("*.crai") , emit: crai, optional: true tuple val(meta), path("*.metrics") , emit: metrics - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), topic: versions, emit: versions_samtools when: task.ext.when == null || task.ext.when @@ -71,10 +71,6 @@ process SAMTOOLS_SORMADUP { - \\ ${prefix}.${extension} - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -87,10 +83,5 @@ process SAMTOOLS_SORMADUP { """ touch ${prefix}.${extension} touch ${prefix}.metrics - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/samtools/sormadup/meta.yml b/modules/nf-core/samtools/sormadup/meta.yml index bb6295bf..02b9ad4e 100644 --- a/modules/nf-core/samtools/sormadup/meta.yml +++ b/modules/nf-core/samtools/sormadup/meta.yml @@ -1,4 +1,3 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: "samtools_sormadup" description: Collate/Fixmate/Sort/Markdup SAM/BAM/CRAM file keywords: @@ -20,7 +19,8 @@ tools: homepage: http://www.htslib.org/ documentation: http://www.htslib.org/doc/samtools.html doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] + licence: + - "MIT" args_id: "$args" identifier: biotools:samtools - samtools_collate: @@ -31,7 +31,8 @@ tools: homepage: http://www.htslib.org/ documentation: http://www.htslib.org/doc/samtools.html doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] + licence: + - "MIT" args_id: "$args2" identifier: biotools:samtools - samtools_fixmate: @@ -42,7 +43,8 @@ tools: homepage: http://www.htslib.org/ documentation: http://www.htslib.org/doc/samtools.html doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] + licence: + - "MIT" args_id: "$args3" identifier: biotools:samtools - samtools_sort: @@ -53,7 +55,8 @@ tools: homepage: http://www.htslib.org/ documentation: http://www.htslib.org/doc/samtools.html doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] + licence: + - "MIT" args_id: "$args4" identifier: biotools:samtools - samtools_markdup: @@ -64,7 +67,8 @@ tools: homepage: http://www.htslib.org/ documentation: http://www.htslib.org/doc/samtools.html doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] + licence: + - "MIT" args_id: "$args5" identifier: biotools:samtools input: @@ -88,6 +92,11 @@ input: description: Reference genome file pattern: "*.{fasta,fa,fna}" ontologies: [] + - fai: + type: file + description: Reference genome index file + pattern: "*.fai" + ontologies: [] output: bam: - - meta: @@ -144,13 +153,27 @@ output: description: Duplicate metrics file pattern: "*.metrics" ontologies: [] + versions_samtools: + - - ${task.process}: + type: string + description: The process the versions were collected from + - samtools: + type: string + description: The tool name + - "samtools version | sed '1!d;s/.* //'": + type: eval + description: The command used to generate the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The process the versions were collected from + - samtools: + type: string + description: The tool name + - "samtools version | sed '1!d;s/.* //'": + type: eval + description: The command used to generate the version of the tool authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/samtools/sormadup/tests/main.nf.test b/modules/nf-core/samtools/sormadup/tests/main.nf.test index 574d70c6..f9bc34e5 100644 --- a/modules/nf-core/samtools/sormadup/tests/main.nf.test +++ b/modules/nf-core/samtools/sormadup/tests/main.nf.test @@ -13,22 +13,23 @@ nextflow_process { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + input[0] = [ + [id: 'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) + ] + input[1] = [ + [ id:'fasta' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ] """ } } then { + assert process.success assertAll( - { assert process.success }, { assert snapshot(process.out).match() } ) } @@ -42,23 +43,24 @@ nextflow_process { } process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + input[0] = [ + [id: 'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) + ] + input[1] = [ + [ id:'fasta' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ] """ } } then { + assert process.success def fasta = params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta' assertAll( - { assert process.success }, { assert snapshot( cram( @@ -67,6 +69,7 @@ nextflow_process { ).getReadsMD5(), file(process.out.crai[0][1]).name, process.out.metrics, + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) @@ -81,22 +84,23 @@ nextflow_process { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + input[0] = [ + [id: 'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) + ] + input[1] = [ + [ id:'fasta' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ] """ } } then { + assert process.success assertAll( - { assert process.success }, { assert snapshot(process.out).match() } ) } diff --git a/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap b/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap index 7d36514f..9d04d5d2 100644 --- a/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sormadup/tests/main.nf.test.snap @@ -5,8 +5,7 @@ "0": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] @@ -23,20 +22,22 @@ "4": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.metrics:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "5": [ - "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" + [ + "SAMTOOLS_SORMADUP", + "samtools", + "1.22.1" + ] ], "bam": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] @@ -53,22 +54,25 @@ "metrics": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.metrics:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" + "versions_samtools": [ + [ + "SAMTOOLS_SORMADUP", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T14:41:27.357324" + "timestamp": "2026-02-03T14:50:54.695296905" }, "sarscov2 - cram": { "content": [ @@ -77,18 +81,26 @@ [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.merged.metrics:md5,02eebd31b097e165e1b18d84b023f18d" ] - ] + ], + { + "versions_samtools": [ + [ + "SAMTOOLS_SORMADUP", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-10T15:34:19.685282" + "timestamp": "2026-02-04T09:59:00.393494" }, "sarscov2 - bam": { "content": [ @@ -96,10 +108,9 @@ "0": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "test.bam:md5,22ccf80de9847da1fa532f7774580554" + "test.bam:md5,b191a8b4d5b8b9884def3a613fee914a" ] ], "1": [ @@ -114,22 +125,24 @@ "4": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.metrics:md5,6093d8853805578a1868f22ff68177e7" ] ], "5": [ - "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" + [ + "SAMTOOLS_SORMADUP", + "samtools", + "1.22.1" + ] ], "bam": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "test.bam:md5,22ccf80de9847da1fa532f7774580554" + "test.bam:md5,b191a8b4d5b8b9884def3a613fee914a" ] ], "crai": [ @@ -144,21 +157,24 @@ "metrics": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.metrics:md5,6093d8853805578a1868f22ff68177e7" ] ], - "versions": [ - "versions.yml:md5,f747eda74610b9e2ffbe38a0fe32605c" + "versions_samtools": [ + [ + "SAMTOOLS_SORMADUP", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-10T14:41:11.744386" + "timestamp": "2026-02-04T10:01:06.229966" } } \ No newline at end of file From 1391207e61914361193d22b9653e45ae14b650ee Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:53:23 +0100 Subject: [PATCH 159/228] bump bcl2fastq/bclconvert modules --- modules.json | 4 ++-- modules/nf-core/bcl2fastq/main.nf | 2 +- modules/nf-core/bclconvert/main.nf | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules.json b/modules.json index 8332985d..b2c74466 100644 --- a/modules.json +++ b/modules.json @@ -7,12 +7,12 @@ "nf-core": { "bcl2fastq": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", "installed_by": ["bcl_demultiplex"] }, "bclconvert": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", "installed_by": ["bcl_demultiplex", "modules"], "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, diff --git a/modules/nf-core/bcl2fastq/main.nf b/modules/nf-core/bcl2fastq/main.nf index 2759a364..865f7951 100644 --- a/modules/nf-core/bcl2fastq/main.nf +++ b/modules/nf-core/bcl2fastq/main.nf @@ -1,5 +1,5 @@ process BCL2FASTQ { - tag {"$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } + tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } label 'process_high' container "nf-core/bcl2fastq:2.20.0.422" diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index b61f2240..db0dac03 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -1,5 +1,5 @@ process BCLCONVERT { - tag {"$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } + tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } label 'process_high' container "nf-core/bclconvert:4.4.6" From 69ad5d3365f63e7951f454f382b9a52167923dd8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:55:31 +0100 Subject: [PATCH 160/228] bump biobambam/bamsormadup module --- modules.json | 2 +- .../bamsormadup/biobambam-bamsormadup.diff | 24 +------- .../biobambam/bamsormadup/environment.yml | 2 +- modules/nf-core/biobambam/bamsormadup/main.nf | 6 +- .../biobambam/bamsormadup/tests/main.nf.test | 55 ++++++++++--------- .../bamsormadup/tests/main.nf.test.snap | 49 ++++++++++++----- 6 files changed, 72 insertions(+), 66 deletions(-) diff --git a/modules.json b/modules.json index b2c74466..7a31dc10 100644 --- a/modules.json +++ b/modules.json @@ -18,7 +18,7 @@ }, "biobambam/bamsormadup": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", "installed_by": ["modules"], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, diff --git a/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff b/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff index 9c5a8c3e..ba8b093d 100644 --- a/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff +++ b/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff @@ -4,34 +4,16 @@ Changes in component 'nf-core/biobambam/bamsormadup' Changes in 'biobambam/bamsormadup/main.nf': --- modules/nf-core/biobambam/bamsormadup/main.nf +++ modules/nf-core/biobambam/bamsormadup/main.nf -@@ -6,8 +6,7 @@ - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/biobambam:2.0.183--h9f5acd7_1' : 'biocontainers/biobambam:2.0.183--h9f5acd7_1'}" +@@ -8,8 +8,7 @@ + 'biocontainers/biobambam:2.0.185--h85de650_1'}" input: - tuple val(meta) , path(bams, stageAs: "?/*") - tuple val(meta2), path(fasta) -+ tuple val(meta) , path(bams, stageAs: "?/*"), path(fasta) ++ tuple val(meta) , path(bams, stageAs: "?/*"), path(fasta), path(fai) output: tuple val(meta), path("*.bam") ,optional:true, emit: bam -@@ -25,7 +24,7 @@ - def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = args.contains("outputformat=cram") ? "cram" : "bam" - def input_string = bams instanceof List ? bams.join(" I=") : bams -- if (args.contains("outputformat=cram") && reference == null) error "Reference required for CRAM output." -+ if (args.contains("outputformat=cram") && fasta == null) error "Reference required for CRAM output." - - """ - bamcat \\ -@@ -53,7 +52,7 @@ - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = args.contains("outputformat=cram") ? "cram" : "bam" -- if (args.contains("outputformat=cram") && reference == null) error "Reference required for CRAM output." -+ if (args.contains("outputformat=cram") && fasta == null) error "Reference required for CRAM output." - - """ - touch ${prefix}.${suffix} 'modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap' is unchanged 'modules/nf-core/biobambam/bamsormadup/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/biobambam/bamsormadup/environment.yml b/modules/nf-core/biobambam/bamsormadup/environment.yml index 8c8c3166..948d0ad9 100644 --- a/modules/nf-core/biobambam/bamsormadup/environment.yml +++ b/modules/nf-core/biobambam/bamsormadup/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::biobambam=2.0.183 + - bioconda::biobambam=2.0.185=h85de650_1 diff --git a/modules/nf-core/biobambam/bamsormadup/main.nf b/modules/nf-core/biobambam/bamsormadup/main.nf index bb6edc3e..032e718d 100644 --- a/modules/nf-core/biobambam/bamsormadup/main.nf +++ b/modules/nf-core/biobambam/bamsormadup/main.nf @@ -3,10 +3,12 @@ process BIOBAMBAM_BAMSORMADUP { label "process_medium" conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? 'https://depot.galaxyproject.org/singularity/biobambam:2.0.183--h9f5acd7_1' : 'biocontainers/biobambam:2.0.183--h9f5acd7_1'}" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/biobambam:2.0.185--h85de650_1' : + 'biocontainers/biobambam:2.0.185--h85de650_1'}" input: - tuple val(meta) , path(bams, stageAs: "?/*"), path(fasta) + tuple val(meta) , path(bams, stageAs: "?/*"), path(fasta), path(fai) output: tuple val(meta), path("*.bam") ,optional:true, emit: bam diff --git a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test index 43272ff1..0c4c8498 100644 --- a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test +++ b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test @@ -16,13 +16,13 @@ nextflow_process { process { """ input[0] = [ - [ id:'test', single_end:false ], // meta map - [ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) ] - ] - input[1] = [[:],[]] + ] + input[1] = [[:],[]] """ } @@ -32,13 +32,12 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - bam(process.out.bam[0][1]).getReadsMD5(), - process.out.bam_index, - process.out.cram, - file(process.out.metrics[0][1]).readLines()[3..5], - process.out.versions - ).match() - } + bam(process.out.bam[0][1]).getReadsMD5(), + process.out.bam_index, + process.out.cram, + file(process.out.metrics[0][1]).readLines()[3..5], + process.out.versions.collect{ path(it).yaml } + ).match()} ) } } @@ -49,12 +48,12 @@ nextflow_process { process { """ input[0] = [ - [ id:'test', single_end:false ], // meta map - [ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) ] - ] - input[1] = [[:],[]] + ] + input[1] = [[:],[]] """ } @@ -64,13 +63,12 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - bam(process.out.bam[0][1]).getReadsMD5(), - process.out.bam_index, - process.out.cram, - file(process.out.metrics[0][1]).readLines()[3..5], - process.out.versions - ).match() - } + bam(process.out.bam[0][1]).getReadsMD5(), + process.out.bam_index, + process.out.cram, + file(process.out.metrics[0][1]).readLines()[3..5], + process.out.versions.collect{ path(it).yaml } + ).match()} ) } } @@ -83,12 +81,12 @@ nextflow_process { process { """ input[0] = [ - [ id:'test', single_end:false ], // meta map - [ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) ] - ] - input[1] = [[:],[]] + ] + input[1] = [[:],[]] """ } @@ -97,7 +95,10 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out, + process.out.versions.collect{ path(it).yaml } + ).match() } ) } } diff --git a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap index f7a41ca6..b820e405 100644 --- a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap +++ b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap @@ -14,14 +14,20 @@ "" ], [ - "versions.yml:md5,67ab301f20567acd9d0e648c2a3e158c" + { + "BIOBAMBAM_BAMSORMADUP": { + "bamcat": "2.0.185", + "bamcollate2": "2.0.185", + "bamsormadup": "2.0.185" + } + } ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-09-05T22:00:39.772883" + "timestamp": "2026-02-06T12:52:41.351378528" }, "test-biobambam-bamsormadup-multi-input": { "content": [ @@ -38,14 +44,20 @@ "testN\t0\t2820\t2\t0\t828\t0\t0.293617\t3807" ], [ - "versions.yml:md5,67ab301f20567acd9d0e648c2a3e158c" + { + "BIOBAMBAM_BAMSORMADUP": { + "bamcat": "2.0.185", + "bamcollate2": "2.0.185", + "bamsormadup": "2.0.185" + } + } ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-09-05T22:00:31.187999" + "timestamp": "2026-02-06T12:52:29.639539709" }, "test-biobambam-bamsormadup-single-input-stub": { "content": [ @@ -75,7 +87,7 @@ ] ], "4": [ - "versions.yml:md5,67ab301f20567acd9d0e648c2a3e158c" + "versions.yml:md5,a3e9cdb2ef49dc4722663257b23c5cb6" ], "bam": [ [ @@ -102,14 +114,23 @@ ] ], "versions": [ - "versions.yml:md5,67ab301f20567acd9d0e648c2a3e158c" + "versions.yml:md5,a3e9cdb2ef49dc4722663257b23c5cb6" ] - } + }, + [ + { + "BIOBAMBAM_BAMSORMADUP": { + "bamcat": "2.0.185", + "bamcollate2": "2.0.185", + "bamsormadup": "2.0.185" + } + } + ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-09-05T21:57:13.430982" + "timestamp": "2026-02-06T13:56:01.80534017" } } \ No newline at end of file From fe6f856ba61d1ee615ec87f77ff845f2d3330971 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:59:13 +0100 Subject: [PATCH 161/228] bump aligner module --- modules.json | 11 +- modules/nf-core/bowtie2/align/main.nf | 18 +- modules/nf-core/bowtie2/align/meta.yml | 66 ++- .../nf-core/bowtie2/align/tests/main.nf.test | 24 +- .../bowtie2/align/tests/main.nf.test.snap | 384 ++++++++++++++---- modules/nf-core/bwa/mem/tests/main.nf.test | 5 - .../nf-core/bwa/mem/tests/main.nf.test.snap | 35 +- modules/nf-core/bwamem2/mem/main.nf | 14 +- modules/nf-core/bwamem2/mem/meta.yml | 45 +- .../nf-core/bwamem2/mem/tests/main.nf.test | 8 +- .../bwamem2/mem/tests/main.nf.test.snap | 92 +++-- .../fastq_align_dna/fastq_align_dna.diff | 37 +- subworkflows/nf-core/fastq_align_dna/main.nf | 16 +- .../fastq_align_dna/tests/main.nf.test.snap | 32 +- 14 files changed, 537 insertions(+), 250 deletions(-) diff --git a/modules.json b/modules.json index 7a31dc10..5413652a 100644 --- a/modules.json +++ b/modules.json @@ -24,19 +24,19 @@ }, "bowtie2/align": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "ab146e7909edbf6dcc6459de57eef29dceb61d42", "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, "bwa/mem": { "branch": "master", - "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", + "git_sha": "966ba9887e2b04d89d64db06c01508873bde13b1", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, "bwamem2/mem": { "branch": "master", - "git_sha": "d86336f3e7ae0d5f76c67b0859409769cfeb2af2", + "git_sha": "5dd46a36fca68d6ad1a6b22ec47adc8c6863717d", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, @@ -160,8 +160,9 @@ }, "fastq_align_dna": { "branch": "master", - "git_sha": "070ddae7fb59384d3d85bf69eb9a1d71ab33ada9", - "installed_by": ["subworkflows"] + "git_sha": "5dd46a36fca68d6ad1a6b22ec47adc8c6863717d", + "installed_by": ["subworkflows"], + "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" }, "utils_nextflow_pipeline": { "branch": "master", diff --git a/modules/nf-core/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index 4f153522..86aa8bef 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -20,7 +20,9 @@ process BOWTIE2_ALIGN { tuple val(meta), path("*.crai") , emit: crai , optional:true tuple val(meta), path("*.log") , emit: log tuple val(meta), path("*fastq.gz") , emit: fastq , optional:true - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('bowtie2'), eval("bowtie2 --version 2>&1 | sed -n '1s/.*bowtie2-align-s version //p'"), emit: versions_bowtie2, topic: versions + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), emit: versions_samtools, topic: versions + tuple val("${task.process}"), val('pigz'), eval("pigz --version 2>&1 | sed 's/pigz //'"), emit: versions_pigz, topic: versions when: task.ext.when == null || task.ext.when @@ -68,13 +70,6 @@ process BOWTIE2_ALIGN { if [ -f ${prefix}.unmapped.fastq.2.gz ]; then mv ${prefix}.unmapped.fastq.2.gz ${prefix}.unmapped_2.fastq.gz fi - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bowtie2: \$(echo \$(bowtie2 --version 2>&1) | sed 's/^.*bowtie2-align-s version //; s/ .*\$//') - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS """ stub: @@ -102,13 +97,6 @@ process BOWTIE2_ALIGN { ${create_index} touch ${prefix}.bowtie2.log ${create_unmapped} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bowtie2: \$(echo \$(bowtie2 --version 2>&1) | sed 's/^.*bowtie2-align-s version //; s/ .*\$//') - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS """ } diff --git a/modules/nf-core/bowtie2/align/meta.yml b/modules/nf-core/bowtie2/align/meta.yml index 0c12b28a..2d8051da 100644 --- a/modules/nf-core/bowtie2/align/meta.yml +++ b/modules/nf-core/bowtie2/align/meta.yml @@ -123,13 +123,67 @@ output: pattern: "*.fastq.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format + versions_bowtie2: + - - ${task.process}: + type: string + description: The name of the process + - bowtie2: + type: string + description: The name of the tool + - "bowtie2 --version 2>&1 | sed -n '1s/.*bowtie2-align-s version //p'": + type: eval + description: The expression to obtain the version of bowtie2 + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - "samtools version | sed '1!d;s/.* //'": + type: eval + description: The expression to obtain the version of samtools + versions_pigz: + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - "pigz --version 2>&1 | sed 's/pigz //'": + type: eval + description: The expression to obtain the version of pigz + +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - bowtie2: + type: string + description: The name of the tool + - "bowtie2 --version 2>&1 | sed -n '1s/.*bowtie2-align-s version //p'": + type: eval + description: The expression to obtain the version of bowtie2 + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - "samtools version | sed '1!d;s/.* //'": + type: eval + description: The expression to obtain the version of samtools + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - "pigz --version 2>&1 | sed 's/pigz //'": + type: eval + description: The expression to obtain the version of pigz + authors: - "@joseespinosa" - "@drpatelh" diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test b/modules/nf-core/bowtie2/align/tests/main.nf.test index 0de5950f..1705b66d 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test @@ -47,7 +47,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -93,7 +93,7 @@ nextflow_process { file(process.out.sam[0][1]).readLines()[0..4], process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -139,7 +139,7 @@ nextflow_process { file(process.out.sam[0][1]).readLines()[0..4], process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -184,7 +184,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -232,7 +232,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -280,7 +280,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -326,7 +326,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -375,7 +375,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -423,7 +423,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -468,7 +468,7 @@ nextflow_process { file(process.out.bam[0][1]).name, process.out.log, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) @@ -566,7 +566,7 @@ nextflow_process { file(process.out.csi[0][1]).name, file(process.out.log[0][1]).name, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -613,7 +613,7 @@ nextflow_process { file(process.out.csi[0][1]).name, file(process.out.log[0][1]).name, process.out.fastq, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap index 4ffd62e9..c8c6d4b5 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap @@ -14,15 +14,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T12:45:59.038637" + "timestamp": "2026-02-03T15:18:12.706444258" }, "sarscov2 - fastq, index, fasta, false, false - sam2": { "content": [ @@ -45,15 +65,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-25T08:28:51.065380563" + "timestamp": "2026-02-03T15:17:39.204319466" }, "sarscov2 - [fastq1, fastq2], index, fasta, true, true - cram": { "content": [ @@ -81,15 +121,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-03-24T11:38:12.222762" + "timestamp": "2026-02-03T10:46:53.843035" }, "sarscov2 - fastq, index, fasta, true, false - bam": { "content": [ @@ -106,15 +166,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T12:46:12.766061" + "timestamp": "2026-02-03T15:18:25.788314396" }, "sarscov2 - fastq, large_index, fasta, false, false - bam": { "content": [ @@ -131,15 +211,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T11:24:03.499074" + "timestamp": "2026-02-03T15:18:06.123712951" }, "sarscov2 - fastq, index, fasta, false, true - bam": { "content": [ @@ -156,15 +256,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T11:08:30.329879" + "timestamp": "2026-02-03T15:17:45.85694104" }, "sarscov2 - fastq, index, fasta, true, false - stub": { "content": [ @@ -174,15 +294,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T13:48:54.684859" + "timestamp": "2026-02-03T15:18:45.009237771" }, "sarscov2 - [fastq1, fastq2], index, fasta, false, false - bam": { "content": [ @@ -199,15 +339,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T11:13:41.815354" + "timestamp": "2026-02-03T15:17:52.571603438" }, "sarscov2 - [fastq1, fastq2], index, fasta, false, false - stub": { "content": [ @@ -217,15 +377,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T13:06:00.821232" + "timestamp": "2026-02-03T15:18:38.851739544" }, "sarscov2 - fastq, index, fasta, false, false - sam": { "content": [ @@ -248,15 +428,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-25T08:28:26.086145568" + "timestamp": "2026-02-03T15:17:32.669170305" }, "sarscov2 - [fastq1, fastq2], index, fasta, true, false - bam": { "content": [ @@ -273,15 +473,35 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T12:46:05.840695" + "timestamp": "2026-02-03T15:18:19.168328408" }, "sarscov2 - [fastq1, fastq2], index, fasta, false, true - bam": { "content": [ @@ -298,14 +518,34 @@ [ ], - [ - "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" - ] + { + "versions_bowtie2": [ + [ + "BOWTIE2_ALIGN", + "bowtie2", + "2.5.4" + ] + ], + "versions_pigz": [ + [ + "BOWTIE2_ALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "BOWTIE2_ALIGN", + "samtools", + "1.21" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T11:18:52.825034" + "timestamp": "2026-02-03T15:17:59.201650301" } } \ No newline at end of file diff --git a/modules/nf-core/bwa/mem/tests/main.nf.test b/modules/nf-core/bwa/mem/tests/main.nf.test index 5de2c2f4..d7b69b9e 100644 --- a/modules/nf-core/bwa/mem/tests/main.nf.test +++ b/modules/nf-core/bwa/mem/tests/main.nf.test @@ -49,7 +49,6 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -84,7 +83,6 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -120,7 +118,6 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -156,7 +153,6 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -192,7 +188,6 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5() ).match() } diff --git a/modules/nf-core/bwa/mem/tests/main.nf.test.snap b/modules/nf-core/bwa/mem/tests/main.nf.test.snap index 51496a3c..70b7b89b 100644 --- a/modules/nf-core/bwa/mem/tests/main.nf.test.snap +++ b/modules/nf-core/bwa/mem/tests/main.nf.test.snap @@ -13,14 +13,13 @@ [ "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "37b4ee1649480bd1ff98666447f64fa5", "798439cbd7fd81cbcc5078022dc5479d" ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-23T11:05:11.396076472" + "timestamp": "2026-01-26T15:16:52.718077761" }, "Single-End Sort": { "content": [ @@ -36,14 +35,13 @@ [ "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "57106634fcaf3bf503d5487a7717c5d3", "94fcf617f5b994584c4e8d4044e16b4f" ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-23T11:05:19.529514701" + "timestamp": "2026-01-26T15:17:00.554958251" }, "Paired-End": { "content": [ @@ -59,14 +57,13 @@ [ "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "57770ff7c7186ed40c42f3d71c16ce3c", "57aeef88ed701a8ebc8e2f0a381b2a6" ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-23T11:05:27.433790935" + "timestamp": "2026-01-26T15:17:08.162122031" }, "Paired-End Sort": { "content": [ @@ -82,14 +79,13 @@ [ "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "8f5d8f83b485dcfa1f47a73ae645e3a7", "af8628d9df18b2d3d4f6fd47ef2bb872" ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-23T11:05:35.775774487" + "timestamp": "2026-01-26T15:17:15.713464923" }, "Single-end - stub": { "content": [ @@ -182,14 +178,13 @@ [ "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "57770ff7c7186ed40c42f3d71c16ce3c", "57aeef88ed701a8ebc8e2f0a381b2a6" ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-23T11:05:43.764589371" + "timestamp": "2026-01-26T15:17:23.395002931" }, "Paired-end - stub": { "content": [ diff --git a/modules/nf-core/bwamem2/mem/main.nf b/modules/nf-core/bwamem2/mem/main.nf index 830c1710..5ac348f2 100644 --- a/modules/nf-core/bwamem2/mem/main.nf +++ b/modules/nf-core/bwamem2/mem/main.nf @@ -17,7 +17,7 @@ process BWAMEM2_MEM { tuple val(meta), path("*.cram") , emit: cram, optional:true tuple val(meta), path("*.crai") , emit: crai, optional:true tuple val(meta), path("*.csi") , emit: csi , optional:true - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('bwamem2'), eval('bwa-mem2 version | grep -o -E "[0-9]+(\\.[0-9]+)+"'), emit: versions_bwamem2, topic: versions when: task.ext.when == null || task.ext.when @@ -44,12 +44,6 @@ process BWAMEM2_MEM { \$INDEX \\ $reads \\ | samtools $samtools_command $args2 -@ $task.cpus ${reference} -o ${prefix}.${extension} - - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bwamem2: \$(echo \$(bwa-mem2 version 2>&1) | sed 's/.* //') - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -71,11 +65,5 @@ process BWAMEM2_MEM { """ touch ${prefix}.${extension} ${create_index} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bwamem2: \$(echo \$(bwa-mem2 version 2>&1) | sed 's/.* //') - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/bwamem2/mem/meta.yml b/modules/nf-core/bwamem2/mem/meta.yml index 6c7d1728..bcfd006d 100644 --- a/modules/nf-core/bwamem2/mem/meta.yml +++ b/modules/nf-core/bwamem2/mem/meta.yml @@ -16,7 +16,8 @@ tools: homepage: https://github.com/bwa-mem2/bwa-mem2 documentation: http://www.htslib.org/doc/samtools.html arxiv: arXiv:1303.3997 - licence: ["MIT"] + licence: + - "MIT" identifier: "biotools:bwa-mem2" input: - - meta: @@ -30,8 +31,8 @@ input: List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. ontologies: - - edam: "http://edamontology.org/data_2044" # Sequence - - edam: "http://edamontology.org/format_1930" # FASTQ + - edam: "http://edamontology.org/data_2044" + - edam: "http://edamontology.org/format_1930" - - meta2: type: map description: | @@ -42,7 +43,7 @@ input: description: BWA genome index files pattern: "Directory containing BWA index *.{0132,amb,ann,bwt.2bit.64,pac}" ontologies: - - edam: "http://edamontology.org/data_3210" # Genome index + - edam: "http://edamontology.org/data_3210" - - meta3: type: map description: | @@ -53,8 +54,8 @@ input: description: Reference genome in FASTA format pattern: "*.{fa,fasta,fna}" ontologies: - - edam: "http://edamontology.org/data_2044" # Sequence - - edam: "http://edamontology.org/format_1929" # FASTA + - edam: "http://edamontology.org/data_2044" + - edam: "http://edamontology.org/format_1929" - sort_bam: type: boolean description: use samtools sort (true) or samtools view (false) @@ -71,7 +72,7 @@ output: description: Output SAM file containing read alignments pattern: "*.{sam}" ontologies: - - edam: "http://edamontology.org/format_2573" # SAM + - edam: "http://edamontology.org/format_2573" bam: - - meta: type: map @@ -83,7 +84,7 @@ output: description: Output BAM file containing read alignments pattern: "*.{bam}" ontologies: - - edam: "http://edamontology.org/format_2572" # BAM + - edam: "http://edamontology.org/format_2572" cram: - - meta: type: map @@ -95,7 +96,7 @@ output: description: Output CRAM file containing read alignments pattern: "*.{cram}" ontologies: - - edam: "http://edamontology.org/format_3462" # CRAM + - edam: "http://edamontology.org/format_3462" crai: - - meta: type: map @@ -118,13 +119,27 @@ output: description: Index file for BAM file pattern: "*.{csi}" ontologies: [] + versions_bwamem2: + - - ${task.process}: + type: string + description: The name of the process + - bwamem2: + type: string + description: The name of the tool + - bwa-mem2 version | grep -o -E "[0-9]+(\.[0-9]+)+": + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - bwamem2: + type: string + description: The name of the tool + - bwa-mem2 version | grep -o -E "[0-9]+(\.[0-9]+)+": + type: eval + description: The expression to obtain the version of the tool authors: - "@maxulysse" - "@matthdsm" diff --git a/modules/nf-core/bwamem2/mem/tests/main.nf.test b/modules/nf-core/bwamem2/mem/tests/main.nf.test index 9e0ab14a..20e37254 100644 --- a/modules/nf-core/bwamem2/mem/tests/main.nf.test +++ b/modules/nf-core/bwamem2/mem/tests/main.nf.test @@ -46,7 +46,7 @@ nextflow_process { { assert snapshot( bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions")} ).match() } ) } @@ -75,7 +75,7 @@ nextflow_process { { assert snapshot( bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions")} ).match() } ) } @@ -107,7 +107,7 @@ nextflow_process { { assert snapshot( bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions")} ).match() } ) } @@ -139,7 +139,7 @@ nextflow_process { { assert snapshot( bam(process.out.bam[0][1]).getHeaderMD5(), bam(process.out.bam[0][1]).getReadsMD5(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions")} ).match() } ) } diff --git a/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap b/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap index b7d40a68..74763935 100644 --- a/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap +++ b/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap @@ -3,15 +3,21 @@ "content": [ "e414c2d48e2e44c2c52c20ecd88e8bd8", "57aeef88ed701a8ebc8e2f0a381b2a6", - [ - "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" - ] + { + "versions_bwamem2": [ + [ + "BWAMEM2_MEM", + "bwamem2", + "2.2.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-23T11:44:52.73673293" + "timestamp": "2026-02-09T16:25:00.500092" }, "sarscov2 - [fastq1, fastq2], index, fasta, true - stub": { "content": [ @@ -44,7 +50,11 @@ ] ], "5": [ - "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" + [ + "BWAMEM2_MEM", + "bwamem2", + "2.2.1" + ] ], "bam": [ [ @@ -73,57 +83,79 @@ "sam": [ ], - "versions": [ - "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" + "versions_bwamem2": [ + [ + "BWAMEM2_MEM", + "bwamem2", + "2.2.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-23T11:45:14.834888709" + "timestamp": "2026-02-09T16:25:22.004027" }, "sarscov2 - [fastq1, fastq2], index, fasta, true": { "content": [ "716ed1ef39deaad346ca7cf86e08f959", "af8628d9df18b2d3d4f6fd47ef2bb872", - [ - "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" - ] + { + "versions_bwamem2": [ + [ + "BWAMEM2_MEM", + "bwamem2", + "2.2.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-23T11:45:04.750057645" + "timestamp": "2026-02-09T16:25:14.131056" }, "sarscov2 - fastq, index, fasta, false": { "content": [ "283a83f604f3f5338acedfee349dccf4", "798439cbd7fd81cbcc5078022dc5479d", - [ - "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" - ] + { + "versions_bwamem2": [ + [ + "BWAMEM2_MEM", + "bwamem2", + "2.2.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-23T11:44:28.57550711" + "timestamp": "2026-02-09T16:24:34.624533" }, "sarscov2 - fastq, index, fasta, true": { "content": [ "ed99048bb552cac58e39923b550b6d5b", "94fcf617f5b994584c4e8d4044e16b4f", - [ - "versions.yml:md5,3574188ab1f33fd99cff9f5562dfb885" - ] + { + "versions_bwamem2": [ + [ + "BWAMEM2_MEM", + "bwamem2", + "2.2.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-23T11:44:40.437183765" + "timestamp": "2026-02-09T16:24:47.191245" } } \ No newline at end of file diff --git a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff index 3b39944b..dbe123ad 100644 --- a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff +++ b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff @@ -3,24 +3,7 @@ Changes in component 'nf-core/fastq_align_dna' Changes in 'fastq_align_dna/main.nf': --- subworkflows/nf-core/fastq_align_dna/main.nf +++ subworkflows/nf-core/fastq_align_dna/main.nf -@@ -5,68 +5,77 @@ - // - - --include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" --include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' --include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' --include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" --include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' --include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" -+include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" -+include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' -+include { BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' -+include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" -+include { SNAPALIGNER_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' -+include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" - - +@@ -16,55 +16,66 @@ workflow FASTQ_ALIGN_DNA { take: @@ -70,7 +53,6 @@ Changes in 'fastq_align_dna/main.nf': - BOWTIE2_ALIGN(ch_reads, ch_aligner_index, ch_fasta, false, sort) // if aligner is bowtie2 + BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) -- ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions) - } - else if (aligner == 'bwamem'){ - BWAMEM1_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem @@ -87,7 +69,6 @@ Changes in 'fastq_align_dna/main.nf': + + BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) -- ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions) - } - else if (aligner == 'dragmap'){ - DRAGMAP_ALIGN(ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is dragmap @@ -106,13 +87,6 @@ Changes in 'fastq_align_dna/main.nf': - } - else if (aligner == 'strobealign'){ - STROBEALIGN (ch_reads, ch_fasta, ch_aligner_index, sort) // If aligner is strobealign -- ch_bam = ch_bam.mix(STROBEALIGN.out.bam) -- ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) -- ch_versions = ch_versions.mix(STROBEALIGN.out.versions) -- } -- else { -- error "Unknown aligner: ${aligner}" -- } + ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) + + SNAPALIGNER_ALIGN(ch_to_align.snap) // If aligner is snap @@ -121,8 +95,13 @@ Changes in 'fastq_align_dna/main.nf': + ch_versions = ch_versions.mix(SNAPALIGNER_ALIGN.out.versions.first()) + + STROBEALIGN(ch_to_align.strobe, sort) // If aligner is strobealign -+ ch_bam = ch_bam.mix(STROBEALIGN.out.bam) -+ ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) + ch_bam = ch_bam.mix(STROBEALIGN.out.bam) + ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) +- ch_versions = ch_versions.mix(STROBEALIGN.out.versions) +- } +- else { +- error "Unknown aligner: ${aligner}" +- } + ch_versions = ch_versions.mix(STROBEALIGN.out.versions.first()) emit: diff --git a/subworkflows/nf-core/fastq_align_dna/main.nf b/subworkflows/nf-core/fastq_align_dna/main.nf index 95cdf670..37e62d70 100644 --- a/subworkflows/nf-core/fastq_align_dna/main.nf +++ b/subworkflows/nf-core/fastq_align_dna/main.nf @@ -5,12 +5,12 @@ // -include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" -include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' -include { BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' -include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" -include { SNAPALIGNER_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' -include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" +include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" +include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' +include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' +include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" +include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' +include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" @@ -73,8 +73,8 @@ workflow FASTQ_ALIGN_DNA { ch_versions = ch_versions.mix(SNAPALIGNER_ALIGN.out.versions.first()) STROBEALIGN(ch_to_align.strobe, sort) // If aligner is strobealign - ch_bam = ch_bam.mix(STROBEALIGN.out.bam) - ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) + ch_bam = ch_bam.mix(STROBEALIGN.out.bam) + ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) ch_versions = ch_versions.mix(STROBEALIGN.out.versions.first()) emit: diff --git a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap index 9e34d924..60e6bea9 100644 --- a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap +++ b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap @@ -9,14 +9,14 @@ ], [ - "versions.yml:md5,792091aac50160e3fbc865eba482e0c4" + ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-23T11:46:20.36265064" + "timestamp": "2026-02-09T16:57:50.690737" }, "test_fastq_align_dragmap_PE": { "content": [ @@ -113,14 +113,14 @@ ], [ - "versions.yml:md5,792091aac50160e3fbc865eba482e0c4" + ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-23T11:46:07.813351063" + "timestamp": "2026-02-09T16:57:37.848527" }, "test_fastq_align_bwa_mem_PE": { "content": [ @@ -144,13 +144,13 @@ "test_fastq_align_bowtie2_SE": { "content": [ "test.bam", - "versions.yml:md5,ef191e9624d747934f15d368715d87db" + null ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T14:20:30.468391" + "timestamp": "2026-02-03T15:14:58.560970561" }, "test_fastq_align_dragmap_SE": { "content": [ @@ -174,13 +174,13 @@ "test_fastq_align_bowtie2_PE": { "content": [ "test.bam", - "versions.yml:md5,ef191e9624d747934f15d368715d87db" + null ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-03-24T14:25:41.372083" + "timestamp": "2026-02-03T15:15:05.862448716" }, "test_fastq_align_snapaligner_PE": { "content": [ From fca02a203d4bbaf161bbd1afe595a920ec4b6e26 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:05:41 +0100 Subject: [PATCH 162/228] update remaining modules --- modules.json | 12 +- modules/nf-core/fastp/main.nf | 22 +- modules/nf-core/fastp/meta.yml | 29 +- modules/nf-core/fastp/tests/main.nf.test | 18 +- modules/nf-core/fastp/tests/main.nf.test.snap | 326 ++++++++++++------ modules/nf-core/gnu/sort/main.nf | 10 +- modules/nf-core/gnu/sort/meta.yml | 26 +- modules/nf-core/gnu/sort/tests/main.nf.test | 20 +- .../nf-core/gnu/sort/tests/main.nf.test.snap | 110 +++--- modules/nf-core/mosdepth/environment.yml | 3 +- modules/nf-core/mosdepth/main.nf | 25 +- modules/nf-core/mosdepth/meta.yml | 28 +- modules/nf-core/mosdepth/mosdepth.diff | 4 +- modules/nf-core/mosdepth/tests/main.nf.test | 68 ++-- .../nf-core/mosdepth/tests/main.nf.test.snap | 112 ++++-- .../nf-core/mosdepth/tests/nextflow.config | 5 + .../nf-core/mosdepth/tests/quantized.config | 3 - .../nf-core/mosdepth/tests/threshold.config | 3 - modules/nf-core/mosdepth/tests/window.config | 3 - modules/nf-core/samtools/convert/main.nf | 15 +- modules/nf-core/samtools/convert/meta.yml | 31 +- .../samtools/convert/tests/main.nf.test | 87 ++--- .../samtools/convert/tests/main.nf.test.snap | 158 ++++----- modules/nf-core/samtools/coverage/main.nf | 7 +- modules/nf-core/samtools/coverage/meta.yml | 32 +- .../samtools/coverage/tests/main.nf.test.snap | 60 +++- modules/nf-core/samtools/sort/meta.yml | 1 + 27 files changed, 716 insertions(+), 502 deletions(-) create mode 100644 modules/nf-core/mosdepth/tests/nextflow.config delete mode 100644 modules/nf-core/mosdepth/tests/quantized.config delete mode 100644 modules/nf-core/mosdepth/tests/threshold.config delete mode 100644 modules/nf-core/mosdepth/tests/window.config diff --git a/modules.json b/modules.json index 5413652a..4ec35dbd 100644 --- a/modules.json +++ b/modules.json @@ -48,12 +48,12 @@ }, "fastp": { "branch": "master", - "git_sha": "b8f1de0ac853ae5b56c63450d47438f899c553d0", + "git_sha": "a331ecfd1aa48b2b2298aab23bb4516c800e410b", "installed_by": ["modules"] }, "gnu/sort": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "f35fac92470336be03b96bae7547d81d88a3331a", "installed_by": ["modules"] }, "md5sum": { @@ -63,7 +63,7 @@ }, "mosdepth": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "6832b69ef7f98c54876d6436360b6b945370c615", "installed_by": ["modules"], "patch": "modules/nf-core/mosdepth/mosdepth.diff" }, @@ -93,13 +93,13 @@ }, "samtools/convert": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "51fa714751883254ede046c50acf20076b46ca81", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/convert/samtools-convert.diff" }, "samtools/coverage": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "4154ced8a82f5f17b57e48c68dbb03ecb0e9ca14", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, @@ -121,7 +121,7 @@ }, "samtools/sort": { "branch": "master", - "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", + "git_sha": "5cb9a8694da0a0e550921636bb60bc8c56445fd7", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/sort/samtools-sort.diff" }, diff --git a/modules/nf-core/fastp/main.nf b/modules/nf-core/fastp/main.nf index 7538fc3a..e13509ca 100644 --- a/modules/nf-core/fastp/main.nf +++ b/modules/nf-core/fastp/main.nf @@ -20,7 +20,7 @@ process FASTP { tuple val(meta), path('*.log') , emit: log tuple val(meta), path('*.fail.fastq.gz') , optional:true, emit: reads_fail tuple val(meta), path('*.merged.fastq.gz'), optional:true, emit: reads_merged - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('fastp'), eval('fastp --version 2>&1 | sed -e "s/fastp //g"'), emit: versions_fastp, topic: versions when: task.ext.when == null || task.ext.when @@ -49,11 +49,6 @@ process FASTP { $args \\ 2>| >(tee ${prefix}.fastp.log >&2) \\ | gzip -c > ${prefix}.fastp.fastq.gz - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastp: \$(fastp --version 2>&1 | sed -e "s/fastp //g") - END_VERSIONS """ } else if (meta.single_end) { """ @@ -69,11 +64,6 @@ process FASTP { $fail_fastq \\ $args \\ 2>| >(tee ${prefix}.fastp.log >&2) - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastp: \$(fastp --version 2>&1 | sed -e "s/fastp //g") - END_VERSIONS """ } else { def merge_fastq = save_merged ? "-m --merged_out ${prefix}.merged.fastq.gz" : '' @@ -94,11 +84,6 @@ process FASTP { --detect_adapter_for_pe \\ $args \\ 2>| >(tee ${prefix}.fastp.log >&2) - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastp: \$(fastp --version 2>&1 | sed -e "s/fastp //g") - END_VERSIONS """ } @@ -115,10 +100,5 @@ process FASTP { touch "${prefix}.fastp.json" touch "${prefix}.fastp.html" touch "${prefix}.fastp.log" - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastp: \$(fastp --version 2>&1 | sed -e "s/fastp //g") - END_VERSIONS """ } diff --git a/modules/nf-core/fastp/meta.yml b/modules/nf-core/fastp/meta.yml index 324025fe..a67be395 100644 --- a/modules/nf-core/fastp/meta.yml +++ b/modules/nf-core/fastp/meta.yml @@ -54,6 +54,7 @@ output: description: The trimmed/modified/unmerged fastq reads pattern: "*fastp.fastq.gz" ontologies: + - edam: http://edamontology.org/format_1930 # FASTQ - edam: http://edamontology.org/format_3989 # GZIP format json: - - meta: @@ -100,6 +101,7 @@ output: description: Reads the failed the preprocessing pattern: "*fail.fastq.gz" ontologies: + - edam: http://edamontology.org/format_1930 # FASTQ - edam: http://edamontology.org/format_3989 # GZIP format reads_merged: - - meta: @@ -112,16 +114,31 @@ output: description: Reads that were successfully merged pattern: "*.{merged.fastq.gz}" ontologies: [] + versions_fastp: + - - "${task.process}": + type: string + description: The name of the process + - fastp: + type: string + description: The name of the tool + - 'fastp --version 2>&1 | sed -e "s/fastp //g"': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - "${task.process}": + type: string + description: The name of the process + - fastp: + type: string + description: The name of the tool + - 'fastp --version 2>&1 | sed -e "s/fastp //g"': + type: eval + description: The expression to obtain the version of the tool authors: - "@drpatelh" - "@kevinmenden" + - "@eit-maxlcummins" maintainers: - "@drpatelh" - "@kevinmenden" diff --git a/modules/nf-core/fastp/tests/main.nf.test b/modules/nf-core/fastp/tests/main.nf.test index 5125705c..b7901578 100644 --- a/modules/nf-core/fastp/tests/main.nf.test +++ b/modules/nf-core/fastp/tests/main.nf.test @@ -39,7 +39,7 @@ nextflow_process { process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.versions).match() + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } @@ -80,7 +80,7 @@ nextflow_process { process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.versions).match() } + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } } @@ -117,7 +117,7 @@ nextflow_process { { assert process.out.reads_merged == [] }, { assert snapshot( process.out.reads, - process.out.versions).match() } + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } } @@ -154,7 +154,7 @@ nextflow_process { process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.versions).match() } + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } } @@ -194,7 +194,7 @@ nextflow_process { process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.versions).match() } + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } } @@ -233,7 +233,7 @@ nextflow_process { process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.versions).match() }, + process.out.findAll { key, val -> key.startsWith('versions') }).match() }, ) } } @@ -272,7 +272,7 @@ nextflow_process { process.out.reads, process.out.reads_fail, process.out.reads_merged, - process.out.versions).match() } + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } } @@ -312,7 +312,7 @@ nextflow_process { process.out.reads_fail, process.out.reads_merged, process.out.reads_merged, - process.out.versions).match() } + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } } @@ -354,7 +354,7 @@ nextflow_process { process.out.reads_fail, process.out.reads_merged, process.out.reads_merged, - process.out.versions).match() } + process.out.findAll { key, val -> key.startsWith('versions') }).match() } ) } } diff --git a/modules/nf-core/fastp/tests/main.nf.test.snap b/modules/nf-core/fastp/tests/main.nf.test.snap index 2276fc08..56772358 100644 --- a/modules/nf-core/fastp/tests/main.nf.test.snap +++ b/modules/nf-core/fastp/tests/main.nf.test.snap @@ -39,7 +39,11 @@ ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -77,16 +81,20 @@ "reads_merged": [ ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-11T09:55:42.073182" + "timestamp": "2026-01-22T13:00:52.14535813" }, "test_fastp_paired_end": { "content": [ @@ -108,15 +116,21 @@ [ ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:32:22.887952042" + "timestamp": "2026-01-23T09:46:26.421773402" }, "test_fastp_paired_end_merged_adapterlist": { "content": [ @@ -144,15 +158,21 @@ "test.merged.fastq.gz:md5,c873bb1ab3fa859dcc47306465e749d5" ] ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:32:53.752975682" + "timestamp": "2026-01-23T09:46:59.832295907" }, "test_fastp_single_end_qc_only": { "content": [ @@ -174,15 +194,21 @@ [ ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-19T16:23:36.149003" + "timestamp": "2026-01-23T09:47:06.486959565" }, "test_fastp_paired_end_trim_fail": { "content": [ @@ -214,15 +240,21 @@ [ ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:32:41.270456637" + "timestamp": "2026-01-23T09:46:46.736511024" }, "fastp - stub test_fastp_interleaved": { "content": [ @@ -270,7 +302,11 @@ ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -314,16 +350,20 @@ "reads_merged": [ ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-11T09:55:19.47199" + "timestamp": "2026-01-22T13:00:16.097071654" }, "test_fastp_single_end - stub": { "content": [ @@ -371,7 +411,11 @@ ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -415,16 +459,20 @@ "reads_merged": [ ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-11T09:55:09.617001" + "timestamp": "2026-01-22T13:00:03.317192706" }, "test_fastp_paired_end_merged_adapterlist - stub": { "content": [ @@ -481,7 +529,11 @@ ] ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -534,16 +586,20 @@ "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:33:44.204950729" + "timestamp": "2026-01-22T13:00:44.851708205" }, "test_fastp_paired_end_merged - stub": { "content": [ @@ -600,7 +656,11 @@ ] ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -653,16 +713,20 @@ "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:33:38.518882433" + "timestamp": "2026-01-22T13:00:37.581047713" }, "test_fastp_paired_end_merged": { "content": [ @@ -690,15 +754,21 @@ "test.merged.fastq.gz:md5,c873bb1ab3fa859dcc47306465e749d5" ] ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:32:47.366974895" + "timestamp": "2026-01-23T09:46:53.190202914" }, "test_fastp_paired_end - stub": { "content": [ @@ -749,7 +819,11 @@ ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -796,16 +870,20 @@ "reads_merged": [ ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:33:16.494574544" + "timestamp": "2026-01-22T13:00:09.585957282" }, "test_fastp_single_end": { "content": [ @@ -824,15 +902,21 @@ [ ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-19T16:23:08.469846" + "timestamp": "2026-01-23T09:46:19.624824985" }, "test_fastp_single_end_trim_fail - stub": { "content": [ @@ -886,7 +970,11 @@ ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -936,16 +1024,20 @@ "reads_merged": [ ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-11T09:55:23.871395" + "timestamp": "2026-01-22T13:00:22.800659826" }, "test_fastp_paired_end_trim_fail - stub": { "content": [ @@ -1006,7 +1098,11 @@ ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -1063,16 +1159,20 @@ "reads_merged": [ ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.04.8" + "nextflow": "25.10.2" }, - "timestamp": "2025-12-22T14:33:32.863505882" + "timestamp": "2026-01-22T13:00:30.271734068" }, "fastp test_fastp_interleaved": { "content": [ @@ -1085,15 +1185,21 @@ "test.fastp.fastq.gz:md5,217d62dc13a23e92513a1bd8e1bcea39" ] ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-19T16:23:16.479494" + "timestamp": "2026-01-23T09:46:33.4628687" }, "test_fastp_single_end_trim_fail": { "content": [ @@ -1118,15 +1224,21 @@ [ ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-19T16:23:20.299076" + "timestamp": "2026-01-23T09:46:39.895973372" }, "test_fastp_paired_end_qc_only": { "content": [ @@ -1148,15 +1260,21 @@ [ ], - [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" - ] + { + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-19T16:23:40.113724" + "timestamp": "2026-01-23T09:47:13.015833707" }, "test_fastp_paired_end_qc_only - stub": { "content": [ @@ -1198,7 +1316,11 @@ ], "6": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + [ + "FASTP", + "fastp", + "1.0.1" + ] ], "html": [ [ @@ -1236,15 +1358,19 @@ "reads_merged": [ ], - "versions": [ - "versions.yml:md5,c4974822658d02533e660fae343f281b" + "versions_fastp": [ + [ + "FASTP", + "fastp", + "1.0.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-11T09:55:46.696419" + "timestamp": "2026-01-22T13:00:59.670106791" } } \ No newline at end of file diff --git a/modules/nf-core/gnu/sort/main.nf b/modules/nf-core/gnu/sort/main.nf index 6190210d..a16f6291 100644 --- a/modules/nf-core/gnu/sort/main.nf +++ b/modules/nf-core/gnu/sort/main.nf @@ -12,7 +12,7 @@ process GNU_SORT { output: tuple val(meta), path( "${output_file}" ) , emit: sorted - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('coreutils'), eval("sort --version |& sed '1!d ; s/sort (GNU coreutils) //'"), emit: versions_coreutils, topic: versions when: task.ext.when == null || task.ext.when @@ -26,10 +26,6 @@ process GNU_SORT { """ sort ${args} ${input} > ${output_file} - cat <<-END_VERSIONS > versions.yml - "${task.process}": - coreutils: \$(sort --version |& sed '1!d ; s/sort (GNU coreutils) //') - END_VERSIONS """ stub: @@ -40,9 +36,5 @@ process GNU_SORT { """ touch ${output_file} - cat <<-END_VERSIONS > versions.yml - "${task.process}": - coreutils: \$(sort --version |& sed '1!d ; s/sort (GNU coreutils) //') - END_VERSIONS """ } diff --git a/modules/nf-core/gnu/sort/meta.yml b/modules/nf-core/gnu/sort/meta.yml index feba2c1f..48dde4a0 100644 --- a/modules/nf-core/gnu/sort/meta.yml +++ b/modules/nf-core/gnu/sort/meta.yml @@ -42,13 +42,27 @@ output: Groovy Map containing sample information e.g. [ id:'test', single_end:false ] pattern: "${output_file}" + versions_coreutils: + - - ${task.process}: + type: string + description: The process the versions were collected from + - coreutils: + type: string + description: The tool name + - "sort --version |& sed '1!d ; s/sort (GNU coreutils) //'": + type: string + description: The command used to generate the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The process the versions were collected from + - coreutils: + type: string + description: The tool name + - "sort --version |& sed '1!d ; s/sort (GNU coreutils) //'": + type: string + description: The command used to generate the version of the tool authors: - "@DLBPointon" maintainers: diff --git a/modules/nf-core/gnu/sort/tests/main.nf.test b/modules/nf-core/gnu/sort/tests/main.nf.test index e4030187..dbe473d2 100644 --- a/modules/nf-core/gnu/sort/tests/main.nf.test +++ b/modules/nf-core/gnu/sort/tests/main.nf.test @@ -27,11 +27,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, - { assert snapshot( - file(process.out.sorted[0][1]).name - ).match("genome_sort") - } + { assert snapshot(process.out).match() } ) } @@ -54,11 +50,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, - { assert snapshot( - file(process.out.sorted[0][1]).name - ).match("interval_sort") - } + { assert snapshot(process.out).match() } ) } @@ -82,11 +74,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, - { assert snapshot( - file(process.out.sorted[0][1]).name - ).match("csv_sort") - } + { assert snapshot(process.out).match() } ) } @@ -111,7 +99,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() }, + { assert snapshot(process.out).match() } ) } diff --git a/modules/nf-core/gnu/sort/tests/main.nf.test.snap b/modules/nf-core/gnu/sort/tests/main.nf.test.snap index 20e17080..f57dc6bb 100644 --- a/modules/nf-core/gnu/sort/tests/main.nf.test.snap +++ b/modules/nf-core/gnu/sort/tests/main.nf.test.snap @@ -11,7 +11,11 @@ ] ], "1": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ], "sorted": [ [ @@ -21,26 +25,20 @@ "test.csv.sorted:md5,0b52d1b4c4a0c6e972c6f94aafd75a1d" ] ], - "versions": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + "versions_coreutils": [ + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" - }, - "timestamp": "2025-04-30T14:27:50.564838" - }, - "interval_sort": { - "content": [ - "test.bed.sorted" - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-04-30T14:27:34.740893" + "timestamp": "2026-01-23T15:48:28.77537237" }, "unsorted_csv_sort_stub": { "content": [ @@ -54,7 +52,11 @@ ] ], "1": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ], "sorted": [ [ @@ -64,26 +66,20 @@ "test.csv.sorted:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + "versions_coreutils": [ + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-04-30T14:28:06.468116" - }, - "csv_sort": { - "content": [ - "test.csv.sorted" - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" - }, - "timestamp": "2025-04-30T14:27:50.596931" + "timestamp": "2026-01-23T15:48:45.534463019" }, "unsorted_genome_sort": { "content": [ @@ -97,7 +93,11 @@ ] ], "1": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ], "sorted": [ [ @@ -107,26 +107,20 @@ "genome_test.bed.sorted:md5,fd97f7efafdbbfa71d9b560f10b4b048" ] ], - "versions": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + "versions_coreutils": [ + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-04-30T14:27:19.192354" - }, - "genome_sort": { - "content": [ - "genome_test.bed.sorted" - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" - }, - "timestamp": "2025-04-30T14:27:19.234221" + "timestamp": "2026-01-23T15:47:54.290932481" }, "unsorted_intervals_sort": { "content": [ @@ -140,7 +134,11 @@ ] ], "1": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ], "sorted": [ [ @@ -150,15 +148,19 @@ "test.bed.sorted:md5,abbce903ef263d38b2f71856387799ab" ] ], - "versions": [ - "versions.yml:md5,0d7afd9c97fa2ed3cc6273a6158fb1c8" + "versions_coreutils": [ + [ + "GNU_SORT", + "coreutils", + "9.5" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.4" + "nf-test": "0.9.3", + "nextflow": "25.04.8" }, - "timestamp": "2025-04-30T14:27:34.711885" + "timestamp": "2026-01-23T15:48:11.626509684" } } \ No newline at end of file diff --git a/modules/nf-core/mosdepth/environment.yml b/modules/nf-core/mosdepth/environment.yml index 97c93721..1c7f3ee8 100644 --- a/modules/nf-core/mosdepth/environment.yml +++ b/modules/nf-core/mosdepth/environment.yml @@ -5,6 +5,5 @@ channels: - bioconda dependencies: # renovate: datasource=conda depName=bioconda/mosdepth - - mosdepth=0.3.11=h0ec343a_1 - # renovate: datasource=conda depName=bioconda/htslib - htslib=1.22.1 + - mosdepth=0.3.11=h0ec343a_1 diff --git a/modules/nf-core/mosdepth/main.nf b/modules/nf-core/mosdepth/main.nf index 8166ac0b..b5ee3823 100644 --- a/modules/nf-core/mosdepth/main.nf +++ b/modules/nf-core/mosdepth/main.nf @@ -23,7 +23,7 @@ process MOSDEPTH { tuple val(meta), path('*.quantized.bed.gz.csi') , optional:true, emit: quantized_csi tuple val(meta), path('*.thresholds.bed.gz') , optional:true, emit: thresholds_bed tuple val(meta), path('*.thresholds.bed.gz.csi'), optional:true, emit: thresholds_csi - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('mosdepth'), eval("mosdepth --version | sed 's/mosdepth //g'"), topic: versions, emit: versions_mosdepth when: task.ext.when == null || task.ext.when @@ -33,11 +33,11 @@ process MOSDEPTH { def prefix = task.ext.prefix ?: "${meta.id}" def reference = fasta ? "--fasta ${fasta}" : "" def interval = bed ? "--by ${bed}" : "" - if (bed && args.contains("--by")) { + if (bed && (args.contains("--by") || args.contains("-b "))) { error "'--by' can only be specified once when running mosdepth! Either remove input BED file definition or remove '--by' from 'ext.args' definition" } - if (!bed && args.contains("--thresholds")) { - error "'--thresholds' can only be specified in conjunction with '--by'" + if (args.contains("--thresholds") && !(bed || args.contains("--by") || args.contains("-b "))) { + error "'--thresholds' can only be specified in conjunction with '--by' or an input bed file" } """ @@ -48,15 +48,17 @@ process MOSDEPTH { $args \\ $prefix \\ $bam - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - mosdepth: \$(mosdepth --version 2>&1 | sed 's/^.*mosdepth //; s/ .*\$//') - END_VERSIONS """ stub: + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" + if (bed && (args.contains("--by") || args.contains("-b "))) { + error "'--by' can only be specified once when running mosdepth! Either remove input BED file definition or remove '--by' from 'ext.args' definition" + } + if (args.contains("--thresholds") && !(bed || args.contains("--by") || args.contains("-b "))) { + error "'--thresholds' can only be specified in conjunction with '--by' or an input bed file" + } """ touch ${prefix}.global.dist.txt touch ${prefix}.region.dist.txt @@ -70,10 +72,5 @@ process MOSDEPTH { touch ${prefix}.quantized.bed.gz.csi echo "" | gzip > ${prefix}.thresholds.bed.gz touch ${prefix}.thresholds.bed.gz.csi - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - mosdepth: \$(mosdepth --version 2>&1 | sed 's/^.*mosdepth //; s/ .*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/mosdepth/meta.yml b/modules/nf-core/mosdepth/meta.yml index af1ea44a..04c8bfe1 100644 --- a/modules/nf-core/mosdepth/meta.yml +++ b/modules/nf-core/mosdepth/meta.yml @@ -178,13 +178,28 @@ output: description: Index file for BED file with threshold coverage pattern: "*.{thresholds.bed.gz.csi}" ontologies: [] + versions_mosdepth: + - - ${task.process}: + type: string + description: The process the versions were collected from + - mosdepth: + type: string + description: The tool name + - "mosdepth --version | sed 's/mosdepth //g'": + type: string + description: The command used to generate the version of the tool + +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The process the versions were collected from + - mosdepth: + type: string + description: The tool name + - "mosdepth --version | sed 's/mosdepth //g'": + type: string + description: The command used to generate the version of the tool authors: - "@joseespinosa" - "@drpatelh" @@ -192,6 +207,5 @@ authors: - "@matthdsm" maintainers: - "@joseespinosa" - - "@drpatelh" - "@ramprasadn" - "@matthdsm" diff --git a/modules/nf-core/mosdepth/mosdepth.diff b/modules/nf-core/mosdepth/mosdepth.diff index 59a3adf0..ba8f8c40 100644 --- a/modules/nf-core/mosdepth/mosdepth.diff +++ b/modules/nf-core/mosdepth/mosdepth.diff @@ -16,8 +16,6 @@ Changes in 'mosdepth/main.nf': tuple val(meta), path('*.global.dist.txt') , emit: global_txt 'modules/nf-core/mosdepth/tests/main.nf.test.snap' is unchanged -'modules/nf-core/mosdepth/tests/threshold.config' is unchanged -'modules/nf-core/mosdepth/tests/quantized.config' is unchanged +'modules/nf-core/mosdepth/tests/nextflow.config' is unchanged 'modules/nf-core/mosdepth/tests/main.nf.test' is unchanged -'modules/nf-core/mosdepth/tests/window.config' is unchanged ************************************************************ diff --git a/modules/nf-core/mosdepth/tests/main.nf.test b/modules/nf-core/mosdepth/tests/main.nf.test index 0b3c860d..b05dde5b 100644 --- a/modules/nf-core/mosdepth/tests/main.nf.test +++ b/modules/nf-core/mosdepth/tests/main.nf.test @@ -7,10 +7,14 @@ nextflow_process { tag "modules" tag "modules_nfcore" tag "mosdepth" + config "./nextflow.config" test("homo_sapiens - bam, bai, []") { when { + params { + module_args = "" + } process { """ input[0] = [ @@ -25,9 +29,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } @@ -36,6 +40,9 @@ nextflow_process { test("homo_sapiens - bam, bai, bed") { when { + params { + module_args = "" + } process { """ input[0] = [ @@ -50,9 +57,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } @@ -61,6 +68,9 @@ nextflow_process { test("homo_sapiens - cram, crai, []") { when { + params { + module_args = "" + } process { """ input[0] = [ @@ -78,9 +88,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } @@ -89,6 +99,9 @@ nextflow_process { test("homo_sapiens - cram, crai, bed") { when { + params { + module_args = "" + } process { """ input[0] = [ @@ -106,9 +119,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } @@ -116,8 +129,10 @@ nextflow_process { test("homo_sapiens - bam, bai, [] - window") { - config "./window.config" when { + params { + module_args = "--by 100" + } process { """ input[0] = [ @@ -132,9 +147,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } @@ -142,8 +157,10 @@ nextflow_process { test("homo_sapiens - bam, bai, [] - quantized") { - config "./quantized.config" when { + params { + module_args = "--quantize 0:1:4:100:200" + } process { """ input[0] = [ @@ -158,9 +175,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } @@ -168,8 +185,10 @@ nextflow_process { test("homo_sapiens - bam, bai, bed - thresholds") { - config "./threshold.config" when { + params { + module_args = "--thresholds 1,10,20,30" + } process { """ input[0] = [ @@ -184,9 +203,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } @@ -194,8 +213,10 @@ nextflow_process { test("homo_sapiens - bam, bai, bed - fail") { - config "./window.config" when { + params { + module_args = "--by 100" + } process { """ input[0] = [ @@ -210,9 +231,7 @@ nextflow_process { } then { - assertAll( - { assert process.failed } - ) + assert process.failed } } @@ -221,6 +240,9 @@ nextflow_process { options "-stub" when { + params { + module_args = "" + } process { """ input[0] = [ @@ -235,9 +257,9 @@ nextflow_process { } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(process.out).match()} ) } diff --git a/modules/nf-core/mosdepth/tests/main.nf.test.snap b/modules/nf-core/mosdepth/tests/main.nf.test.snap index a063dd9f..c27fcc79 100644 --- a/modules/nf-core/mosdepth/tests/main.nf.test.snap +++ b/modules/nf-core/mosdepth/tests/main.nf.test.snap @@ -39,7 +39,11 @@ ] ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ [ @@ -221,8 +225,12 @@ "test.thresholds.bed.gz.csi:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], @@ -260,7 +268,11 @@ ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ [ @@ -394,8 +406,12 @@ "thresholds_csi": [ ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], @@ -433,7 +449,11 @@ ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ @@ -555,8 +575,12 @@ "thresholds_csi": [ ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], @@ -594,7 +618,11 @@ ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ [ @@ -728,8 +756,12 @@ "thresholds_csi": [ ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], @@ -767,7 +799,11 @@ ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ [ @@ -901,8 +937,12 @@ "thresholds_csi": [ ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], @@ -940,7 +980,11 @@ ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ @@ -1038,8 +1082,12 @@ "thresholds_csi": [ ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], @@ -1077,7 +1125,11 @@ ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ @@ -1175,8 +1227,12 @@ "thresholds_csi": [ ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], @@ -1226,7 +1282,11 @@ ] ], "12": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ], "2": [ [ @@ -1372,8 +1432,12 @@ "test.thresholds.bed.gz.csi:md5,2c52ab89e7496af475de3cb2ca04c7b3" ] ], - "versions": [ - "versions.yml:md5,74f14bf8082836f8dc941b8c77c176fb" + "versions_mosdepth": [ + [ + "MOSDEPTH", + "mosdepth", + "0.3.11" + ] ] } ], diff --git a/modules/nf-core/mosdepth/tests/nextflow.config b/modules/nf-core/mosdepth/tests/nextflow.config new file mode 100644 index 00000000..b21c05b5 --- /dev/null +++ b/modules/nf-core/mosdepth/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: "MOSDEPTH" { + ext.args = params.module_args + } +} diff --git a/modules/nf-core/mosdepth/tests/quantized.config b/modules/nf-core/mosdepth/tests/quantized.config deleted file mode 100644 index c208a4ce..00000000 --- a/modules/nf-core/mosdepth/tests/quantized.config +++ /dev/null @@ -1,3 +0,0 @@ -process { - ext.args = "--quantize 0:1:4:100:200" -} diff --git a/modules/nf-core/mosdepth/tests/threshold.config b/modules/nf-core/mosdepth/tests/threshold.config deleted file mode 100644 index 3302da60..00000000 --- a/modules/nf-core/mosdepth/tests/threshold.config +++ /dev/null @@ -1,3 +0,0 @@ -process { - ext.args = "--thresholds 1,10,20,30" -} diff --git a/modules/nf-core/mosdepth/tests/window.config b/modules/nf-core/mosdepth/tests/window.config deleted file mode 100644 index 7f0d08d6..00000000 --- a/modules/nf-core/mosdepth/tests/window.config +++ /dev/null @@ -1,3 +0,0 @@ -process { - ext.args = "--by 100" -} diff --git a/modules/nf-core/samtools/convert/main.nf b/modules/nf-core/samtools/convert/main.nf index f4003d42..f302b319 100644 --- a/modules/nf-core/samtools/convert/main.nf +++ b/modules/nf-core/samtools/convert/main.nf @@ -8,14 +8,15 @@ process SAMTOOLS_CONVERT { 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(index), path(fasta), path(fai) + tuple val(meta), path(input), path(index) + tuple val(meta2), path(fasta), path(fai) output: tuple val(meta), path("*.bam") , emit: bam , optional: true tuple val(meta), path("*.cram") , emit: cram, optional: true tuple val(meta), path("*.bai") , emit: bai , optional: true tuple val(meta), path("*.crai") , emit: crai, optional: true - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), topic: versions, emit: versions_samtools when: task.ext.when == null || task.ext.when @@ -34,11 +35,6 @@ process SAMTOOLS_CONVERT { -o ${prefix}.${output_extension} samtools index -@${task.cpus} ${prefix}.${output_extension} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -49,10 +45,5 @@ process SAMTOOLS_CONVERT { """ touch ${prefix}.${output_extension} touch ${prefix}.${output_extension}.${index_extension} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/samtools/convert/meta.yml b/modules/nf-core/samtools/convert/meta.yml index 519812ab..286f812f 100644 --- a/modules/nf-core/samtools/convert/meta.yml +++ b/modules/nf-core/samtools/convert/meta.yml @@ -42,11 +42,6 @@ input: description: Reference file to create the CRAM file pattern: "*.{fasta,fa}" ontologies: [] - - - meta3: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - fai: type: file description: Reference index file to create the CRAM file @@ -97,13 +92,27 @@ output: description: filtered/converted CRAM index pattern: "*{.crai}" ontologies: [] + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool authors: - "@FriederikeHanssen" - "@maxulysse" diff --git a/modules/nf-core/samtools/convert/tests/main.nf.test b/modules/nf-core/samtools/convert/tests/main.nf.test index cd603c53..638caabe 100644 --- a/modules/nf-core/samtools/convert/tests/main.nf.test +++ b/modules/nf-core/samtools/convert/tests/main.nf.test @@ -9,99 +9,88 @@ nextflow_process { tag "samtools" tag "samtools/convert" - test("sarscov2 - [bam, bai], fasta, fai") { + test("sarscov2 - [bam, bai], [fasta, fai]") { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + input[0] = [ + [id: 'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[2] = Channel.of([ - [ id:'fai' ], // meta map + ] + input[1] = [ + [ id:'fasta' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) - ]) + ] """ } } then { - assertAll( - { assert process.success }, - { assert snapshot(file(process.out.cram[0][1]).name).match("bam_to_cram_alignment") }, - { assert snapshot(file(process.out.crai[0][1]).name).match("bam_to_cram_index") }, - { assert snapshot(process.out.versions).match("bam_to_cram_versions") } - ) + assert process.success + assert snapshot( + process.out.cram.collect{ meta, cram_file -> [ meta, file(cram_file).name] }, + process.out.crai.collect{ meta, crai_file -> [ meta, file(crai_file).name] }, + ["versions_samtools": process.out.versions_samtools] + ).match() } } - test("homo_sapiens - [cram, crai], fasta, fai") { + test("homo_sapiens - [cram, crai], [fasta, fai]") { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + 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] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) - ]) - input[2] = Channel.of([ - [ id:'fai' ], // meta map + ] + input[1] = [ + [ id:'fasta' ], + 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) - ]) + ] """ } } then { - assertAll( - { assert process.success }, - { assert snapshot(file(process.out.bam[0][1]).name).match("cram_to_bam_alignment") }, - { assert snapshot(file(process.out.bai[0][1]).name).match("cram_to_bam_alignment_index") }, - { assert snapshot(process.out.versions).match("cram_to_bam_versions") } - ) + assert process.success + assert snapshot( + process.out.bam.collect{ meta, bam_file -> [ meta, file(bam_file).name, bam(bam_file).getReadsMD5()] }, + process.out.bai.collect{ meta, bai_file -> [ meta, file(bai_file).name] }, + ["versions_samtools": process.out.versions_samtools] + ).match() } } - test("sarscov2 - [bam, bai], fasta, fai - stub") { + test("sarscov2 - [bam, bai], [fasta, fai] - stub") { options "-stub" when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + input[0] = [ + [id: 'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[2] = Channel.of([ - [ id:'fai' ], // meta map + ] + input[1] = [ + [ id:'fasta' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) - ]) + ] """ } } then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match("stub") } - ) + assert process.success + assert snapshot(sanitizeOutput(process.out)).match() } } } diff --git a/modules/nf-core/samtools/convert/tests/main.nf.test.snap b/modules/nf-core/samtools/convert/tests/main.nf.test.snap index a9ef27e0..57e7ccb3 100644 --- a/modules/nf-core/samtools/convert/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/convert/tests/main.nf.test.snap @@ -1,78 +1,76 @@ { - "cram_to_bam_alignment": { - "content": [ - "test.bam" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-06T11:14:51.300147176" - }, - "bam_to_cram_alignment": { - "content": [ - "test.cram" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-06T11:14:36.625470184" - }, - "cram_to_bam_versions": { + "sarscov2 - [bam, bai], [fasta, fai]": { "content": [ [ - "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" - ] + [ + { + "id": "test" + }, + "test.cram" + ] + ], + [ + [ + { + "id": "test" + }, + "test.cram.crai" + ] + ], + { + "versions_samtools": [ + [ + "SAMTOOLS_CONVERT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-10T13:05:31.58641" + "timestamp": "2026-02-05T11:02:26.691358025" }, - "bam_to_cram_versions": { + "homo_sapiens - [cram, crai], [fasta, fai]": { "content": [ [ - "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" - ] + [ + { + "id": "test" + }, + "test.bam", + "2f11e4fe3390b8ad0a1852616fd1da04" + ] + ], + [ + [ + { + "id": "test" + }, + "test.bam.bai" + ] + ], + { + "versions_samtools": [ + [ + "SAMTOOLS_CONVERT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-10T13:05:26.933516" + "timestamp": "2026-02-05T11:24:13.012572069" }, - "stub": { + "sarscov2 - [bam, bai], [fasta, fai] - stub": { "content": [ { - "0": [ - - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.cram:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "test.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" - ], "bai": [ ], @@ -82,8 +80,7 @@ "crai": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" ] @@ -91,41 +88,24 @@ "cram": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.cram:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,13f74b35a5030e75c1e819b2cf602db8" + "versions_samtools": [ + [ + "SAMTOOLS_CONVERT", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T13:05:36.333776" - }, - "bam_to_cram_index": { - "content": [ - "test.cram.crai" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-06T11:14:36.640009334" - }, - "cram_to_bam_alignment_index": { - "content": [ - "test.bam.bai" - ], - "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2024-03-06T11:14:51.304477426" + "timestamp": "2026-02-05T11:24:19.471055529" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/coverage/main.nf b/modules/nf-core/samtools/coverage/main.nf index e2adfddd..25754d35 100644 --- a/modules/nf-core/samtools/coverage/main.nf +++ b/modules/nf-core/samtools/coverage/main.nf @@ -12,7 +12,7 @@ process SAMTOOLS_COVERAGE { output: tuple val(meta), path("*.txt"), emit: coverage - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), topic: versions, emit: versions_samtools when: task.ext.when == null || task.ext.when @@ -32,11 +32,6 @@ process SAMTOOLS_COVERAGE { -o ${prefix}.txt \\ $reference \\ $input - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//' ) - END_VERSIONS """ stub: diff --git a/modules/nf-core/samtools/coverage/meta.yml b/modules/nf-core/samtools/coverage/meta.yml index 28dceb03..754f5f49 100644 --- a/modules/nf-core/samtools/coverage/meta.yml +++ b/modules/nf-core/samtools/coverage/meta.yml @@ -60,17 +60,33 @@ output: e.g. [ id:'test', single_end:false ] - "*.txt": type: file - description: Tabulated text containing the coverage at each position or region - or an ASCII-art histogram (with --histogram). + description: Tabulated text containing the coverage at each position or + region or an ASCII-art histogram (with --histogram). pattern: "*.txt" ontologies: [] + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool + +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool + authors: - "@LouisLeNezet" maintainers: diff --git a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap index 68cc3697..2069c8c1 100644 --- a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap @@ -12,7 +12,11 @@ ] ], "1": [ - "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" + [ + "SAMTOOLS_COVERAGE", + "samtools", + "1.22.1" + ] ], "coverage": [ [ @@ -23,16 +27,20 @@ "test.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" + "versions_samtools": [ + [ + "SAMTOOLS_COVERAGE", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T13:06:14.846123" + "timestamp": "2026-01-22T10:43:34.392105918" }, "test_samtools_coverage_bam": { "content": [ @@ -47,7 +55,11 @@ ] ], "1": [ - "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" + [ + "SAMTOOLS_COVERAGE", + "samtools", + "1.22.1" + ] ], "coverage": [ [ @@ -58,16 +70,20 @@ "test.txt:md5,99a521b3bf53b6acf8055a44a571ea84" ] ], - "versions": [ - "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" + "versions_samtools": [ + [ + "SAMTOOLS_COVERAGE", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T13:06:06.18797" + "timestamp": "2026-01-22T10:43:08.216921812" }, "test_samtools_coverage_cram": { "content": [ @@ -82,7 +98,11 @@ ] ], "1": [ - "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" + [ + "SAMTOOLS_COVERAGE", + "samtools", + "1.22.1" + ] ], "coverage": [ [ @@ -93,15 +113,19 @@ "test.txt:md5,ce896534bac51cfcc97e5508ae907e99" ] ], - "versions": [ - "versions.yml:md5,a457b33609ed582818fbe3bc2a20008a" + "versions_samtools": [ + [ + "SAMTOOLS_COVERAGE", + "samtools", + "1.22.1" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-10-02T11:22:34.018328" + "timestamp": "2026-01-22T10:43:15.389524183" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/sort/meta.yml b/modules/nf-core/samtools/sort/meta.yml index 809a57fc..69968304 100644 --- a/modules/nf-core/samtools/sort/meta.yml +++ b/modules/nf-core/samtools/sort/meta.yml @@ -131,6 +131,7 @@ topics: - "samtools version | sed '1!d;s/.* //'": type: string description: The command used to generate the version of the tool + authors: - "@drpatelh" - "@ewels" From 38dd555289e56357a4efcd85465431380cb9f54d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:26:44 +0100 Subject: [PATCH 163/228] topic conversion work --- modules/nf-core/samtools/convert/main.nf | 3 +- subworkflows/local/fastq_align_rna/main.nf | 13 +- .../local/fastq_to_aligned_cram/main.nf | 10 -- .../fastq_align_dna/fastq_align_dna.diff | 145 +++++++++++------- subworkflows/nf-core/fastq_align_dna/main.nf | 126 ++++++++------- workflows/preprocessing.nf | 3 - 6 files changed, 149 insertions(+), 151 deletions(-) diff --git a/modules/nf-core/samtools/convert/main.nf b/modules/nf-core/samtools/convert/main.nf index f302b319..c3ee32ac 100644 --- a/modules/nf-core/samtools/convert/main.nf +++ b/modules/nf-core/samtools/convert/main.nf @@ -8,8 +8,7 @@ process SAMTOOLS_CONVERT { 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(index) - tuple val(meta2), path(fasta), path(fai) + tuple val(meta), path(input), path(index), path(fasta), path(fai) output: tuple val(meta), path("*.bam") , emit: bam , optional: true diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index 5e86bff2..676b6172 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -16,7 +16,6 @@ workflow FASTQ_ALIGN_RNA { main: ch_bam = channel.empty() ch_reports = channel.empty() - ch_versions = channel.empty() ch_reads_aligner_index_gtf .branch { meta, reads, aligner, index, gtf -> @@ -42,23 +41,15 @@ workflow FASTQ_ALIGN_RNA { ) // Concatenate splice junction files - def ch_splice_junctions_to_merge = group_junctions(STAR_ALIGN.out.spl_junc_tab) - - SORT_MERGE_SPLICE_JUNCTIONS(ch_splice_junctions_to_merge) - ch_versions = ch_versions.mix(SORT_MERGE_SPLICE_JUNCTIONS.out.versions.first()) - + SORT_MERGE_SPLICE_JUNCTIONS(group_junctions(STAR_ALIGN.out.spl_junc_tab)) // Concatenate junction files - def ch_junctions_to_merge = group_junctions(STAR_ALIGN.out.junction) - - SORT_MERGE_JUNCTIONS(ch_junctions_to_merge) - ch_versions = ch_versions.mix(SORT_MERGE_JUNCTIONS.out.versions.first()) + SORT_MERGE_JUNCTIONS(group_junctions(STAR_ALIGN.out.junction)) emit: bam = ch_bam // channel: [ [meta], bam ] splice_junctions = SORT_MERGE_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] junctions = SORT_MERGE_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] reports = ch_reports // channel: [ [meta], log ] - versions = ch_versions // channel: [ versions.yml ] } def group_junctions(ch) { diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 226e97b9..9ce33bc8 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -22,8 +22,6 @@ workflow FASTQ_TO_CRAM { ch_meta_reads_aligner_index_fasta_gtf // channel: [mandatory] [meta, [fastq, ...], aligner [bowtie2, bwamem, bwamem2, dragmap, snap, star], aligner_index, fasta, gtf] main: - - ch_versions = channel.empty() ch_sormadup_metrics = channel.empty() /* @@ -33,7 +31,6 @@ workflow FASTQ_TO_CRAM { */ ch_meta_reads_aligner_index_fasta_gtf.dump(tag: "FASTQ_TO_CRAM: reads to align", pretty: true) - ch_meta_reads_aligner_index_fasta_gtf .branch { meta, reads, aligner, index, fasta, gtf -> rna: meta.sample_type == "RNA" @@ -51,12 +48,9 @@ workflow FASTQ_TO_CRAM { ch_meta_reads_aligner_index_fasta_datatype.dna, false, ) - ch_versions = ch_versions.mix(FASTQ_ALIGN_DNA.out.versions) - FASTQ_ALIGN_RNA( ch_meta_reads_aligner_index_fasta_datatype.rna ) - ch_versions = ch_versions.mix(FASTQ_ALIGN_DNA.out.versions) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -110,13 +104,11 @@ workflow FASTQ_TO_CRAM { BIOBAMBAM_BAMSORMADUP(ch_bam_fasta.bamsormadup) ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch: true, failOnDuplicate: true)) ch_sormadup_metrics = ch_sormadup_metrics.mix(BIOBAMBAM_BAMSORMADUP.out.metrics) - ch_versions = ch_versions.mix(BIOBAMBAM_BAMSORMADUP.out.versions.first()) // SAMTOOLS_SORMADUP([meta, [bam, bam]], fasta) SAMTOOLS_SORMADUP(ch_bam_fasta.samtools) ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch: true, failOnDuplicate: true)) ch_sormadup_metrics = ch_sormadup_metrics.mix(SAMTOOLS_SORMADUP.out.metrics) - ch_versions = ch_versions.mix(SAMTOOLS_SORMADUP.out.versions.first()) // Merge bam files and compress // SAMTOOLS_SORT([meta, [bam, bam], fasta],index_format) @@ -147,7 +139,6 @@ workflow FASTQ_TO_CRAM { .set { ch_bam_bai_fasta_fai } SAMTOOLS_CONVERT(ch_bam_bai_fasta_fai) - ch_versions = ch_versions.mix(SAMTOOLS_CONVERT.out.versions.first()) ch_markdup_index.cram .mix( @@ -162,5 +153,4 @@ workflow FASTQ_TO_CRAM { rna_junctions = FASTQ_ALIGN_RNA.out.junctions sormadup_metrics = ch_sormadup_metrics align_reports = FASTQ_ALIGN_DNA.out.reports - versions = ch_versions } diff --git a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff index dbe123ad..5aec63ce 100644 --- a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff +++ b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff @@ -3,7 +3,24 @@ Changes in component 'nf-core/fastq_align_dna' Changes in 'fastq_align_dna/main.nf': --- subworkflows/nf-core/fastq_align_dna/main.nf +++ subworkflows/nf-core/fastq_align_dna/main.nf -@@ -16,55 +16,66 @@ +@@ -5,70 +5,75 @@ + // + + +-include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" +-include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' +-include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' +-include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" +-include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' +-include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" ++include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" ++include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' ++include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' ++include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" ++include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' ++include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" + + workflow FASTQ_ALIGN_DNA { take: @@ -12,8 +29,8 @@ Changes in 'fastq_align_dna/main.nf': - ch_fasta // channel: [mandatory] fasta file - aligner // string: [mandatory] aligner [bowtie2, bwamem, bwamem2, dragmap, snap] - sort // boolean: [mandatory] true -> sort, false -> don't sort -+ ch_reads_aligner_index_fasta // channel: [mandatory] reads, aligner, index, fasta -+ sort // boolean: [mandatory] true -> sort, false -> don't sort ++ ch_reads_aligner_index_fasta // channel: [mandatory] reads, aligner, index, fasta ++ sort // boolean: [mandatory] true -> sort, false -> don't sort main: @@ -21,62 +38,44 @@ Changes in 'fastq_align_dna/main.nf': - ch_bam = Channel.empty() - ch_reports = Channel.empty() - ch_versions = Channel.empty() -+ ch_bam_index = channel.empty() -+ ch_bam = channel.empty() -+ ch_reports = channel.empty() -+ ch_versions = channel.empty() -+ -+ ch_reads_aligner_index_fasta.branch { meta, reads, aligner, index, fasta -> -+ bowtie2 : aligner == 'bowtie2' -+ return [meta, reads, index, fasta] -+ bwamem : aligner == 'bwamem' -+ return [meta, reads, index, fasta] -+ bwamem2 : aligner == 'bwamem2' -+ return [meta, reads, index, fasta] -+ dragmap : aligner == 'dragmap' -+ return [meta, reads, index, fasta] -+ snap : aligner == 'snap' -+ return [meta, reads, index] -+ strobe : aligner == 'strobe' -+ return [meta, reads, fasta, index] -+ other : true -+ } -+ .set{ch_to_align} -+ -+ // Throw error for all samples with unsupported aligners -+ ch_to_align.other.map{ meta, _reads, aligner, _index, _fasta -> -+ error "Unsupported aligner ${aligner} for sample ${meta.id}" -+ } ++ ch_bam_index = channel.empty() ++ ch_bam = channel.empty() ++ ch_reports = channel.empty() - // Align fastq files to reference genome and (optionally) sort +- // Align fastq files to reference genome and (optionally) sort - if (aligner == 'bowtie2') { - BOWTIE2_ALIGN(ch_reads, ch_aligner_index, ch_fasta, false, sort) // if aligner is bowtie2 -+ BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 - ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) -- } +- ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) ++ ch_reads_aligner_index_fasta ++ .branch { meta, reads, aligner, index, fasta -> ++ bowtie2: aligner == 'bowtie2' ++ return [meta, reads, index, fasta] ++ bwamem: aligner == 'bwamem' ++ return [meta, reads, index, fasta] ++ bwamem2: aligner == 'bwamem2' ++ return [meta, reads, index, fasta] ++ dragmap: aligner == 'dragmap' ++ return [meta, reads, index, fasta] ++ snap: aligner == 'snap' ++ return [meta, reads, index] ++ strobe: aligner == 'strobe' ++ return [meta, reads, fasta, index] ++ other: true + } - else if (aligner == 'bwamem'){ - BWAMEM1_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem -+ ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions.first()) -+ -+ BWAMEM1_MEM (ch_to_align.bwamem, sort) // If aligner is bwa-mem - ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) - ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) +- ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) +- ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) - ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions) - } - else if (aligner == 'bwamem2'){ - BWAMEM2_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem2 -+ ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions.first()) -+ -+ BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 - ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) +- ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) - } - else if (aligner == 'dragmap'){ - DRAGMAP_ALIGN(ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is dragmap -+ ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions.first()) -+ -+ DRAGMAP_ALIGN(ch_to_align.dragmap, sort) // If aligner is dragmap - ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) - ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) +- ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) +- ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) - ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions) - } - else if (aligner == 'snap'){ @@ -87,25 +86,53 @@ Changes in 'fastq_align_dna/main.nf': - } - else if (aligner == 'strobealign'){ - STROBEALIGN (ch_reads, ch_fasta, ch_aligner_index, sort) // If aligner is strobealign -+ ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) -+ -+ SNAPALIGNER_ALIGN(ch_to_align.snap) // If aligner is snap -+ ch_bam = ch_bam.mix(SNAPALIGNER_ALIGN.out.bam) -+ ch_bam_index.mix(SNAPALIGNER_ALIGN.out.bai) -+ ch_versions = ch_versions.mix(SNAPALIGNER_ALIGN.out.versions.first()) -+ -+ STROBEALIGN(ch_to_align.strobe, sort) // If aligner is strobealign - ch_bam = ch_bam.mix(STROBEALIGN.out.bam) - ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) +- ch_bam = ch_bam.mix(STROBEALIGN.out.bam) +- ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) - ch_versions = ch_versions.mix(STROBEALIGN.out.versions) - } - else { - error "Unknown aligner: ${aligner}" - } -+ ch_versions = ch_versions.mix(STROBEALIGN.out.versions.first()) ++ .set { ch_to_align } ++ ++ // Throw error for all samples with unsupported aligners ++ ch_to_align.other.map { meta, _reads, aligner, _index, _fasta -> ++ error("Unsupported aligner ${aligner} for sample ${meta.id}") ++ } ++ ++ // Align fastq files to reference genome and (optionally) sort ++ BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) ++ // if aligner is bowtie2 ++ ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) ++ BWAMEM1_MEM(ch_to_align.bwamem, sort) ++ // If aligner is bwa-mem ++ ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) ++ ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) ++ BWAMEM2_MEM(ch_to_align.bwamem2, sort) ++ // If aligner is bwa-mem2 ++ ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) ++ DRAGMAP_ALIGN(ch_to_align.dragmap, sort) ++ // If aligner is dragmap ++ ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) ++ ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) ++ SNAP_ALIGN(ch_to_align.snap) ++ // If aligner is snap ++ ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) ++ ch_bam_index.mix(SNAP_ALIGN.out.bai) ++ STROBEALIGN(ch_to_align.strobe, sort) ++ // If aligner is strobealign ++ ch_bam = ch_bam.mix(STROBEALIGN.out.bam) ++ ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) emit: - bam = ch_bam // channel: [ [meta], bam ] +- bam = ch_bam // channel: [ [meta], bam ] +- bam_index = ch_bam_index // channel: [ [meta], csi/bai ] +- reports = ch_reports // channel: [ [meta], log ] +- versions = ch_versions // channel: [ versions.yml ] ++ bam = ch_bam // channel: [ [meta], bam ] ++ bam_index = ch_bam_index // channel: [ [meta], csi/bai ] ++ reports = ch_reports // channel: [ [meta], log ] + } 'subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap' is unchanged 'subworkflows/nf-core/fastq_align_dna/tests/main.nf.test' is unchanged diff --git a/subworkflows/nf-core/fastq_align_dna/main.nf b/subworkflows/nf-core/fastq_align_dna/main.nf index 37e62d70..3e7cf051 100644 --- a/subworkflows/nf-core/fastq_align_dna/main.nf +++ b/subworkflows/nf-core/fastq_align_dna/main.nf @@ -5,81 +5,75 @@ // -include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" -include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' -include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' -include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" -include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' -include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" +include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" +include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' +include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' +include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" +include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' +include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" workflow FASTQ_ALIGN_DNA { take: - ch_reads_aligner_index_fasta // channel: [mandatory] reads, aligner, index, fasta - sort // boolean: [mandatory] true -> sort, false -> don't sort + ch_reads_aligner_index_fasta // channel: [mandatory] reads, aligner, index, fasta + sort // boolean: [mandatory] true -> sort, false -> don't sort main: - ch_bam_index = channel.empty() - ch_bam = channel.empty() - ch_reports = channel.empty() - ch_versions = channel.empty() - - ch_reads_aligner_index_fasta.branch { meta, reads, aligner, index, fasta -> - bowtie2 : aligner == 'bowtie2' - return [meta, reads, index, fasta] - bwamem : aligner == 'bwamem' - return [meta, reads, index, fasta] - bwamem2 : aligner == 'bwamem2' - return [meta, reads, index, fasta] - dragmap : aligner == 'dragmap' - return [meta, reads, index, fasta] - snap : aligner == 'snap' - return [meta, reads, index] - strobe : aligner == 'strobe' - return [meta, reads, fasta, index] - other : true - } - .set{ch_to_align} - - // Throw error for all samples with unsupported aligners - ch_to_align.other.map{ meta, _reads, aligner, _index, _fasta -> - error "Unsupported aligner ${aligner} for sample ${meta.id}" + ch_bam_index = channel.empty() + ch_bam = channel.empty() + ch_reports = channel.empty() + + ch_reads_aligner_index_fasta + .branch { meta, reads, aligner, index, fasta -> + bowtie2: aligner == 'bowtie2' + return [meta, reads, index, fasta] + bwamem: aligner == 'bwamem' + return [meta, reads, index, fasta] + bwamem2: aligner == 'bwamem2' + return [meta, reads, index, fasta] + dragmap: aligner == 'dragmap' + return [meta, reads, index, fasta] + snap: aligner == 'snap' + return [meta, reads, index] + strobe: aligner == 'strobe' + return [meta, reads, fasta, index] + other: true } - - // Align fastq files to reference genome and (optionally) sort - BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) // if aligner is bowtie2 - ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) - ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions.first()) - - BWAMEM1_MEM (ch_to_align.bwamem, sort) // If aligner is bwa-mem - ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) - ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) - ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions.first()) - - BWAMEM2_MEM (ch_to_align.bwamem2, sort) // If aligner is bwa-mem2 - ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) - ch_versions = ch_versions.mix(BWAMEM2_MEM.out.versions.first()) - - DRAGMAP_ALIGN(ch_to_align.dragmap, sort) // If aligner is dragmap - ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) - ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) - ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions.first()) - - SNAPALIGNER_ALIGN(ch_to_align.snap) // If aligner is snap - ch_bam = ch_bam.mix(SNAPALIGNER_ALIGN.out.bam) - ch_bam_index.mix(SNAPALIGNER_ALIGN.out.bai) - ch_versions = ch_versions.mix(SNAPALIGNER_ALIGN.out.versions.first()) - - STROBEALIGN(ch_to_align.strobe, sort) // If aligner is strobealign - ch_bam = ch_bam.mix(STROBEALIGN.out.bam) - ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) - ch_versions = ch_versions.mix(STROBEALIGN.out.versions.first()) + .set { ch_to_align } + + // Throw error for all samples with unsupported aligners + ch_to_align.other.map { meta, _reads, aligner, _index, _fasta -> + error("Unsupported aligner ${aligner} for sample ${meta.id}") + } + + // Align fastq files to reference genome and (optionally) sort + BOWTIE2_ALIGN(ch_to_align.bowtie2, false, sort) + // if aligner is bowtie2 + ch_bam = ch_bam.mix(BOWTIE2_ALIGN.out.bam) + BWAMEM1_MEM(ch_to_align.bwamem, sort) + // If aligner is bwa-mem + ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) + ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) + BWAMEM2_MEM(ch_to_align.bwamem2, sort) + // If aligner is bwa-mem2 + ch_bam = ch_bam.mix(BWAMEM2_MEM.out.bam) + DRAGMAP_ALIGN(ch_to_align.dragmap, sort) + // If aligner is dragmap + ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) + ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) + SNAP_ALIGN(ch_to_align.snap) + // If aligner is snap + ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) + ch_bam_index.mix(SNAP_ALIGN.out.bai) + STROBEALIGN(ch_to_align.strobe, sort) + // If aligner is strobealign + ch_bam = ch_bam.mix(STROBEALIGN.out.bam) + ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) emit: - bam = ch_bam // channel: [ [meta], bam ] - bam_index = ch_bam_index // channel: [ [meta], csi/bai ] - reports = ch_reports // channel: [ [meta], log ] - versions = ch_versions // channel: [ versions.yml ] + bam = ch_bam // channel: [ [meta], bam ] + bam_index = ch_bam_index // channel: [ [meta], csi/bai ] + reports = ch_reports // channel: [ [meta], log ] } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 365327af..e440222c 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -196,7 +196,6 @@ workflow PREPROCESSING { false, ) ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) - ch_versions = ch_versions.mix(FASTP.out.versions.first()) // edit meta.id to match sample name FASTP.out.reads @@ -240,9 +239,7 @@ workflow PREPROCESSING { FASTQ_TO_CRAM( ch_meta_reads_aligner_index_fasta_gtf ) - ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics) - ch_versions = ch_versions.mix(FASTQ_TO_CRAM.out.versions) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 2772ae24a79cae082f6ab3b8fa67b2db5f2e606d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:35:15 +0100 Subject: [PATCH 164/228] more topic work --- modules/nf-core/samtools/convert/samtools-convert.diff | 5 ++--- subworkflows/local/coverage/main.nf | 6 ------ workflows/preprocessing.nf | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/modules/nf-core/samtools/convert/samtools-convert.diff b/modules/nf-core/samtools/convert/samtools-convert.diff index bd28d5da..2ded55b4 100644 --- a/modules/nf-core/samtools/convert/samtools-convert.diff +++ b/modules/nf-core/samtools/convert/samtools-convert.diff @@ -4,13 +4,12 @@ Changes in component 'nf-core/samtools/convert' Changes in 'samtools/convert/main.nf': --- modules/nf-core/samtools/convert/main.nf +++ modules/nf-core/samtools/convert/main.nf -@@ -8,9 +8,7 @@ +@@ -8,8 +8,7 @@ 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(index) -- tuple val(meta2), path(fasta) -- tuple val(meta3), path(fai) +- tuple val(meta2), path(fasta), path(fai) + tuple val(meta), path(input), path(index), path(fasta), path(fai) output: diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 501b0773..cca3ca59 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -20,18 +20,14 @@ workflow COVERAGE { return [meta, cram, crai, roi, fasta] } ) - ch_versions = ch_versions.mix(MOSDEPTH.out.versions.first()) SAMTOOLS_COVERAGE( ch_meta_cram_crai_fasta_fai_roi.map { meta, cram, crai, fasta, fai, _roi -> return [meta, cram, crai, fasta, fai] } ) - ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) ch_coverageqc_files = ch_coverageqc_files.merge(SAMTOOLS_COVERAGE.out.coverage) - ch_genelists.view() - PANELCOVERAGE( MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> if (genelists !instanceof List) { @@ -52,7 +48,6 @@ workflow COVERAGE { } } ) - ch_versions = ch_versions.mix(PANELCOVERAGE.out.versions.first()) ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) emit: @@ -70,5 +65,4 @@ workflow COVERAGE { mosdepth_thresholds_csi = MOSDEPTH.out.thresholds_csi samtools_coverage = SAMTOOLS_COVERAGE.out.coverage panelcoverage = PANELCOVERAGE.out.regiondist - versions = ch_versions } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index e440222c..94cb7fdb 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -269,7 +269,6 @@ workflow PREPROCESSING { COVERAGE.out.mosdepth_regions, COVERAGE.out.samtools_coverage, ) - ch_versions = ch_versions.mix(COVERAGE.out.versions) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 693fad72f03c1d886f191e5bcf9bc87bedd06b3e Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:42:09 +0100 Subject: [PATCH 165/228] add falco for unsupported fastq qc --- main.nf | 10 ++ modules.json | 5 + modules/nf-core/falco/environment.yml | 7 ++ modules/nf-core/falco/main.nf | 57 +++++++++ modules/nf-core/falco/meta.yml | 61 ++++++++++ modules/nf-core/falco/tests/main.nf.test | 108 ++++++++++++++++++ modules/nf-core/falco/tests/main.nf.test.snap | 61 ++++++++++ workflows/preprocessing.nf | 11 ++ 8 files changed, 320 insertions(+) create mode 100644 modules/nf-core/falco/environment.yml create mode 100644 modules/nf-core/falco/main.nf create mode 100644 modules/nf-core/falco/meta.yml create mode 100644 modules/nf-core/falco/tests/main.nf.test create mode 100644 modules/nf-core/falco/tests/main.nf.test.snap diff --git a/main.nf b/main.nf index 03dfac1a..6b0e25f3 100644 --- a/main.nf +++ b/main.nf @@ -68,6 +68,8 @@ workflow { demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by:1) demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() + falco_html = PREPROCESSING.out.falco_html + falco_txt = PREPROCESSING.out.falco_txt fastp_json = PREPROCESSING.out.fastp_json fastp_html = PREPROCESSING.out.fastp_html crams = PREPROCESSING.out.crams @@ -121,6 +123,14 @@ output { def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" fastq >> out_path } } + falco_html { path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } } + falco_txt { path { meta, txt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" as String : "${meta.samplename}/${txt.name}" + txt >> out_path + } } fastp_json { path { meta, json -> def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" json >> out_path diff --git a/modules.json b/modules.json index 0b710f92..845562bf 100644 --- a/modules.json +++ b/modules.json @@ -46,6 +46,11 @@ "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, + "falco": { + "branch": "master", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "installed_by": ["modules"] + }, "fastp": { "branch": "master", "git_sha": "b8f1de0ac853ae5b56c63450d47438f899c553d0", diff --git a/modules/nf-core/falco/environment.yml b/modules/nf-core/falco/environment.yml new file mode 100644 index 00000000..59c973a9 --- /dev/null +++ b/modules/nf-core/falco/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::falco=1.2.1 diff --git a/modules/nf-core/falco/main.nf b/modules/nf-core/falco/main.nf new file mode 100644 index 00000000..a4b343b2 --- /dev/null +++ b/modules/nf-core/falco/main.nf @@ -0,0 +1,57 @@ +process FALCO { + tag "$meta.id" + label 'process_single' + + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/falco:1.2.1--h867801b_3': + 'biocontainers/falco:1.2.1--h867801b_3' }" + + input: + tuple val(meta), path(reads) + + output: + tuple val(meta), path("*.html"), emit: html + tuple val(meta), path("*.txt") , emit: txt + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + if ( reads.toList().size() == 1 ) { + """ + falco $args --threads $task.cpus ${reads} -D ${prefix}_fastqc_data.txt -S ${prefix}_summary.txt -R ${prefix}_report.html + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + falco:\$( falco --version | sed -e "s/falco//g" ) + END_VERSIONS + """ + } else { + """ + falco $args --threads $task.cpus ${reads} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + falco:\$( falco --version | sed -e "s/falco//g" ) + END_VERSIONS + """ + } + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}_data.txt + touch ${prefix}_fastqc_data.html + touch ${prefix}_summary.txt + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + falco: \$( falco --version | sed -e "s/falco v//g" ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/falco/meta.yml b/modules/nf-core/falco/meta.yml new file mode 100644 index 00000000..1450f2da --- /dev/null +++ b/modules/nf-core/falco/meta.yml @@ -0,0 +1,61 @@ +name: falco +description: Run falco on sequenced reads +keywords: + - quality control + - qc + - adapters + - fastq +tools: + - fastqc: + description: "falco is a drop-in C++ implementation of FastQC to assess the quality + of sequence reads." + homepage: "https://falco.readthedocs.io/" + documentation: "https://falco.readthedocs.io/" + licence: ["GPL v3"] + identifier: biotools:falco-rna +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files of size 1 and 2 for single-end and paired-end data, + respectively. + ontologies: [] +output: + html: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.html": + type: file + description: FastQC like report + pattern: "*_{fastqc_report.html}" + ontologies: [] + txt: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.txt": + type: file + description: falco report data + pattern: "*_{data.txt}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@lucacozzuto" +maintainers: + - "@lucacozzuto" diff --git a/modules/nf-core/falco/tests/main.nf.test b/modules/nf-core/falco/tests/main.nf.test new file mode 100644 index 00000000..816c72ba --- /dev/null +++ b/modules/nf-core/falco/tests/main.nf.test @@ -0,0 +1,108 @@ +nextflow_process { + + name "Test Process FALCO" + script "../main.nf" + process "FALCO" + + tag "modules" + tag "modules_nfcore" + tag "falco" + + test("sarscov2 - fastq - single end") { + + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:true ], + [ + file( + params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], + checkIfExists: true + ), + ], + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.txt, + file(process.out.html.get(0).get(1)).list(), + ).match() + }, + ) + } + + } + + test("sarscov2 - fastq - paired end") { + + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:false ], + [ + file( + params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], + checkIfExists: true + ), + file( + params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], + checkIfExists: true + ), + ], + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.txt, + process.out.html.get(0).get(1).collect{ it.split("/")[-1] }.sort(), + ).match() + }, + ) + } + + } + + test("sarscov2 - fastq - interleaved") { + + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:false ], + [ + file( + params.test_data['sarscov2']['illumina']['test_interleaved_fastq_gz'], + checkIfExists: true + ), + ], + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.txt, + file(process.out.html.get(0).get(1)).list(), + ).match() + }, + ) + } + + } + +} diff --git a/modules/nf-core/falco/tests/main.nf.test.snap b/modules/nf-core/falco/tests/main.nf.test.snap new file mode 100644 index 00000000..34ac64e3 --- /dev/null +++ b/modules/nf-core/falco/tests/main.nf.test.snap @@ -0,0 +1,61 @@ +{ + "sarscov2 - fastq - single end": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test_fastqc_data.txt:md5,36d989bb9e2d5a632e19452f4e6c2a4e", + "test_summary.txt:md5,a925aec214a83d2f6252847166f2ef3a" + ] + ] + ], + null + ], + "timestamp": "2024-02-02T16:28:17.756764" + }, + "sarscov2 - fastq - paired end": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.fastq.gz_fastqc_data.txt:md5,36d989bb9e2d5a632e19452f4e6c2a4e", + "test_1.fastq.gz_summary.txt:md5,a925aec214a83d2f6252847166f2ef3a", + "test_2.fastq.gz_fastqc_data.txt:md5,ad5c45dfc8f79754dd5d8029456b715b", + "test_2.fastq.gz_summary.txt:md5,d0cb642adefb5635a25e808f1f38780a" + ] + ] + ], + [ + "test_1.fastq.gz_fastqc_report.html", + "test_2.fastq.gz_fastqc_report.html" + ] + ], + "timestamp": "2024-02-02T16:22:11.757473" + }, + "sarscov2 - fastq - interleaved": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_fastqc_data.txt:md5,b5e593f140fe578bdd25ceb84e98fd37", + "test_summary.txt:md5,ca52f458b1223d89db69e2d5e73cf867" + ] + ] + ], + null + ], + "timestamp": "2024-02-02T16:28:36.035899" + } +} \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 6d2802eb..3bc525fb 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -7,6 +7,7 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules +include { FALCO } from '../modules/nf-core/falcon/main' include { FASTP } from '../modules/nf-core/fastp/main' include { MD5SUM } from '../modules/nf-core/md5sum/main' include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' @@ -202,6 +203,14 @@ workflow PREPROCESSING { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + // MODULE: FALCO + // Run FALCO for "unsupported" fastq QC + // FALCO([meta, fastq]) + FALCO(ch_fastq_per_sample.other, false) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.html) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.txt) + ch_versions = ch_versions.mix(FALCO.out.versions.first()) + // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) @@ -485,6 +494,8 @@ workflow PREPROCESSING { demultiplex_reports = BCL_DEMULTIPLEX.out.reports demultiplex_logs = BCL_DEMULTIPLEX.out.logs demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other + falco_html = FALCO.out.html + falco_txt = FALCO.out.txt fastp_json = FASTP.out.json fastp_html = FASTP.out.html crams = FASTQ_TO_CRAM.out.cram_crai From 4ed927795877c6302c0b9dc2de1b07f4261345c4 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 08:45:02 +0100 Subject: [PATCH 166/228] fix typo + linting --- main.nf | 456 ++++++++++++++++++++++--------------- workflows/preprocessing.nf | 208 ++++++++--------- 2 files changed, 375 insertions(+), 289 deletions(-) diff --git a/main.nf b/main.nf index 6b0e25f3..412538d8 100644 --- a/main.nf +++ b/main.nf @@ -64,195 +64,277 @@ workflow { ) publish: - demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) - demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by:1) - demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) - demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() - falco_html = PREPROCESSING.out.falco_html - falco_txt = PREPROCESSING.out.falco_txt - fastp_json = PREPROCESSING.out.fastp_json - fastp_html = PREPROCESSING.out.fastp_html - crams = PREPROCESSING.out.crams - rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions - rna_junctions = PREPROCESSING.out.rna_junctions - align_reports = PREPROCESSING.out.align_reports - sormadup_metrics = PREPROCESSING.out.sormadup_metrics - mosdepth_global = PREPROCESSING.out.mosdepth_global - mosdepth_summary = PREPROCESSING.out.mosdepth_summary - mosdepth_regions = PREPROCESSING.out.mosdepth_regions - mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 - mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed - mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi - mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed - mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi - mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed - mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi - mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed - mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi - samtools_coverage = PREPROCESSING.out.samtools_coverage - panelcoverage = PREPROCESSING.out.panelcoverage - samtools_stats = PREPROCESSING.out.samtools_stats - samtools_flagstat = PREPROCESSING.out.samtools_flagstat - samtools_idxstats = PREPROCESSING.out.samtools_idxstats - picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics + demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by: 1) + demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by: 1) + demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by: 1) + demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() + falco_html = PREPROCESSING.out.falco_html + falco_txt = PREPROCESSING.out.falco_txt + fastp_json = PREPROCESSING.out.fastp_json + fastp_html = PREPROCESSING.out.fastp_html + crams = PREPROCESSING.out.crams + rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions + rna_junctions = PREPROCESSING.out.rna_junctions + align_reports = PREPROCESSING.out.align_reports + sormadup_metrics = PREPROCESSING.out.sormadup_metrics + mosdepth_global = PREPROCESSING.out.mosdepth_global + mosdepth_summary = PREPROCESSING.out.mosdepth_summary + mosdepth_regions = PREPROCESSING.out.mosdepth_regions + mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed + mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi + mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed + mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi + mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed + mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi + samtools_coverage = PREPROCESSING.out.samtools_coverage + panelcoverage = PREPROCESSING.out.panelcoverage + samtools_stats = PREPROCESSING.out.samtools_stats + samtools_flagstat = PREPROCESSING.out.samtools_flagstat + samtools_idxstats = PREPROCESSING.out.samtools_idxstats + picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics picard_multiplemetrics_pdf = PREPROCESSING.out.picard_multiplemetrics_pdf - picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics - picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics - md5sums = PREPROCESSING.out.md5sums - multiqc_main_report = PREPROCESSING.out.multiqc_main_report - multiqc_main_data = PREPROCESSING.out.multiqc_main_data - multiqc_main_plots = PREPROCESSING.out.multiqc_main_plots - multiqc_library_report = PREPROCESSING.out.multiqc_library_report - multiqc_library_data = PREPROCESSING.out.multiqc_library_data - multiqc_library_plots = PREPROCESSING.out.multiqc_library_plots + picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics + picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics + md5sums = PREPROCESSING.out.md5sums + multiqc_main_report = PREPROCESSING.out.multiqc_main_report + multiqc_main_data = PREPROCESSING.out.multiqc_main_data + multiqc_main_plots = PREPROCESSING.out.multiqc_main_plots + multiqc_library_report = PREPROCESSING.out.multiqc_library_report + multiqc_library_data = PREPROCESSING.out.multiqc_library_data + multiqc_library_plots = PREPROCESSING.out.multiqc_library_plots } output { - demultiplex_interop { path { _meta, bin -> - bin >> "Interop/${bin.name}" - } } - demultiplex_reports { path { meta, report -> - def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" - report >> out_path - } } - demultiplex_logs { path { meta, log -> - def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" - log >> out_path - } } - demultiplex_fastq { path { meta, fastq -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" - fastq >> out_path - } } - falco_html { path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path - } } - falco_txt { path { meta, txt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" as String : "${meta.samplename}/${txt.name}" - txt >> out_path - } } - fastp_json { path { meta, json -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" - json >> out_path - } } - fastp_html { path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path - } } - crams { path { meta, cram, crai -> - def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" - def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" - cram >> out_cram - crai >> out_crai - } } - rna_splice_junctions { path { meta, sjt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" - sjt >> out_path - } } - rna_junctions { path { meta, junctions -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" - junctions >> out_path - } } - align_reports { path { meta, log -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" - log >> out_path - } } - sormadup_metrics { path { meta, metrics -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" - metrics >> out_path - } } - mosdepth_global { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_summary { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_d4 { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_quantized_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_quantized_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_thresholds_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_thresholds_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_coverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - panelcoverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_stats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_flagstat { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_idxstats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_multiplemetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_multiplemetrics_pdf { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_wgsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_hsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - md5sums { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - multiqc_main_report { path "multiqc/" } - multiqc_main_data { path "multiqc/" } - multiqc_main_plots { path "multiqc/" } - multiqc_library_report { path "multiqc/" } - multiqc_library_data { path "multiqc/" } - multiqc_library_plots { path "multiqc/" } + demultiplex_interop { + path { _meta, bin -> + bin >> "Interop/${bin.name}" + } + } + demultiplex_reports { + path { meta, report -> + def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" + report >> out_path + } + } + demultiplex_logs { + path { meta, log -> + def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" + log >> out_path + } + } + demultiplex_fastq { + path { meta, fastq -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" + fastq >> out_path + } + } + falco_html { + path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } + } + falco_txt { + path { meta, txt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" as String : "${meta.samplename}/${txt.name}" + txt >> out_path + } + } + fastp_json { + path { meta, json -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" + json >> out_path + } + } + fastp_html { + path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } + } + crams { + path { meta, cram, crai -> + def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" + def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" + cram >> out_cram + crai >> out_crai + } + } + rna_splice_junctions { + path { meta, sjt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" + sjt >> out_path + } + } + rna_junctions { + path { meta, junctions -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" + junctions >> out_path + } + } + align_reports { + path { meta, log -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" + log >> out_path + } + } + sormadup_metrics { + path { meta, metrics -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" + metrics >> out_path + } + } + mosdepth_global { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_summary { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_d4 { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_quantized_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_quantized_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_thresholds_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_thresholds_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_coverage { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + panelcoverage { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_stats { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_flagstat { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_idxstats { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_multiplemetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_multiplemetrics_pdf { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_wgsmetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_hsmetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + md5sums { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + multiqc_main_report { + path "multiqc/" + } + multiqc_main_data { + path "multiqc/" + } + multiqc_main_plots { + path "multiqc/" + } + multiqc_library_report { + path "multiqc/" + } + multiqc_library_data { + path "multiqc/" + } + multiqc_library_plots { + path "multiqc/" + } } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 3bc525fb..e76ee226 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -1,4 +1,4 @@ -include { samplesheetToList } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -7,26 +7,26 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules -include { FALCO } from '../modules/nf-core/falcon/main' -include { FASTP } from '../modules/nf-core/fastp/main' -include { MD5SUM } from '../modules/nf-core/md5sum/main' -include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' -include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' -include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' -include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' +include { FALCO } from '../modules/nf-core/falco/main' +include { FASTP } from '../modules/nf-core/fastp/main' +include { MD5SUM } from '../modules/nf-core/md5sum/main' +include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' +include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' +include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' +include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' // Subworkflows -include { BAM_QC } from '../subworkflows/local/bam_qc/main' -include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' -include { COVERAGE } from '../subworkflows/local/coverage/main' -include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' +include { BAM_QC } from '../subworkflows/local/bam_qc/main' +include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' +include { COVERAGE } from '../subworkflows/local/coverage/main' +include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' // Functions -include { paramsSummaryMap } from 'plugin/nf-schema' -include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' -include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -37,10 +37,10 @@ include { getGenomeAttribute } from '../subworkflows/local/utils_nfco workflow PREPROCESSING { take: ch_samplesheet // channel: samplesheet read in from --input - genomes // map: genome reference files - markdup // string: markdup method to use - roi // file: regions of interest bed file to be applied to all samples - genelists // file: directory containing genelist bed files for coverage analysis + genomes // map: genome reference files + markdup // string: markdup method to use + roi // file: regions of interest bed file to be applied to all samples + genelists // file: directory containing genelist bed files for coverage analysis main: ch_versions = channel.empty() @@ -79,7 +79,7 @@ workflow PREPROCESSING { BCL_DEMULTIPLEX.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) ch_multiqc_files = ch_multiqc_files.mix( BCL_DEMULTIPLEX.out.reports, - BCL_DEMULTIPLEX.out.stats + BCL_DEMULTIPLEX.out.stats, ) ch_versions = ch_versions.mix(BCL_DEMULTIPLEX.out.versions) @@ -197,7 +197,7 @@ workflow PREPROCESSING { ch_fastq_per_sample.supported.dump(tag: "Supported FASTQ per sample", pretty: true) ch_fastq_per_sample.other.dump(tag: "Other FASTQ per sample", pretty: true) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FASTQ TRIMMING AND QC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -206,15 +206,17 @@ workflow PREPROCESSING { // MODULE: FALCO // Run FALCO for "unsupported" fastq QC // FALCO([meta, fastq]) - FALCO(ch_fastq_per_sample.other, false) - ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.html) - ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.txt) - ch_versions = ch_versions.mix(FALCO.out.versions.first()) + FALCO(ch_fastq_per_sample.other) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.html) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.txt) + ch_versions = ch_versions.mix(FALCO.out.versions.first()) // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) - FASTP(ch_fastq_per_sample.supported.map{ meta, fastq -> return [meta, fastq, []] }, false, false, false) + FASTP(ch_fastq_per_sample.supported.map { meta, fastq -> + return [meta, fastq, []] + }, false, false, false) ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) ch_versions = ch_versions.mix(FASTP.out.versions.first()) @@ -239,22 +241,23 @@ workflow PREPROCESSING { ch_trimmed_reads.dump(tag: "Supported trimmed reads per sample", pretty: true) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: FASTQ TO ALIGNED CRAM CONVERSION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - ch_trimmed_reads.map { meta, reads -> - return [ - meta, - reads, - meta.aligner, - getGenomeAttribute(meta.genome_data, meta.aligner), - getGenomeAttribute(meta.genome_data, "fasta"), - getGenomeAttribute(meta.genome_data, "gtf"), - ] - } - .set { ch_meta_reads_aligner_index_fasta_gtf } + ch_trimmed_reads + .map { meta, reads -> + return [ + meta, + reads, + meta.aligner, + getGenomeAttribute(meta.genome_data, meta.aligner), + getGenomeAttribute(meta.genome_data, "fasta"), + getGenomeAttribute(meta.genome_data, "gtf"), + ] + } + .set { ch_meta_reads_aligner_index_fasta_gtf } FASTQ_TO_CRAM( ch_meta_reads_aligner_index_fasta_gtf, @@ -414,7 +417,7 @@ workflow PREPROCESSING { // // Collate and save software versions // - def topic_versions = Channel.topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path @@ -423,9 +426,9 @@ workflow PREPROCESSING { def topic_versions_string = topic_versions.versions_tuple .map { process, tool, version -> - [ process[process.lastIndexOf(':')+1..-1], " ${tool}: ${version}" ] + [process[process.lastIndexOf(':') + 1..-1], " ${tool}: ${version}"] } - .groupTuple(by:0) + .groupTuple(by: 0) .map { process, tool_versions -> tool_versions.unique().sort() "${process}:\n${tool_versions.join('\n')}" @@ -437,42 +440,43 @@ workflow PREPROCESSING { storeDir: "${params.outdir}/pipeline_info", name: 'nf_cmgg_preprocessing_software_mqc_versions.yml', sort: true, - newLine: true + newLine: true, ) - .map { file -> [[id: 'main'], file] } // add meta for multiqc + .map { file -> [[id: 'main'], file] } .set { ch_collated_versions } // // MODULE: MultiQC // - ch_multiqc_config = channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_config = channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) ch_multiqc_custom_config = params.multiqc_config ? channel.fromPath(params.multiqc_config, checkIfExists: true) : channel.empty() - ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() + ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") ch_workflow_summary = channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml').map{ file -> [[id: 'main'], file] }) + ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml').map { file -> [[id: 'main'], file] }) - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true).map{ file -> [[id: 'main'], file] }) + ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true).map { file -> [[id: 'main'], file] }) - ch_multiqc_files = ch_multiqc_files.map { meta, files -> - return [meta.library ? [id: meta.library] : [id: 'main'], files] - } - .branch { meta, files -> - main: meta.id == 'main' + ch_multiqc_files = ch_multiqc_files + .map { meta, files -> + return [meta.library ? [id: meta.library] : [id: 'main'], files] + } + .branch { meta, files -> + main: meta.id == 'main' return files - library: meta.id != 'main' + library: meta.id != 'main' return [meta, files instanceof List ? files : [files]] - } + } ch_multiqc_files.main.dump(tag: "MULTIQC files - main", pretty: true) ch_multiqc_files.library.dump(tag: "MULTIQC files - library", pretty: true) MULTIQC_MAIN( - ch_multiqc_files.main.collect().map{ files -> [[id: 'main'], files] }, + ch_multiqc_files.main.collect().map { files -> [[id: 'main'], files] }, ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), @@ -481,7 +485,7 @@ workflow PREPROCESSING { ) MULTIQC_LIBRARY( - ch_multiqc_files.library.transpose(by:1).groupTuple(), + ch_multiqc_files.library.transpose(by: 1).groupTuple(), ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), @@ -490,48 +494,48 @@ workflow PREPROCESSING { ) emit: - demultiplex_interop = BCL_DEMULTIPLEX.out.interop - demultiplex_reports = BCL_DEMULTIPLEX.out.reports - demultiplex_logs = BCL_DEMULTIPLEX.out.logs - demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other - falco_html = FALCO.out.html - falco_txt = FALCO.out.txt - fastp_json = FASTP.out.json - fastp_html = FASTP.out.html - crams = FASTQ_TO_CRAM.out.cram_crai - rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions - rna_junctions = FASTQ_TO_CRAM.out.rna_junctions - align_reports = FASTQ_TO_CRAM.out.align_reports - sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics - mosdepth_global = mosdepth_global_out - mosdepth_summary = mosdepth_summary_out - mosdepth_regions = mosdepth_regions_out - mosdepth_per_base_d4 = mosdepth_per_base_d4_out - mosdepth_per_base_bed = mosdepth_per_base_bed_out - mosdepth_per_base_csi = mosdepth_per_base_csi_out - mosdepth_regions_bed = mosdepth_regions_bed_out - mosdepth_regions_csi = mosdepth_regions_csi_out - mosdepth_quantized_bed = mosdepth_quantized_bed_out - mosdepth_quantized_csi = mosdepth_quantized_csi_out - mosdepth_thresholds_bed = mosdepth_thresholds_bed_out - mosdepth_thresholds_csi = mosdepth_thresholds_csi_out - samtools_coverage = samtools_coverage_out - panelcoverage = panelcoverage_out - samtools_stats = BAM_QC.out.samtools_stats - samtools_flagstat = BAM_QC.out.samtools_flagstat - samtools_idxstats = BAM_QC.out.samtools_idxstats - picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics - picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf - picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics - picard_hsmetrics = BAM_QC.out.picard_hsmetrics - md5sums = MD5SUM.out.checksum - multiqc_main_report = MULTIQC_MAIN.out.report.toList() - multiqc_main_data = MULTIQC_MAIN.out.data.toList() - multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() - multiqc_library_report = MULTIQC_LIBRARY.out.report - multiqc_library_data = MULTIQC_LIBRARY.out.data - multiqc_library_plots = MULTIQC_LIBRARY.out.plots - versions = ch_versions + demultiplex_interop = BCL_DEMULTIPLEX.out.interop + demultiplex_reports = BCL_DEMULTIPLEX.out.reports + demultiplex_logs = BCL_DEMULTIPLEX.out.logs + demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other + falco_html = FALCO.out.html + falco_txt = FALCO.out.txt + fastp_json = FASTP.out.json + fastp_html = FASTP.out.html + crams = FASTQ_TO_CRAM.out.cram_crai + rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions + rna_junctions = FASTQ_TO_CRAM.out.rna_junctions + align_reports = FASTQ_TO_CRAM.out.align_reports + sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics + mosdepth_global = mosdepth_global_out + mosdepth_summary = mosdepth_summary_out + mosdepth_regions = mosdepth_regions_out + mosdepth_per_base_d4 = mosdepth_per_base_d4_out + mosdepth_per_base_bed = mosdepth_per_base_bed_out + mosdepth_per_base_csi = mosdepth_per_base_csi_out + mosdepth_regions_bed = mosdepth_regions_bed_out + mosdepth_regions_csi = mosdepth_regions_csi_out + mosdepth_quantized_bed = mosdepth_quantized_bed_out + mosdepth_quantized_csi = mosdepth_quantized_csi_out + mosdepth_thresholds_bed = mosdepth_thresholds_bed_out + mosdepth_thresholds_csi = mosdepth_thresholds_csi_out + samtools_coverage = samtools_coverage_out + panelcoverage = panelcoverage_out + samtools_stats = BAM_QC.out.samtools_stats + samtools_flagstat = BAM_QC.out.samtools_flagstat + samtools_idxstats = BAM_QC.out.samtools_idxstats + picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics + picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf + picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics + picard_hsmetrics = BAM_QC.out.picard_hsmetrics + md5sums = MD5SUM.out.checksum + multiqc_main_report = MULTIQC_MAIN.out.report.toList() + multiqc_main_data = MULTIQC_MAIN.out.data.toList() + multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() + multiqc_library_report = MULTIQC_LIBRARY.out.report + multiqc_library_data = MULTIQC_LIBRARY.out.data + multiqc_library_plots = MULTIQC_LIBRARY.out.plots + versions = ch_versions } /* From 27e1dd69a242604229c55694947adaa6cbab641d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 09:04:36 +0100 Subject: [PATCH 167/228] drop unused gh workflows --- .github/workflows/fix-linting.yml | 89 ------------------------------- .github/workflows/fix_linting.yml | 89 ------------------------------- 2 files changed, 178 deletions(-) delete mode 100644 .github/workflows/fix-linting.yml delete mode 100644 .github/workflows/fix_linting.yml diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml deleted file mode 100644 index 2230aafb..00000000 --- a/.github/workflows/fix-linting.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Fix linting from a comment -on: - issue_comment: - types: [created] - -jobs: - fix-linting: - # Only run if comment is on a PR with the main repo, and if it contains the magic keywords - if: > - contains(github.event.comment.html_url, '/pull/') && - contains(github.event.comment.body, '@nf-core-bot fix linting') && - github.repository == 'nf-cmgg/preprocessing' - runs-on: ubuntu-latest - steps: - # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - with: - token: ${{ secrets.nf_core_bot_auth_token }} - - # indication that the linting is being fixed - - name: React on comment - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: eyes - - # Action runs on the issue comment, so we don't get the PR by default - # Use the gh cli to check out the PR - - name: Checkout Pull Request - run: gh pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} - - # Install and run pre-commit - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 - with: - python-version: 3.11 - - - name: Install pre-commit - run: pip install pre-commit - - - name: Run pre-commit - id: pre-commit - run: pre-commit run --all-files - continue-on-error: true - - # indication that the linting has finished - - name: react if linting finished succesfully - if: steps.pre-commit.outcome == 'success' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: "+1" - - - name: Commit & push changes - id: commit-and-push - if: steps.pre-commit.outcome == 'failure' - run: | - git config user.email "core@nf-co.re" - git config user.name "nf-core-bot" - git config push.default upstream - git add . - git status - git commit -m "[automated] Fix code linting" - git push - - - name: react if linting errors were fixed - id: react-if-fixed - if: steps.commit-and-push.outcome == 'success' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: hooray - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: confused - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - issue-number: ${{ github.event.issue.number }} - body: | - @${{ github.actor }} I tried to fix the linting errors, but it didn't work. Please fix them manually. - See [CI log](https://github.com/nf-cmgg/preprocessing/actions/runs/${{ github.run_id }}) for more details. diff --git a/.github/workflows/fix_linting.yml b/.github/workflows/fix_linting.yml deleted file mode 100644 index 63b82243..00000000 --- a/.github/workflows/fix_linting.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Fix linting from a comment -on: - issue_comment: - types: [created] - -jobs: - fix-linting: - # Only run if comment is on a PR with the main repo, and if it contains the magic keywords - if: > - contains(github.event.comment.html_url, '/pull/') && - contains(github.event.comment.body, '@nf-core-bot fix linting') && - github.repository == 'nf-cmgg/preprocessing' - runs-on: ubuntu-latest - steps: - # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - token: ${{ secrets.nf_core_bot_auth_token }} - - # indication that the linting is being fixed - - name: React on comment - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: eyes - - # Action runs on the issue comment, so we don't get the PR by default - # Use the gh cli to check out the PR - - name: Checkout Pull Request - run: gh pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} - - # Install and run pre-commit - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 - with: - python-version: "3.14" - - - name: Install pre-commit - run: pip install pre-commit - - - name: Run pre-commit - id: pre-commit - run: pre-commit run --all-files - continue-on-error: true - - # indication that the linting has finished - - name: react if linting finished succesfully - if: steps.pre-commit.outcome == 'success' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: "+1" - - - name: Commit & push changes - id: commit-and-push - if: steps.pre-commit.outcome == 'failure' - run: | - git config user.email "core@nf-co.re" - git config user.name "nf-core-bot" - git config push.default upstream - git add . - git status - git commit -m "[automated] Fix code linting" - git push - - - name: react if linting errors were fixed - id: react-if-fixed - if: steps.commit-and-push.outcome == 'success' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: hooray - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: confused - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - issue-number: ${{ github.event.issue.number }} - body: | - @${{ github.actor }} I tried to fix the linting errors, but it didn't work. Please fix them manually. - See [CI log](https://github.com/nf-cmgg/preprocessing/actions/runs/${{ github.run_id }}) for more details. From 9ebb533815b3826902d3d1f9c19f3bb762f4c1bc Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 09:04:57 +0100 Subject: [PATCH 168/228] calculate checksums for fastq output --- workflows/preprocessing.nf | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index e76ee226..12d4b8b2 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -214,9 +214,14 @@ workflow PREPROCESSING { // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) - FASTP(ch_fastq_per_sample.supported.map { meta, fastq -> - return [meta, fastq, []] - }, false, false, false) + FASTP( + ch_fastq_per_sample.supported.map { meta, fastq -> + return [meta, fastq, []] + }, + false, + false, + false, + ) ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) ch_versions = ch_versions.mix(FASTP.out.versions.first()) @@ -402,9 +407,11 @@ workflow PREPROCESSING { */ MD5SUM( - FASTQ_TO_CRAM.out.cram_crai.map { meta, cram, _crai -> - return [meta, cram] - }, + ch_fastq_per_sample.other.mix( + FASTQ_TO_CRAM.out.cram_crai.map { meta, cram, _crai -> + return [meta, cram] + } + ), false, ) ch_versions = ch_versions.mix(MD5SUM.out.versions.first()) From e5bd5487129a9a1315e70fae760d529e041e56d9 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:03:53 +0100 Subject: [PATCH 169/228] nextflow config lint --- nextflow.config | 272 +++++++++++++++++++------------------------ nextflow_schema.json | 51 -------- 2 files changed, 121 insertions(+), 202 deletions(-) diff --git a/nextflow.config b/nextflow.config index 2beb9d9e..c6205a67 100644 --- a/nextflow.config +++ b/nextflow.config @@ -10,33 +10,33 @@ params { // Input options - input = null + input = null // References - genome = null - igenomes_base = '/references/' - igenomes_ignore = false + genome = null + igenomes_base = '/references/' + igenomes_ignore = false // Analysis options - markdup = 'bamsormadup' - umi_aware = false - skip_trimming = false - split_fastq = 100000000 - trim_front = 0 - trim_tail = 0 - adapter_R1 = null - adapter_R2 = null - run_coverage = true - disable_picard_metrics = false - roi = null - genelists = null + markdup = 'bamsormadup' + umi_aware = false + skip_trimming = false + split_fastq = 100000000 + trim_front = 0 + trim_tail = 0 + adapter_R1 = null + adapter_R2 = null + run_coverage = true + disable_picard_metrics = false + roi = null + genelists = null // MultiQC options - multiqc_config = null - multiqc_title = null - multiqc_logo = null - max_multiqc_email_size = '25.MB' - multiqc_methods_description = null + multiqc_config = null + multiqc_title = null + multiqc_logo = null + max_multiqc_email_size = '25.MB' + multiqc_methods_description = null // Boilerplate options outdir = null @@ -51,28 +51,19 @@ params { show_hidden = false version = false pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' - trace_report_suffix = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') + trace_report_suffix = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') // Config options - config_profile_name = null - config_profile_description = null + config_profile_name = null + config_profile_description = null - custom_config_version = 'master' - custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" - config_profile_contact = null - config_profile_url = null - - // CMGG Config options - cmgg_config_profile_name = null - cmgg_config_profile_description = null - - cmgg_custom_config_version = 'main' - cmgg_custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.cmgg_custom_config_version}" - cmgg_config_profile_contact = null - cmgg_config_profile_url = null + custom_config_version = 'main' + custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.custom_config_version}" + config_profile_contact = null + config_profile_url = null // Schema validation default options - validate_params = true + validate_params = true } // Load base.config by default for all pipelines @@ -83,40 +74,40 @@ includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ profiles { debug { - dumpHashes = true - process.beforeScript = 'echo $HOSTNAME' - cleanup = false + dumpHashes = true + process.beforeScript = 'echo $HOSTNAME' + cleanup = false nextflow.enable.configProcessNamesValidation = true } conda { - conda.enabled = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - conda.channels = ['conda-forge', 'bioconda'] - apptainer.enabled = false + conda.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + conda.channels = ['conda-forge', 'bioconda'] + apptainer.enabled = false } mamba { - conda.enabled = true - conda.useMamba = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + conda.enabled = true + conda.useMamba = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } docker { - docker.enabled = true - conda.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false - docker.runOptions = '-u $(id -u):$(id -g)' + docker.enabled = true + conda.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + docker.runOptions = '-u $(id -u):$(id -g)' } arm64 { process.arch = 'arm64' @@ -130,54 +121,54 @@ profiles { wave.strategy = 'conda,container' } emulate_amd64 { - docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' } singularity { - singularity.enabled = true - singularity.autoMounts = true - conda.enabled = false - docker.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + singularity.enabled = true + singularity.autoMounts = true + conda.enabled = false + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } podman { - podman.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + podman.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } shifter { - shifter.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + shifter.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } charliecloud { - charliecloud.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - apptainer.enabled = false + charliecloud.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + apptainer.enabled = false } apptainer { - apptainer.enabled = true - apptainer.autoMounts = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false + apptainer.enabled = true + apptainer.autoMounts = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false } wave { apptainer.ociAutoPull = true @@ -187,12 +178,16 @@ profiles { wave.strategy = 'conda,container' } gpu { - docker.runOptions = '-u $(id -u):$(id -g) --gpus all' - apptainer.runOptions = '--nv' - singularity.runOptions = '--nv' + docker.runOptions = '-u $(id -u):$(id -g) --gpus all' + apptainer.runOptions = '--nv' + singularity.runOptions = '--nv' + } + test { + includeConfig 'conf/test.config' + } + test_full { + includeConfig 'conf/test_full.config' } - test { includeConfig 'conf/test.config' } - test_full { includeConfig 'conf/test_full.config' } } // Load nf-core custom profiles from different institutions @@ -203,19 +198,15 @@ includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !pa // Load nf-cmgg/preprocessing custom profiles from different institutions. -// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs -// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" - -// Load nf-cmgg/preprocessing custom profiles from nf-cmgg/configs. -includeConfig params.cmgg_custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.cmgg_custom_config_base.startsWith('http')) ? "${params.cmgg_custom_config_base}/pipeline/preprocessing.config" : "/dev/null" +includeConfig params.custom_config_base && params.custom_config_base.contains('nf-cmgg') && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled // Set to your registry if you have a mirror of containers -apptainer.registry = 'quay.io' -docker.registry = 'quay.io' -podman.registry = 'quay.io' -singularity.registry = 'quay.io' +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' charliecloud.registry = 'quay.io' // Export these variables to prevent local Python/R libraries from conflicting with those in the container @@ -230,58 +221,37 @@ env { } // Set bash options -process.shell = [ - "bash", - "-C", // No clobber - prevent output redirection from overwriting files. - "-e", // Exit if a tool returns a non-zero status/exit code - "-u", // Treat unset variables and parameters as an error - "-o", // Returns the status of the last command to exit.. - "pipefail" // ..with a non-zero status or zero if all successfully execute -] +process.shell = ["bash", "-C", "-e", "-u", "-o", "pipefail"] // Disable process selector warnings by default. Use debug profile to enable warnings. nextflow.enable.configProcessNamesValidation = false timeline { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/execution_timeline_${params.trace_report_suffix}.html" + file = "${params.outdir}/pipeline_info/execution_timeline_${params.trace_report_suffix}.html" } report { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/execution_report_${params.trace_report_suffix}.html" + file = "${params.outdir}/pipeline_info/execution_report_${params.trace_report_suffix}.html" } trace { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt" + file = "${params.outdir}/pipeline_info/execution_trace_${params.trace_report_suffix}.txt" } dag { - enabled = true + enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" } manifest { name = 'nf-cmgg/preprocessing' contributors = [ - [ - name: 'Matthias De Smet', - affiliation: 'Center for Medical Genetics Ghent, Ghent University, Belgium', - email: 'matthias.desmet@ugent.be', - github: '@matthdsm', - contribution: ["author","maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: 'https://orcid.org/0000-0003-2555-3114' - ], - [ - name: ' Nicolas Vannieuwkerke', - affiliation: 'Center for Medical Genetics Ghent, Ghent University Hospital, Belgium', - email: 'nicolas.vannieuwkerke@ugent.be', - github: '@nvnieuwk', - contribution: ["maintainer"], // List of contribution types ('author', 'maintainer' or 'contributor') - orcid: 'https://orcid.org/0009-0003-5619-1555' - ], + [name: 'Matthias De Smet', affiliation: 'Center for Medical Genetics Ghent, Ghent University, Belgium', email: 'matthias.desmet@ugent.be', github: '@matthdsm', contribution: ["author", "maintainer"], orcid: 'https://orcid.org/0000-0003-2555-3114'], + [name: ' Nicolas Vannieuwkerke', affiliation: 'Center for Medical Genetics Ghent, Ghent University Hospital, Belgium', email: 'nicolas.vannieuwkerke@ugent.be', github: '@nvnieuwk', contribution: ["maintainer"], orcid: 'https://orcid.org/0009-0003-5619-1555'], ] homePage = 'https://github.com/nf-cmgg/preprocessing' description = """Demultiplexing, adapter trimming, alignment, and coverage calculation for NGS data.""" @@ -294,12 +264,12 @@ manifest { // Nextflow plugins plugins { - id 'nf-schema@2.6.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.6.1' } validation { defaultIgnoreParams = ["genomes"] - monochromeLogs = params.monochrome_logs + monochromeLogs = params.monochrome_logs } // Load modules.config for DSL2 module specific options diff --git a/nextflow_schema.json b/nextflow_schema.json index 63d39f34..19a00a3f 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -174,54 +174,6 @@ } } }, - "cmgg_institutional_config_options": { - "title": "nf-cmgg config options", - "type": "object", - "fa_icon": "fas fa-university", - "description": "Parameters used to describe centralised config profiles. These should not be edited.", - "help_text": "The centralised nf-cmgg configuration profiles use a handful of pipeline parameters to describe themselves. This information is then printed to the Nextflow log when you run a pipeline. You should not need to change these values when you run a pipeline.", - "properties": { - "cmgg_custom_config_version": { - "type": "string", - "description": "Git commit id for nf-cmgg configs.", - "default": "master", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_custom_config_base": { - "type": "string", - "description": "Base directory for nf-cmgg configs.", - "default": "https://raw.githubusercontent.com/nf-cmgg/configs/master", - "hidden": true, - "help_text": "If you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.", - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_name": { - "type": "string", - "description": "nf-cmgg config name.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_description": { - "type": "string", - "description": "nf-cmgg config description.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_contact": { - "type": "string", - "description": "nf-cmgg config contact information.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_url": { - "type": "string", - "description": "nf-cmgg config URL link.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - } - } - }, "generic_options": { "title": "Generic options", "type": "object", @@ -363,9 +315,6 @@ { "$ref": "#/$defs/institutional_config_options" }, - { - "$ref": "#/$defs/cmgg_institutional_config_options" - }, { "$ref": "#/$defs/generic_options" } From 78e0750ad6dcf296a76c297e4b0f10166c130a72 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 11:49:18 +0100 Subject: [PATCH 170/228] fix tests --- conf/modules.config | 3 ++ .../nf-core/picard/collecthsmetrics/main.nf | 5 +-- .../picard/collectmultiplemetrics/main.nf | 2 ++ .../nf-core/picard/collectwgsmetrics/main.nf | 2 ++ subworkflows/local/coverage/main.nf | 10 +++--- tests/config/igenomes_test.config | 1 + .../local/fastq_align_rna/main.nf.test.snap | 2 +- .../fastq_to_aligned_cram/main.nf.test.snap | 32 +++++++++---------- 8 files changed, 32 insertions(+), 25 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 36734a8a..07ea1623 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -305,4 +305,7 @@ env { MOSDEPTH_Q0 = 'NO_COVERAGE' MOSDEPTH_Q1 = 'LOW_COVERAGE' MOSDEPTH_Q2 = 'CALLABLE' + + // Set TMPDIR for all modules + TMPDIR = "$PWD" } diff --git a/modules/nf-core/picard/collecthsmetrics/main.nf b/modules/nf-core/picard/collecthsmetrics/main.nf index a1dc56d8..914ae62c 100644 --- a/modules/nf-core/picard/collecthsmetrics/main.nf +++ b/modules/nf-core/picard/collecthsmetrics/main.nf @@ -45,6 +45,7 @@ process PICARD_COLLECTHSMETRICS { """ + export TMP=\$PWD $bait_intervallist_cmd $target_intervallist_cmd @@ -57,8 +58,8 @@ process PICARD_COLLECTHSMETRICS { --BAIT_INTERVALS $bait_interval_list \\ --TARGET_INTERVALS $target_interval_list \\ --INPUT $bam \\ - --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics - + --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics \\ + --TMP_DIR . cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index e4d74998..b1a45737 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -29,12 +29,14 @@ process PICARD_COLLECTMULTIPLEMETRICS { avail_mem = (task.memory.mega*0.8).intValue() } """ + export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectMultipleMetrics \\ $args \\ --INPUT $bam \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ + --TMP_DIR . \\ $reference cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/picard/collectwgsmetrics/main.nf b/modules/nf-core/picard/collectwgsmetrics/main.nf index cd4a7711..bd8d5b5f 100644 --- a/modules/nf-core/picard/collectwgsmetrics/main.nf +++ b/modules/nf-core/picard/collectwgsmetrics/main.nf @@ -29,6 +29,7 @@ process PICARD_COLLECTWGSMETRICS { avail_mem = (task.memory.mega*0.8).intValue() } """ + export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectWgsMetrics \\ @@ -36,6 +37,7 @@ process PICARD_COLLECTWGSMETRICS { --INPUT $bam \\ --OUTPUT ${prefix}.CollectWgsMetrics.coverage_metrics \\ --REFERENCE_SEQUENCE ${fasta} \\ + --TMP_DIR . \\ $interval diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 27a19c43..58e76db6 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -34,13 +34,11 @@ workflow COVERAGE { PANELCOVERAGE( MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> - if (genelists !instanceof List) { - // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... - genelists = [genelists] - } + // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... + def genelists_array = genelists !instanceof List ? [genelists] : genelists def filtered_genelists = meta.tag.toLowerCase() == "seqcap" - ? genelists.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } - : genelists.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } + ? genelists_array.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } + : genelists_array.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } if (filtered_genelists.size() > 0) { return [ diff --git a/tests/config/igenomes_test.config b/tests/config/igenomes_test.config index 80984075..74154eec 100644 --- a/tests/config/igenomes_test.config +++ b/tests/config/igenomes_test.config @@ -9,6 +9,7 @@ params { gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" } } + genelists = null } aws { diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index 2cd3d63c..cf11ffe9 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -119,4 +119,4 @@ }, "timestamp": "2024-05-28T16:17:08.089796673" } -} +} \ No newline at end of file diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index aabf04cd..1714e2fb 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -3,7 +3,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -25,13 +25,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ], "versions": [ "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", @@ -49,7 +49,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -71,10 +71,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -112,7 +112,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -134,10 +134,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -174,7 +174,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -269,7 +269,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -291,13 +291,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ], "versions": [ "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", @@ -311,4 +311,4 @@ }, "timestamp": "2025-12-17T14:51:22.925873858" } -} +} \ No newline at end of file From d5e139208c0a63affa44e149513e8921266c96ed Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 11:50:33 +0100 Subject: [PATCH 171/228] module patches --- .../picard-collecthsmetrics.diff | 18 +++++++++++++++++- .../picard-collectmultiplemetrics.diff | 15 +++++++++++++++ .../picard-collectwgsmetrics.diff | 16 ++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff index 5907d093..1407a35a 100644 --- a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff +++ b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff @@ -26,7 +26,7 @@ Changes in 'picard/collecthsmetrics/main.nf': def avail_mem = 3072 if (!task.memory) { -@@ -37,14 +33,14 @@ +@@ -37,18 +33,19 @@ def bait_intervallist_cmd = "" if (bait_intervals =~ /.(bed|bed.gz)$/){ bait_interval_list = bait_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") @@ -43,6 +43,22 @@ Changes in 'picard/collecthsmetrics/main.nf': } + """ ++ export TMP=\$PWD + + $bait_intervallist_cmd + $target_intervallist_cmd +@@ -61,8 +58,8 @@ + --BAIT_INTERVALS $bait_interval_list \\ + --TARGET_INTERVALS $target_interval_list \\ + --INPUT $bam \\ +- --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics +- ++ --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics \\ ++ --TMP_DIR . + + cat <<-END_VERSIONS > versions.yml + "${task.process}": 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff index 489076fb..d4fbba56 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff +++ b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff @@ -15,6 +15,21 @@ Changes in 'picard/collectmultiplemetrics/main.nf': output: tuple val(meta), path("*_metrics"), emit: metrics +@@ -31,12 +29,14 @@ + avail_mem = (task.memory.mega*0.8).intValue() + } + """ ++ export TMP=\$PWD + picard \\ + -Xmx${avail_mem}M \\ + CollectMultipleMetrics \\ + $args \\ + --INPUT $bam \\ + --OUTPUT ${prefix}.CollectMultipleMetrics \\ ++ --TMP_DIR . \\ + $reference + + cat <<-END_VERSIONS > versions.yml 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff index bf843c60..04fea62a 100644 --- a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff +++ b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff @@ -15,6 +15,22 @@ Changes in 'picard/collectwgsmetrics/main.nf': path intervallist output: +@@ -31,6 +29,7 @@ + avail_mem = (task.memory.mega*0.8).intValue() + } + """ ++ export TMP=\$PWD + picard \\ + -Xmx${avail_mem}M \\ + CollectWgsMetrics \\ +@@ -38,6 +37,7 @@ + --INPUT $bam \\ + --OUTPUT ${prefix}.CollectWgsMetrics.coverage_metrics \\ + --REFERENCE_SEQUENCE ${fasta} \\ ++ --TMP_DIR . \\ + $interval + + 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test' is unchanged From 35dec2c82d66e17b3306235364d9469d435064c9 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 12:26:28 +0100 Subject: [PATCH 172/228] fix snapshot --- tests/workflows/preprocessing.nf.test.snap | 36 ++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 0bdfd83c..d40bc343 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -44,6 +44,12 @@ ], "demultiplex_reports": [ + ], + "falco_html": [ + + ], + "falco_txt": [ + ], "fastp_html": [ [ @@ -394,7 +400,7 @@ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -670,9 +676,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-23T13:59:59.404732" + "timestamp": "2026-02-11T12:00:40.443933" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -719,6 +725,12 @@ ], "demultiplex_reports": [ + ], + "falco_html": [ + + ], + "falco_txt": [ + ], "fastp_html": [ [ @@ -853,7 +865,7 @@ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -1019,9 +1031,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-23T14:06:35.503463" + "timestamp": "2026-02-11T12:11:20.398961" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1067,6 +1079,12 @@ ], "demultiplex_reports": [ + ], + "falco_html": [ + + ], + "falco_txt": [ + ], "fastp_html": [ [ @@ -1336,7 +1354,7 @@ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -1604,8 +1622,8 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-23T14:04:00.643521" + "timestamp": "2026-02-11T12:06:12.331519" } } \ No newline at end of file From 78b9e050f7bd558e08cb76359a5e2a80099fe943 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:08:18 +0100 Subject: [PATCH 173/228] fix coverage issues --- conf/base.config | 38 ++++---- conf/modules.config | 66 +++++++------- conf/test_full.config | 4 +- nf-test.config | 12 +-- subworkflows/local/bam_qc/main.nf | 18 ++-- subworkflows/local/coverage/main.nf | 17 ++-- subworkflows/local/fastq_align_rna/main.nf | 19 ++-- .../local/fastq_to_aligned_cram/main.nf | 14 +-- .../main.nf | 87 ++++++++----------- tests/config/igenomes_test.config | 14 +-- .../subworkflows/local/coverage/main.nf.test | 10 +-- .../local/coverage/main.nf.test.snap | 38 ++++++-- workflows/preprocessing.nf | 3 +- 13 files changed, 174 insertions(+), 166 deletions(-) diff --git a/conf/base.config b/conf/base.config index ff798214..ac353851 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,41 +10,41 @@ process { - cpus = { 1 * task.attempt } - memory = { 8.GB * task.attempt } - time = { 4.h * task.attempt } + cpus = { 1 * task.attempt } + memory = { 8.GB * task.attempt } + time = { 4.h * task.attempt } errorStrategy = { task.exitStatus in ((130..145) + 104 + 175 + 50001 + 50002 + 50003 + 50004 + 50005 + 50006) ? 'retry' : 'finish' } maxRetries = 3 maxErrors = '-1' // Process-specific resource requirements - withLabel:process_single { - cpus = { 1 } + withLabel: process_single { + cpus = { 1 } memory = { 8.GB * task.attempt } - time = { 4.h * task.attempt } + time = { 4.h * task.attempt } } - withLabel:process_low { - cpus = { 2 * task.attempt } + withLabel: process_low { + cpus = { 2 * task.attempt } memory = { 16.GB * task.attempt } - time = { 4.h * task.attempt } + time = { 4.h * task.attempt } } - withLabel:process_medium { - cpus = { 8 * task.attempt } + withLabel: process_medium { + cpus = { 8 * task.attempt } memory = { 64.GB * task.attempt } - time = { 8.h * task.attempt } + time = { 8.h * task.attempt } } - withLabel:process_high { - cpus = { 16 * task.attempt } + withLabel: process_high { + cpus = { 16 * task.attempt } memory = { 128.GB * task.attempt } - time = { 16.h * task.attempt } + time = { 16.h * task.attempt } } - withLabel:process_long { - time = { 20.h * task.attempt } + withLabel: process_long { + time = { 20.h * task.attempt } } - withLabel:error_ignore { + withLabel: error_ignore { errorStrategy = 'ignore' } - withLabel:error_retry { + withLabel: error_retry { errorStrategy = 'retry' maxRetries = 2 } diff --git a/conf/modules.config b/conf/modules.config index 07ea1623..a284297f 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -14,9 +14,9 @@ process { // BCL convert withName: '.*BCL_DEMULTIPLEX:BCLCONVERT' { - cpus = 16 - memory = { 64.GB * task.attempt } - ext.args = { + cpus = 16 + memory = { 64.GB * task.attempt } + ext.args = { [ meta.lane ? "--bcl-only-lane ${meta.lane}" : "", "--force", @@ -27,16 +27,16 @@ process { // FastP withName: '.*FASTP' { - cpus = 4 - memory = { 4.GB * task.attempt } - ext.args = { + cpus = 4 + memory = { 4.GB * task.attempt } + ext.args = { [ - params.split_fastq > 0 ? "--split_by_lines ${params.split_fastq * 4}" : '', - params.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", - params.trim_front > 0 ? "--trim_front1 ${params.trim_front}" : "", - params.trim_tail > 0 ? "--trim_tail1 ${params.trim_tail}" : "", - params.adapter_R1 ? "--adapter_sequence ${params.adapter_R1}" : "", - params.adapter_R2 ? "--adapter_sequence_r2 ${params.adapter_R2}" : "", + params.split_fastq > 0 ? "--split_by_lines ${params.split_fastq * 4}" : '', + params.skip_trimming ? "--disable_adapter_trimming" : "--detect_adapter_for_pe", + params.trim_front > 0 ? "--trim_front1 ${params.trim_front}" : "", + params.trim_tail > 0 ? "--trim_tail1 ${params.trim_tail}" : "", + params.adapter_R1 ? "--adapter_sequence ${params.adapter_R1}" : "", + params.adapter_R2 ? "--adapter_sequence_r2 ${params.adapter_R2}" : "", "--compression 1", ].join(" ").trim() } @@ -57,7 +57,7 @@ process { withName: '.*FASTQ_ALIGN_DNA:BOWTIE2_ALIGN' { cpus = 16 memory = 32.GB - ext.args = { + ext.args = { [ "--local", "--fast-local", @@ -65,7 +65,7 @@ process { meta.readgroup ? "--rg " + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join(" --rg ") : "", ].join(" ").trim() } - ext.args2 = "--fast" + ext.args2 = "--fast" } //// BWA mem/BWA mem2 @@ -90,9 +90,7 @@ process { cpus = 16 memory = 32.GB ext.args = { - [ - meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : "" - ].join(" ").trim() + [meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : ""].join(" ").trim() } ext.args2 = "--fast" } @@ -107,8 +105,8 @@ process { //// SNAP withName: '.*FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { - cpus = 16 - memory = 64.GB + cpus = 16 + memory = 64.GB ext.args = { [ "-b-", @@ -125,8 +123,8 @@ process { //// STROBEALIGN withName: '.*FASTQ_ALIGN_DNA:STROBEALIGN' { - cpus = 16 - memory = 32.GB + cpus = 16 + memory = 32.GB ext.args = { [ meta.readgroup ? "--rg-id ${meta.readgroup.ID}" : "", @@ -139,9 +137,9 @@ process { //// STAR withName: '.*FASTQ_ALIGN_RNA:STAR_ALIGN' { ext.prefix = { "${meta.id}.star" } - cpus = 16 - memory = 64.GB - ext.args = { + cpus = 16 + memory = 64.GB + ext.args = { [ "--readFilesCommand gunzip -c", "--twopassMode Basic", @@ -222,9 +220,9 @@ process { //// Samtools convert withName: '.*FASTQ_TO_CRAM:SAMTOOLS_CONVERT' { - cpus = 8 - memory = 8.GB - ext.args = { + cpus = 8 + memory = 8.GB + ext.args = { [ "-C", "--output-fmt cram,version=3.0", @@ -247,15 +245,15 @@ process { //// Samtools coverage withName: '.*COVERAGE:SAMTOOLS_COVERAGE' { - cpus = 1 - memory = 1.GB + cpus = 1 + memory = 1.GB ext.prefix = { "${meta.id}.coverage" } } // QC withName: '.*BAM_QC:SAMTOOLS_.*$' { - cpus = 1 + cpus = 1 memory = 1.GB } @@ -267,15 +265,15 @@ process { } withName: '.*MD5SUM' { - cpus = 1 + cpus = 1 memory = 128.MB } // MultiQC withName: '.*MULTIQC_.*$' { container = "cmgg/multiqc_cmgg:0.0.2-multiqc-v1.33" - cpus = 1 - memory = 4.GB + cpus = 1 + memory = 4.GB } withName: '.*MULTIQC_MAIN' { ext.prefix = { params.multiqc_title ? params.multiqc_title : "multiqc" } @@ -307,5 +305,5 @@ env { MOSDEPTH_Q2 = 'CALLABLE' // Set TMPDIR for all modules - TMPDIR = "$PWD" + TMPDIR = "\$PWD" } diff --git a/conf/test_full.config b/conf/test_full.config index 6225119a..bad1c6f1 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -17,8 +17,8 @@ params { // Input data for full size test // TODO nf-core: Specify the paths to your full test data ( on nf-core/test-datasets or directly in repositories, e.g. SRA) // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' // Genome references - genome = 'R64-1-1' + genome = 'R64-1-1' } diff --git a/nf-test.config b/nf-test.config index fa368ccb..c5d343b4 100644 --- a/nf-test.config +++ b/nf-test.config @@ -1,21 +1,21 @@ config { // location for all nf-test tests - testsDir "." + testsDir = "." // nf-test directory including temporary files for each test - workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + workDir = System.getenv("NFT_WORKDIR") ?: ".nf-test" // location of an optional nextflow.config file specific for executing tests - configFile "tests/nextflow.config" + configFile = "tests/nextflow.config" // ignore tests coming from the nf-core/modules repo - ignore 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*' + ignore = ['modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*'] // run all test with defined profile(s) from the main nextflow.config - profile "test" + profile = "test" // list of filenames or patterns that should be trigger a full test run - triggers 'nextflow.config', 'nf-test.config', 'conf/test.config', 'tests/nextflow.config', 'tests/.nftignore' + triggers = ['nextflow.config', 'nf-test.config', 'conf/test.config', 'tests/nextflow.config', 'tests/.nftignore'] // load the necessary plugins plugins { diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index e35555a8..1f20203d 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -11,7 +11,7 @@ include { PICARD_COLLECTWGSMETRICS } from '../../../modules/nf-core/picard/ workflow BAM_QC { take: ch_bam_bai_roi_fasta_fai_dict // channel: [ val(meta), path(bam), path(bai), path(roi), path(fasta), path(fai), path(dict)] - disable_picard // boolean + disable_picard // boolean main: ch_versions = channel.empty() @@ -72,12 +72,12 @@ workflow BAM_QC { } emit: - samtools_stats = SAMTOOLS_STATS.out.stats - samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat - samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats - picard_multiplemetrics = ch_picard_multiplemetrics - picard_multiplemetrics_pdf = ch_picard_multiplemetrics_pdf - picard_wgsmetrics = ch_picard_wgsmetrics - picard_hsmetrics = ch_picard_hsmetrics - versions = ch_versions + samtools_stats = SAMTOOLS_STATS.out.stats + samtools_flagstat = SAMTOOLS_FLAGSTAT.out.flagstat + samtools_idxstats = SAMTOOLS_IDXSTATS.out.idxstats + picard_multiplemetrics = ch_picard_multiplemetrics + picard_multiplemetrics_pdf = ch_picard_multiplemetrics_pdf + picard_wgsmetrics = ch_picard_wgsmetrics + picard_hsmetrics = ch_picard_hsmetrics + versions = ch_versions } diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 58e76db6..a3959d84 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -13,7 +13,6 @@ workflow COVERAGE { main: ch_versions = channel.empty() - ch_coverageqc_files = channel.empty() MOSDEPTH( ch_meta_cram_crai_fasta_fai_roi.map { meta, cram, crai, fasta, _fai, roi -> @@ -28,17 +27,18 @@ workflow COVERAGE { } ) ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) - ch_coverageqc_files = ch_coverageqc_files.merge(SAMTOOLS_COVERAGE.out.coverage) - - ch_genelists.view() PANELCOVERAGE( - MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> + MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists) + .view() + .map { meta, bed, index, genelists -> // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... - def genelists_array = genelists !instanceof List ? [genelists] : genelists + if (genelists !instanceof List) { + genelists = [genelists] + } def filtered_genelists = meta.tag.toLowerCase() == "seqcap" - ? genelists_array.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } - : genelists_array.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } + ? genelists.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } + : genelists.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } if (filtered_genelists.size() > 0) { return [ @@ -51,7 +51,6 @@ workflow COVERAGE { } ) ch_versions = ch_versions.mix(PANELCOVERAGE.out.versions.first()) - ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) emit: mosdepth_global = MOSDEPTH.out.global_txt diff --git a/subworkflows/local/fastq_align_rna/main.nf b/subworkflows/local/fastq_align_rna/main.nf index ce0d6862..1ca27833 100644 --- a/subworkflows/local/fastq_align_rna/main.nf +++ b/subworkflows/local/fastq_align_rna/main.nf @@ -5,9 +5,9 @@ // -include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" -include { GNU_SORT as SORT_MERGE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" -include { GNU_SORT as SORT_MERGE_SPLICE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" +include { STAR_ALIGN } from "../../../modules/nf-core/star/align/main.nf" +include { GNU_SORT as SORT_MERGE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" +include { GNU_SORT as SORT_MERGE_SPLICE_JUNCTIONS } from "../../../modules/nf-core/gnu/sort/main.nf" workflow FASTQ_ALIGN_RNA { take: @@ -55,15 +55,16 @@ workflow FASTQ_ALIGN_RNA { ch_versions = ch_versions.mix(SORT_MERGE_JUNCTIONS.out.versions.first()) emit: - bam = ch_bam // channel: [ [meta], bam ] - splice_junctions = SORT_MERGE_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] - junctions = SORT_MERGE_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] - reports = ch_reports // channel: [ [meta], log ] - versions = ch_versions // channel: [ versions.yml ] + bam = ch_bam // channel: [ [meta], bam ] + splice_junctions = SORT_MERGE_SPLICE_JUNCTIONS.out.sorted // channel: [ [meta], splice_junctions ] + junctions = SORT_MERGE_JUNCTIONS.out.sorted // channel: [ [meta], junctions ] + reports = ch_reports // channel: [ [meta], log ] + versions = ch_versions // channel: [ versions.yml ] } def group_junctions(ch) { - return ch.map { meta, files -> + return ch + .map { meta, files -> def gk = (meta.chunks as Integer ?: 1) return [ groupKey( diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 1460d083..1e4a23fb 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -20,7 +20,7 @@ include { getGenomeAttribute } from '../../local/utils_nfcore_preprocessing_p workflow FASTQ_TO_CRAM { take: ch_meta_reads_aligner_index_fasta_gtf // channel: [mandatory] [meta, [fastq, ...], aligner [bowtie2, bwamem, bwamem2, dragmap, snap, star], aligner_index, fasta, gtf] - markdup // string: [optional ] markdup [bamsormadup, samtools, false] + markdup // string: [optional ] markdup [bamsormadup, samtools, false] main: @@ -151,10 +151,10 @@ workflow FASTQ_TO_CRAM { ch_cram_crai.dump(tag: "FASTQ_TO_CRAM: cram and crai", pretty: true) emit: - cram_crai = ch_cram_crai - rna_splice_junctions = FASTQ_ALIGN_RNA.out.splice_junctions - rna_junctions = FASTQ_ALIGN_RNA.out.junctions - sormadup_metrics = ch_sormadup_metrics - align_reports = FASTQ_ALIGN_DNA.out.reports - versions = ch_versions + cram_crai = ch_cram_crai + rna_splice_junctions = FASTQ_ALIGN_RNA.out.splice_junctions + rna_junctions = FASTQ_ALIGN_RNA.out.junctions + sormadup_metrics = ch_sormadup_metrics + align_reports = FASTQ_ALIGN_DNA.out.reports + versions = ch_versions } diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf index c66aaf01..16fc49ab 100644 --- a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -8,15 +8,15 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { samplesheetToList } from 'plugin/nf-schema' -include { paramsHelp } from 'plugin/nf-schema' -include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' -include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' +include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { imNotification } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -25,16 +25,15 @@ include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipelin */ workflow PIPELINE_INITIALISATION { - take: - version // boolean: Display version and exit - validate_params // boolean: Boolean whether to validate parameters against the schema at runtime + version // boolean: Display version and exit + validate_params // boolean: Boolean whether to validate parameters against the schema at runtime nextflow_cli_args // array: List of positional nextflow CLI args - outdir // string: The output directory where the results will be saved - input // string: Path to input samplesheet - help // boolean: Display help message and exit - help_full // boolean: Show the full help message - show_hidden // boolean: Show hidden parameters in the help message + outdir // string: The output directory where the results will be saved + input // string: Path to input samplesheet + help // boolean: Display help message and exit + help_full // boolean: Show the full help message + show_hidden // boolean: Show hidden parameters in the help message main: @@ -43,11 +42,11 @@ workflow PIPELINE_INITIALISATION { // // Print version and exit if required and dump pipeline parameters to JSON file // - UTILS_NEXTFLOW_PIPELINE ( + UTILS_NEXTFLOW_PIPELINE( version, true, outdir, - workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 + workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1, ) // @@ -55,7 +54,7 @@ workflow PIPELINE_INITIALISATION { // command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir " - UTILS_NFSCHEMA_PLUGIN ( + UTILS_NFSCHEMA_PLUGIN( workflow, validate_params, null, @@ -64,13 +63,13 @@ workflow PIPELINE_INITIALISATION { show_hidden, "", "", - command + command, ) // // Check config provided to the pipeline // - UTILS_NFCORE_PIPELINE ( + UTILS_NFCORE_PIPELINE( nextflow_cli_args ) @@ -97,15 +96,14 @@ workflow PIPELINE_INITIALISATION { */ workflow PIPELINE_COMPLETION { - take: - email // string: email address - email_on_fail // string: email address sent on pipeline failure + email // string: email address + email_on_fail // string: email address sent on pipeline failure plaintext_email // boolean: Send plain-text email instead of HTML - outdir // path: Path to output directory where results will be published + outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output - hook_url // string: hook URL for notifications - multiqc_report // string: Path to MultiQC report + hook_url // string: hook URL for notifications + multiqc_report // string: Path to MultiQC report main: summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") @@ -134,7 +132,7 @@ workflow PIPELINE_COMPLETION { } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error("Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting") } } @@ -157,19 +155,19 @@ def validateInputSamplesheet(input) { def (metas, fastqs) = input[1..2] // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end - def endedness_ok = metas.collect{ meta -> meta.single_end }.unique().size == 1 + def endedness_ok = metas.collect { meta -> meta.single_end }.unique().size == 1 if (!endedness_ok) { error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") } - return [ metas[0], fastqs ] + return [metas[0], fastqs] } // // Get attribute from genome config file e.g. fasta // def getGenomeAttribute(genomes, attribute) { if (genomes && genomes.containsKey(attribute)) { - return genomes[ attribute ] + return genomes[attribute] } return null } @@ -179,11 +177,7 @@ def getGenomeAttribute(genomes, attribute) { // def genomeExistsError() { if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + - " Currently, the available genome keys are:\n" + - " ${params.genomes.keySet().join(", ")}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + " Currently, the available genome keys are:\n" + " ${params.genomes.keySet().join(", ")}\n" + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" error(error_string) } } @@ -194,12 +188,7 @@ def toolCitationText() { // TODO nf-core: Optionally add in-text citation tools to this list. // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", // Uncomment function in methodsDescriptionText to render in MultiQC report - def citation_text = [ - "Tools used in the workflow included:", - "FastQC (Andrews 2010),", - "MultiQC (Ewels et al. 2016)", - "." - ].join(' ').trim() + def citation_text = ["Tools used in the workflow included:", "FastQC (Andrews 2010),", "MultiQC (Ewels et al. 2016)", "."].join(' ').trim() return citation_text } @@ -208,10 +197,7 @@ def toolBibliographyText() { // TODO nf-core: Optionally add bibliographic entries to this list. // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", // Uncomment function in methodsDescriptionText to render in MultiQC report - def reference_text = [ - "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", - "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " - ].join(' ').trim() + def reference_text = ["
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • "].join(' ').trim() return reference_text } @@ -233,7 +219,10 @@ def methodsDescriptionText(mqc_methods_yaml) { temp_doi_ref += "(doi: ${doi_ref.replace("https://doi.org/", "").replace(" ", "")}), " } meta["doi_text"] = temp_doi_ref.substring(0, temp_doi_ref.length() - 2) - } else meta["doi_text"] = "" + } + else { + meta["doi_text"] = "" + } meta["nodoi_text"] = meta.manifest_map.doi ? "" : "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " // Tool references @@ -247,7 +236,7 @@ def methodsDescriptionText(mqc_methods_yaml) { def methods_text = mqc_methods_yaml.text - def engine = new groovy.text.SimpleTemplateEngine() + def engine = new groovy.text.SimpleTemplateEngine() def description_html = engine.createTemplate(methods_text).make(meta) return description_html.toString() diff --git a/tests/config/igenomes_test.config b/tests/config/igenomes_test.config index 74154eec..cac18b9e 100644 --- a/tests/config/igenomes_test.config +++ b/tests/config/igenomes_test.config @@ -1,15 +1,15 @@ params { genomes { GRCh38 { - bwamem = "s3://test-data/genomics/homo_sapiens/genome/bwa/" - dict = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict" - fai = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - fasta = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" - star = "s3://test-data/genomics/homo_sapiens/genome/star/" - gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + bwamem = "s3://test-data/genomics/homo_sapiens/genome/bwa/" + dict = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict" + fai = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + fasta = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + star = "s3://test-data/genomics/homo_sapiens/genome/star/" + gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + genelists = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" } } - genelists = null } aws { diff --git a/tests/subworkflows/local/coverage/main.nf.test b/tests/subworkflows/local/coverage/main.nf.test index 8792b87c..7b90545d 100644 --- a/tests/subworkflows/local/coverage/main.nf.test +++ b/tests/subworkflows/local/coverage/main.nf.test @@ -23,9 +23,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - input[1] = Channel.value([ - file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) - ]) + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" + input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } @@ -52,9 +51,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - input[1] = Channel.value([ - file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) - ]) + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" + input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 4df77336..7bd91330 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -45,7 +45,10 @@ "single_end": false, "tag": "WES" }, - "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" + [ + "test_Treatable_ID_per_exon.mosdepth.region.dist.txt:md5,6c2b5237d98e0a2f118a3553c2ba478e", + "test_bladder_cancer_per_exon.mosdepth.region.dist.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "14": [ @@ -232,7 +235,10 @@ "single_end": false, "tag": "WES" }, - "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" + [ + "test_Treatable_ID_per_exon.mosdepth.region.dist.txt:md5,6c2b5237d98e0a2f118a3553c2ba478e", + "test_bladder_cancer_per_exon.mosdepth.region.dist.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "samtools_coverage": [ @@ -254,9 +260,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-09T12:02:48.263146" + "timestamp": "2026-02-11T14:05:13.106828" }, "Coverage - seqcap": { "content": [ @@ -298,10 +304,18 @@ ] ], "13": [ - + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test_seqcap_Connective_tissue_per_exon.mosdepth.region.dist.txt:md5,e098c901acb1da8c2cf64a248306e71c" + ] ], "14": [ "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", + "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ], "2": [ @@ -477,7 +491,14 @@ ], "panelcoverage": [ - + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test_seqcap_Connective_tissue_per_exon.mosdepth.region.dist.txt:md5,e098c901acb1da8c2cf64a248306e71c" + ] ], "samtools_coverage": [ [ @@ -491,14 +512,15 @@ ], "versions": [ "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", + "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-09T12:02:26.604953" + "timestamp": "2026-02-11T13:54:02.513877" } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 12d4b8b2..8bf03814 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -59,7 +59,8 @@ workflow PREPROCESSING { roi = roi ? file(roi, checkIfExists: true) : null - genelists = genelists ? channel.value(file(genelists + "/*.bed", checkIfExists: true)) : channel.empty() + // construct a value channel containing an array of files, because the coverage subworkflow expects a channel of arrays of genelist files (to allow for multiple genelist files per sample) + ch_genelists = genelists ? channel.fromPath(genelists).collect().map { files -> [ files ] } : channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From c5e10a3082783deccf24fd15d8b7332832d94ef2 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:05:33 +0100 Subject: [PATCH 174/228] fix genelist path parsing --- tests/subworkflows/local/coverage/main.nf.test | 8 ++++---- workflows/preprocessing.nf | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/subworkflows/local/coverage/main.nf.test b/tests/subworkflows/local/coverage/main.nf.test index 7b90545d..c13bd512 100644 --- a/tests/subworkflows/local/coverage/main.nf.test +++ b/tests/subworkflows/local/coverage/main.nf.test @@ -23,8 +23,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" - input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists" + input[1] = channel.fromPath(genelists_path + "/*.bed").collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } @@ -51,8 +51,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" - input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists" + input[1] = channel.fromPath(genelists_path + "/*.bed").collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 8bf03814..8e79fe1c 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -60,7 +60,7 @@ workflow PREPROCESSING { roi = roi ? file(roi, checkIfExists: true) : null // construct a value channel containing an array of files, because the coverage subworkflow expects a channel of arrays of genelist files (to allow for multiple genelist files per sample) - ch_genelists = genelists ? channel.fromPath(genelists).collect().map { files -> [ files ] } : channel.empty() + ch_genelists = genelists ? channel.fromPath(genelists + "/*.bed").collect().map { files -> [ files ] } : channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From f4f213d56a7916e433a8bd96ff28e33af194890f Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:13:12 +0100 Subject: [PATCH 175/228] fix variable name --- workflows/preprocessing.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 8e79fe1c..c590253c 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -333,7 +333,7 @@ workflow PREPROCESSING { def samtools_coverage_out = channel.empty() def panelcoverage_out = channel.empty() if (params.run_coverage) { - COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) + COVERAGE(ch_cram_crai_fasta_fai_roi, ch_genelists) ch_multiqc_files = ch_multiqc_files.mix( COVERAGE.out.mosdepth_summary, COVERAGE.out.mosdepth_global, From 20f538bcd12ed36c0fefb5a54dae61104b0e6abc Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:42:09 +0100 Subject: [PATCH 176/228] add falco for unsupported fastq qc --- main.nf | 424 ++++++++---------- modules.json | 5 + modules/nf-core/falco/environment.yml | 7 + modules/nf-core/falco/main.nf | 57 +++ modules/nf-core/falco/meta.yml | 61 +++ modules/nf-core/falco/tests/main.nf.test | 108 +++++ modules/nf-core/falco/tests/main.nf.test.snap | 61 +++ workflows/preprocessing.nf | 103 +++-- 8 files changed, 534 insertions(+), 292 deletions(-) create mode 100644 modules/nf-core/falco/environment.yml create mode 100644 modules/nf-core/falco/main.nf create mode 100644 modules/nf-core/falco/meta.yml create mode 100644 modules/nf-core/falco/tests/main.nf.test create mode 100644 modules/nf-core/falco/tests/main.nf.test.snap diff --git a/main.nf b/main.nf index f9ce7868..dda235c6 100644 --- a/main.nf +++ b/main.nf @@ -62,35 +62,37 @@ workflow { ) publish: - demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by: 1) - demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by: 1) - demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by: 1) - demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() - fastp_json = PREPROCESSING.out.fastp_json - fastp_html = PREPROCESSING.out.fastp_html - crams = PREPROCESSING.out.crams - rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions - rna_junctions = PREPROCESSING.out.rna_junctions - align_reports = PREPROCESSING.out.align_reports - sormadup_metrics = PREPROCESSING.out.sormadup_metrics - mosdepth_global = PREPROCESSING.out.mosdepth_global - mosdepth_summary = PREPROCESSING.out.mosdepth_summary - mosdepth_regions = PREPROCESSING.out.mosdepth_regions - mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 - mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed - mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi - mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed - mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi - mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed - mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi - mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed - mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi - samtools_coverage = PREPROCESSING.out.samtools_coverage - panelcoverage = PREPROCESSING.out.panelcoverage - samtools_stats = PREPROCESSING.out.samtools_stats - samtools_flagstat = PREPROCESSING.out.samtools_flagstat - samtools_idxstats = PREPROCESSING.out.samtools_idxstats - picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics + demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) + demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by:1) + demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) + demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() + falco_html = PREPROCESSING.out.falco_html + falco_txt = PREPROCESSING.out.falco_txt + fastp_json = PREPROCESSING.out.fastp_json + fastp_html = PREPROCESSING.out.fastp_html + crams = PREPROCESSING.out.crams + rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions + rna_junctions = PREPROCESSING.out.rna_junctions + align_reports = PREPROCESSING.out.align_reports + sormadup_metrics = PREPROCESSING.out.sormadup_metrics + mosdepth_global = PREPROCESSING.out.mosdepth_global + mosdepth_summary = PREPROCESSING.out.mosdepth_summary + mosdepth_regions = PREPROCESSING.out.mosdepth_regions + mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed + mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi + mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed + mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi + mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed + mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi + samtools_coverage = PREPROCESSING.out.samtools_coverage + panelcoverage = PREPROCESSING.out.panelcoverage + samtools_stats = PREPROCESSING.out.samtools_stats + samtools_flagstat = PREPROCESSING.out.samtools_flagstat + samtools_idxstats = PREPROCESSING.out.samtools_idxstats + picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics picard_multiplemetrics_pdf = PREPROCESSING.out.picard_multiplemetrics_pdf picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics @@ -104,221 +106,151 @@ workflow { } output { - demultiplex_interop { - path { _meta, bin -> - bin >> "Interop/${bin.name}" - } - } - demultiplex_reports { - path { meta, report -> - def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" - report >> out_path - } - } - demultiplex_logs { - path { meta, log -> - def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" - log >> out_path - } - } - demultiplex_fastq { - path { meta, fastq -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" - fastq >> out_path - } - } - fastp_json { - path { meta, json -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" - json >> out_path - } - } - fastp_html { - path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path - } - } - crams { - path { meta, cram, crai -> - def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" - def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" - cram >> out_cram - crai >> out_crai - } - } - rna_splice_junctions { - path { meta, sjt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" - sjt >> out_path - } - } - rna_junctions { - path { meta, junctions -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" - junctions >> out_path - } - } - align_reports { - path { meta, log -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" - log >> out_path - } - } - sormadup_metrics { - path { meta, metrics -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" - metrics >> out_path - } - } - mosdepth_global { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_summary { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_regions { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_per_base_d4 { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_per_base_bed { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_per_base_csi { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_regions_bed { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_regions_csi { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_quantized_bed { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_quantized_csi { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_thresholds_bed { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - mosdepth_thresholds_csi { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - samtools_coverage { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - panelcoverage { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - samtools_stats { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - samtools_flagstat { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - samtools_idxstats { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - picard_multiplemetrics { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - picard_multiplemetrics_pdf { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - picard_wgsmetrics { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - picard_hsmetrics { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - md5sums { - path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } - } - multiqc_main_report { - path "multiqc/" - } - multiqc_main_data { - path "multiqc/" - } - multiqc_main_plots { - path "multiqc/" - } - multiqc_library_report { - path "multiqc/" - } - multiqc_library_data { - path "multiqc/" - } - multiqc_library_plots { - path "multiqc/" - } + demultiplex_interop { path { _meta, bin -> + bin >> "Interop/${bin.name}" + } } + demultiplex_reports { path { meta, report -> + def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" + report >> out_path + } } + demultiplex_logs { path { meta, log -> + def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" + log >> out_path + } } + demultiplex_fastq { path { meta, fastq -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" + fastq >> out_path + } } + falco_html { path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } } + falco_txt { path { meta, txt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" as String : "${meta.samplename}/${txt.name}" + txt >> out_path + } } + fastp_json { path { meta, json -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" + json >> out_path + } } + fastp_html { path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } } + crams { path { meta, cram, crai -> + def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" + def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" + cram >> out_cram + crai >> out_crai + } } + rna_splice_junctions { path { meta, sjt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" + sjt >> out_path + } } + rna_junctions { path { meta, junctions -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" + junctions >> out_path + } } + align_reports { path { meta, log -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" + log >> out_path + } } + sormadup_metrics { path { meta, metrics -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" + metrics >> out_path + } } + mosdepth_global { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_summary { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_regions { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_per_base_d4 { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_per_base_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_per_base_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_regions_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_regions_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_quantized_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_quantized_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_thresholds_bed { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + mosdepth_thresholds_csi { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_coverage { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + panelcoverage { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_stats { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_flagstat { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + samtools_idxstats { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_multiplemetrics { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_multiplemetrics_pdf { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_wgsmetrics { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + picard_hsmetrics { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + md5sums { path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } } + multiqc_main_report { path "multiqc/" } + multiqc_main_data { path "multiqc/" } + multiqc_main_plots { path "multiqc/" } + multiqc_library_report { path "multiqc/" } + multiqc_library_data { path "multiqc/" } + multiqc_library_plots { path "multiqc/" } } diff --git a/modules.json b/modules.json index 4ec35dbd..a75b44bf 100644 --- a/modules.json +++ b/modules.json @@ -46,6 +46,11 @@ "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, + "falco": { + "branch": "master", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "installed_by": ["modules"] + }, "fastp": { "branch": "master", "git_sha": "a331ecfd1aa48b2b2298aab23bb4516c800e410b", diff --git a/modules/nf-core/falco/environment.yml b/modules/nf-core/falco/environment.yml new file mode 100644 index 00000000..59c973a9 --- /dev/null +++ b/modules/nf-core/falco/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::falco=1.2.1 diff --git a/modules/nf-core/falco/main.nf b/modules/nf-core/falco/main.nf new file mode 100644 index 00000000..a4b343b2 --- /dev/null +++ b/modules/nf-core/falco/main.nf @@ -0,0 +1,57 @@ +process FALCO { + tag "$meta.id" + label 'process_single' + + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/falco:1.2.1--h867801b_3': + 'biocontainers/falco:1.2.1--h867801b_3' }" + + input: + tuple val(meta), path(reads) + + output: + tuple val(meta), path("*.html"), emit: html + tuple val(meta), path("*.txt") , emit: txt + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + if ( reads.toList().size() == 1 ) { + """ + falco $args --threads $task.cpus ${reads} -D ${prefix}_fastqc_data.txt -S ${prefix}_summary.txt -R ${prefix}_report.html + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + falco:\$( falco --version | sed -e "s/falco//g" ) + END_VERSIONS + """ + } else { + """ + falco $args --threads $task.cpus ${reads} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + falco:\$( falco --version | sed -e "s/falco//g" ) + END_VERSIONS + """ + } + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}_data.txt + touch ${prefix}_fastqc_data.html + touch ${prefix}_summary.txt + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + falco: \$( falco --version | sed -e "s/falco v//g" ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/falco/meta.yml b/modules/nf-core/falco/meta.yml new file mode 100644 index 00000000..1450f2da --- /dev/null +++ b/modules/nf-core/falco/meta.yml @@ -0,0 +1,61 @@ +name: falco +description: Run falco on sequenced reads +keywords: + - quality control + - qc + - adapters + - fastq +tools: + - fastqc: + description: "falco is a drop-in C++ implementation of FastQC to assess the quality + of sequence reads." + homepage: "https://falco.readthedocs.io/" + documentation: "https://falco.readthedocs.io/" + licence: ["GPL v3"] + identifier: biotools:falco-rna +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files of size 1 and 2 for single-end and paired-end data, + respectively. + ontologies: [] +output: + html: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.html": + type: file + description: FastQC like report + pattern: "*_{fastqc_report.html}" + ontologies: [] + txt: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.txt": + type: file + description: falco report data + pattern: "*_{data.txt}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@lucacozzuto" +maintainers: + - "@lucacozzuto" diff --git a/modules/nf-core/falco/tests/main.nf.test b/modules/nf-core/falco/tests/main.nf.test new file mode 100644 index 00000000..816c72ba --- /dev/null +++ b/modules/nf-core/falco/tests/main.nf.test @@ -0,0 +1,108 @@ +nextflow_process { + + name "Test Process FALCO" + script "../main.nf" + process "FALCO" + + tag "modules" + tag "modules_nfcore" + tag "falco" + + test("sarscov2 - fastq - single end") { + + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:true ], + [ + file( + params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], + checkIfExists: true + ), + ], + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.txt, + file(process.out.html.get(0).get(1)).list(), + ).match() + }, + ) + } + + } + + test("sarscov2 - fastq - paired end") { + + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:false ], + [ + file( + params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], + checkIfExists: true + ), + file( + params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], + checkIfExists: true + ), + ], + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.txt, + process.out.html.get(0).get(1).collect{ it.split("/")[-1] }.sort(), + ).match() + }, + ) + } + + } + + test("sarscov2 - fastq - interleaved") { + + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:false ], + [ + file( + params.test_data['sarscov2']['illumina']['test_interleaved_fastq_gz'], + checkIfExists: true + ), + ], + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.txt, + file(process.out.html.get(0).get(1)).list(), + ).match() + }, + ) + } + + } + +} diff --git a/modules/nf-core/falco/tests/main.nf.test.snap b/modules/nf-core/falco/tests/main.nf.test.snap new file mode 100644 index 00000000..34ac64e3 --- /dev/null +++ b/modules/nf-core/falco/tests/main.nf.test.snap @@ -0,0 +1,61 @@ +{ + "sarscov2 - fastq - single end": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test_fastqc_data.txt:md5,36d989bb9e2d5a632e19452f4e6c2a4e", + "test_summary.txt:md5,a925aec214a83d2f6252847166f2ef3a" + ] + ] + ], + null + ], + "timestamp": "2024-02-02T16:28:17.756764" + }, + "sarscov2 - fastq - paired end": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.fastq.gz_fastqc_data.txt:md5,36d989bb9e2d5a632e19452f4e6c2a4e", + "test_1.fastq.gz_summary.txt:md5,a925aec214a83d2f6252847166f2ef3a", + "test_2.fastq.gz_fastqc_data.txt:md5,ad5c45dfc8f79754dd5d8029456b715b", + "test_2.fastq.gz_summary.txt:md5,d0cb642adefb5635a25e808f1f38780a" + ] + ] + ], + [ + "test_1.fastq.gz_fastqc_report.html", + "test_2.fastq.gz_fastqc_report.html" + ] + ], + "timestamp": "2024-02-02T16:22:11.757473" + }, + "sarscov2 - fastq - interleaved": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_fastqc_data.txt:md5,b5e593f140fe578bdd25ceb84e98fd37", + "test_summary.txt:md5,ca52f458b1223d89db69e2d5e73cf867" + ] + ] + ], + null + ], + "timestamp": "2024-02-02T16:28:36.035899" + } +} \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 94cb7fdb..6f10a5af 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -7,12 +7,13 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules -include { FASTP } from '../modules/nf-core/fastp/main' -include { MD5SUM } from '../modules/nf-core/md5sum/main' -include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' -include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' -include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' -include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' +include { FALCO } from '../modules/nf-core/falcon/main' +include { FASTP } from '../modules/nf-core/fastp/main' +include { MD5SUM } from '../modules/nf-core/md5sum/main' +include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' +include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' +include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' +include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' // Subworkflows include { BAM_QC } from '../subworkflows/local/bam_qc/main' @@ -184,6 +185,14 @@ workflow PREPROCESSING { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + // MODULE: FALCO + // Run FALCO for "unsupported" fastq QC + // FALCO([meta, fastq]) + FALCO(ch_fastq_per_sample.other, false) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.html) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.txt) + ch_versions = ch_versions.mix(FALCO.out.versions.first()) + // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) @@ -399,46 +408,48 @@ workflow PREPROCESSING { ) emit: - demultiplex_interop = BCL_DEMULTIPLEX.out.interop - demultiplex_reports = BCL_DEMULTIPLEX.out.reports - demultiplex_logs = BCL_DEMULTIPLEX.out.logs - demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other - fastp_json = FASTP.out.json - fastp_html = FASTP.out.html - crams = FASTQ_TO_CRAM.out.cram_crai - rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions - rna_junctions = FASTQ_TO_CRAM.out.rna_junctions - align_reports = FASTQ_TO_CRAM.out.align_reports - sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics - mosdepth_global = COVERAGE.out.mosdepth_global - mosdepth_summary = COVERAGE.out.mosdepth_summary - mosdepth_regions = COVERAGE.out.mosdepth_regions - mosdepth_per_base_d4 = COVERAGE.out.mosdepth_per_base_d4 - mosdepth_per_base_bed = COVERAGE.out.mosdepth_per_base_bed - mosdepth_per_base_csi = COVERAGE.out.mosdepth_per_base_csi - mosdepth_regions_bed = COVERAGE.out.mosdepth_regions_bed - mosdepth_regions_csi = COVERAGE.out.mosdepth_regions_csi - mosdepth_quantized_bed = COVERAGE.out.mosdepth_quantized_bed - mosdepth_quantized_csi = COVERAGE.out.mosdepth_quantized_csi - mosdepth_thresholds_bed = COVERAGE.out.mosdepth_thresholds_bed - mosdepth_thresholds_csi = COVERAGE.out.mosdepth_thresholds_csi - samtools_coverage = COVERAGE.out.samtools_coverage - panelcoverage = COVERAGE.out.panelcoverage - samtools_stats = BAM_QC.out.samtools_stats - samtools_flagstat = BAM_QC.out.samtools_flagstat - samtools_idxstats = BAM_QC.out.samtools_idxstats - picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics - picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf - picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics - picard_hsmetrics = BAM_QC.out.picard_hsmetrics - md5sums = MD5SUM.out.checksum - multiqc_main_report = MULTIQC_MAIN.out.report.toList() - multiqc_main_data = MULTIQC_MAIN.out.data.toList() - multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() - multiqc_library_report = MULTIQC_LIBRARY.out.report - multiqc_library_data = MULTIQC_LIBRARY.out.data - multiqc_library_plots = MULTIQC_LIBRARY.out.plots - versions = ch_versions + demultiplex_interop = BCL_DEMULTIPLEX.out.interop + demultiplex_reports = BCL_DEMULTIPLEX.out.reports + demultiplex_logs = BCL_DEMULTIPLEX.out.logs + demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other + falco_html = FALCO.out.html + falco_txt = FALCO.out.txt + fastp_json = FASTP.out.json + fastp_html = FASTP.out.html + crams = FASTQ_TO_CRAM.out.cram_crai + rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions + rna_junctions = FASTQ_TO_CRAM.out.rna_junctions + align_reports = FASTQ_TO_CRAM.out.align_reports + sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics + mosdepth_global = mosdepth_global_out + mosdepth_summary = mosdepth_summary_out + mosdepth_regions = mosdepth_regions_out + mosdepth_per_base_d4 = mosdepth_per_base_d4_out + mosdepth_per_base_bed = mosdepth_per_base_bed_out + mosdepth_per_base_csi = mosdepth_per_base_csi_out + mosdepth_regions_bed = mosdepth_regions_bed_out + mosdepth_regions_csi = mosdepth_regions_csi_out + mosdepth_quantized_bed = mosdepth_quantized_bed_out + mosdepth_quantized_csi = mosdepth_quantized_csi_out + mosdepth_thresholds_bed = mosdepth_thresholds_bed_out + mosdepth_thresholds_csi = mosdepth_thresholds_csi_out + samtools_coverage = samtools_coverage_out + panelcoverage = panelcoverage_out + samtools_stats = BAM_QC.out.samtools_stats + samtools_flagstat = BAM_QC.out.samtools_flagstat + samtools_idxstats = BAM_QC.out.samtools_idxstats + picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics + picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf + picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics + picard_hsmetrics = BAM_QC.out.picard_hsmetrics + md5sums = MD5SUM.out.checksum + multiqc_main_report = MULTIQC_MAIN.out.report.toList() + multiqc_main_data = MULTIQC_MAIN.out.data.toList() + multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() + multiqc_library_report = MULTIQC_LIBRARY.out.report + multiqc_library_data = MULTIQC_LIBRARY.out.data + multiqc_library_plots = MULTIQC_LIBRARY.out.plots + versions = ch_versions } /* From 0aa6686d54179a7292fa57abc44f4f62bc70f85a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 08:45:02 +0100 Subject: [PATCH 177/228] fix typo + linting --- main.nf | 438 ++++++++++++++++++++++--------------- workflows/preprocessing.nf | 117 +++++----- 2 files changed, 316 insertions(+), 239 deletions(-) diff --git a/main.nf b/main.nf index dda235c6..aed6d7b5 100644 --- a/main.nf +++ b/main.nf @@ -62,37 +62,37 @@ workflow { ) publish: - demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by:1) - demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by:1) - demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by:1) - demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() - falco_html = PREPROCESSING.out.falco_html - falco_txt = PREPROCESSING.out.falco_txt - fastp_json = PREPROCESSING.out.fastp_json - fastp_html = PREPROCESSING.out.fastp_html - crams = PREPROCESSING.out.crams - rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions - rna_junctions = PREPROCESSING.out.rna_junctions - align_reports = PREPROCESSING.out.align_reports - sormadup_metrics = PREPROCESSING.out.sormadup_metrics - mosdepth_global = PREPROCESSING.out.mosdepth_global - mosdepth_summary = PREPROCESSING.out.mosdepth_summary - mosdepth_regions = PREPROCESSING.out.mosdepth_regions - mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 - mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed - mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi - mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed - mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi - mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed - mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi - mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed - mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi - samtools_coverage = PREPROCESSING.out.samtools_coverage - panelcoverage = PREPROCESSING.out.panelcoverage - samtools_stats = PREPROCESSING.out.samtools_stats - samtools_flagstat = PREPROCESSING.out.samtools_flagstat - samtools_idxstats = PREPROCESSING.out.samtools_idxstats - picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics + demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by: 1) + demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by: 1) + demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by: 1) + demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() + falco_html = PREPROCESSING.out.falco_html + falco_txt = PREPROCESSING.out.falco_txt + fastp_json = PREPROCESSING.out.fastp_json + fastp_html = PREPROCESSING.out.fastp_html + crams = PREPROCESSING.out.crams + rna_splice_junctions = PREPROCESSING.out.rna_splice_junctions + rna_junctions = PREPROCESSING.out.rna_junctions + align_reports = PREPROCESSING.out.align_reports + sormadup_metrics = PREPROCESSING.out.sormadup_metrics + mosdepth_global = PREPROCESSING.out.mosdepth_global + mosdepth_summary = PREPROCESSING.out.mosdepth_summary + mosdepth_regions = PREPROCESSING.out.mosdepth_regions + mosdepth_per_base_d4 = PREPROCESSING.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = PREPROCESSING.out.mosdepth_per_base_bed + mosdepth_per_base_csi = PREPROCESSING.out.mosdepth_per_base_csi + mosdepth_regions_bed = PREPROCESSING.out.mosdepth_regions_bed + mosdepth_regions_csi = PREPROCESSING.out.mosdepth_regions_csi + mosdepth_quantized_bed = PREPROCESSING.out.mosdepth_quantized_bed + mosdepth_quantized_csi = PREPROCESSING.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = PREPROCESSING.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = PREPROCESSING.out.mosdepth_thresholds_csi + samtools_coverage = PREPROCESSING.out.samtools_coverage + panelcoverage = PREPROCESSING.out.panelcoverage + samtools_stats = PREPROCESSING.out.samtools_stats + samtools_flagstat = PREPROCESSING.out.samtools_flagstat + samtools_idxstats = PREPROCESSING.out.samtools_idxstats + picard_multiplemetrics = PREPROCESSING.out.picard_multiplemetrics picard_multiplemetrics_pdf = PREPROCESSING.out.picard_multiplemetrics_pdf picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics @@ -106,151 +106,233 @@ workflow { } output { - demultiplex_interop { path { _meta, bin -> - bin >> "Interop/${bin.name}" - } } - demultiplex_reports { path { meta, report -> - def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" - report >> out_path - } } - demultiplex_logs { path { meta, log -> - def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" - log >> out_path - } } - demultiplex_fastq { path { meta, fastq -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" - fastq >> out_path - } } - falco_html { path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path - } } - falco_txt { path { meta, txt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" as String : "${meta.samplename}/${txt.name}" - txt >> out_path - } } - fastp_json { path { meta, json -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" - json >> out_path - } } - fastp_html { path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path - } } - crams { path { meta, cram, crai -> - def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" - def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" - cram >> out_cram - crai >> out_crai - } } - rna_splice_junctions { path { meta, sjt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" - sjt >> out_path - } } - rna_junctions { path { meta, junctions -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" - junctions >> out_path - } } - align_reports { path { meta, log -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" - log >> out_path - } } - sormadup_metrics { path { meta, metrics -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" - metrics >> out_path - } } - mosdepth_global { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_summary { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_d4 { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_per_base_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_regions_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_quantized_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_quantized_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_thresholds_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - mosdepth_thresholds_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_coverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - panelcoverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_stats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_flagstat { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - samtools_idxstats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_multiplemetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_multiplemetrics_pdf { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_wgsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - picard_hsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - md5sums { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path - } } - multiqc_main_report { path "multiqc/" } - multiqc_main_data { path "multiqc/" } - multiqc_main_plots { path "multiqc/" } - multiqc_library_report { path "multiqc/" } - multiqc_library_data { path "multiqc/" } - multiqc_library_plots { path "multiqc/" } + demultiplex_interop { + path { _meta, bin -> + bin >> "Interop/${bin.name}" + } + } + demultiplex_reports { + path { meta, report -> + def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" + report >> out_path + } + } + demultiplex_logs { + path { meta, log -> + def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" + log >> out_path + } + } + demultiplex_fastq { + path { meta, fastq -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" + fastq >> out_path + } + } + falco_html { + path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } + } + falco_txt { + path { meta, txt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" as String : "${meta.samplename}/${txt.name}" + txt >> out_path + } + } + fastp_json { + path { meta, json -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" + json >> out_path + } + } + fastp_html { + path { meta, html -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" + html >> out_path + } + } + crams { + path { meta, cram, crai -> + def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" + def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" + cram >> out_cram + crai >> out_crai + } + } + rna_splice_junctions { + path { meta, sjt -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" + sjt >> out_path + } + } + rna_junctions { + path { meta, junctions -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" + junctions >> out_path + } + } + align_reports { + path { meta, log -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" + log >> out_path + } + } + sormadup_metrics { + path { meta, metrics -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" + metrics >> out_path + } + } + mosdepth_global { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_summary { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_d4 { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_per_base_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_regions_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_quantized_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_quantized_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_thresholds_bed { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + mosdepth_thresholds_csi { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_coverage { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + panelcoverage { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_stats { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_flagstat { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + samtools_idxstats { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_multiplemetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_multiplemetrics_pdf { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_wgsmetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + picard_hsmetrics { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + md5sums { + path { meta, _file -> + def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" + return out_path + } + } + multiqc_main_report { + path "multiqc/" + } + multiqc_main_data { + path "multiqc/" + } + multiqc_main_plots { + path "multiqc/" + } + multiqc_library_report { + path "multiqc/" + } + multiqc_library_data { + path "multiqc/" + } + multiqc_library_plots { + path "multiqc/" + } } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 6f10a5af..477f5fd2 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -7,13 +7,13 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules -include { FALCO } from '../modules/nf-core/falcon/main' -include { FASTP } from '../modules/nf-core/fastp/main' -include { MD5SUM } from '../modules/nf-core/md5sum/main' -include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' -include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' -include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' -include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' +include { FALCO } from '../modules/nf-core/falco/main' +include { FASTP } from '../modules/nf-core/fastp/main' +include { MD5SUM } from '../modules/nf-core/md5sum/main' +include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' +include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' +include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' +include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' // Subworkflows include { BAM_QC } from '../subworkflows/local/bam_qc/main' @@ -188,22 +188,17 @@ workflow PREPROCESSING { // MODULE: FALCO // Run FALCO for "unsupported" fastq QC // FALCO([meta, fastq]) - FALCO(ch_fastq_per_sample.other, false) - ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.html) - ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.txt) - ch_versions = ch_versions.mix(FALCO.out.versions.first()) + FALCO(ch_fastq_per_sample.other) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.html) + ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.txt) + ch_versions = ch_versions.mix(FALCO.out.versions.first()) // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) - FASTP( - ch_fastq_per_sample.supported.map { meta, fastq -> - return [meta, fastq, []] - }, - false, - false, - false, - ) + FASTP(ch_fastq_per_sample.supported.map { meta, fastq -> + return [meta, fastq, []] + }, false, false, false) ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) // edit meta.id to match sample name @@ -408,48 +403,48 @@ workflow PREPROCESSING { ) emit: - demultiplex_interop = BCL_DEMULTIPLEX.out.interop - demultiplex_reports = BCL_DEMULTIPLEX.out.reports - demultiplex_logs = BCL_DEMULTIPLEX.out.logs - demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other - falco_html = FALCO.out.html - falco_txt = FALCO.out.txt - fastp_json = FASTP.out.json - fastp_html = FASTP.out.html - crams = FASTQ_TO_CRAM.out.cram_crai - rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions - rna_junctions = FASTQ_TO_CRAM.out.rna_junctions - align_reports = FASTQ_TO_CRAM.out.align_reports - sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics - mosdepth_global = mosdepth_global_out - mosdepth_summary = mosdepth_summary_out - mosdepth_regions = mosdepth_regions_out - mosdepth_per_base_d4 = mosdepth_per_base_d4_out - mosdepth_per_base_bed = mosdepth_per_base_bed_out - mosdepth_per_base_csi = mosdepth_per_base_csi_out - mosdepth_regions_bed = mosdepth_regions_bed_out - mosdepth_regions_csi = mosdepth_regions_csi_out - mosdepth_quantized_bed = mosdepth_quantized_bed_out - mosdepth_quantized_csi = mosdepth_quantized_csi_out - mosdepth_thresholds_bed = mosdepth_thresholds_bed_out - mosdepth_thresholds_csi = mosdepth_thresholds_csi_out - samtools_coverage = samtools_coverage_out - panelcoverage = panelcoverage_out - samtools_stats = BAM_QC.out.samtools_stats - samtools_flagstat = BAM_QC.out.samtools_flagstat - samtools_idxstats = BAM_QC.out.samtools_idxstats - picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics - picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf - picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics - picard_hsmetrics = BAM_QC.out.picard_hsmetrics - md5sums = MD5SUM.out.checksum - multiqc_main_report = MULTIQC_MAIN.out.report.toList() - multiqc_main_data = MULTIQC_MAIN.out.data.toList() - multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() - multiqc_library_report = MULTIQC_LIBRARY.out.report - multiqc_library_data = MULTIQC_LIBRARY.out.data - multiqc_library_plots = MULTIQC_LIBRARY.out.plots - versions = ch_versions + demultiplex_interop = BCL_DEMULTIPLEX.out.interop + demultiplex_reports = BCL_DEMULTIPLEX.out.reports + demultiplex_logs = BCL_DEMULTIPLEX.out.logs + demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other + falco_html = FALCO.out.html + falco_txt = FALCO.out.txt + fastp_json = FASTP.out.json + fastp_html = FASTP.out.html + crams = FASTQ_TO_CRAM.out.cram_crai + rna_splice_junctions = FASTQ_TO_CRAM.out.rna_splice_junctions + rna_junctions = FASTQ_TO_CRAM.out.rna_junctions + align_reports = FASTQ_TO_CRAM.out.align_reports + sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics + mosdepth_global = mosdepth_global_out + mosdepth_summary = mosdepth_summary_out + mosdepth_regions = mosdepth_regions_out + mosdepth_per_base_d4 = mosdepth_per_base_d4_out + mosdepth_per_base_bed = mosdepth_per_base_bed_out + mosdepth_per_base_csi = mosdepth_per_base_csi_out + mosdepth_regions_bed = mosdepth_regions_bed_out + mosdepth_regions_csi = mosdepth_regions_csi_out + mosdepth_quantized_bed = mosdepth_quantized_bed_out + mosdepth_quantized_csi = mosdepth_quantized_csi_out + mosdepth_thresholds_bed = mosdepth_thresholds_bed_out + mosdepth_thresholds_csi = mosdepth_thresholds_csi_out + samtools_coverage = samtools_coverage_out + panelcoverage = panelcoverage_out + samtools_stats = BAM_QC.out.samtools_stats + samtools_flagstat = BAM_QC.out.samtools_flagstat + samtools_idxstats = BAM_QC.out.samtools_idxstats + picard_multiplemetrics = BAM_QC.out.picard_multiplemetrics + picard_multiplemetrics_pdf = BAM_QC.out.picard_multiplemetrics_pdf + picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics + picard_hsmetrics = BAM_QC.out.picard_hsmetrics + md5sums = MD5SUM.out.checksum + multiqc_main_report = MULTIQC_MAIN.out.report.toList() + multiqc_main_data = MULTIQC_MAIN.out.data.toList() + multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() + multiqc_library_report = MULTIQC_LIBRARY.out.report + multiqc_library_data = MULTIQC_LIBRARY.out.data + multiqc_library_plots = MULTIQC_LIBRARY.out.plots + versions = ch_versions } /* From 2dd72229226dc557cc4a2f1c550267f45265a7fe Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 09:04:36 +0100 Subject: [PATCH 178/228] drop unused gh workflows --- .github/workflows/fix-linting.yml | 89 ------------------------------- .github/workflows/fix_linting.yml | 89 ------------------------------- 2 files changed, 178 deletions(-) delete mode 100644 .github/workflows/fix-linting.yml delete mode 100644 .github/workflows/fix_linting.yml diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml deleted file mode 100644 index 2230aafb..00000000 --- a/.github/workflows/fix-linting.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Fix linting from a comment -on: - issue_comment: - types: [created] - -jobs: - fix-linting: - # Only run if comment is on a PR with the main repo, and if it contains the magic keywords - if: > - contains(github.event.comment.html_url, '/pull/') && - contains(github.event.comment.body, '@nf-core-bot fix linting') && - github.repository == 'nf-cmgg/preprocessing' - runs-on: ubuntu-latest - steps: - # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - with: - token: ${{ secrets.nf_core_bot_auth_token }} - - # indication that the linting is being fixed - - name: React on comment - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: eyes - - # Action runs on the issue comment, so we don't get the PR by default - # Use the gh cli to check out the PR - - name: Checkout Pull Request - run: gh pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} - - # Install and run pre-commit - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 - with: - python-version: 3.11 - - - name: Install pre-commit - run: pip install pre-commit - - - name: Run pre-commit - id: pre-commit - run: pre-commit run --all-files - continue-on-error: true - - # indication that the linting has finished - - name: react if linting finished succesfully - if: steps.pre-commit.outcome == 'success' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: "+1" - - - name: Commit & push changes - id: commit-and-push - if: steps.pre-commit.outcome == 'failure' - run: | - git config user.email "core@nf-co.re" - git config user.name "nf-core-bot" - git config push.default upstream - git add . - git status - git commit -m "[automated] Fix code linting" - git push - - - name: react if linting errors were fixed - id: react-if-fixed - if: steps.commit-and-push.outcome == 'success' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: hooray - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - comment-id: ${{ github.event.comment.id }} - reactions: confused - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 - with: - issue-number: ${{ github.event.issue.number }} - body: | - @${{ github.actor }} I tried to fix the linting errors, but it didn't work. Please fix them manually. - See [CI log](https://github.com/nf-cmgg/preprocessing/actions/runs/${{ github.run_id }}) for more details. diff --git a/.github/workflows/fix_linting.yml b/.github/workflows/fix_linting.yml deleted file mode 100644 index 63b82243..00000000 --- a/.github/workflows/fix_linting.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Fix linting from a comment -on: - issue_comment: - types: [created] - -jobs: - fix-linting: - # Only run if comment is on a PR with the main repo, and if it contains the magic keywords - if: > - contains(github.event.comment.html_url, '/pull/') && - contains(github.event.comment.body, '@nf-core-bot fix linting') && - github.repository == 'nf-cmgg/preprocessing' - runs-on: ubuntu-latest - steps: - # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - token: ${{ secrets.nf_core_bot_auth_token }} - - # indication that the linting is being fixed - - name: React on comment - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: eyes - - # Action runs on the issue comment, so we don't get the PR by default - # Use the gh cli to check out the PR - - name: Checkout Pull Request - run: gh pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} - - # Install and run pre-commit - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 - with: - python-version: "3.14" - - - name: Install pre-commit - run: pip install pre-commit - - - name: Run pre-commit - id: pre-commit - run: pre-commit run --all-files - continue-on-error: true - - # indication that the linting has finished - - name: react if linting finished succesfully - if: steps.pre-commit.outcome == 'success' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: "+1" - - - name: Commit & push changes - id: commit-and-push - if: steps.pre-commit.outcome == 'failure' - run: | - git config user.email "core@nf-co.re" - git config user.name "nf-core-bot" - git config push.default upstream - git add . - git status - git commit -m "[automated] Fix code linting" - git push - - - name: react if linting errors were fixed - id: react-if-fixed - if: steps.commit-and-push.outcome == 'success' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: hooray - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: confused - - - name: react if linting errors were not fixed - if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 - with: - issue-number: ${{ github.event.issue.number }} - body: | - @${{ github.actor }} I tried to fix the linting errors, but it didn't work. Please fix them manually. - See [CI log](https://github.com/nf-cmgg/preprocessing/actions/runs/${{ github.run_id }}) for more details. From d534d9029b21cfb8c393377c9a3c150974d4c6dc Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 09:04:57 +0100 Subject: [PATCH 179/228] calculate checksums for fastq output --- workflows/preprocessing.nf | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 477f5fd2..541f0359 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -196,9 +196,14 @@ workflow PREPROCESSING { // MODULE: fastp // Run QC, trimming and adapter removal // FASTP([meta, fastq, adapter_fasta], save_trimmed, save_merged) - FASTP(ch_fastq_per_sample.supported.map { meta, fastq -> - return [meta, fastq, []] - }, false, false, false) + FASTP( + ch_fastq_per_sample.supported.map { meta, fastq -> + return [meta, fastq, []] + }, + false, + false, + false, + ) ch_multiqc_files = ch_multiqc_files.mix(FASTP.out.json) // edit meta.id to match sample name @@ -311,9 +316,11 @@ workflow PREPROCESSING { */ MD5SUM( - FASTQ_TO_CRAM.out.cram_crai.map { meta, cram, _crai -> - return [meta, cram] - }, + ch_fastq_per_sample.other.mix( + FASTQ_TO_CRAM.out.cram_crai.map { meta, cram, _crai -> + return [meta, cram] + } + ), false, ) ch_versions = ch_versions.mix(MD5SUM.out.versions.first()) From 670c18d2097226dde718ede0a5310d7db2630ee2 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:03:53 +0100 Subject: [PATCH 180/228] nextflow config lint --- nextflow.config | 6 +----- nextflow_schema.json | 51 -------------------------------------------- 2 files changed, 1 insertion(+), 56 deletions(-) diff --git a/nextflow.config b/nextflow.config index 05719293..13067b73 100644 --- a/nextflow.config +++ b/nextflow.config @@ -197,11 +197,7 @@ includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !pa // Load nf-cmgg/preprocessing custom profiles from different institutions. -// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs -// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" - -// Load nf-cmgg/preprocessing custom profiles from nf-cmgg/configs. -includeConfig params.cmgg_custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.cmgg_custom_config_base.startsWith('http')) ? "${params.cmgg_custom_config_base}/pipeline/preprocessing.config" : "/dev/null" +includeConfig params.custom_config_base && params.custom_config_base.contains('nf-cmgg') && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/preprocessing.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled diff --git a/nextflow_schema.json b/nextflow_schema.json index 722c57ce..e0d5f227 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -123,54 +123,6 @@ } } }, - "cmgg_institutional_config_options": { - "title": "nf-cmgg config options", - "type": "object", - "fa_icon": "fas fa-university", - "description": "Parameters used to describe centralised config profiles. These should not be edited.", - "help_text": "The centralised nf-cmgg configuration profiles use a handful of pipeline parameters to describe themselves. This information is then printed to the Nextflow log when you run a pipeline. You should not need to change these values when you run a pipeline.", - "properties": { - "cmgg_custom_config_version": { - "type": "string", - "description": "Git commit id for nf-cmgg configs.", - "default": "master", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_custom_config_base": { - "type": "string", - "description": "Base directory for nf-cmgg configs.", - "default": "https://raw.githubusercontent.com/nf-cmgg/configs/master", - "hidden": true, - "help_text": "If you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.", - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_name": { - "type": "string", - "description": "nf-cmgg config name.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_description": { - "type": "string", - "description": "nf-cmgg config description.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_contact": { - "type": "string", - "description": "nf-cmgg config contact information.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, - "cmgg_config_profile_url": { - "type": "string", - "description": "nf-cmgg config URL link.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - } - } - }, "generic_options": { "title": "Generic options", "type": "object", @@ -312,9 +264,6 @@ { "$ref": "#/$defs/institutional_config_options" }, - { - "$ref": "#/$defs/cmgg_institutional_config_options" - }, { "$ref": "#/$defs/generic_options" } From 5e9a2d54c05ad9f1d4a967c4207cd6b2b5f22876 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 11:49:18 +0100 Subject: [PATCH 181/228] fix tests --- conf/modules.config | 3 +++ modules/nf-core/picard/collecthsmetrics/main.nf | 5 +++-- modules/nf-core/picard/collectmultiplemetrics/main.nf | 2 ++ modules/nf-core/picard/collectwgsmetrics/main.nf | 2 ++ subworkflows/local/coverage/main.nf | 10 ++++------ tests/config/igenomes_test.config | 1 + 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 16f7338f..03f7047a 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -305,4 +305,7 @@ env { MOSDEPTH_Q0 = 'NO_COVERAGE' MOSDEPTH_Q1 = 'LOW_COVERAGE' MOSDEPTH_Q2 = 'CALLABLE' + + // Set TMPDIR for all modules + TMPDIR = "$PWD" } diff --git a/modules/nf-core/picard/collecthsmetrics/main.nf b/modules/nf-core/picard/collecthsmetrics/main.nf index 63b3479c..22d95d57 100644 --- a/modules/nf-core/picard/collecthsmetrics/main.nf +++ b/modules/nf-core/picard/collecthsmetrics/main.nf @@ -45,6 +45,7 @@ process PICARD_COLLECTHSMETRICS { """ + export TMP=\$PWD $bait_intervallist_cmd $target_intervallist_cmd @@ -57,8 +58,8 @@ process PICARD_COLLECTHSMETRICS { --BAIT_INTERVALS $bait_interval_list \\ --TARGET_INTERVALS $target_interval_list \\ --INPUT $bam \\ - --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics - + --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics \\ + --TMP_DIR . """ stub: diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index 158a746f..28d8eaa0 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -30,6 +30,7 @@ process PICARD_COLLECTMULTIPLEMETRICS { avail_mem = (task.memory.mega*0.8).intValue() } """ + export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectMultipleMetrics \\ @@ -37,6 +38,7 @@ process PICARD_COLLECTMULTIPLEMETRICS { --INPUT $bam \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ $intervals_cmd \\ + --TMP_DIR . \\ $reference_cmd """ diff --git a/modules/nf-core/picard/collectwgsmetrics/main.nf b/modules/nf-core/picard/collectwgsmetrics/main.nf index 63330d22..a631b03f 100644 --- a/modules/nf-core/picard/collectwgsmetrics/main.nf +++ b/modules/nf-core/picard/collectwgsmetrics/main.nf @@ -29,6 +29,7 @@ process PICARD_COLLECTWGSMETRICS { avail_mem = (task.memory.mega*0.8).intValue() } """ + export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectWgsMetrics \\ @@ -36,6 +37,7 @@ process PICARD_COLLECTWGSMETRICS { --INPUT $bam \\ --OUTPUT ${prefix}.CollectWgsMetrics.coverage_metrics \\ --REFERENCE_SEQUENCE ${fasta} \\ + --TMP_DIR . \\ $interval """ diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index cca3ca59..ccbf27ad 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -30,13 +30,11 @@ workflow COVERAGE { PANELCOVERAGE( MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> - if (genelists !instanceof List) { - // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... - genelists = [genelists] - } + // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... + def genelists_array = genelists !instanceof List ? [genelists] : genelists def filtered_genelists = meta.tag.toLowerCase() == "seqcap" - ? genelists.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } - : genelists.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } + ? genelists_array.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } + : genelists_array.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } if (filtered_genelists.size() > 0) { return [ diff --git a/tests/config/igenomes_test.config b/tests/config/igenomes_test.config index 80984075..74154eec 100644 --- a/tests/config/igenomes_test.config +++ b/tests/config/igenomes_test.config @@ -9,6 +9,7 @@ params { gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" } } + genelists = null } aws { From de6df09db397aaf0bbd6ee49f6a5326069f8b89e Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 11:50:33 +0100 Subject: [PATCH 182/228] module patches --- .../picard-collecthsmetrics.diff | 18 +++++++++++++++++- .../picard-collectwgsmetrics.diff | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff index 5907d093..1407a35a 100644 --- a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff +++ b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff @@ -26,7 +26,7 @@ Changes in 'picard/collecthsmetrics/main.nf': def avail_mem = 3072 if (!task.memory) { -@@ -37,14 +33,14 @@ +@@ -37,18 +33,19 @@ def bait_intervallist_cmd = "" if (bait_intervals =~ /.(bed|bed.gz)$/){ bait_interval_list = bait_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") @@ -43,6 +43,22 @@ Changes in 'picard/collecthsmetrics/main.nf': } + """ ++ export TMP=\$PWD + + $bait_intervallist_cmd + $target_intervallist_cmd +@@ -61,8 +58,8 @@ + --BAIT_INTERVALS $bait_interval_list \\ + --TARGET_INTERVALS $target_interval_list \\ + --INPUT $bam \\ +- --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics +- ++ --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics \\ ++ --TMP_DIR . + + cat <<-END_VERSIONS > versions.yml + "${task.process}": 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff index bf843c60..04fea62a 100644 --- a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff +++ b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff @@ -15,6 +15,22 @@ Changes in 'picard/collectwgsmetrics/main.nf': path intervallist output: +@@ -31,6 +29,7 @@ + avail_mem = (task.memory.mega*0.8).intValue() + } + """ ++ export TMP=\$PWD + picard \\ + -Xmx${avail_mem}M \\ + CollectWgsMetrics \\ +@@ -38,6 +37,7 @@ + --INPUT $bam \\ + --OUTPUT ${prefix}.CollectWgsMetrics.coverage_metrics \\ + --REFERENCE_SEQUENCE ${fasta} \\ ++ --TMP_DIR . \\ + $interval + + 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test' is unchanged From 32604dc4b2eafd1735e2a57d738c48f91418a4b3 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 12:26:28 +0100 Subject: [PATCH 183/228] fix snapshot --- tests/workflows/preprocessing.nf.test.snap | 36 ++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 0bdfd83c..d40bc343 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -44,6 +44,12 @@ ], "demultiplex_reports": [ + ], + "falco_html": [ + + ], + "falco_txt": [ + ], "fastp_html": [ [ @@ -394,7 +400,7 @@ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -670,9 +676,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-23T13:59:59.404732" + "timestamp": "2026-02-11T12:00:40.443933" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -719,6 +725,12 @@ ], "demultiplex_reports": [ + ], + "falco_html": [ + + ], + "falco_txt": [ + ], "fastp_html": [ [ @@ -853,7 +865,7 @@ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -1019,9 +1031,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-23T14:06:35.503463" + "timestamp": "2026-02-11T12:11:20.398961" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1067,6 +1079,12 @@ ], "demultiplex_reports": [ + ], + "falco_html": [ + + ], + "falco_txt": [ + ], "fastp_html": [ [ @@ -1336,7 +1354,7 @@ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -1604,8 +1622,8 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-23T14:04:00.643521" + "timestamp": "2026-02-11T12:06:12.331519" } } \ No newline at end of file From fbe585296220819e4b9bb2636e8342c5abe6a9ec Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:08:18 +0100 Subject: [PATCH 184/228] fix coverage issues --- conf/modules.config | 6 +-- subworkflows/local/coverage/main.nf | 17 +++++---- tests/config/igenomes_test.config | 14 +++---- .../subworkflows/local/coverage/main.nf.test | 10 ++--- .../local/coverage/main.nf.test.snap | 38 +++++++++++++++---- workflows/preprocessing.nf | 3 +- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 03f7047a..0c65d04c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -90,9 +90,7 @@ process { cpus = 16 memory = 32.GB ext.args = { - [ - meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : "" - ].join(" ").trim() + [meta.readgroup ? "--RGSM \"@RG\\t" + meta.readgroup.findResults { rg -> rg.value?.trim() ? "${rg.key}:${rg.value}" : null }.join("\\t") + "\"" : ""].join(" ").trim() } ext.args2 = "--fast" } @@ -307,5 +305,5 @@ env { MOSDEPTH_Q2 = 'CALLABLE' // Set TMPDIR for all modules - TMPDIR = "$PWD" + TMPDIR = "\$PWD" } diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index ccbf27ad..5f9637d7 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -13,7 +13,6 @@ workflow COVERAGE { main: ch_versions = channel.empty() - ch_coverageqc_files = channel.empty() MOSDEPTH( ch_meta_cram_crai_fasta_fai_roi.map { meta, cram, crai, fasta, _fai, roi -> @@ -26,15 +25,19 @@ workflow COVERAGE { return [meta, cram, crai, fasta, fai] } ) - ch_coverageqc_files = ch_coverageqc_files.merge(SAMTOOLS_COVERAGE.out.coverage) + ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) PANELCOVERAGE( - MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> + MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists) + .view() + .map { meta, bed, index, genelists -> // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... - def genelists_array = genelists !instanceof List ? [genelists] : genelists + if (genelists !instanceof List) { + genelists = [genelists] + } def filtered_genelists = meta.tag.toLowerCase() == "seqcap" - ? genelists_array.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } - : genelists_array.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } + ? genelists.findAll { genelist -> genelist.name.toLowerCase().contains("seqcap") } + : genelists.findAll { genelist -> !genelist.name.toLowerCase().contains("seqcap") } if (filtered_genelists.size() > 0) { return [ @@ -46,7 +49,7 @@ workflow COVERAGE { } } ) - ch_coverageqc_files = ch_coverageqc_files.mix(PANELCOVERAGE.out.regiondist) + ch_versions = ch_versions.mix(PANELCOVERAGE.out.versions.first()) emit: mosdepth_global = MOSDEPTH.out.global_txt diff --git a/tests/config/igenomes_test.config b/tests/config/igenomes_test.config index 74154eec..cac18b9e 100644 --- a/tests/config/igenomes_test.config +++ b/tests/config/igenomes_test.config @@ -1,15 +1,15 @@ params { genomes { GRCh38 { - bwamem = "s3://test-data/genomics/homo_sapiens/genome/bwa/" - dict = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict" - fai = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" - fasta = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" - star = "s3://test-data/genomics/homo_sapiens/genome/star/" - gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + bwamem = "s3://test-data/genomics/homo_sapiens/genome/bwa/" + dict = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict" + fai = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai" + fasta = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" + star = "s3://test-data/genomics/homo_sapiens/genome/star/" + gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + genelists = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" } } - genelists = null } aws { diff --git a/tests/subworkflows/local/coverage/main.nf.test b/tests/subworkflows/local/coverage/main.nf.test index 8792b87c..7b90545d 100644 --- a/tests/subworkflows/local/coverage/main.nf.test +++ b/tests/subworkflows/local/coverage/main.nf.test @@ -23,9 +23,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - input[1] = Channel.value([ - file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) - ]) + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" + input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } @@ -52,9 +51,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - input[1] = Channel.value([ - file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/genelists/genelist_chr21_per_exon.bed",checkIfExists:true) - ]) + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" + input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 4df77336..7bd91330 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -45,7 +45,10 @@ "single_end": false, "tag": "WES" }, - "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" + [ + "test_Treatable_ID_per_exon.mosdepth.region.dist.txt:md5,6c2b5237d98e0a2f118a3553c2ba478e", + "test_bladder_cancer_per_exon.mosdepth.region.dist.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "14": [ @@ -232,7 +235,10 @@ "single_end": false, "tag": "WES" }, - "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,e5c7b4f381721888249c57aa55be2d34" + [ + "test_Treatable_ID_per_exon.mosdepth.region.dist.txt:md5,6c2b5237d98e0a2f118a3553c2ba478e", + "test_bladder_cancer_per_exon.mosdepth.region.dist.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] ] ], "samtools_coverage": [ @@ -254,9 +260,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-09T12:02:48.263146" + "timestamp": "2026-02-11T14:05:13.106828" }, "Coverage - seqcap": { "content": [ @@ -298,10 +304,18 @@ ] ], "13": [ - + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test_seqcap_Connective_tissue_per_exon.mosdepth.region.dist.txt:md5,e098c901acb1da8c2cf64a248306e71c" + ] ], "14": [ "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", + "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ], "2": [ @@ -477,7 +491,14 @@ ], "panelcoverage": [ - + [ + { + "id": "test", + "single_end": false, + "tag": "seqcap" + }, + "test_seqcap_Connective_tissue_per_exon.mosdepth.region.dist.txt:md5,e098c901acb1da8c2cf64a248306e71c" + ] ], "samtools_coverage": [ [ @@ -491,14 +512,15 @@ ], "versions": [ "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", + "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-09T12:02:26.604953" + "timestamp": "2026-02-11T13:54:02.513877" } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 541f0359..b1ca0220 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -54,7 +54,8 @@ workflow PREPROCESSING { error("Unable to determine input type, please check inputs") } .set { ch_inputs_from_samplesheet } - genelists = genelists ? channel.value(file(genelists + "/*.bed", checkIfExists: true)) : channel.empty() + // construct a value channel containing an array of files, because the coverage subworkflow expects a channel of arrays of genelist files (to allow for multiple genelist files per sample) + ch_genelists = genelists ? channel.fromPath(genelists).collect().map { files -> [ files ] } : channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From e0e95915aff55dffb6f74aa75409e9bee71ad88a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:05:33 +0100 Subject: [PATCH 185/228] fix genelist path parsing --- tests/subworkflows/local/coverage/main.nf.test | 8 ++++---- workflows/preprocessing.nf | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/subworkflows/local/coverage/main.nf.test b/tests/subworkflows/local/coverage/main.nf.test index 7b90545d..c13bd512 100644 --- a/tests/subworkflows/local/coverage/main.nf.test +++ b/tests/subworkflows/local/coverage/main.nf.test @@ -23,8 +23,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" - input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists" + input[1] = channel.fromPath(genelists_path + "/*.bed").collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } @@ -51,8 +51,8 @@ nextflow_workflow { file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true), ]) // genelists - def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" - input[1] = channel.fromPath(genelists_path).collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } + def genelists_path = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists" + input[1] = channel.fromPath(genelists_path + "/*.bed").collect().map{ files -> [ files ] }.ifEmpty { channel.empty() } """ } } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index b1ca0220..3cdcc9c1 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -55,7 +55,7 @@ workflow PREPROCESSING { } .set { ch_inputs_from_samplesheet } // construct a value channel containing an array of files, because the coverage subworkflow expects a channel of arrays of genelist files (to allow for multiple genelist files per sample) - ch_genelists = genelists ? channel.fromPath(genelists).collect().map { files -> [ files ] } : channel.empty() + ch_genelists = genelists ? channel.fromPath(genelists + "/*.bed").collect().map { files -> [ files ] } : channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 8d2580e5b15b41840f6aed00628e980c03f0c568 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:20:21 +0100 Subject: [PATCH 186/228] deprecate global analysis params in favor of per sample settings --- modules/nf-core/picard/collectmultiplemetrics/main.nf | 3 ++- workflows/preprocessing.nf | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index 28d8eaa0..d6e200f9 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -39,7 +39,8 @@ process PICARD_COLLECTMULTIPLEMETRICS { --OUTPUT ${prefix}.CollectMultipleMetrics \\ $intervals_cmd \\ --TMP_DIR . \\ - $reference_cmd + $reference_cmd \\ + $intervals_cmd """ stub: diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 3cdcc9c1..f93c2d09 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -251,7 +251,7 @@ workflow PREPROCESSING { ) ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics) - /* +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: COVERAGE ANALYSIS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From c238ce4741d22b904e72dceb5a8a5566584b6a25 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:51:55 +0100 Subject: [PATCH 187/228] nextflow lint --- workflows/preprocessing.nf | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index f93c2d09..274c2013 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -258,7 +258,7 @@ workflow PREPROCESSING { */ FASTQ_TO_CRAM.out.cram_crai .filter { meta, _cram, _crai -> - meta.run_coverage && meta.run_coverage.toBoolean() + meta.run_coverage.toBoolean() } .map { meta, cram, crai -> return [ @@ -424,20 +424,20 @@ workflow PREPROCESSING { rna_junctions = FASTQ_TO_CRAM.out.rna_junctions align_reports = FASTQ_TO_CRAM.out.align_reports sormadup_metrics = FASTQ_TO_CRAM.out.sormadup_metrics - mosdepth_global = mosdepth_global_out - mosdepth_summary = mosdepth_summary_out - mosdepth_regions = mosdepth_regions_out - mosdepth_per_base_d4 = mosdepth_per_base_d4_out - mosdepth_per_base_bed = mosdepth_per_base_bed_out - mosdepth_per_base_csi = mosdepth_per_base_csi_out - mosdepth_regions_bed = mosdepth_regions_bed_out - mosdepth_regions_csi = mosdepth_regions_csi_out - mosdepth_quantized_bed = mosdepth_quantized_bed_out - mosdepth_quantized_csi = mosdepth_quantized_csi_out - mosdepth_thresholds_bed = mosdepth_thresholds_bed_out - mosdepth_thresholds_csi = mosdepth_thresholds_csi_out - samtools_coverage = samtools_coverage_out - panelcoverage = panelcoverage_out + mosdepth_global = COVERAGE.out.mosdepth_global + mosdepth_summary = COVERAGE.out.mosdepth_summary + mosdepth_regions = COVERAGE.out.mosdepth_regions + mosdepth_per_base_d4 = COVERAGE.out.mosdepth_per_base_d4 + mosdepth_per_base_bed = COVERAGE.out.mosdepth_per_base_bed + mosdepth_per_base_csi = COVERAGE.out.mosdepth_per_base_csi + mosdepth_regions_bed = COVERAGE.out.mosdepth_regions_bed + mosdepth_regions_csi = COVERAGE.out.mosdepth_regions_csi + mosdepth_quantized_bed = COVERAGE.out.mosdepth_quantized_bed + mosdepth_quantized_csi = COVERAGE.out.mosdepth_quantized_csi + mosdepth_thresholds_bed = COVERAGE.out.mosdepth_thresholds_bed + mosdepth_thresholds_csi = COVERAGE.out.mosdepth_thresholds_csi + samtools_coverage = COVERAGE.out.samtools_coverage + panelcoverage = COVERAGE.out.panelcoverage samtools_stats = BAM_QC.out.samtools_stats samtools_flagstat = BAM_QC.out.samtools_flagstat samtools_idxstats = BAM_QC.out.samtools_idxstats From d9ab5efeb06c45d595f6340f063bc6f48780b6a2 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:24:01 +0100 Subject: [PATCH 188/228] nextflow lint entire pipeline --- subworkflows/local/bam_qc/main.nf | 1 - subworkflows/local/coverage/main.nf | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index d6e1c8bd..d9cd0f7c 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -52,7 +52,6 @@ workflow BAM_QC { PICARD_COLLECTHSMETRICS(ch_picard_coverage.hsmetrics) ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics - ch_picard_hsmetrics = PICARD_COLLECTHSMETRICS.out.metrics emit: samtools_stats = SAMTOOLS_STATS.out.stats diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 5f9637d7..0f9a42d3 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -66,4 +66,5 @@ workflow COVERAGE { mosdepth_thresholds_csi = MOSDEPTH.out.thresholds_csi samtools_coverage = SAMTOOLS_COVERAGE.out.coverage panelcoverage = PANELCOVERAGE.out.regiondist + versions = ch_versions } From 92cb905b1c60e255c309e318d52242795257e931 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:36:06 +0100 Subject: [PATCH 189/228] bump picard/collectmultiplemetrics module --- modules/nf-core/picard/collectmultiplemetrics/main.nf | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index d6e200f9..11b00464 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -37,7 +37,6 @@ process PICARD_COLLECTMULTIPLEMETRICS { $args \\ --INPUT $bam \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ - $intervals_cmd \\ --TMP_DIR . \\ $reference_cmd \\ $intervals_cmd From 068421893213f5fd23c549c2d81d5806d70b61a9 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:35:15 +0100 Subject: [PATCH 190/228] more topic work --- subworkflows/local/coverage/main.nf | 1 - 1 file changed, 1 deletion(-) diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 0f9a42d3..5f9637d7 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -66,5 +66,4 @@ workflow COVERAGE { mosdepth_thresholds_csi = MOSDEPTH.out.thresholds_csi samtools_coverage = SAMTOOLS_COVERAGE.out.coverage panelcoverage = PANELCOVERAGE.out.regiondist - versions = ch_versions } From a9323bbbe51b5a0bea69a56f84d10290861b9c43 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:56:31 +0100 Subject: [PATCH 191/228] lint (again) --- subworkflows/local/coverage/main.nf | 4 +- subworkflows/nf-core/bcl_demultiplex/main.nf | 141 ++++++------- .../bcl_demultiplex/tests/nextflow.config | 13 +- .../nf-core/utils_nextflow_pipeline/main.nf | 22 +- .../nf-core/utils_nfcore_pipeline/main.nf | 198 +++++++++--------- .../tests/nextflow.config | 2 +- .../nf-core/utils_nfschema_plugin/main.nf | 49 ++--- .../tests/nextflow.config | 2 +- workflows/preprocessing.nf | 6 +- 9 files changed, 215 insertions(+), 222 deletions(-) diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 5f9637d7..ca70e40a 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -28,9 +28,7 @@ workflow COVERAGE { ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) PANELCOVERAGE( - MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists) - .view() - .map { meta, bed, index, genelists -> + MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).view().map { meta, bed, index, genelists -> // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... if (genelists !instanceof List) { genelists = [genelists] diff --git a/subworkflows/nf-core/bcl_demultiplex/main.nf b/subworkflows/nf-core/bcl_demultiplex/main.nf index bfe1ae83..fefa3af3 100644 --- a/subworkflows/nf-core/bcl_demultiplex/main.nf +++ b/subworkflows/nf-core/bcl_demultiplex/main.nf @@ -9,66 +9,64 @@ include { BCL2FASTQ } from "../../../modules/nf-core/bcl2fastq/main" workflow BCL_DEMULTIPLEX { take: - ch_flowcell // [[id:"", lane:""], samplesheet.csv, path/to/bcl/files] - demultiplexer // bclconvert or bcl2fastq + ch_flowcell // [[id:"", lane:""], samplesheet.csv, path/to/bcl/files] + demultiplexer // bclconvert or bcl2fastq main: - ch_versions = channel.empty() - ch_fastq = channel.empty() - ch_reports = channel.empty() - ch_stats = channel.empty() - ch_interop = channel.empty() - ch_logs = channel.empty() + ch_versions = channel.empty() + ch_fastq = channel.empty() + ch_reports = channel.empty() + ch_stats = channel.empty() + ch_interop = channel.empty() + ch_logs = channel.empty() - // Split flowcells into separate channels containing run as tar and run as path - // https://nextflow.slack.com/archives/C02T98A23U7/p1650963988498929 - ch_flowcell - .branch { _meta, _samplesheet, run -> - tar: run.toString().endsWith(".tar.gz") - dir: true - }.set { ch_flowcells } + // Split flowcells into separate channels containing run as tar and run as path + // https://nextflow.slack.com/archives/C02T98A23U7/p1650963988498929 + ch_flowcell + .branch { _meta, _samplesheet, run -> + tar: run.toString().endsWith(".tar.gz") + dir: true + } + .set { ch_flowcells } - ch_flowcells.tar - .multiMap { meta, samplesheet, run -> - samplesheets: [ meta, samplesheet ] - run_dirs: [ meta, run ] - }.set { ch_flowcells_tar } + ch_flowcells.tar + .multiMap { meta, samplesheet, run -> + samplesheets: [meta, samplesheet] + run_dirs: [meta, run] + } + .set { ch_flowcells_tar } - // Runs when run_dir is a tar archive - // Re-join the metadata and the untarred run directory with the samplesheet - ch_flowcells_tar_merged = ch_flowcells_tar - .samplesheets - .join( ch_flowcells_tar.run_dirs ) + // Runs when run_dir is a tar archive + // Re-join the metadata and the untarred run directory with the samplesheet + ch_flowcells_tar_merged = ch_flowcells_tar.samplesheets.join(ch_flowcells_tar.run_dirs) - // Merge the two channels back together - ch_flowcells = ch_flowcells.dir.mix(ch_flowcells_tar_merged) + // Merge the two channels back together + ch_flowcells = ch_flowcells.dir.mix(ch_flowcells_tar_merged) - // MODULE: bclconvert - // Demultiplex the bcl files - if (demultiplexer == "bclconvert") { - BCLCONVERT( ch_flowcells ) - ch_fastq = ch_fastq.mix(BCLCONVERT.out.fastq) - 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_versions = ch_versions.mix(BCLCONVERT.out.versions.first()) - } + // MODULE: bclconvert + // Demultiplex the bcl files + if (demultiplexer == "bclconvert") { + BCLCONVERT(ch_flowcells) + ch_fastq = ch_fastq.mix(BCLCONVERT.out.fastq) + 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_versions = ch_versions.mix(BCLCONVERT.out.versions.first()) + } - // MODULE: bcl2fastq - // Demultiplex the bcl files - if (demultiplexer == "bcl2fastq") { - BCL2FASTQ( ch_flowcells ) - ch_fastq = ch_fastq.mix(BCL2FASTQ.out.fastq) - 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_versions = ch_versions.mix(BCL2FASTQ.out.versions.first()) - } + // MODULE: bcl2fastq + // Demultiplex the bcl files + if (demultiplexer == "bcl2fastq") { + BCL2FASTQ(ch_flowcells) + ch_fastq = ch_fastq.mix(BCL2FASTQ.out.fastq) + 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_versions = ch_versions.mix(BCL2FASTQ.out.versions.first()) + } - // Generate meta for each fastq - ch_fastq - // reshapes the channel from a single emit of [meta, [fastq, fastq, fastq...]] - // to emits per fastq file like [meta, fastq] + // Generate meta for each fastq + ch_fastq .transpose() .map { fc_meta, fastq -> def meta = [:] @@ -86,7 +84,7 @@ workflow BCL_DEMULTIPLEX { line = buffered.readLine() buffered.close() } - if ( line != null && line.startsWith('@') ) { + if (line != null && line.startsWith('@')) { line = line.substring(1) // expected format is like: // xx:yy:FLOWCELLID:LANE:... (seven fields) @@ -95,45 +93,40 @@ workflow BCL_DEMULTIPLEX { // "@::::::: :::" //def sequencer_serial = fields[0] //def run_nubmer = fields[1] - def fcid = fields[2] - def lane = fields[3] - def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" + def fcid = fields[2] + def lane = fields[3] + def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" def ID = [fcid, lane].join(".") def PU = [fcid, lane, index].findAll().join(".") def PL = "ILLUMINA" def SM = fastq.getSimpleName().toString() - ~/_S[0-9]+.*$/ - meta.readgroup = [ - "ID": ID, - "SM": SM, - "PL": PL, - "PU": PU - ] + meta.readgroup = ["ID": ID, "SM": SM, "PL": PL, "PU": PU] meta.empty = false - } else { - println "No reads were found in FASTQ file: ${fastq}" + } + else { + println("No reads were found in FASTQ file: ${fastq}") meta.readgroup = [:] meta.empty = true } return [meta, fastq] } - // Group by the meta id so that we can find mate pairs if they exist .groupTuple(by: [0]) .map { meta, fastq -> meta.single_end = fastq.size() == 1 return [meta, fastq.flatten()] } .branch { meta, _fastq -> - fastq : meta.empty == false - empty_fastq : meta.empty == true + fastq: meta.empty == false + empty_fastq: meta.empty == true } - .set{ch_fastq_with_meta} + .set { ch_fastq_with_meta } emit: - fastq = ch_fastq_with_meta.fastq - empty_fastq = ch_fastq_with_meta.empty_fastq - reports = ch_reports - stats = ch_stats - interop = ch_interop - logs = ch_logs - versions = ch_versions + fastq = ch_fastq_with_meta.fastq + empty_fastq = ch_fastq_with_meta.empty_fastq + reports = ch_reports + stats = ch_stats + interop = ch_interop + logs = ch_logs + versions = ch_versions } diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config b/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config index dd8bfa2a..555a2ec7 100644 --- a/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config +++ b/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config @@ -1,13 +1,12 @@ process { withName: BCLCONVERT { - ext.args = {[ - meta.lane ? "--bcl-only-lane ${meta.lane}" : "", - "--force" - ].join(" ").trim()} + ext.args = { + [meta.lane ? "--bcl-only-lane ${meta.lane}" : "", "--force"].join(" ").trim() + } } withName: BCL2FASTQ { - ext.args = {[ - "--tiles s_1_1101" - ].join(" ").trim()} + ext.args = { + ["--tiles s_1_1101"].join(" ").trim() + } } } diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index d6e593e8..7049caef 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -10,9 +10,9 @@ workflow UTILS_NEXTFLOW_PIPELINE { take: - print_version // boolean: print version - dump_parameters // boolean: dump parameters - outdir // path: base directory used to publish pipeline results + print_version // boolean: print version + dump_parameters // boolean: dump parameters + outdir // path: base directory used to publish pipeline results check_conda_channels // boolean: check conda channels main: @@ -72,10 +72,10 @@ def getWorkflowVersion() { // def dumpParametersToJSON(outdir) { def timestamp = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') - def filename = "params_${timestamp}.json" - def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") - def jsonStr = groovy.json.JsonOutput.toJson(params) - temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") + def jsonStr = groovy.json.JsonOutput.toJson(params) + temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) nextflow.extension.FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") temp_pf.delete() @@ -91,12 +91,12 @@ def checkCondaChannels() { def config = parser.load("conda config --show channels".execute().text) channels = config.channels } - catch (NullPointerException e) { + catch (e: NullPointerException) { log.debug(e) log.warn("Could not verify conda channel configuration.") return null } - catch (IOException e) { + catch (e: IOException) { log.debug(e) log.warn("Could not verify conda channel configuration.") return null @@ -111,7 +111,8 @@ def checkCondaChannels() { def channel_priority_violation = required_channels_in_order != channels.findAll { ch -> ch in required_channels_in_order } if (channels_missing | channel_priority_violation) { - log.warn """\ + log.warn( + """\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There is a problem with your Conda configuration! You will need to set-up the conda-forge and bioconda channels correctly. @@ -122,5 +123,6 @@ def checkCondaChannels() { ${required_channels_in_order} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" """.stripIndent(true) + ) } } diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a4..cf586322 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -125,12 +125,12 @@ def paramsSummaryMultiqc(summary_params) { } def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String - yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" - yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" - yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" - yaml_file_text += "plot_type: 'html'\n" - yaml_file_text += "data: |\n" - yaml_file_text += "${summary_section}" + yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" + yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" + yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" + yaml_file_text += "plot_type: 'html'\n" + yaml_file_text += "data: |\n" + yaml_file_text += "${summary_section}" return yaml_file_text } @@ -138,67 +138,67 @@ def paramsSummaryMultiqc(summary_params) { // // ANSII colours used for terminal logging // -def logColours(monochrome_logs=true) { +def logColours(monochrome_logs = true) { def colorcodes = [:] as Map // Reset / Meta - colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" - colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" - colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" + colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" + colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" + colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m" - colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" - colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" - colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" + colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" + colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" + colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" // Regular Colors - colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" - colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" - colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" + colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" + colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" + colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" - colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" + colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" - colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" - colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" + colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" + colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" // Bold - colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" - colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" - colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" + colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" + colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" + colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" - colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" + colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" - colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" - colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" + colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" + colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" // Underline - colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" - colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" - colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" + colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" + colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" + colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" - colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" + colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" - colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" - colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" + colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" + colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" // High Intensity - colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" - colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" - colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" + colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" + colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" + colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" - colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" + colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" - colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" - colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" + colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" + colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" // Bold High Intensity - colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" - colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" - colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" + colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" + colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" + colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" - colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" + colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" - colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" - colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" + colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" + colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" return colorcodes } @@ -208,17 +208,21 @@ def logColours(monochrome_logs=true) { def getSingleReport(multiqc_reports) { if (multiqc_reports instanceof Path) { return multiqc_reports - } else if (multiqc_reports instanceof List) { + } + else if (multiqc_reports instanceof List) { if (multiqc_reports.size() == 0) { log.warn("[${workflow.manifest.name}] No reports found from process 'MULTIQC'") return null - } else if (multiqc_reports.size() == 1) { + } + else if (multiqc_reports.size() == 1) { return multiqc_reports.first() - } else { + } + else { log.warn("[${workflow.manifest.name}] Found multiple reports from process 'MULTIQC', will use only one") return multiqc_reports.first() } - } else { + } + else { return null } } @@ -226,7 +230,7 @@ def getSingleReport(multiqc_reports) { // // Construct and send completion email // -def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs=true, multiqc_report=null) { +def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs = true, multiqc_report = null) { // Set up the e-mail variables def subject = "[${workflow.manifest.name}] Successful: ${workflow.runName}" @@ -243,35 +247,35 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi } def misc_fields = [:] - misc_fields['Date Started'] = workflow.start - misc_fields['Date Completed'] = workflow.complete + misc_fields['Date Started'] = workflow.start + misc_fields['Date Completed'] = workflow.complete misc_fields['Pipeline script file path'] = workflow.scriptFile - misc_fields['Pipeline script hash ID'] = workflow.scriptId + misc_fields['Pipeline script hash ID'] = workflow.scriptId if (workflow.repository) { - misc_fields['Pipeline repository Git URL'] = workflow.repository + misc_fields['Pipeline repository Git URL'] = workflow.repository } if (workflow.commitId) { misc_fields['Pipeline repository Git Commit'] = workflow.commitId } if (workflow.revision) { - misc_fields['Pipeline Git branch/tag'] = workflow.revision + misc_fields['Pipeline Git branch/tag'] = workflow.revision } - misc_fields['Nextflow Version'] = workflow.nextflow.version - misc_fields['Nextflow Build'] = workflow.nextflow.build + misc_fields['Nextflow Version'] = workflow.nextflow.version + misc_fields['Nextflow Build'] = workflow.nextflow.build misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp def email_fields = [:] - email_fields['version'] = getWorkflowVersion() - email_fields['runName'] = workflow.runName - email_fields['success'] = workflow.success + email_fields['version'] = getWorkflowVersion() + email_fields['runName'] = workflow.runName + email_fields['success'] = workflow.success email_fields['dateComplete'] = workflow.complete - email_fields['duration'] = workflow.duration - email_fields['exitStatus'] = workflow.exitStatus + email_fields['duration'] = workflow.duration + email_fields['exitStatus'] = workflow.exitStatus email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - email_fields['errorReport'] = (workflow.errorReport ?: 'None') - email_fields['commandLine'] = workflow.commandLine - email_fields['projectDir'] = workflow.projectDir - email_fields['summary'] = summary << misc_fields + email_fields['errorReport'] = (workflow.errorReport ?: 'None') + email_fields['commandLine'] = workflow.commandLine + email_fields['projectDir'] = workflow.projectDir + email_fields['summary'] = summary << misc_fields // On success try attach the multiqc report def mqc_report = getSingleReport(multiqc_report) @@ -283,22 +287,22 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi } // Render the TXT template - def engine = new groovy.text.GStringTemplateEngine() - def tf = new File("${workflow.projectDir}/assets/email_template.txt") + def engine = new groovy.text.GStringTemplateEngine() + def tf = new File("${workflow.projectDir}/assets/email_template.txt") def txt_template = engine.createTemplate(tf).make(email_fields) - def email_txt = txt_template.toString() + def email_txt = txt_template.toString() // Render the HTML template - def hf = new File("${workflow.projectDir}/assets/email_template.html") + def hf = new File("${workflow.projectDir}/assets/email_template.html") def html_template = engine.createTemplate(hf).make(email_fields) - def email_html = html_template.toString() + def email_html = html_template.toString() // Render the sendmail template def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as MemoryUnit - def smail_fields = [email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes()] - def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") - def sendmail_template = engine.createTemplate(sf).make(smail_fields) - def sendmail_html = sendmail_template.toString() + def smail_fields = [email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes()] + def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") + def sendmail_template = engine.createTemplate(sf).make(smail_fields) + def sendmail_html = sendmail_template.toString() // Send the HTML e-mail def colors = logColours(monochrome_logs) as Map @@ -313,7 +317,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi ['sendmail', '-t'].execute() << sendmail_html log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Sent summary e-mail to ${email_address} (sendmail)-") } - catch (Exception msg) { + catch (msg: Exception) { log.debug(msg.toString()) log.debug("Trying with mail instead of sendmail") // Catch failures and try with plaintext @@ -339,7 +343,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi // // Print pipeline summary on completion // -def completionSummary(monochrome_logs=true) { +def completionSummary(monochrome_logs = true) { def colors = logColours(monochrome_logs) as Map if (workflow.success) { if (workflow.stats.ignoredCount == 0) { @@ -367,44 +371,44 @@ def imNotification(summary_params, hook_url) { } def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId + misc_fields['start'] = workflow.start + misc_fields['complete'] = workflow.complete + misc_fields['scriptfile'] = workflow.scriptFile + misc_fields['scriptid'] = workflow.scriptId if (workflow.repository) { misc_fields['repository'] = workflow.repository } if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId + misc_fields['commitid'] = workflow.commitId } if (workflow.revision) { - misc_fields['revision'] = workflow.revision + misc_fields['revision'] = workflow.revision } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp + misc_fields['nxf_version'] = workflow.nextflow.version + misc_fields['nxf_build'] = workflow.nextflow.build + misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success + msg_fields['version'] = getWorkflowVersion() + msg_fields['runName'] = workflow.runName + msg_fields['success'] = workflow.success msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus + msg_fields['duration'] = workflow.duration + msg_fields['exitStatus'] = workflow.exitStatus msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields + msg_fields['errorReport'] = (workflow.errorReport ?: 'None') + msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") + msg_fields['projectDir'] = workflow.projectDir + msg_fields['summary'] = summary << misc_fields // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() + def engine = new groovy.text.GStringTemplateEngine() // Different JSON depending on the service provider // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") + def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" + def hf = new File("${workflow.projectDir}/assets/${json_path}") def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() + def json_message = json_template.toString() // POST def post = new URL(hook_url).openConnection() diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config index d0a926bf..a09572e5 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config @@ -3,7 +3,7 @@ manifest { author = """nf-core""" homePage = 'https://127.0.0.1' description = """Dummy pipeline""" - nextflowVersion = '!>=23.04.0' + nextflowVersion = '!>=23.04.0' version = '9.9.9' doi = 'https://doi.org/10.5281/zenodo.5070524' } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf index 1df8b76f..e2821afd 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -7,25 +7,20 @@ include { validateParameters } from 'plugin/nf-schema' include { paramsHelp } from 'plugin/nf-schema' workflow UTILS_NFSCHEMA_PLUGIN { - take: - input_workflow // workflow: the workflow object used by nf-schema to get metadata from the workflow - validate_params // boolean: validate the parameters - parameters_schema // string: path to the parameters JSON schema. - // this has to be the same as the schema given to `validation.parametersSchema` - // when this input is empty it will automatically use the configured schema or - // "${projectDir}/nextflow_schema.json" as default. This input should not be empty - // for meta pipelines - help // boolean: show help message - help_full // boolean: show full help message - show_hidden // boolean: show hidden parameters in help message - before_text // string: text to show before the help message and parameters summary - after_text // string: text to show after the help message and parameters summary - command // string: an example command of the pipeline + input_workflow // workflow: the workflow object used by nf-schema to get metadata from the workflow + validate_params // boolean: validate the parameters + parameters_schema // string: path to the parameters JSON schema. + help // boolean: show help message + help_full // boolean: show full help message + show_hidden // boolean: show hidden parameters in help message + before_text // string: text to show before the help message and parameters summary + after_text // string: text to show after the help message and parameters summary + command // string: an example command of the pipeline main: - if(help || help_full) { + if (help || help_full) { help_options = [ beforeText: before_text, afterText: after_text, @@ -33,14 +28,16 @@ workflow UTILS_NFSCHEMA_PLUGIN { showHidden: show_hidden, fullHelp: help_full, ] - if(parameters_schema) { + if (parameters_schema) { help_options << [parametersSchema: parameters_schema] } - log.info paramsHelp( - help_options, - (params.help instanceof String && params.help != "true") ? params.help : "", + log.info( + paramsHelp( + help_options, + params.help instanceof String && params.help != "true" ? params.help : "", + ) ) - exit 0 + exit(0) } // @@ -49,20 +46,20 @@ workflow UTILS_NFSCHEMA_PLUGIN { // summary_options = [:] - if(parameters_schema) { + if (parameters_schema) { summary_options << [parametersSchema: parameters_schema] } - log.info before_text - log.info paramsSummaryLog(summary_options, input_workflow) - log.info after_text + log.info(before_text) + log.info(paramsSummaryLog(summary_options, input_workflow)) + log.info(after_text) // // Validate the parameters using nextflow_schema.json or the schema // given via the validation.parametersSchema configuration option // - if(validate_params) { + if (validate_params) { validateOptions = [:] - if(parameters_schema) { + if (parameters_schema) { validateOptions << [parametersSchema: parameters_schema] } validateParameters(validateOptions) diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index f6537cc3..c8ce8606 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -4,5 +4,5 @@ plugins { validation { parametersSchema = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" - monochromeLogs = true + monochromeLogs = true } diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 274c2013..034397f4 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -55,7 +55,7 @@ workflow PREPROCESSING { } .set { ch_inputs_from_samplesheet } // construct a value channel containing an array of files, because the coverage subworkflow expects a channel of arrays of genelist files (to allow for multiple genelist files per sample) - ch_genelists = genelists ? channel.fromPath(genelists + "/*.bed").collect().map { files -> [ files ] } : channel.empty() + ch_genelists = genelists ? channel.fromPath(genelists + "/*.bed").collect().map { files -> [files] } : channel.empty() /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -251,7 +251,7 @@ workflow PREPROCESSING { ) ch_multiqc_files = ch_multiqc_files.mix(FASTQ_TO_CRAM.out.sormadup_metrics) -/* + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // STEP: COVERAGE ANALYSIS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -272,7 +272,7 @@ workflow PREPROCESSING { } .set { ch_cram_crai_fasta_fai_roi } - COVERAGE(ch_cram_crai_fasta_fai_roi, genelists) + COVERAGE(ch_cram_crai_fasta_fai_roi, ch_genelists) ch_multiqc_files = ch_multiqc_files.mix( COVERAGE.out.mosdepth_summary, COVERAGE.out.mosdepth_global, From 53d72df3491fba9d9aa385c5aaf585f0c3121e00 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:06:55 +0100 Subject: [PATCH 192/228] nf-core linting --- modules.json | 4 +- modules/nf-core/bclconvert/bclconvert.diff | 25 --- modules/nf-core/bclconvert/main.nf | 4 +- modules/nf-core/samtools/coverage/meta.yml | 5 - .../samtools/coverage/samtools-coverage.diff | 5 +- .../samtools/coverage/tests/main.nf.test | 86 +++----- .../samtools/coverage/tests/main.nf.test.snap | 56 +---- nextflow.config | 13 +- subworkflows/local/coverage/main.nf | 2 +- subworkflows/nf-core/bcl_demultiplex/main.nf | 141 +++++++------ .../bcl_demultiplex/tests/nextflow.config | 13 +- .../nf-core/utils_nextflow_pipeline/main.nf | 22 +- .../nf-core/utils_nfcore_pipeline/main.nf | 198 +++++++++--------- .../tests/nextflow.config | 2 +- .../nf-core/utils_nfschema_plugin/main.nf | 49 +++-- .../tests/nextflow.config | 2 +- 16 files changed, 268 insertions(+), 359 deletions(-) delete mode 100644 modules/nf-core/bclconvert/bclconvert.diff diff --git a/modules.json b/modules.json index a75b44bf..3b6b2674 100644 --- a/modules.json +++ b/modules.json @@ -13,7 +13,7 @@ "bclconvert": { "branch": "master", "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", - "installed_by": ["bcl_demultiplex", "modules"], + "installed_by": ["bcl_demultiplex"], "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, "biobambam/bamsormadup": { @@ -104,7 +104,7 @@ }, "samtools/coverage": { "branch": "master", - "git_sha": "4154ced8a82f5f17b57e48c68dbb03ecb0e9ca14", + "git_sha": "b2e78932ef01165fd85829513eaca29eff8e640a", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, diff --git a/modules/nf-core/bclconvert/bclconvert.diff b/modules/nf-core/bclconvert/bclconvert.diff deleted file mode 100644 index dc0dee2d..00000000 --- a/modules/nf-core/bclconvert/bclconvert.diff +++ /dev/null @@ -1,25 +0,0 @@ -Changes in component 'nf-core/bclconvert' -'modules/nf-core/bclconvert/LICENSE' is unchanged -'modules/nf-core/bclconvert/Dockerfile' is unchanged -'modules/nf-core/bclconvert/README.md' is unchanged -'modules/nf-core/bclconvert/.gitignore' is unchanged -'modules/nf-core/bclconvert/meta.yml' is unchanged -Changes in 'bclconvert/main.nf': ---- modules/nf-core/bclconvert/main.nf -+++ modules/nf-core/bclconvert/main.nf -@@ -12,8 +12,8 @@ - tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true - tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true - tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true -- tuple val(meta), path("output/Reports") , emit: reports -- tuple val(meta), path("output/Logs") , emit: logs -+ tuple val(meta), path("output/Reports/*") , emit: reports -+ tuple val(meta), path("output/Logs/*") , emit: logs - tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true - path("versions.yml") , emit: versions - - -'modules/nf-core/bclconvert/tests/main.nf.test.snap' is unchanged -'modules/nf-core/bclconvert/tests/nextflow.config' is unchanged -'modules/nf-core/bclconvert/tests/main.nf.test' is unchanged -************************************************************ diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index db0dac03..f1caafc3 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -12,8 +12,8 @@ process BCLCONVERT { tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true - tuple val(meta), path("output/Reports/*") , emit: reports - tuple val(meta), path("output/Logs/*") , emit: logs + tuple val(meta), path("output/Reports") , emit: reports + tuple val(meta), path("output/Logs") , emit: logs tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true path("versions.yml") , emit: versions diff --git a/modules/nf-core/samtools/coverage/meta.yml b/modules/nf-core/samtools/coverage/meta.yml index 754f5f49..b2262177 100644 --- a/modules/nf-core/samtools/coverage/meta.yml +++ b/modules/nf-core/samtools/coverage/meta.yml @@ -41,11 +41,6 @@ input: description: Reference genome file pattern: "*.{fa,fasta}" ontologies: [] - - - meta3: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - fai: type: file description: Reference genome index file diff --git a/modules/nf-core/samtools/coverage/samtools-coverage.diff b/modules/nf-core/samtools/coverage/samtools-coverage.diff index 5dbbbd9e..fe18381a 100644 --- a/modules/nf-core/samtools/coverage/samtools-coverage.diff +++ b/modules/nf-core/samtools/coverage/samtools-coverage.diff @@ -4,13 +4,12 @@ Changes in component 'nf-core/samtools/coverage' Changes in 'samtools/coverage/main.nf': --- modules/nf-core/samtools/coverage/main.nf +++ modules/nf-core/samtools/coverage/main.nf -@@ -8,9 +8,7 @@ +@@ -8,8 +8,7 @@ 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(input), path(input_index) -- tuple val(meta2), path(fasta) -- tuple val(meta3), path(fai) +- tuple val(meta2), path(fasta), path(fai) + tuple val(meta), path(input), path(input_index), path(fasta), path(fai) output: diff --git a/modules/nf-core/samtools/coverage/tests/main.nf.test b/modules/nf-core/samtools/coverage/tests/main.nf.test index ffd36109..c59ba4f8 100644 --- a/modules/nf-core/samtools/coverage/tests/main.nf.test +++ b/modules/nf-core/samtools/coverage/tests/main.nf.test @@ -14,19 +14,12 @@ nextflow_process { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + input[0] = [ + [id: 'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [:], // meta map - [] - ]) - input[2] = Channel.of([ - [:], // meta map - [] - ]) + ] + input[1] = [[], [], []] """ } } @@ -34,7 +27,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } } @@ -44,19 +37,16 @@ nextflow_process { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + 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] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) - ]) - input[2] = Channel.of([ - [ id:'fai' ], // meta map + ] + input[1] = [ + [ id:'fasta_fai' ], + 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) - ]) + ] """ } } @@ -73,19 +63,15 @@ nextflow_process { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + 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] = Channel.of([ - [:], // meta map - [] - ]) - input[2] = Channel.of([ - [ id:'fai' ], // meta map + ] + input[1] = [ + [ id:'fai' ], [], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) - ]) + ] """ } } @@ -102,19 +88,16 @@ nextflow_process { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + 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] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[2] = Channel.of([ - [:], // meta map + ] + input[1] = [ + [ id:'fasta' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), [] - ]) + ] """ } } @@ -135,19 +118,16 @@ nextflow_process { when { process { """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map + input[0] = [ + [id: 'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ]) - input[1] = Channel.of([ - [ id:'fasta' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[2] = Channel.of([ - [ id:'fai' ], // meta map + ] + input[1] = [ + [ id:'fasta' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) - ]) + ] """ } } @@ -155,7 +135,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } diff --git a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap index 2069c8c1..256c6507 100644 --- a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap @@ -2,27 +2,10 @@ "test_samtools_coverage_stub": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - "SAMTOOLS_COVERAGE", - "samtools", - "1.22.1" - ] - ], "coverage": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] @@ -38,34 +21,17 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.3" }, - "timestamp": "2026-01-22T10:43:34.392105918" + "timestamp": "2026-02-10T15:27:27.16473081" }, "test_samtools_coverage_bam": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.txt:md5,99a521b3bf53b6acf8055a44a571ea84" - ] - ], - "1": [ - [ - "SAMTOOLS_COVERAGE", - "samtools", - "1.22.1" - ] - ], "coverage": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.txt:md5,99a521b3bf53b6acf8055a44a571ea84" ] @@ -81,9 +47,9 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.3" }, - "timestamp": "2026-01-22T10:43:08.216921812" + "timestamp": "2026-02-10T15:27:06.759689511" }, "test_samtools_coverage_cram": { "content": [ @@ -91,8 +57,7 @@ "0": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.txt:md5,ce896534bac51cfcc97e5508ae907e99" ] @@ -107,8 +72,7 @@ "coverage": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "test.txt:md5,ce896534bac51cfcc97e5508ae907e99" ] @@ -124,8 +88,8 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.3" }, - "timestamp": "2026-01-22T10:43:15.389524183" + "timestamp": "2026-02-10T15:27:12.949845604" } } \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index 13067b73..d3896216 100644 --- a/nextflow.config +++ b/nextflow.config @@ -47,20 +47,11 @@ params { config_profile_name = null config_profile_description = null - custom_config_version = 'master' - custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" + custom_config_version = 'main' + custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null - // CMGG Config options - cmgg_config_profile_name = null - cmgg_config_profile_description = null - - cmgg_custom_config_version = 'main' - cmgg_custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.cmgg_custom_config_version}" - cmgg_config_profile_contact = null - cmgg_config_profile_url = null - // Schema validation default options validate_params = true } diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index ca70e40a..82d6cb30 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -28,7 +28,7 @@ workflow COVERAGE { ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) PANELCOVERAGE( - MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).view().map { meta, bed, index, genelists -> + MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> // Because groovy typing sucks ass; apparently an array of 1 is automatically converted to a string... if (genelists !instanceof List) { genelists = [genelists] diff --git a/subworkflows/nf-core/bcl_demultiplex/main.nf b/subworkflows/nf-core/bcl_demultiplex/main.nf index fefa3af3..bfe1ae83 100644 --- a/subworkflows/nf-core/bcl_demultiplex/main.nf +++ b/subworkflows/nf-core/bcl_demultiplex/main.nf @@ -9,64 +9,66 @@ include { BCL2FASTQ } from "../../../modules/nf-core/bcl2fastq/main" workflow BCL_DEMULTIPLEX { take: - ch_flowcell // [[id:"", lane:""], samplesheet.csv, path/to/bcl/files] - demultiplexer // bclconvert or bcl2fastq + ch_flowcell // [[id:"", lane:""], samplesheet.csv, path/to/bcl/files] + demultiplexer // bclconvert or bcl2fastq main: - ch_versions = channel.empty() - ch_fastq = channel.empty() - ch_reports = channel.empty() - ch_stats = channel.empty() - ch_interop = channel.empty() - ch_logs = channel.empty() + ch_versions = channel.empty() + ch_fastq = channel.empty() + ch_reports = channel.empty() + ch_stats = channel.empty() + ch_interop = channel.empty() + ch_logs = channel.empty() - // Split flowcells into separate channels containing run as tar and run as path - // https://nextflow.slack.com/archives/C02T98A23U7/p1650963988498929 - ch_flowcell - .branch { _meta, _samplesheet, run -> - tar: run.toString().endsWith(".tar.gz") - dir: true - } - .set { ch_flowcells } + // Split flowcells into separate channels containing run as tar and run as path + // https://nextflow.slack.com/archives/C02T98A23U7/p1650963988498929 + ch_flowcell + .branch { _meta, _samplesheet, run -> + tar: run.toString().endsWith(".tar.gz") + dir: true + }.set { ch_flowcells } - ch_flowcells.tar - .multiMap { meta, samplesheet, run -> - samplesheets: [meta, samplesheet] - run_dirs: [meta, run] - } - .set { ch_flowcells_tar } + ch_flowcells.tar + .multiMap { meta, samplesheet, run -> + samplesheets: [ meta, samplesheet ] + run_dirs: [ meta, run ] + }.set { ch_flowcells_tar } - // Runs when run_dir is a tar archive - // Re-join the metadata and the untarred run directory with the samplesheet - ch_flowcells_tar_merged = ch_flowcells_tar.samplesheets.join(ch_flowcells_tar.run_dirs) + // Runs when run_dir is a tar archive + // Re-join the metadata and the untarred run directory with the samplesheet + ch_flowcells_tar_merged = ch_flowcells_tar + .samplesheets + .join( ch_flowcells_tar.run_dirs ) - // Merge the two channels back together - ch_flowcells = ch_flowcells.dir.mix(ch_flowcells_tar_merged) + // Merge the two channels back together + ch_flowcells = ch_flowcells.dir.mix(ch_flowcells_tar_merged) - // MODULE: bclconvert - // Demultiplex the bcl files - if (demultiplexer == "bclconvert") { - BCLCONVERT(ch_flowcells) - ch_fastq = ch_fastq.mix(BCLCONVERT.out.fastq) - 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_versions = ch_versions.mix(BCLCONVERT.out.versions.first()) - } + // MODULE: bclconvert + // Demultiplex the bcl files + if (demultiplexer == "bclconvert") { + BCLCONVERT( ch_flowcells ) + ch_fastq = ch_fastq.mix(BCLCONVERT.out.fastq) + 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_versions = ch_versions.mix(BCLCONVERT.out.versions.first()) + } - // MODULE: bcl2fastq - // Demultiplex the bcl files - if (demultiplexer == "bcl2fastq") { - BCL2FASTQ(ch_flowcells) - ch_fastq = ch_fastq.mix(BCL2FASTQ.out.fastq) - 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_versions = ch_versions.mix(BCL2FASTQ.out.versions.first()) - } + // MODULE: bcl2fastq + // Demultiplex the bcl files + if (demultiplexer == "bcl2fastq") { + BCL2FASTQ( ch_flowcells ) + ch_fastq = ch_fastq.mix(BCL2FASTQ.out.fastq) + 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_versions = ch_versions.mix(BCL2FASTQ.out.versions.first()) + } - // Generate meta for each fastq - ch_fastq + // Generate meta for each fastq + ch_fastq + // reshapes the channel from a single emit of [meta, [fastq, fastq, fastq...]] + // to emits per fastq file like [meta, fastq] .transpose() .map { fc_meta, fastq -> def meta = [:] @@ -84,7 +86,7 @@ workflow BCL_DEMULTIPLEX { line = buffered.readLine() buffered.close() } - if (line != null && line.startsWith('@')) { + if ( line != null && line.startsWith('@') ) { line = line.substring(1) // expected format is like: // xx:yy:FLOWCELLID:LANE:... (seven fields) @@ -93,40 +95,45 @@ workflow BCL_DEMULTIPLEX { // "@::::::: :::" //def sequencer_serial = fields[0] //def run_nubmer = fields[1] - def fcid = fields[2] - def lane = fields[3] - def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" + def fcid = fields[2] + def lane = fields[3] + def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" def ID = [fcid, lane].join(".") def PU = [fcid, lane, index].findAll().join(".") def PL = "ILLUMINA" def SM = fastq.getSimpleName().toString() - ~/_S[0-9]+.*$/ - meta.readgroup = ["ID": ID, "SM": SM, "PL": PL, "PU": PU] + meta.readgroup = [ + "ID": ID, + "SM": SM, + "PL": PL, + "PU": PU + ] meta.empty = false - } - else { - println("No reads were found in FASTQ file: ${fastq}") + } else { + println "No reads were found in FASTQ file: ${fastq}" meta.readgroup = [:] meta.empty = true } return [meta, fastq] } + // Group by the meta id so that we can find mate pairs if they exist .groupTuple(by: [0]) .map { meta, fastq -> meta.single_end = fastq.size() == 1 return [meta, fastq.flatten()] } .branch { meta, _fastq -> - fastq: meta.empty == false - empty_fastq: meta.empty == true + fastq : meta.empty == false + empty_fastq : meta.empty == true } - .set { ch_fastq_with_meta } + .set{ch_fastq_with_meta} emit: - fastq = ch_fastq_with_meta.fastq - empty_fastq = ch_fastq_with_meta.empty_fastq - reports = ch_reports - stats = ch_stats - interop = ch_interop - logs = ch_logs - versions = ch_versions + fastq = ch_fastq_with_meta.fastq + empty_fastq = ch_fastq_with_meta.empty_fastq + reports = ch_reports + stats = ch_stats + interop = ch_interop + logs = ch_logs + versions = ch_versions } diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config b/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config index 555a2ec7..dd8bfa2a 100644 --- a/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config +++ b/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config @@ -1,12 +1,13 @@ process { withName: BCLCONVERT { - ext.args = { - [meta.lane ? "--bcl-only-lane ${meta.lane}" : "", "--force"].join(" ").trim() - } + ext.args = {[ + meta.lane ? "--bcl-only-lane ${meta.lane}" : "", + "--force" + ].join(" ").trim()} } withName: BCL2FASTQ { - ext.args = { - ["--tiles s_1_1101"].join(" ").trim() - } + ext.args = {[ + "--tiles s_1_1101" + ].join(" ").trim()} } } diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index 7049caef..d6e593e8 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -10,9 +10,9 @@ workflow UTILS_NEXTFLOW_PIPELINE { take: - print_version // boolean: print version - dump_parameters // boolean: dump parameters - outdir // path: base directory used to publish pipeline results + print_version // boolean: print version + dump_parameters // boolean: dump parameters + outdir // path: base directory used to publish pipeline results check_conda_channels // boolean: check conda channels main: @@ -72,10 +72,10 @@ def getWorkflowVersion() { // def dumpParametersToJSON(outdir) { def timestamp = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') - def filename = "params_${timestamp}.json" - def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") - def jsonStr = groovy.json.JsonOutput.toJson(params) - temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") + def jsonStr = groovy.json.JsonOutput.toJson(params) + temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) nextflow.extension.FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") temp_pf.delete() @@ -91,12 +91,12 @@ def checkCondaChannels() { def config = parser.load("conda config --show channels".execute().text) channels = config.channels } - catch (e: NullPointerException) { + catch (NullPointerException e) { log.debug(e) log.warn("Could not verify conda channel configuration.") return null } - catch (e: IOException) { + catch (IOException e) { log.debug(e) log.warn("Could not verify conda channel configuration.") return null @@ -111,8 +111,7 @@ def checkCondaChannels() { def channel_priority_violation = required_channels_in_order != channels.findAll { ch -> ch in required_channels_in_order } if (channels_missing | channel_priority_violation) { - log.warn( - """\ + log.warn """\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There is a problem with your Conda configuration! You will need to set-up the conda-forge and bioconda channels correctly. @@ -123,6 +122,5 @@ def checkCondaChannels() { ${required_channels_in_order} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" """.stripIndent(true) - ) } } diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index cf586322..2f30e9a4 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -125,12 +125,12 @@ def paramsSummaryMultiqc(summary_params) { } def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String - yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" - yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" - yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" - yaml_file_text += "plot_type: 'html'\n" - yaml_file_text += "data: |\n" - yaml_file_text += "${summary_section}" + yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" + yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" + yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" + yaml_file_text += "plot_type: 'html'\n" + yaml_file_text += "data: |\n" + yaml_file_text += "${summary_section}" return yaml_file_text } @@ -138,67 +138,67 @@ def paramsSummaryMultiqc(summary_params) { // // ANSII colours used for terminal logging // -def logColours(monochrome_logs = true) { +def logColours(monochrome_logs=true) { def colorcodes = [:] as Map // Reset / Meta - colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" - colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" - colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" + colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" + colorcodes['bold'] = monochrome_logs ? '' : "\033[1m" + colorcodes['dim'] = monochrome_logs ? '' : "\033[2m" colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m" - colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" - colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" - colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" + colorcodes['blink'] = monochrome_logs ? '' : "\033[5m" + colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m" + colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" // Regular Colors - colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" - colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" - colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" + colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" + colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" + colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" - colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" + colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" - colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" - colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" + colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" + colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" // Bold - colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" - colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" - colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" + colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" + colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" + colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" - colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" + colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" - colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" - colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" + colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" + colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" // Underline - colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" - colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" - colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" + colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" + colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" + colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" - colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" + colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" - colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" - colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" + colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" + colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" // High Intensity - colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" - colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" - colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" + colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" + colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" + colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" - colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" + colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" - colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" - colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" + colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" + colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" // Bold High Intensity - colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" - colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" - colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" + colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" + colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" + colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" - colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" + colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" - colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" - colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" + colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" + colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" return colorcodes } @@ -208,21 +208,17 @@ def logColours(monochrome_logs = true) { def getSingleReport(multiqc_reports) { if (multiqc_reports instanceof Path) { return multiqc_reports - } - else if (multiqc_reports instanceof List) { + } else if (multiqc_reports instanceof List) { if (multiqc_reports.size() == 0) { log.warn("[${workflow.manifest.name}] No reports found from process 'MULTIQC'") return null - } - else if (multiqc_reports.size() == 1) { + } else if (multiqc_reports.size() == 1) { return multiqc_reports.first() - } - else { + } else { log.warn("[${workflow.manifest.name}] Found multiple reports from process 'MULTIQC', will use only one") return multiqc_reports.first() } - } - else { + } else { return null } } @@ -230,7 +226,7 @@ def getSingleReport(multiqc_reports) { // // Construct and send completion email // -def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs = true, multiqc_report = null) { +def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs=true, multiqc_report=null) { // Set up the e-mail variables def subject = "[${workflow.manifest.name}] Successful: ${workflow.runName}" @@ -247,35 +243,35 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi } def misc_fields = [:] - misc_fields['Date Started'] = workflow.start - misc_fields['Date Completed'] = workflow.complete + misc_fields['Date Started'] = workflow.start + misc_fields['Date Completed'] = workflow.complete misc_fields['Pipeline script file path'] = workflow.scriptFile - misc_fields['Pipeline script hash ID'] = workflow.scriptId + misc_fields['Pipeline script hash ID'] = workflow.scriptId if (workflow.repository) { - misc_fields['Pipeline repository Git URL'] = workflow.repository + misc_fields['Pipeline repository Git URL'] = workflow.repository } if (workflow.commitId) { misc_fields['Pipeline repository Git Commit'] = workflow.commitId } if (workflow.revision) { - misc_fields['Pipeline Git branch/tag'] = workflow.revision + misc_fields['Pipeline Git branch/tag'] = workflow.revision } - misc_fields['Nextflow Version'] = workflow.nextflow.version - misc_fields['Nextflow Build'] = workflow.nextflow.build + misc_fields['Nextflow Version'] = workflow.nextflow.version + misc_fields['Nextflow Build'] = workflow.nextflow.build misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp def email_fields = [:] - email_fields['version'] = getWorkflowVersion() - email_fields['runName'] = workflow.runName - email_fields['success'] = workflow.success + email_fields['version'] = getWorkflowVersion() + email_fields['runName'] = workflow.runName + email_fields['success'] = workflow.success email_fields['dateComplete'] = workflow.complete - email_fields['duration'] = workflow.duration - email_fields['exitStatus'] = workflow.exitStatus + email_fields['duration'] = workflow.duration + email_fields['exitStatus'] = workflow.exitStatus email_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - email_fields['errorReport'] = (workflow.errorReport ?: 'None') - email_fields['commandLine'] = workflow.commandLine - email_fields['projectDir'] = workflow.projectDir - email_fields['summary'] = summary << misc_fields + email_fields['errorReport'] = (workflow.errorReport ?: 'None') + email_fields['commandLine'] = workflow.commandLine + email_fields['projectDir'] = workflow.projectDir + email_fields['summary'] = summary << misc_fields // On success try attach the multiqc report def mqc_report = getSingleReport(multiqc_report) @@ -287,22 +283,22 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi } // Render the TXT template - def engine = new groovy.text.GStringTemplateEngine() - def tf = new File("${workflow.projectDir}/assets/email_template.txt") + def engine = new groovy.text.GStringTemplateEngine() + def tf = new File("${workflow.projectDir}/assets/email_template.txt") def txt_template = engine.createTemplate(tf).make(email_fields) - def email_txt = txt_template.toString() + def email_txt = txt_template.toString() // Render the HTML template - def hf = new File("${workflow.projectDir}/assets/email_template.html") + def hf = new File("${workflow.projectDir}/assets/email_template.html") def html_template = engine.createTemplate(hf).make(email_fields) - def email_html = html_template.toString() + def email_html = html_template.toString() // Render the sendmail template def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as MemoryUnit - def smail_fields = [email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes()] - def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") - def sendmail_template = engine.createTemplate(sf).make(smail_fields) - def sendmail_html = sendmail_template.toString() + def smail_fields = [email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes()] + def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") + def sendmail_template = engine.createTemplate(sf).make(smail_fields) + def sendmail_html = sendmail_template.toString() // Send the HTML e-mail def colors = logColours(monochrome_logs) as Map @@ -317,7 +313,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi ['sendmail', '-t'].execute() << sendmail_html log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Sent summary e-mail to ${email_address} (sendmail)-") } - catch (msg: Exception) { + catch (Exception msg) { log.debug(msg.toString()) log.debug("Trying with mail instead of sendmail") // Catch failures and try with plaintext @@ -343,7 +339,7 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi // // Print pipeline summary on completion // -def completionSummary(monochrome_logs = true) { +def completionSummary(monochrome_logs=true) { def colors = logColours(monochrome_logs) as Map if (workflow.success) { if (workflow.stats.ignoredCount == 0) { @@ -371,44 +367,44 @@ def imNotification(summary_params, hook_url) { } def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId + misc_fields['start'] = workflow.start + misc_fields['complete'] = workflow.complete + misc_fields['scriptfile'] = workflow.scriptFile + misc_fields['scriptid'] = workflow.scriptId if (workflow.repository) { misc_fields['repository'] = workflow.repository } if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId + misc_fields['commitid'] = workflow.commitId } if (workflow.revision) { - misc_fields['revision'] = workflow.revision + misc_fields['revision'] = workflow.revision } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp + misc_fields['nxf_version'] = workflow.nextflow.version + misc_fields['nxf_build'] = workflow.nextflow.build + misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success + msg_fields['version'] = getWorkflowVersion() + msg_fields['runName'] = workflow.runName + msg_fields['success'] = workflow.success msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus + msg_fields['duration'] = workflow.duration + msg_fields['exitStatus'] = workflow.exitStatus msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields + msg_fields['errorReport'] = (workflow.errorReport ?: 'None') + msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") + msg_fields['projectDir'] = workflow.projectDir + msg_fields['summary'] = summary << misc_fields // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() + def engine = new groovy.text.GStringTemplateEngine() // Different JSON depending on the service provider // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") + def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" + def hf = new File("${workflow.projectDir}/assets/${json_path}") def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() + def json_message = json_template.toString() // POST def post = new URL(hook_url).openConnection() diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config index a09572e5..d0a926bf 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config @@ -3,7 +3,7 @@ manifest { author = """nf-core""" homePage = 'https://127.0.0.1' description = """Dummy pipeline""" - nextflowVersion = '!>=23.04.0' + nextflowVersion = '!>=23.04.0' version = '9.9.9' doi = 'https://doi.org/10.5281/zenodo.5070524' } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf index e2821afd..1df8b76f 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -7,20 +7,25 @@ include { validateParameters } from 'plugin/nf-schema' include { paramsHelp } from 'plugin/nf-schema' workflow UTILS_NFSCHEMA_PLUGIN { + take: - input_workflow // workflow: the workflow object used by nf-schema to get metadata from the workflow - validate_params // boolean: validate the parameters - parameters_schema // string: path to the parameters JSON schema. - help // boolean: show help message - help_full // boolean: show full help message - show_hidden // boolean: show hidden parameters in help message - before_text // string: text to show before the help message and parameters summary - after_text // string: text to show after the help message and parameters summary - command // string: an example command of the pipeline + input_workflow // workflow: the workflow object used by nf-schema to get metadata from the workflow + validate_params // boolean: validate the parameters + parameters_schema // string: path to the parameters JSON schema. + // this has to be the same as the schema given to `validation.parametersSchema` + // when this input is empty it will automatically use the configured schema or + // "${projectDir}/nextflow_schema.json" as default. This input should not be empty + // for meta pipelines + help // boolean: show help message + help_full // boolean: show full help message + show_hidden // boolean: show hidden parameters in help message + before_text // string: text to show before the help message and parameters summary + after_text // string: text to show after the help message and parameters summary + command // string: an example command of the pipeline main: - if (help || help_full) { + if(help || help_full) { help_options = [ beforeText: before_text, afterText: after_text, @@ -28,16 +33,14 @@ workflow UTILS_NFSCHEMA_PLUGIN { showHidden: show_hidden, fullHelp: help_full, ] - if (parameters_schema) { + if(parameters_schema) { help_options << [parametersSchema: parameters_schema] } - log.info( - paramsHelp( - help_options, - params.help instanceof String && params.help != "true" ? params.help : "", - ) + log.info paramsHelp( + help_options, + (params.help instanceof String && params.help != "true") ? params.help : "", ) - exit(0) + exit 0 } // @@ -46,20 +49,20 @@ workflow UTILS_NFSCHEMA_PLUGIN { // summary_options = [:] - if (parameters_schema) { + if(parameters_schema) { summary_options << [parametersSchema: parameters_schema] } - log.info(before_text) - log.info(paramsSummaryLog(summary_options, input_workflow)) - log.info(after_text) + log.info before_text + log.info paramsSummaryLog(summary_options, input_workflow) + log.info after_text // // Validate the parameters using nextflow_schema.json or the schema // given via the validation.parametersSchema configuration option // - if (validate_params) { + if(validate_params) { validateOptions = [:] - if (parameters_schema) { + if(parameters_schema) { validateOptions << [parametersSchema: parameters_schema] } validateParameters(validateOptions) diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index c8ce8606..f6537cc3 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -4,5 +4,5 @@ plugins { validation { parametersSchema = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" - monochromeLogs = true + monochromeLogs = true } From 58afbd1d2e0ddacc6529487468019cc3bf69726a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:12:58 +0100 Subject: [PATCH 193/228] patch modules --- .../picard-collecthsmetrics.diff | 4 +-- .../picard-collectmultiplemetrics.diff | 27 ++++++++++++++++--- .../picard-collectwgsmetrics.diff | 2 +- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff index 1407a35a..f4bf1eda 100644 --- a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff +++ b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff @@ -56,9 +56,9 @@ Changes in 'picard/collecthsmetrics/main.nf': - + --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics \\ + --TMP_DIR . + """ - cat <<-END_VERSIONS > versions.yml - "${task.process}": + stub: 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collecthsmetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff index 0a40ffb6..1d7cbf60 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff +++ b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff @@ -15,7 +15,17 @@ Changes in 'picard/collectmultiplemetrics/main.nf': output: tuple val(meta), path("*_metrics"), emit: metrics -@@ -31,12 +29,14 @@ +@@ -23,7 +21,8 @@ + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" +- def reference = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" ++ def intervals_cmd = intervals ? "--INTERVALS ${intervals.join(',')}" : "" ++ def reference_cmd = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" + def avail_mem = 3072 + if (!task.memory) { + log.info '[Picard CollectMultipleMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.' +@@ -31,14 +30,16 @@ avail_mem = (task.memory.mega*0.8).intValue() } """ @@ -26,10 +36,21 @@ Changes in 'picard/collectmultiplemetrics/main.nf': $args \\ --INPUT $bam \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ +- $reference +- + --TMP_DIR . \\ - $reference ++ $reference_cmd \\ ++ $intervals_cmd + """ - cat <<-END_VERSIONS > versions.yml + stub: +@@ -54,6 +55,5 @@ + touch ${prefix}.CollectMultipleMetrics.quality_by_cycle.pdf + touch ${prefix}.CollectMultipleMetrics.insert_size_histogram.pdf + touch ${prefix}.CollectMultipleMetrics.quality_distribution_metrics +- + """ + } 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff index 04fea62a..c7503d9b 100644 --- a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff +++ b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff @@ -30,7 +30,7 @@ Changes in 'picard/collectwgsmetrics/main.nf': + --TMP_DIR . \\ $interval - + """ 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test' is unchanged From c627fe42115ae55596ac2499be0f76815713b0fa Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:18:17 +0100 Subject: [PATCH 194/228] remove versions --- subworkflows/local/coverage/main.nf | 1 - 1 file changed, 1 deletion(-) diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 82d6cb30..7df1cf7d 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -25,7 +25,6 @@ workflow COVERAGE { return [meta, cram, crai, fasta, fai] } ) - ch_versions = ch_versions.mix(SAMTOOLS_COVERAGE.out.versions.first()) PANELCOVERAGE( MOSDEPTH.out.per_base_bed.join(MOSDEPTH.out.per_base_csi).combine(ch_genelists).map { meta, bed, index, genelists -> From b875892ca4b325e9a824aa22058f83f2621e54d4 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:46:11 +0100 Subject: [PATCH 195/228] panelcoverage: topic + make parallel --- modules/local/panelcoverage/main.nf | 25 +++----------- .../local/panelcoverage/main.nf.test.snap | 34 +++++++++++++++---- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/modules/local/panelcoverage/main.nf b/modules/local/panelcoverage/main.nf index a731f817..6e29a9c6 100644 --- a/modules/local/panelcoverage/main.nf +++ b/modules/local/panelcoverage/main.nf @@ -1,6 +1,6 @@ process PANELCOVERAGE { tag "${meta.id}" - label 'process_single' + label 'process_medium' conda "${moduleDir}/environment.yml" container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container @@ -12,24 +12,13 @@ process PANELCOVERAGE { output: tuple val(meta), path("*.mosdepth.region.dist.txt"), emit: regiondist - path "versions.yml", emit: versions - - when: - task.ext.when == null || task.ext.when + tuple val("${task.process}"), val('cmgg_genelists'), eval('cmgg_genelists -v 2>&1 | sed \"s/^.*cmgg_genelists version //\"'), emit: versions_cmgg_genelists, topic: versions + tuple val("${task.process}"), val('bedtools'), eval('bedtools --version 2>&1 | sed \"s/^.*bedtools v//\"'), emit: versions_bedtools, topic: versions script: def prefix = task.ext.prefix ?: "${meta.id}" """ - for GENELIST in ${genelists} - do - cmgg_genelists regiondist --samplename ${prefix} --perbase ${perbase} --genelist \$GENELIST - done - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cmgg_genelists: \$(cmgg_genelists -v 2>&1 | sed 's/^.*cmgg_genelists version //') - bedtools: \$(echo \$(bedtools --version 2>&1) | sed 's/^.*bedtools v//' )) - END_VERSIONS + echo ${genelists} | tr ' ' '\n' | xargs -n 1 -P ${task.cpus} -I {} cmgg_genelists regiondist --samplename ${prefix} --perbase ${perbase} --genelist {} """ stub: @@ -40,11 +29,5 @@ process PANELCOVERAGE { name=\$(basename \$GENELIST .bed) touch ${prefix}_\${name}.mosdepth.region.dist.txt done - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cmgg_genelists: \$(cmgg_genelists --version 2>&1 | sed 's/^.*cmgg_genelists version //') - bedtools: \$(echo \$(bedtools --version 2>&1) | sed 's/^.*bedtools v//' )) - END_VERSIONS """ } diff --git a/tests/modules/local/panelcoverage/main.nf.test.snap b/tests/modules/local/panelcoverage/main.nf.test.snap index cdb60adb..4a912279 100644 --- a/tests/modules/local/panelcoverage/main.nf.test.snap +++ b/tests/modules/local/panelcoverage/main.nf.test.snap @@ -12,7 +12,18 @@ ] ], "1": [ - "versions.yml:md5,2452395e283f5046f40bee1d26a09121" + [ + "PANELCOVERAGE", + "cmgg_genelists", + "0.1.0" + ] + ], + "2": [ + [ + "PANELCOVERAGE", + "bedtools", + "2.31.1" + ] ], "regiondist": [ [ @@ -23,15 +34,26 @@ "test_genelist_chr21_per_exon.mosdepth.region.dist.txt:md5,b29a7f12cef3be13215923edf6dde674" ] ], - "versions": [ - "versions.yml:md5,2452395e283f5046f40bee1d26a09121" + "versions_bedtools": [ + [ + "PANELCOVERAGE", + "bedtools", + "2.31.1" + ] + ], + "versions_cmgg_genelists": [ + [ + "PANELCOVERAGE", + "cmgg_genelists", + "0.1.0" + ] ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.3", + "nextflow": "25.10.4" }, - "timestamp": "2024-04-12T14:47:04.895941" + "timestamp": "2026-02-11T19:45:02.994288" } } \ No newline at end of file From c6d16cde19d5cacadbc642f03e87c629eeef38a2 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:47:15 +0100 Subject: [PATCH 196/228] coverage: drop versions --- subworkflows/local/coverage/main.nf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/subworkflows/local/coverage/main.nf b/subworkflows/local/coverage/main.nf index 7df1cf7d..a3458574 100644 --- a/subworkflows/local/coverage/main.nf +++ b/subworkflows/local/coverage/main.nf @@ -11,9 +11,6 @@ workflow COVERAGE { ch_genelists // channel: [optional] [genelists] main: - - ch_versions = channel.empty() - MOSDEPTH( ch_meta_cram_crai_fasta_fai_roi.map { meta, cram, crai, fasta, _fai, roi -> return [meta, cram, crai, roi, fasta] @@ -46,7 +43,6 @@ workflow COVERAGE { } } ) - ch_versions = ch_versions.mix(PANELCOVERAGE.out.versions.first()) emit: mosdepth_global = MOSDEPTH.out.global_txt From 48c69b7c868a8f94b67863a94c19dbc731c04cad Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:53:01 +0100 Subject: [PATCH 197/228] fix bcl* outputs --- modules/nf-core/bcl2fastq/bcl2fastq.diff | 101 +++++++++++++++++ modules/nf-core/bcl2fastq/main.nf | 40 +++---- .../nf-core/bcl2fastq/tests/nextflow.config | 2 +- modules/nf-core/bclconvert/bclconvert.diff | 107 ++++++++++++++++++ modules/nf-core/bclconvert/main.nf | 41 ++++--- .../nf-core/bclconvert/tests/nextflow.config | 2 +- 6 files changed, 250 insertions(+), 43 deletions(-) create mode 100644 modules/nf-core/bcl2fastq/bcl2fastq.diff create mode 100644 modules/nf-core/bclconvert/bclconvert.diff diff --git a/modules/nf-core/bcl2fastq/bcl2fastq.diff b/modules/nf-core/bcl2fastq/bcl2fastq.diff new file mode 100644 index 00000000..0e24436c --- /dev/null +++ b/modules/nf-core/bcl2fastq/bcl2fastq.diff @@ -0,0 +1,101 @@ +Changes in component 'nf-core/bcl2fastq' +'modules/nf-core/bcl2fastq/LICENSE' is unchanged +'modules/nf-core/bcl2fastq/Dockerfile' is unchanged +'modules/nf-core/bcl2fastq/README.md' is unchanged +'modules/nf-core/bcl2fastq/.gitignore' is unchanged +'modules/nf-core/bcl2fastq/meta.yml' is unchanged +Changes in 'bcl2fastq/main.nf': +--- modules/nf-core/bcl2fastq/main.nf ++++ modules/nf-core/bcl2fastq/main.nf +@@ -1,5 +1,5 @@ + process BCL2FASTQ { +- tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } ++ tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } + label 'process_high' + + container "nf-core/bcl2fastq:2.20.0.422" +@@ -8,14 +8,14 @@ + tuple val(meta), path(samplesheet), path(run_dir) + + output: +- tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq +- tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , optional:true, emit: fastq_idx +- tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz") , optional:true, emit: undetermined +- tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz") , optional:true, emit: undetermined_idx +- tuple val(meta), path("output/Reports") , emit: reports +- tuple val(meta), path("output/Stats") , emit: stats +- tuple val(meta), path("InterOp/*.bin") , emit: interop +- path("versions.yml") , emit: versions ++ tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz"), emit: fastq ++ tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), optional: true, emit: fastq_idx ++ tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), optional: true, emit: undetermined ++ tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), optional: true, emit: undetermined_idx ++ tuple val(meta), path("output/Reports/*"), emit: reports ++ tuple val(meta), path("output/Stats/*"), emit: stats ++ tuple val(meta), path("InterOp/*.bin"), emit: interop ++ path ("versions.yml"), emit: versions + + when: + task.ext.when == null || task.ext.when +@@ -23,7 +23,7 @@ + script: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { +- error "BCL2FASTQ module does not support Conda. Please use Docker / Singularity / Podman instead." ++ error("BCL2FASTQ module does not support Conda. Please use Docker / Singularity / Podman instead.") + } + def args = task.ext.args ?: '' + def args2 = task.ext.args2 ?: '' +@@ -37,27 +37,27 @@ + + if ${input_tar}; then + ## Ensures --strip-components only applied when top level of tar contents is a directory +- ## If just files or multiple directories, place all in $input_dir ++ ## If just files or multiple directories, place all in ${input_dir} + + if [[ \$(tar -taf ${run_dir} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then + tar \\ +- -C $input_dir --strip-components 1 \\ ++ -C ${input_dir} --strip-components 1 \\ + -xavf \\ +- $args2 \\ +- $run_dir \\ +- $args3 ++ ${args2} \\ ++ ${run_dir} \\ ++ ${args3} + else + tar \\ +- -C $input_dir \\ ++ -C ${input_dir} \\ + -xavf \\ +- $args2 \\ +- $run_dir \\ +- $args3 ++ ${args2} \\ ++ ${run_dir} \\ ++ ${args3} + fi + fi + + bcl2fastq \\ +- $args \\ ++ ${args} \\ + --output-dir output \\ + --runfolder-dir ${input_dir} \\ + --sample-sheet ${samplesheet} \\ + +'modules/nf-core/bcl2fastq/tests/main.nf.test.snap' is unchanged +Changes in 'bcl2fastq/tests/nextflow.config': +--- modules/nf-core/bcl2fastq/tests/nextflow.config ++++ modules/nf-core/bcl2fastq/tests/nextflow.config +@@ -2,5 +2,5 @@ + + publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + +- ext.args = "--tiles s_1_1101" ++ ext.args = "--tiles s_1_1101" + } + +'modules/nf-core/bcl2fastq/tests/main.nf.test' is unchanged +************************************************************ diff --git a/modules/nf-core/bcl2fastq/main.nf b/modules/nf-core/bcl2fastq/main.nf index 865f7951..b06bec18 100644 --- a/modules/nf-core/bcl2fastq/main.nf +++ b/modules/nf-core/bcl2fastq/main.nf @@ -1,5 +1,5 @@ process BCL2FASTQ { - tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } + tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } label 'process_high' container "nf-core/bcl2fastq:2.20.0.422" @@ -8,14 +8,14 @@ process BCL2FASTQ { tuple val(meta), path(samplesheet), path(run_dir) output: - tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq - tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , optional:true, emit: fastq_idx - tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz") , optional:true, emit: undetermined - tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz") , optional:true, emit: undetermined_idx - tuple val(meta), path("output/Reports") , emit: reports - tuple val(meta), path("output/Stats") , emit: stats - tuple val(meta), path("InterOp/*.bin") , emit: interop - path("versions.yml") , emit: versions + tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz"), emit: fastq + tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), optional: true, emit: fastq_idx + tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), optional: true, emit: undetermined + tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), optional: true, emit: undetermined_idx + tuple val(meta), path("output/Reports/*"), emit: reports + tuple val(meta), path("output/Stats/*"), emit: stats + tuple val(meta), path("InterOp/*.bin"), emit: interop + path ("versions.yml"), emit: versions when: task.ext.when == null || task.ext.when @@ -23,7 +23,7 @@ process BCL2FASTQ { script: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "BCL2FASTQ module does not support Conda. Please use Docker / Singularity / Podman instead." + error("BCL2FASTQ module does not support Conda. Please use Docker / Singularity / Podman instead.") } def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' @@ -37,27 +37,27 @@ process BCL2FASTQ { if ${input_tar}; then ## Ensures --strip-components only applied when top level of tar contents is a directory - ## If just files or multiple directories, place all in $input_dir + ## If just files or multiple directories, place all in ${input_dir} if [[ \$(tar -taf ${run_dir} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then tar \\ - -C $input_dir --strip-components 1 \\ + -C ${input_dir} --strip-components 1 \\ -xavf \\ - $args2 \\ - $run_dir \\ - $args3 + ${args2} \\ + ${run_dir} \\ + ${args3} else tar \\ - -C $input_dir \\ + -C ${input_dir} \\ -xavf \\ - $args2 \\ - $run_dir \\ - $args3 + ${args2} \\ + ${run_dir} \\ + ${args3} fi fi bcl2fastq \\ - $args \\ + ${args} \\ --output-dir output \\ --runfolder-dir ${input_dir} \\ --sample-sheet ${samplesheet} \\ diff --git a/modules/nf-core/bcl2fastq/tests/nextflow.config b/modules/nf-core/bcl2fastq/tests/nextflow.config index d1985111..38ad79af 100644 --- a/modules/nf-core/bcl2fastq/tests/nextflow.config +++ b/modules/nf-core/bcl2fastq/tests/nextflow.config @@ -2,5 +2,5 @@ process { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - ext.args = "--tiles s_1_1101" + ext.args = "--tiles s_1_1101" } diff --git a/modules/nf-core/bclconvert/bclconvert.diff b/modules/nf-core/bclconvert/bclconvert.diff new file mode 100644 index 00000000..caa6b812 --- /dev/null +++ b/modules/nf-core/bclconvert/bclconvert.diff @@ -0,0 +1,107 @@ +Changes in component 'nf-core/bclconvert' +'modules/nf-core/bclconvert/LICENSE' is unchanged +'modules/nf-core/bclconvert/Dockerfile' is unchanged +'modules/nf-core/bclconvert/README.md' is unchanged +'modules/nf-core/bclconvert/.gitignore' is unchanged +'modules/nf-core/bclconvert/meta.yml' is unchanged +Changes in 'bclconvert/main.nf': +--- modules/nf-core/bclconvert/main.nf ++++ modules/nf-core/bclconvert/main.nf +@@ -1,5 +1,5 @@ + process BCLCONVERT { +- tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } ++ tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } + label 'process_high' + + container "nf-core/bclconvert:4.4.6" +@@ -8,14 +8,14 @@ + tuple val(meta), path(samplesheet), path(run_dir) + + output: +- tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq +- tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true +- tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true +- tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true +- tuple val(meta), path("output/Reports") , emit: reports +- tuple val(meta), path("output/Logs") , emit: logs +- tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true +- path("versions.yml") , emit: versions ++ tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz"), emit: fastq ++ tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), emit: fastq_idx, optional: true ++ tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined, optional: true ++ tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional: true ++ tuple val(meta), path("output/Reports/*"), emit: reports ++ tuple val(meta), path("output/Logs/*"), emit: logs ++ tuple val(meta), path("output/InterOp/*.bin"), emit: interop, optional: true ++ path ("versions.yml"), emit: versions + + when: + task.ext.when == null || task.ext.when +@@ -23,7 +23,7 @@ + script: + // Exit if running this module with -profile conda / -profile mamba + if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { +- error "BCLCONVERT module does not support Conda. Please use Docker / Singularity / Podman instead." ++ error("BCLCONVERT module does not support Conda. Please use Docker / Singularity / Podman instead.") + } + def args = task.ext.args ?: '' + def args2 = task.ext.args2 ?: '' +@@ -37,27 +37,27 @@ + + if ${input_tar}; then + ## Ensures --strip-components only applied when top level of tar contents is a directory +- ## If just files or multiple directories, place all in $input_dir ++ ## If just files or multiple directories, place all in ${input_dir} + + if [[ \$(tar -taf ${run_dir} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then + tar \\ +- -C $input_dir --strip-components 1 \\ ++ -C ${input_dir} --strip-components 1 \\ + -xavf \\ +- $args2 \\ +- $run_dir \\ +- $args3 ++ ${args2} \\ ++ ${run_dir} \\ ++ ${args3} + else + tar \\ +- -C $input_dir \\ ++ -C ${input_dir} \\ + -xavf \\ +- $args2 \\ +- $run_dir \\ +- $args3 ++ ${args2} \\ ++ ${run_dir} \\ ++ ${args3} + fi + fi + + bcl-convert \\ +- $args \\ ++ ${args} \\ + --output-directory output \\ + --bcl-input-directory ${input_dir} \\ + --sample-sheet ${samplesheet} +@@ -107,5 +107,4 @@ + bclconvert: \$(bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //') + END_VERSIONS + """ +- + } + +'modules/nf-core/bclconvert/tests/main.nf.test.snap' is unchanged +Changes in 'bclconvert/tests/nextflow.config': +--- modules/nf-core/bclconvert/tests/nextflow.config ++++ modules/nf-core/bclconvert/tests/nextflow.config +@@ -1,5 +1,5 @@ + process { +- withName: "BCLCONVERT" { ++ withName: BCLCONVERT { + ext.args = params.module_args + } + } + +'modules/nf-core/bclconvert/tests/main.nf.test' is unchanged +************************************************************ diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index f1caafc3..6b164908 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -1,5 +1,5 @@ process BCLCONVERT { - tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } + tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } label 'process_high' container "nf-core/bclconvert:4.4.6" @@ -8,14 +8,14 @@ process BCLCONVERT { tuple val(meta), path(samplesheet), path(run_dir) output: - tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq - tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true - tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true - tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true - tuple val(meta), path("output/Reports") , emit: reports - tuple val(meta), path("output/Logs") , emit: logs - tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true - path("versions.yml") , emit: versions + tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz"), emit: fastq + tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), emit: fastq_idx, optional: true + tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined, optional: true + tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional: true + tuple val(meta), path("output/Reports/*"), emit: reports + tuple val(meta), path("output/Logs/*"), emit: logs + tuple val(meta), path("output/InterOp/*.bin"), emit: interop, optional: true + path ("versions.yml"), emit: versions when: task.ext.when == null || task.ext.when @@ -23,7 +23,7 @@ process BCLCONVERT { script: // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "BCLCONVERT module does not support Conda. Please use Docker / Singularity / Podman instead." + error("BCLCONVERT module does not support Conda. Please use Docker / Singularity / Podman instead.") } def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' @@ -37,27 +37,27 @@ process BCLCONVERT { if ${input_tar}; then ## Ensures --strip-components only applied when top level of tar contents is a directory - ## If just files or multiple directories, place all in $input_dir + ## If just files or multiple directories, place all in ${input_dir} if [[ \$(tar -taf ${run_dir} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then tar \\ - -C $input_dir --strip-components 1 \\ + -C ${input_dir} --strip-components 1 \\ -xavf \\ - $args2 \\ - $run_dir \\ - $args3 + ${args2} \\ + ${run_dir} \\ + ${args3} else tar \\ - -C $input_dir \\ + -C ${input_dir} \\ -xavf \\ - $args2 \\ - $run_dir \\ - $args3 + ${args2} \\ + ${run_dir} \\ + ${args3} fi fi bcl-convert \\ - $args \\ + ${args} \\ --output-directory output \\ --bcl-input-directory ${input_dir} \\ --sample-sheet ${samplesheet} @@ -107,5 +107,4 @@ process BCLCONVERT { bclconvert: \$(bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //') END_VERSIONS """ - } diff --git a/modules/nf-core/bclconvert/tests/nextflow.config b/modules/nf-core/bclconvert/tests/nextflow.config index 848581b5..47e194a6 100644 --- a/modules/nf-core/bclconvert/tests/nextflow.config +++ b/modules/nf-core/bclconvert/tests/nextflow.config @@ -1,5 +1,5 @@ process { - withName: "BCLCONVERT" { + withName: BCLCONVERT { ext.args = params.module_args } } From 530564b204df65ee0db1a226e8dd9b1a4a652e46 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 20:21:02 +0100 Subject: [PATCH 198/228] fix bamsormadup inputs --- modules.json | 3 +- .../local/fastq_to_aligned_cram/main.nf | 14 +++--- .../fastq_to_aligned_cram/main.nf.test.snap | 43 +++++-------------- 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/modules.json b/modules.json index 3b6b2674..253f63c6 100644 --- a/modules.json +++ b/modules.json @@ -8,7 +8,8 @@ "bcl2fastq": { "branch": "master", "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", - "installed_by": ["bcl_demultiplex"] + "installed_by": ["bcl_demultiplex"], + "patch": "modules/nf-core/bcl2fastq/bcl2fastq.diff" }, "bclconvert": { "branch": "master", diff --git a/subworkflows/local/fastq_to_aligned_cram/main.nf b/subworkflows/local/fastq_to_aligned_cram/main.nf index 9ce33bc8..dfccf2d5 100644 --- a/subworkflows/local/fastq_to_aligned_cram/main.nf +++ b/subworkflows/local/fastq_to_aligned_cram/main.nf @@ -83,16 +83,16 @@ workflow FASTQ_TO_CRAM { } .groupTuple() .map { meta, files -> - return [meta, files.flatten(), getGenomeAttribute(meta.genome_data, 'fasta')] + return [meta, files.flatten(), getGenomeAttribute(meta.genome_data, 'fasta'), getGenomeAttribute(meta.genome_data, 'fai')] } .dump(tag: "FASTQ_TO_CRAM: aligned bam per sample", pretty: true) - .branch { meta, files, fasta -> + .branch { meta, files, fasta, fai -> bamsormadup: meta.markdup == "bamsormadup" - return [meta, files, fasta] + return [meta, files, fasta, fai] samtools: meta.markdup == "samtools" - return [meta, files, fasta] + return [meta, files, fasta, fai] sort: meta.markdup == "false" || meta.markdup == false - return [meta, files, fasta] + return [meta, files, fasta, fai] unknown: true error("markdup option ${meta.markdup} not supported") } @@ -100,12 +100,12 @@ workflow FASTQ_TO_CRAM { ch_markdup_index = channel.empty() - // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta) + // BIOBAMBAM_BAMSORMADUP([meta, [bam, bam]], fasta, fai) BIOBAMBAM_BAMSORMADUP(ch_bam_fasta.bamsormadup) ch_markdup_index = ch_markdup_index.mix(BIOBAMBAM_BAMSORMADUP.out.bam.join(BIOBAMBAM_BAMSORMADUP.out.bam_index, failOnMismatch: true, failOnDuplicate: true)) ch_sormadup_metrics = ch_sormadup_metrics.mix(BIOBAMBAM_BAMSORMADUP.out.metrics) - // SAMTOOLS_SORMADUP([meta, [bam, bam]], fasta) + // SAMTOOLS_SORMADUP([meta, [bam, bam]], fasta, fai) SAMTOOLS_SORMADUP(ch_bam_fasta.samtools) ch_markdup_index = ch_markdup_index.mix(SAMTOOLS_SORMADUP.out.cram.join(SAMTOOLS_SORMADUP.out.crai, failOnMismatch: true, failOnDuplicate: true)) ch_sormadup_metrics = ch_sormadup_metrics.mix(SAMTOOLS_SORMADUP.out.metrics) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index 5db51b5f..eb4e865f 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -33,18 +33,14 @@ ], "sormadup_metrics": [ - ], - "versions": [ - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nextflow": "25.10.4" }, - "timestamp": "2026-02-10T09:29:24.149695" + "timestamp": "2026-02-11T20:19:51.825749" }, "fastq to cram - bwa - bamsormadup": { "content": [ @@ -96,20 +92,14 @@ }, "test.merged.metrics.txt:md5,4ee20f12cb4d6077479a08310c8f6c70" ] - ], - "versions": [ - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", - "versions.yml:md5,9598e8236a8fbab0f6745715fa0de9d3", - "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nextflow": "25.10.4" }, - "timestamp": "2026-02-10T09:24:26.615795" + "timestamp": "2026-02-11T20:10:31.616836" }, "fastq to cram - bwa - samtools sormadup": { "content": [ @@ -161,19 +151,14 @@ }, "test.merged.metrics:md5,795c73aa836eb480e418f52db98e37cc" ] - ], - "versions": [ - "versions.yml:md5,53fb2eac4cab0b817e852418eb0ba719", - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nextflow": "25.10.4" }, - "timestamp": "2026-02-10T09:27:45.908866" + "timestamp": "2026-02-11T20:15:15.495706" }, "fastq to cram - star - bamsormadup": { "content": [ @@ -261,18 +246,14 @@ }, "test.merged.metrics.txt:md5,641527401576375d7c0b0b54fbaf63ab" ] - ], - "versions": [ - "versions.yml:md5,9598e8236a8fbab0f6745715fa0de9d3", - "versions.yml:md5,d8544811f6b511ef45e9c3547430a30d" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nextflow": "25.10.4" }, - "timestamp": "2026-02-10T09:26:55.879993" + "timestamp": "2026-02-11T20:13:35.19973" }, "fastq to cram - bwa - samtools sort": { "content": [ @@ -308,17 +289,13 @@ ], "sormadup_metrics": [ - ], - "versions": [ - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75", - "versions.yml:md5,5f142fd2dfa129d6b28f1368516bca75" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nextflow": "25.10.4" }, - "timestamp": "2026-02-10T09:28:34.042629" + "timestamp": "2026-02-11T20:16:26.285299" } } \ No newline at end of file From 6474ddc56798cc04bcb7b1e082fe42c0646468e8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 20:44:37 +0100 Subject: [PATCH 199/228] fix bam_qc --- .../nf-core/picard/collectwgsmetrics/main.nf | 2 +- .../picard-collectwgsmetrics.diff | 2 +- subworkflows/local/bam_qc/main.nf | 2 +- .../local/bam_qc/main.nf.test.snap | 111 +++++++++++++----- 4 files changed, 87 insertions(+), 30 deletions(-) diff --git a/modules/nf-core/picard/collectwgsmetrics/main.nf b/modules/nf-core/picard/collectwgsmetrics/main.nf index a631b03f..b8d1ee42 100644 --- a/modules/nf-core/picard/collectwgsmetrics/main.nf +++ b/modules/nf-core/picard/collectwgsmetrics/main.nf @@ -8,7 +8,7 @@ process PICARD_COLLECTWGSMETRICS { 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" input: - tuple val(meta), path(bam), path(bai) ,path(fasta) ,path(fai) + tuple val(meta), path(bam), path(bai) ,path(fasta) ,path(fai), path(dict) path intervallist output: diff --git a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff index c7503d9b..c1389e4e 100644 --- a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff +++ b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff @@ -11,7 +11,7 @@ Changes in 'picard/collectwgsmetrics/main.nf': - tuple val(meta), path(bam), path(bai) - tuple val(meta2), path(fasta) - tuple val(meta3), path(fai) -+ tuple val(meta), path(bam), path(bai) ,path(fasta) ,path(fai) ++ tuple val(meta), path(bam), path(bai) ,path(fasta) ,path(fai), path(dict) path intervallist output: diff --git a/subworkflows/local/bam_qc/main.nf b/subworkflows/local/bam_qc/main.nf index d9cd0f7c..b6cd772c 100644 --- a/subworkflows/local/bam_qc/main.nf +++ b/subworkflows/local/bam_qc/main.nf @@ -41,7 +41,7 @@ workflow BAM_QC { ch_picard .branch { meta, bam, bai, roi, fasta, fai, dict -> hsmetrics: roi != [] - return [meta, bam, bai, roi, fasta, fai, dict] + return [meta, bam, bai, roi, roi, fasta, fai, dict] wgsmetrics: roi == [] return [meta, bam, bai, fasta, fai, dict] } diff --git a/tests/subworkflows/local/bam_qc/main.nf.test.snap b/tests/subworkflows/local/bam_qc/main.nf.test.snap index 3392b3dd..5b809485 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test.snap +++ b/tests/subworkflows/local/bam_qc/main.nf.test.snap @@ -3,13 +3,46 @@ "content": [ { "picard_hsmetrics": [ - + [ + { + "disable_picard_metrics": false, + "id": "test", + "single_end": false + }, + "test.CollectHsMetrics.coverage_metrics" + ] ], "picard_multiplemetrics": [ - + [ + { + "disable_picard_metrics": false, + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.alignment_summary_metrics", + "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics", + "test.CollectMultipleMetrics.insert_size_metrics", + "test.CollectMultipleMetrics.quality_by_cycle_metrics", + "test.CollectMultipleMetrics.quality_distribution_metrics" + ] + ] ], "picard_multiplemetrics_pdf": [ - + [ + { + "disable_picard_metrics": false, + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf", + "test.CollectMultipleMetrics.insert_size_histogram.pdf", + "test.CollectMultipleMetrics.quality_by_cycle.pdf", + "test.CollectMultipleMetrics.quality_distribution.pdf", + "test.CollectMultipleMetrics.read_length_histogram.pdf" + ] + ] ], "picard_wgsmetrics": [ @@ -43,18 +76,14 @@ }, "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] - ], - "versions": [ - "versions.yml:md5,15389a9f97668f320b9628da1903a93b", - "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nextflow": "25.10.4" }, - "timestamp": "2026-02-10T19:21:23.498543" + "timestamp": "2026-02-11T20:41:14.126057" }, "Bam QC - Samtools": { "content": [ @@ -75,7 +104,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": true }, "test.flagstat:md5,167e69b479663a15194ddf56cbc9e60e" ] @@ -84,7 +114,8 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": true }, "test.idxstats:md5,081d0431383fb7ea6b51b7077c6ec93c" ] @@ -93,22 +124,19 @@ [ { "id": "test", - "single_end": false + "single_end": false, + "disable_picard_metrics": true }, "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] - ], - "versions": [ - "versions.yml:md5,15389a9f97668f320b9628da1903a93b", - "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" }, - "timestamp": "2025-12-02T12:50:04.027873" + "timestamp": "2026-02-11T20:27:00.941719" }, "Bam QC - WGSmetrics": { "content": [ @@ -117,13 +145,46 @@ ], "picard_multiplemetrics": [ - + [ + { + "disable_picard_metrics": false, + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.alignment_summary_metrics", + "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics", + "test.CollectMultipleMetrics.insert_size_metrics", + "test.CollectMultipleMetrics.quality_by_cycle_metrics", + "test.CollectMultipleMetrics.quality_distribution_metrics" + ] + ] ], "picard_multiplemetrics_pdf": [ - + [ + { + "disable_picard_metrics": false, + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf", + "test.CollectMultipleMetrics.insert_size_histogram.pdf", + "test.CollectMultipleMetrics.quality_by_cycle.pdf", + "test.CollectMultipleMetrics.quality_distribution.pdf", + "test.CollectMultipleMetrics.read_length_histogram.pdf" + ] + ] ], "picard_wgsmetrics": [ - + [ + { + "disable_picard_metrics": false, + "id": "test", + "single_end": false + }, + "test.CollectWgsMetrics.coverage_metrics" + ] ], "samtools_flagstat": [ [ @@ -154,17 +215,13 @@ }, "test.stats:md5,3535d8d302e61ca0d77ac718db8309f1" ] - ], - "versions": [ - "versions.yml:md5,15389a9f97668f320b9628da1903a93b", - "versions.yml:md5,3fa45af2ff85005c0421d10e0b686bb5" ] } ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nextflow": "25.10.4" }, - "timestamp": "2026-02-10T19:25:10.626677" + "timestamp": "2026-02-11T20:26:15.482881" } } \ No newline at end of file From 3555ab3cd87e989871eea4e8080496465b7e6bcb Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:20:42 +0100 Subject: [PATCH 200/228] fix more tests --- nextflow.config | 62 ++++---- tests/workflows/preprocessing.nf.test | 10 +- tests/workflows/preprocessing.nf.test.snap | 173 +++++++++++++++------ workflows/preprocessing.nf | 10 +- 4 files changed, 167 insertions(+), 88 deletions(-) diff --git a/nextflow.config b/nextflow.config index 010059f3..a5ceb27d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -10,50 +10,50 @@ params { // Input options - input = null + input = null // References - genome = null - igenomes_base = '/references/' - igenomes_ignore = false + genome = null + igenomes_base = '/references/' + igenomes_ignore = false // Analysis options - split_fastq = 100000000 - genelists = null + split_fastq = 100000000 + genelists = null // MultiQC options - multiqc_config = null - multiqc_title = null - multiqc_logo = null - max_multiqc_email_size = '25.MB' - multiqc_methods_description = null + multiqc_config = null + multiqc_title = null + multiqc_logo = null + max_multiqc_email_size = '25.MB' + multiqc_methods_description = null // Boilerplate options - outdir = null - publish_dir_mode = 'copy' - email = null - email_on_fail = null - plaintext_email = false - monochrome_logs = false - hook_url = System.getenv('HOOK_URL') - help = false - help_full = false - show_hidden = false - version = false - pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' - trace_report_suffix = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') + outdir = null + publish_dir_mode = 'copy' + email = null + email_on_fail = null + plaintext_email = false + monochrome_logs = false + hook_url = System.getenv('HOOK_URL') + help = false + help_full = false + show_hidden = false + version = false + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' + trace_report_suffix = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') // Config options - config_profile_name = null - config_profile_description = null + config_profile_name = null + config_profile_description = null - custom_config_version = 'main' - custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.custom_config_version}" - config_profile_contact = null - config_profile_url = null + custom_config_version = 'main' + custom_config_base = "https://raw.githubusercontent.com/nf-cmgg/configs/${params.custom_config_version}" + config_profile_contact = null + config_profile_url = null // Schema validation default options - validate_params = true + validate_params = true } // Load base.config by default for all pipelines diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index dfc856d0..4d5e52cc 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -24,7 +24,8 @@ nextflow_workflow { sample_type: "DNA", aligner: "bwamem", markdup: "bamsormadup", - run_coverage: true + run_coverage: true, + roi: file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true) ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -46,6 +47,7 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] + // genelists input[2] = null """ } @@ -115,6 +117,7 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] + // genelists input[2] = null """ } @@ -165,7 +168,9 @@ nextflow_workflow { sample_type: "DNA", aligner: "bwamem", markdup: "bamsormadup", - run_coverage: true + run_coverage: false, + disable_picard_metrics: true, + roi: file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", checkIfExists: true) ], //fastq_1 file("https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz", checkIfExists: true), @@ -187,6 +192,7 @@ nextflow_workflow { gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" ] ] + // genelists input[2] = null """ } diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index d40bc343..fc2144f1 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -21,8 +21,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -66,6 +68,7 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "readgroup": { "CN": "CMGG", @@ -76,6 +79,7 @@ "SM": "sample1" }, "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -94,6 +98,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "readgroup": { "CN": "CMGG", @@ -111,7 +118,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, "sample1.fastp.json:md5,5a65f5141251ac26b8f0a0d0a618b524" @@ -133,8 +139,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -155,6 +163,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -164,7 +175,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -182,6 +192,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -191,7 +204,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -209,6 +221,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -218,7 +233,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -239,6 +253,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -248,7 +265,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -266,6 +282,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -275,7 +294,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -293,6 +311,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -302,7 +323,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -320,6 +340,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -329,7 +352,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -347,6 +369,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -356,7 +381,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -374,6 +398,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -383,7 +410,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -439,8 +465,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -466,8 +494,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -498,8 +528,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -539,8 +571,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -566,8 +600,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -588,6 +624,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -597,7 +636,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -620,8 +658,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -642,6 +682,9 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -651,7 +694,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -659,18 +701,7 @@ ] ], "versions": [ - "versions.yml:md5,02acae00818ba01a01e2bdb03b574343", - "versions.yml:md5,23b060bcc18a02fc8f981102ef3a3006", - "versions.yml:md5,31df076e5d21d61db772cb39643350e2", - "versions.yml:md5,b702df83d9ece54caa0e765a6286cdd2", - "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", - "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", - "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", - "versions.yml:md5,cdce7da7ce14e29fbd9fd72e88505ffa", - "versions.yml:md5,d00b52835d019d68e58aafd218429a75", - "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", - "versions.yml:md5,f567cdcfb384cc7a2d9ff4dc850f3bad", - "versions.yml:md5,fe9b8b3a8dc895efcf8f7c0b3248ff2d" + "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d" ] } ], @@ -678,7 +709,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-11T12:00:40.443933" + "timestamp": "2026-02-11T21:21:37.068608" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -692,6 +723,7 @@ "groupSize": 1, "groupTarget": { "aligner": "bwamem", + "disable_picard_metrics": true, "genome": "GRCh38", "genome_data": { "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", @@ -702,8 +734,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": false, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -737,6 +771,7 @@ { "aligner": "bwamem", "count": 1, + "disable_picard_metrics": true, "genome": "GRCh38", "genome_data": { "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", @@ -747,6 +782,7 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "readgroup": { "CN": "CMGG", @@ -757,6 +793,7 @@ "SM": "sample1" }, "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": false, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -775,6 +812,10 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": false, + "disable_picard_metrics": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "readgroup": { "CN": "CMGG", @@ -792,7 +833,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "count": 1 }, "sample1.fastp.json:md5,5a65f5141251ac26b8f0a0d0a618b524" @@ -804,6 +844,7 @@ "groupSize": 1, "groupTarget": { "aligner": "bwamem", + "disable_picard_metrics": true, "genome": "GRCh38", "genome_data": { "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", @@ -814,8 +855,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": false, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -915,6 +958,7 @@ "groupSize": 1, "groupTarget": { "aligner": "bwamem", + "disable_picard_metrics": true, "genome": "GRCh38", "genome_data": { "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", @@ -925,8 +969,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": false, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -947,6 +993,10 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": false, + "disable_picard_metrics": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -956,7 +1006,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -969,6 +1018,7 @@ "groupSize": 1, "groupTarget": { "aligner": "bwamem", + "disable_picard_metrics": true, "genome": "GRCh38", "genome_data": { "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", @@ -979,8 +1029,10 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", + "run_coverage": false, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1001,6 +1053,10 @@ "tag": "WES", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": false, + "disable_picard_metrics": true, + "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1010,7 +1066,6 @@ "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" }, - "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "id": "sample1" } }, @@ -1018,14 +1073,7 @@ ] ], "versions": [ - "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", - "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", - "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", - "versions.yml:md5,cdce7da7ce14e29fbd9fd72e88505ffa", - "versions.yml:md5,d00b52835d019d68e58aafd218429a75", - "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", - "versions.yml:md5,f567cdcfb384cc7a2d9ff4dc850f3bad", - "versions.yml:md5,fe9b8b3a8dc895efcf8f7c0b3248ff2d" + "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d" ] } ], @@ -1033,7 +1081,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-11T12:11:20.398961" + "timestamp": "2026-02-11T21:25:53.804729" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1057,7 +1105,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1101,6 +1151,7 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", "readgroup": { "CN": "CMGG", @@ -1110,6 +1161,7 @@ "PU": "H5T2YDSX3.1", "SM": "sample1" }, + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1128,6 +1180,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "readgroup": { "CN": "CMGG", @@ -1166,7 +1220,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1187,6 +1243,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1213,6 +1271,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1239,6 +1299,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1268,6 +1330,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1294,6 +1358,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1329,6 +1395,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1396,7 +1464,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1427,7 +1497,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1458,7 +1530,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1490,7 +1564,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1516,7 +1592,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1537,6 +1615,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1568,7 +1648,9 @@ }, "id": "sample1", "library": "test", + "markdup": "bamsormadup", "organism": "Homo sapiens", + "run_coverage": true, "sample_type": "DNA", "samplename": "sample1", "single_end": false, @@ -1589,6 +1671,8 @@ "tag": "WGS", "sample_type": "DNA", "aligner": "bwamem", + "markdup": "bamsormadup", + "run_coverage": true, "single_end": false, "genome": "GRCh38", "genome_data": { @@ -1605,18 +1689,7 @@ ] ], "versions": [ - "versions.yml:md5,1d2a9b13790c70a69a1f62facc9b3a6c", - "versions.yml:md5,23b060bcc18a02fc8f981102ef3a3006", - "versions.yml:md5,31df076e5d21d61db772cb39643350e2", - "versions.yml:md5,b702df83d9ece54caa0e765a6286cdd2", - "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", - "versions.yml:md5,c4fcc95fcd514eab38e980cacf0d4e8c", - "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d", - "versions.yml:md5,cdce7da7ce14e29fbd9fd72e88505ffa", - "versions.yml:md5,d00b52835d019d68e58aafd218429a75", - "versions.yml:md5,d11c133ecb39ba9f6d7e081a8a6ff868", - "versions.yml:md5,f567cdcfb384cc7a2d9ff4dc850f3bad", - "versions.yml:md5,fe9b8b3a8dc895efcf8f7c0b3248ff2d" + "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d" ] } ], @@ -1624,6 +1697,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-11T12:06:12.331519" + "timestamp": "2026-02-11T22:18:07.06828" } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 034397f4..3954c603 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -270,9 +270,9 @@ workflow PREPROCESSING { meta.roi && meta.roi != [] ? file(meta.roi, checkIfExists: true) : [], ] } - .set { ch_cram_crai_fasta_fai_roi } + .set { ch_coverage } - COVERAGE(ch_cram_crai_fasta_fai_roi, ch_genelists) + COVERAGE(ch_coverage, ch_genelists) ch_multiqc_files = ch_multiqc_files.mix( COVERAGE.out.mosdepth_summary, COVERAGE.out.mosdepth_global, @@ -291,15 +291,15 @@ workflow PREPROCESSING { meta, cram, crai, - (meta.roi && meta.roi) != [] ? file(meta.roi, checkIfExists: true) : [], + meta.roi && meta.roi != [] ? file(meta.roi, checkIfExists: true) : [], getGenomeAttribute(meta.genome_data, "fasta"), getGenomeAttribute(meta.genome_data, "fai"), getGenomeAttribute(meta.genome_data, "dict"), ] } - .set { ch_cram_crai_roi_fasta_fai_dict } + .set { ch_bam_qc } - BAM_QC(ch_cram_crai_roi_fasta_fai_dict) + BAM_QC(ch_bam_qc) ch_multiqc_files = ch_multiqc_files.mix( BAM_QC.out.samtools_stats, BAM_QC.out.samtools_flagstat, From af539d4a17e089faf663673ca7304362a5c23cb1 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:38:28 +0100 Subject: [PATCH 201/228] fix coverage snapshot --- tests/config/igenomes_test.config | 2 +- .../local/coverage/main.nf.test.snap | 24 ++----------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/tests/config/igenomes_test.config b/tests/config/igenomes_test.config index cac18b9e..5ecb24af 100644 --- a/tests/config/igenomes_test.config +++ b/tests/config/igenomes_test.config @@ -7,7 +7,7 @@ params { fasta = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna" star = "s3://test-data/genomics/homo_sapiens/genome/star/" gtf = "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" - genelists = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists/*.bed" + genelists = "s3://test-data/genomics/homo_sapiens/genome/regions/genelists" } } } diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 7bd91330..9934ac1f 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -51,11 +51,6 @@ ] ] ], - "14": [ - "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", - "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", - "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" - ], "2": [ [ { @@ -250,11 +245,6 @@ }, "test.coverage.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] - ], - "versions": [ - "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", - "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", - "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ] } ], @@ -262,7 +252,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-11T14:05:13.106828" + "timestamp": "2026-02-11T22:37:17.825377" }, "Coverage - seqcap": { "content": [ @@ -313,11 +303,6 @@ "test_seqcap_Connective_tissue_per_exon.mosdepth.region.dist.txt:md5,e098c901acb1da8c2cf64a248306e71c" ] ], - "14": [ - "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", - "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", - "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" - ], "2": [ [ { @@ -509,11 +494,6 @@ }, "test.coverage.txt:md5,2d81e108bf4175f2b892ab6e749fdf92" ] - ], - "versions": [ - "versions.yml:md5,67ac37f5eff6c19b8c605a2258aa721c", - "versions.yml:md5,731a006ffa265ac74ad677b4e5a68640", - "versions.yml:md5,8d8a3cea555f0b04692395a47351d7ef" ] } ], @@ -521,6 +501,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-11T13:54:02.513877" + "timestamp": "2026-02-11T22:36:21.526017" } } \ No newline at end of file From 8a64abcbd087c56305975575d4a28891d84683a1 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 11 Feb 2026 22:52:12 +0100 Subject: [PATCH 202/228] fix rna snapshots --- .../local/fastq_align_rna/main.nf.test.snap | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index cf11ffe9..88691d56 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -93,19 +93,14 @@ }, "test.SJ.out.tab:md5,15852c5678c04e86dcb66793b7e02bb9" ] - ], - "versions": [ - "versions.yml:md5,a08c174f2d393f0b39c2cfe003ffafb9", - "versions.yml:md5,e0beb4fb46280de51c432ed766a0cdb2", - "versions.yml:md5,e1135512a195d12c4b6aaadd8e84dcf6" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.2" + "nf-test": "0.9.3", + "nextflow": "25.10.4" }, - "timestamp": "2025-12-17T16:44:58.048883426" + "timestamp": "2026-02-11T22:49:27.454517" }, "fastq align rna - unknown aligner": { "content": [ From 3aa3756dc98f285c986a2435af87bd07b2940aae Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 18 Feb 2026 09:46:34 +0100 Subject: [PATCH 203/228] deprecate bcl_demultiplex, only support bclconvert --- modules.json | 16 +- modules/nf-core/bcl2fastq/.gitignore | 2 - modules/nf-core/bcl2fastq/Dockerfile | 25 -- modules/nf-core/bcl2fastq/LICENSE | 30 -- modules/nf-core/bcl2fastq/README.md | 19 -- modules/nf-core/bcl2fastq/bcl2fastq.diff | 101 ------ modules/nf-core/bcl2fastq/main.nf | 73 ----- modules/nf-core/bcl2fastq/meta.yml | 110 ------- modules/nf-core/bcl2fastq/tests/main.nf.test | 32 -- .../nf-core/bcl2fastq/tests/main.nf.test.snap | 219 ------------- .../nf-core/bcl2fastq/tests/nextflow.config | 6 - modules/nf-core/bclconvert/Dockerfile | 34 +- modules/nf-core/bclconvert/bclconvert.diff | 107 ------- modules/nf-core/bclconvert/main.nf | 111 ++++--- modules/nf-core/bclconvert/meta.yml | 62 ++-- modules/nf-core/bclconvert/tests/main.nf.test | 23 +- .../bclconvert/tests/main.nf.test.snap | 290 ++++++++--------- subworkflows/nf-core/bcl_demultiplex/main.nf | 139 -------- subworkflows/nf-core/bcl_demultiplex/meta.yml | 62 ---- .../bcl_demultiplex/tests/main.nf.test | 100 ------ .../bcl_demultiplex/tests/main.nf.test.snap | 296 ------------------ .../bcl_demultiplex/tests/nextflow.config | 13 - workflows/preprocessing.nf | 25 +- 23 files changed, 292 insertions(+), 1603 deletions(-) delete mode 100644 modules/nf-core/bcl2fastq/.gitignore delete mode 100644 modules/nf-core/bcl2fastq/Dockerfile delete mode 100644 modules/nf-core/bcl2fastq/LICENSE delete mode 100644 modules/nf-core/bcl2fastq/README.md delete mode 100644 modules/nf-core/bcl2fastq/bcl2fastq.diff delete mode 100644 modules/nf-core/bcl2fastq/main.nf delete mode 100644 modules/nf-core/bcl2fastq/meta.yml delete mode 100644 modules/nf-core/bcl2fastq/tests/main.nf.test delete mode 100644 modules/nf-core/bcl2fastq/tests/main.nf.test.snap delete mode 100644 modules/nf-core/bcl2fastq/tests/nextflow.config delete mode 100644 modules/nf-core/bclconvert/bclconvert.diff delete mode 100644 subworkflows/nf-core/bcl_demultiplex/main.nf delete mode 100644 subworkflows/nf-core/bcl_demultiplex/meta.yml delete mode 100644 subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test delete mode 100644 subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap delete mode 100644 subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config diff --git a/modules.json b/modules.json index 253f63c6..448ec404 100644 --- a/modules.json +++ b/modules.json @@ -5,17 +5,10 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { - "bcl2fastq": { - "branch": "master", - "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", - "installed_by": ["bcl_demultiplex"], - "patch": "modules/nf-core/bcl2fastq/bcl2fastq.diff" - }, "bclconvert": { "branch": "master", - "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", - "installed_by": ["bcl_demultiplex"], - "patch": "modules/nf-core/bclconvert/bclconvert.diff" + "git_sha": "547b6a0078c2f4499b64d59edb8ae038b31971b2", + "installed_by": ["modules"] }, "biobambam/bamsormadup": { "branch": "master", @@ -159,11 +152,6 @@ }, "subworkflows": { "nf-core": { - "bcl_demultiplex": { - "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["subworkflows"] - }, "fastq_align_dna": { "branch": "master", "git_sha": "5dd46a36fca68d6ad1a6b22ec47adc8c6863717d", diff --git a/modules/nf-core/bcl2fastq/.gitignore b/modules/nf-core/bcl2fastq/.gitignore deleted file mode 100644 index 45b0ea3a..00000000 --- a/modules/nf-core/bcl2fastq/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -bcl-convert -*.rpm diff --git a/modules/nf-core/bcl2fastq/Dockerfile b/modules/nf-core/bcl2fastq/Dockerfile deleted file mode 100644 index 5600ab84..00000000 --- a/modules/nf-core/bcl2fastq/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# Dockerfile to create container with bcl2fastq -# Push to nfcore/bcl2fastq: - -FROM debian:bullseye-slim -LABEL authors="Matthias De Smet " \ - description="Docker image containing bcl2fastq" -# Disclaimer: this container is not provided nor supported by Illumina -# 'ps' command is needed by some nextflow executions to collect system stats -# Install procps and clean apt cache -RUN apt-get update \ - && apt-get install -y \ - procps \ - && apt-get clean -y && rm -rf /var/lib/apt/lists/* -# Link hostname cmd to fix hardcoded path -RUN ln -s /bin/hostname /usr/bin/hostname - -# Add executable to image -COPY bcl2fastq /usr/local/bin/bcl2fastq - -# Add external libs to image -COPY css /usr/local/share/css -COPY xsl /usr/local/share/xsl - -# Set permission -RUN chmod +x /usr/local/bin/bcl2fastq && chmod -R +rX /usr/local/share/css && chmod -R +rX /usr/local/share/xsl diff --git a/modules/nf-core/bcl2fastq/LICENSE b/modules/nf-core/bcl2fastq/LICENSE deleted file mode 100644 index 6f523227..00000000 --- a/modules/nf-core/bcl2fastq/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -ILLUMINA END-USER SOFTWARE LICENSE AGREEMENT - -IMPORTANT-READ CAREFULLY. THIS IS A LICENSE AGREEMENT THAT YOU ARE REQUIRED TO ACCEPT BEFORE, DOWNLOADING, INSTALLING AND USING ANY SOFTWARE MADE AVAILABLE FROM THE ILLUMINA SUPPORT CENTER (https://support.illumina.com). - -CAREFULLY READ ALL THE TERMS AND CONDITIONS OF THIS LICENSE AGREEMENT BEFORE PROCEEDING WITH DOWNLOADING, INSTALLING, AND/OR USING THE SOFTWARE. YOU ARE NOT PERMITTED TO DOWNLOAD, INSTALL, AND/OR USE THE SOFTWARE UNTIL YOU HAVE AGREED TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS OF THIS LICENSE AGREEMENT. YOU REPRESENT AND WARRANT THAT YOU ARE DULY AUTHORIZED TO ACCEPT THE TERMS AND CONDITIONS OF THIS LICENSE AGREEMENT ON BEHALF OF YOUR EMPLOYER. - -Software made available through the Illumina Support Center is licensed, not sold, to you. Your license to each software program made available through the Illumina Support Center is subject to your prior acceptance of either this Illumina End-User Software License Agreement (“Agreement”), or a custom end user license agreement (“Custom EULA”), if one is provided with the software. Any software that is subject to this Agreement is referred to herein as the “Software.” By accepting this Agreement, you agree the terms and conditions of this Agreement will apply to and govern any and all of your downloads, installations, and uses of each Illumina software program made available through the Illumina Support Center, except that your download, installation, and use of any software provided with a Custom EULA will be governed by the terms and conditions of the Custom EULA. - -This Agreement is made and entered into by and between Illumina, Inc., a Delaware corporation, having offices at 5200 Illumina Way, San Diego, CA 92122 (“Illumina”) and you as the end-user of the Software (hereinafter, “Licensee” or “you”). All software, firmware, and associated media, printed materials, and online and electronic documentation, including any updates or upgrades thereof, made available through the Illumina Support Center (collectively, “Software”) provided to Licensee are for use solely by Licensee and the provisions herein WILL apply with respect to such Software. - -License Grant. Subject to the terms and conditions of this Agreement, Illumina grants to Licensee, under the following terms and conditions, a personal, non-exclusive, revocable, non-transferable, non-sublicensable license, for its internal end-use purposes only, in the ordinary course of Licensee’s business to use the Software in executable object code form only, solely at the Licensee’s facility to, install and use the Software on a single computer accessible only by Licensee (and not on any public network or server), where the single computer is owned, leased, or otherwise substantially controlled by Licensee, for the purpose of processing and analyzing data generated from an Illumina genetic sequencing instrument owned and operated solely by Licensee (the “Product”). In the case of Software provided by Illumina in non-compiled form, Illumina grants Licensee a personal, non-exclusive, non-sublicenseable, restricted right to compile, install, and use one copy of the Software solely for processing and analyzing data generated from the Product. -License Restrictions. Except as expressly permitted in Section 1, Licensee may not make, have made, import, use, copy, reproduce, distribute, display, publish, sell, re-sell, lease, or sub-license the Software, in whole or in part, except as expressly provided for in this Agreement. Licensee may not modify, improve, translate, reverse engineer, decompile, disassemble, or create derivative works of the Software or otherwise attempt to (a) defeat, avoid, by-pass, remove, deactivate, or otherwise circumvent any software protection mechanisms in the Software including, without limitation, any such mechanism used to restrict or control the functionality of the Software, or (b) derive the source code or the underlying ideas, algorithms, structure, or organization form of the Software. Licensee will not allow, at any time, including during and after the term of the license, the Software or any portions or copies thereof in any form to become available to any third parties. Licensee may use the Software solely with genomic data that is generated using the Product; Licensee may not use the Software with any data generated from other products or instruments. Licensee may not use the Software to perform any data analysis services for any third party. -Ownership. The Software is protected by United States and international intellectual property laws. All right, title, and interest in and to the Software (including associated intellectual property rights) are and will remain vested in Illumina or Illumina’s affiliated companies or licensors. Licensee acknowledges that no rights, license or interest to any Illumina trademarks are granted hereunder. Licensee acknowledges that unauthorized reproduction or distribution of the Software, or any portion of it, may result in severe civil and criminal penalties. Illumina reserves all rights in and to the Software not expressly granted to Licensee under this Agreement. -Upgrades/Updates. Illumina may, at its sole discretion, provide updates or upgrades to the Software. In that case, Licensee WILL have the same rights and obligations under such updates or upgrades as it has for the versions of the Software initially provided to Licensee hereunder. Licensee recognizes that Illumina is not obligated to provide any upgrades or updates to, or support for, the Software. -Data Integrity/Loss. Licensee is responsible for the integrity and availability, including preventing the loss of data that Licensee generates, uses, analyzes, manages, or stores in connection with or through its use of the Software, including without limitation, investigating and implementing industry appropriate policies and procedures regarding the provision of access to Licensee’s data, monitoring access and use of Licensee’s data, conducting routine backups and archiving of Licensee’s data, and ensuring the adequacy of anti-virus software. Accordingly, Licensee agrees that Illumina is not responsible for any inability to access, loss or corruption of data as a result of Licensee’s use of the Software, and Illumina has no liability to Licensee in connection with such inability to access, loss or corruption of data. -Term of License. This Agreement will be in effect from the time Licensee expressly accepts the terms and conditions of this license, or otherwise installs the Software, thereby accepting the terms and conditions contained herein, and will remain in effect until terminated. This license will otherwise terminate upon the conditions set forth in this Agreement, if revoked by Illumina, or if Licensee fails to comply with any term or condition of this Agreement including failure to pay any applicable license fee. Licensee agrees upon termination of this Agreement for any reason to immediately discontinue use of and un-install the Software and destroy all copies of the Software in its possession and/or under its control, and return or destroy, at Illumina’s option, any compact disks, floppy disks or other media provided by Illumina storing the Software thereon (together with any authorized copies thereof), as well as any documentation associated therewith -Limited Warranty. Illumina warrants that, for a period of 6 months from the date of download or installation of the Software by Licensee, the Software will perform in all material respects in accordance with the accompanying documentation available on the Illumina Support Center. EXCEPT AND TO THE EXTENT EXPRESSLY PROVIDED IN THE FOREGOING, AND TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS” AND ILLUMINA EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS REGARDING THE SOFTWARE AND RESULTS GENERATED BY THE SOFTWARE, INCLUDING WITHOUT LIMITATION, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, ALL OTHER EXPRESS OR IMPLIED WARRANTIES OR CONDITIONS OF MERCHANTABLE QUALITY, NON-INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE, AND THOSE ARISING BY STATUTE OR OTHERWISE IN LAW OR FROM A COURSE OF DEALING OR USAGE OF TRADE. ILLUMINA DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE"S REQUIREMENTS, OR THAT THE OPERATION OF THE SOFTWARE WILL BE ERROR FREE OR UNINTERRUPTED. -Limitation of Liability. -(a) ILLUMINA’S ENTIRE LIABILITY AND LICENSEE"S EXCLUSIVE REMEDY UNDER THE LIMITED WARRANTY PROVISION OF SECTION 7 ABOVE WILL BE, AT ILLUMINA’S OPTION, EITHER (i) RETURN OF THE PRICE PAID FOR THE SOFTWARE, OR (ii) REPAIR OR REPLACEMENT OF THE PORTIONS OF THE SOFTWARE THAT DO NOT COMPLY WITH ILLUMINA’S LIMITED WARRANTY. THIS LIMITED WARRANTY IS VOID AND ILLUMINA WILL HAVE NO LIABILITY AT ALL IF FAILURE OF THE SOFTWARE TO COMPLY WITH ILLUMINA LIMITED WARRANTY HAS RESULTED FROM: (w) FAILURE TO USE THE SOFTWARE IN ACCORDANCE WITH ILLUMINA’S THEN CURRENT USER MANUAL OR THIS AGREEMENT; (x) ACCIDENT, ABUSE, OR MISAPPLICATION; (y) PRODUCTS OR EQUIPMENT NOT SPECIFIED BY ILLUMINA AS BEING COMPATIBLE WITH THE SOFTWARE; OR (z) IF LICENSEE HAS NOT NOTIFIED ILLUMINA IN WRITING OF THE DEFECT WITHIN THE ABOVE WARRANTY PERIOD. - -(b) TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL ILLUMINA BE LIABLE UNDER ANY THEORY OF CONTRACT, TORT, STRICT LIABILITY OR OTHER LEGAL OR EQUITABLE THEORY FOR ANY PERSONAL INJURY OR ANY INDIRECT, CONSEQUENTIAL, OR INCIDENTAL DAMAGES, EVEN IF ILLUMINA HAS BEEN ADVISED OF THE POSSIBILITY THEREOF INCLUDING, WITHOUT LIMITATION, LOST PROFITS, LOST DATA, INTERRUPTION OF BUSINESS, LOST BUSINESS REVENUE, OTHER ECONOMIC LOSS, OR ANY LOSS OF RECORDED DATA ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE. EXCEPT AND TO THE EXTENT EXPRESSLY PROVIDED IN SECTION 7 AND 8(a) ABOVE OR AS OTHERWISE PERMITTED BY LAW, IN NO EVENT WILL ILLUMINA’S TOTAL LIABILITY TO LICENSEE FOR ALL DAMAGES (OTHER THAN AS MAY BE REQUIRED BY APPLICABLE LAW IN CASES INVOLVING PERSONAL INJURY) EXCEED THE AMOUNT OF $500 USD. THE FOREGOING LIMITATIONS WILL APPLY EVEN IF THE ABOVE STATED REMEDY FAILS OF ITS ESSENTIAL PURPOSE. - -Survival. The limitations of liability and ownership rights of Illumina contained herein and Licensee’s obligations following termination of this Agreement WILL survive the termination of this Agreement for any reason. -Research Use Only. The Software is labeled with a For Research Use Only or similar labeling statement and the performance characteristics of the Software have not been established and the Software is not for use in diagnostic procedures. Licensee acknowledges and agrees that (i) the Software has not been approved, cleared, or licensed by the United States Food and Drug Administration or any other regulatory entity whether foreign or domestic for any specific intended use, whether research, commercial, diagnostic, or otherwise, and (ii) Licensee must ensure it has any regulatory approvals that are necessary for Licensee’s intended uses of the Software. Licensee will comply with all applicable laws and regulations when using and maintaining the Software. -General. Licensee may not sublicense, assign, share, pledge, rent or transfer any of its rights under this Agreement in relation to the Software or any portion thereof including documentation. Illumina reserves the right to change this Agreement at any time. When Illumina makes any changes, Illumina will provide the updated Agreement, or a link to it, on Illumina’s website (www.illumina.com) and such updated Agreement WILL become effective immediately. Licensee’s continued access to or use of the Software represents Licensee’s agreement to any revised Agreement. If one or more provisions of this Agreement are found to be invalid or unenforceable, this Agreement WILL not be rendered inoperative but the remaining provisions WILL continue in full force and effect. This Agreement constitutes the entire agreement between the parties with respect to the subject matter of this Agreement and merges all prior communications except that a “hard-copy” form of licensing agreement relating to the Software previously agreed to in writing by Illumina and Licensee WILL supersede and govern in the event of any conflicting provisions. -Governing Law. This Agreement WILL be governed by and construed in accordance with the laws of the state of California, USA, without regard to its conflicts of laws principles, and independent of where a suit or action hereunder may be filed. -U.S. Government End Users. If Licensee is a branch agency or instrumentality of the United States Government, the following provision applies. The Software is a “commercial item” as that term is defined at 48 C.F.R. 2.101, consisting of “commercial computer software” and “commercial computer software documentation,” as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202 (as applicable). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4, all United States Government end users acquire the Software with only those rights set forth herein. -Contact. Any questions regarding legal rights, duties, obligations, or restrictions associated with the software hereunder should be directed to Illumina, Inc., 5200 Illumina Way, San Diego, CA 92122, Attention: Legal Department, Phone: (858) 202-4500, Fax: (858) 202-4599, web site: www.illumina.com . -Third Party Components. The Software may include third party software (“Third Party Programs”). Some of the Third Party Programs are available under open source or free software licenses. The License Agreement accompanying the Licensed Software does not alter any rights or obligations Licensee may have under those open source or free software licenses. The licenses that govern the terms and conditions of use of the Third Party Programs included in the Licensed Software are provided in the READ ME provided with the Software. The READ ME also contains copyright statements for the various open source software components (or portions thereof) that are distributed with the Licensed Software. -END OF END-USER SOFTWARE LICENSE AGREEMENT. diff --git a/modules/nf-core/bcl2fastq/README.md b/modules/nf-core/bcl2fastq/README.md deleted file mode 100644 index be98aada..00000000 --- a/modules/nf-core/bcl2fastq/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Updating the docker container and making a new module release - -bcl2fastq is a commercial tool from Illumina. The container provided for the bcl2fastq nf-core module is not provided nor supported by Illumina. Updating the bcl2fastq versions in the container and pushing the update to Dockerhub needs to be done manually. - -1. Navigate to the appropriate download page. - [bcl2fastq](https://support.illumina.com/sequencing/sequencing_software/bcl2fastq-conversion-software/downloads.html): download the rpm of the desired bcl2fastq version with `curl` or `wget`. -2. Unpack the RPM package using `rpm2cpio bcl2fastq2-*.rpm | cpio -i --make-directories`. - - Move the executable located in `/usr/bin/bcl2fastq` into the same folder as the Dockerfile. - - Move the `css` and `xsl` directories from `/local/share/` into the same folder as the Dockerfile -3. Create and test the container: - - ```bash - docker build . -t nfcore/bcl2fastq: - ``` - -4. Access rights are needed to push the container to the Dockerhub nfcore organization, please ask a core team member to do so. - - ```bash - docker push nfcore/bcl2fastq: - ``` diff --git a/modules/nf-core/bcl2fastq/bcl2fastq.diff b/modules/nf-core/bcl2fastq/bcl2fastq.diff deleted file mode 100644 index 0e24436c..00000000 --- a/modules/nf-core/bcl2fastq/bcl2fastq.diff +++ /dev/null @@ -1,101 +0,0 @@ -Changes in component 'nf-core/bcl2fastq' -'modules/nf-core/bcl2fastq/LICENSE' is unchanged -'modules/nf-core/bcl2fastq/Dockerfile' is unchanged -'modules/nf-core/bcl2fastq/README.md' is unchanged -'modules/nf-core/bcl2fastq/.gitignore' is unchanged -'modules/nf-core/bcl2fastq/meta.yml' is unchanged -Changes in 'bcl2fastq/main.nf': ---- modules/nf-core/bcl2fastq/main.nf -+++ modules/nf-core/bcl2fastq/main.nf -@@ -1,5 +1,5 @@ - process BCL2FASTQ { -- tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } -+ tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } - label 'process_high' - - container "nf-core/bcl2fastq:2.20.0.422" -@@ -8,14 +8,14 @@ - tuple val(meta), path(samplesheet), path(run_dir) - - output: -- tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq -- tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , optional:true, emit: fastq_idx -- tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz") , optional:true, emit: undetermined -- tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz") , optional:true, emit: undetermined_idx -- tuple val(meta), path("output/Reports") , emit: reports -- tuple val(meta), path("output/Stats") , emit: stats -- tuple val(meta), path("InterOp/*.bin") , emit: interop -- path("versions.yml") , emit: versions -+ tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz"), emit: fastq -+ tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), optional: true, emit: fastq_idx -+ tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), optional: true, emit: undetermined -+ tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), optional: true, emit: undetermined_idx -+ tuple val(meta), path("output/Reports/*"), emit: reports -+ tuple val(meta), path("output/Stats/*"), emit: stats -+ tuple val(meta), path("InterOp/*.bin"), emit: interop -+ path ("versions.yml"), emit: versions - - when: - task.ext.when == null || task.ext.when -@@ -23,7 +23,7 @@ - script: - // Exit if running this module with -profile conda / -profile mamba - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { -- error "BCL2FASTQ module does not support Conda. Please use Docker / Singularity / Podman instead." -+ error("BCL2FASTQ module does not support Conda. Please use Docker / Singularity / Podman instead.") - } - def args = task.ext.args ?: '' - def args2 = task.ext.args2 ?: '' -@@ -37,27 +37,27 @@ - - if ${input_tar}; then - ## Ensures --strip-components only applied when top level of tar contents is a directory -- ## If just files or multiple directories, place all in $input_dir -+ ## If just files or multiple directories, place all in ${input_dir} - - if [[ \$(tar -taf ${run_dir} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then - tar \\ -- -C $input_dir --strip-components 1 \\ -+ -C ${input_dir} --strip-components 1 \\ - -xavf \\ -- $args2 \\ -- $run_dir \\ -- $args3 -+ ${args2} \\ -+ ${run_dir} \\ -+ ${args3} - else - tar \\ -- -C $input_dir \\ -+ -C ${input_dir} \\ - -xavf \\ -- $args2 \\ -- $run_dir \\ -- $args3 -+ ${args2} \\ -+ ${run_dir} \\ -+ ${args3} - fi - fi - - bcl2fastq \\ -- $args \\ -+ ${args} \\ - --output-dir output \\ - --runfolder-dir ${input_dir} \\ - --sample-sheet ${samplesheet} \\ - -'modules/nf-core/bcl2fastq/tests/main.nf.test.snap' is unchanged -Changes in 'bcl2fastq/tests/nextflow.config': ---- modules/nf-core/bcl2fastq/tests/nextflow.config -+++ modules/nf-core/bcl2fastq/tests/nextflow.config -@@ -2,5 +2,5 @@ - - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - -- ext.args = "--tiles s_1_1101" -+ ext.args = "--tiles s_1_1101" - } - -'modules/nf-core/bcl2fastq/tests/main.nf.test' is unchanged -************************************************************ diff --git a/modules/nf-core/bcl2fastq/main.nf b/modules/nf-core/bcl2fastq/main.nf deleted file mode 100644 index b06bec18..00000000 --- a/modules/nf-core/bcl2fastq/main.nf +++ /dev/null @@ -1,73 +0,0 @@ -process BCL2FASTQ { - tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } - label 'process_high' - - container "nf-core/bcl2fastq:2.20.0.422" - - input: - tuple val(meta), path(samplesheet), path(run_dir) - - output: - tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz"), emit: fastq - tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), optional: true, emit: fastq_idx - tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), optional: true, emit: undetermined - tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), optional: true, emit: undetermined_idx - tuple val(meta), path("output/Reports/*"), emit: reports - tuple val(meta), path("output/Stats/*"), emit: stats - tuple val(meta), path("InterOp/*.bin"), emit: interop - path ("versions.yml"), emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - // Exit if running this module with -profile conda / -profile mamba - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error("BCL2FASTQ module does not support Conda. Please use Docker / Singularity / Podman instead.") - } - def args = task.ext.args ?: '' - def args2 = task.ext.args2 ?: '' - def args3 = task.ext.args3 ?: '' - def input_tar = run_dir.toString().endsWith(".tar.gz") ? true : false - def input_dir = input_tar ? run_dir.toString() - '.tar.gz' : run_dir - """ - if [ ! -d ${input_dir} ]; then - mkdir -p ${input_dir} - fi - - if ${input_tar}; then - ## Ensures --strip-components only applied when top level of tar contents is a directory - ## If just files or multiple directories, place all in ${input_dir} - - if [[ \$(tar -taf ${run_dir} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then - tar \\ - -C ${input_dir} --strip-components 1 \\ - -xavf \\ - ${args2} \\ - ${run_dir} \\ - ${args3} - else - tar \\ - -C ${input_dir} \\ - -xavf \\ - ${args2} \\ - ${run_dir} \\ - ${args3} - fi - fi - - bcl2fastq \\ - ${args} \\ - --output-dir output \\ - --runfolder-dir ${input_dir} \\ - --sample-sheet ${samplesheet} \\ - --processing-threads ${task.cpus} - - cp -r ${input_dir}/InterOp . - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bcl2fastq: \$(bcl2fastq -V 2>&1 | grep -m 1 bcl2fastq | sed 's/^.*bcl2fastq v//') - END_VERSIONS - """ -} diff --git a/modules/nf-core/bcl2fastq/meta.yml b/modules/nf-core/bcl2fastq/meta.yml deleted file mode 100644 index af17d591..00000000 --- a/modules/nf-core/bcl2fastq/meta.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: "bcl2fastq" -description: Demultiplex Illumina BCL files -keywords: - - demultiplex - - illumina - - fastq -tools: - - "bcl2fastq": - description: "Demultiplex Illumina BCL files" - homepage: "https://support.illumina.com/sequencing/sequencing_software/bcl2fastq-conversion-software" - documentation: "https://support.illumina.com/content/dam/illumina-support/documents/documentation/software_documentation/bcl2fastq/bcl2fastq2-v2-20-software-guide-15051736-03.pdf" - licence: ["ILLUMINA"] - identifier: "" -input: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - samplesheet: - type: file - description: "Input samplesheet" - pattern: "*.{csv}" - ontologies: - - edam: http://edamontology.org/format_3752 # CSV - - run_dir: - type: file - description: | - Input run directory containing RunInfo.xml and BCL data - Could be a directory or a tar of the directory - ontologies: [] -output: - fastq: - - - meta: - type: map - description: Groovy Map containing sample information - - output/**_S[1-9]*_R?_00?.fastq.gz: - type: file - description: Demultiplexed sample FASTQ files - pattern: "**_S*_L00?_R?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - fastq_idx: - - - meta: - type: map - description: Groovy Map containing sample information - - output/**_S[1-9]*_I?_00?.fastq.gz: - type: file - description: Optional demultiplexed index FASTQ files - pattern: "**_S*_L00?_I?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - undetermined: - - - meta: - type: map - description: Groovy Map containing sample information - - output/**Undetermined_S0*_R?_00?.fastq.gz: - type: file - description: Optional undetermined sample FASTQ files - pattern: "Undetermined_S0_L00?_R?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - undetermined_idx: - - - meta: - type: map - description: Groovy Map containing sample information - - output/**Undetermined_S0*_I?_00?.fastq.gz: - type: file - description: Optional undetermined index FASTQ files - pattern: "Undetermined_S0_L00?_I?_00?.fastq.gz" - ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - reports: - - - meta: - type: map - description: Groovy Map containing sample information - - output/Reports: - type: file - description: Demultiplexing Reports - pattern: "Reports/*" - ontologies: [] - stats: - - - meta: - type: map - description: Groovy Map containing sample information - - output/Stats: - type: file - description: Statistics files - pattern: "Stats/*" - ontologies: [] - interop: - - - meta: - type: map - description: Groovy Map containing sample information - - InterOp/*.bin: - type: file - description: Interop files - pattern: "*.{bin}" - ontologies: [] - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -authors: - - "@matthdsm" -maintainers: - - "@matthdsm" diff --git a/modules/nf-core/bcl2fastq/tests/main.nf.test b/modules/nf-core/bcl2fastq/tests/main.nf.test deleted file mode 100644 index d0e0b9a5..00000000 --- a/modules/nf-core/bcl2fastq/tests/main.nf.test +++ /dev/null @@ -1,32 +0,0 @@ -nextflow_process { - - name "Test Process BCL2FASTQ" - script "modules/nf-core/bcl2fastq/main.nf" - process "BCL2FASTQ" - config "./nextflow.config" - tag "bcl2fastq" - tag "modules" - tag "modules_nfcore" - - test("homo sapiens illumina [bcl]") { - when { - process { - //TODO use new test dataset when available, see https://github.com/nf-core/test-datasets/issues/996 - """ - input[0] = [ - [ id: 'test', lane:1 ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bcl/flowcell_samplesheet.csv', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bcl/flowcell.tar.gz', checkIfExists: true) - ] - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } -} diff --git a/modules/nf-core/bcl2fastq/tests/main.nf.test.snap b/modules/nf-core/bcl2fastq/tests/main.nf.test.snap deleted file mode 100644 index 8addecc2..00000000 --- a/modules/nf-core/bcl2fastq/tests/main.nf.test.snap +++ /dev/null @@ -1,219 +0,0 @@ -{ - "homo sapiens illumina [bcl]": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "lane": 1 - }, - "Sample1_S1_L001_R1_001.fastq.gz:md5,0675fb6365322eaafb33c0f8e862b54b" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - [ - [ - [ - [ - [ - "lane.html:md5,794e48287f47a9f22dcb6b6d0c22c3eb", - "laneBarcode.html:md5,2bbdae3ee57151eab520c966597d7438" - ], - [ - - ] - ] - ], - [ - [ - [ - "lane.html:md5,f741870307050dcea79a838f5971770f", - "laneBarcode.html:md5,ffe2e863811c76cb9da27d5d124e0611" - ], - [ - "lane.html:md5,cca97e771d3491dbc8cd3fe389595b09", - "laneBarcode.html:md5,cca97e771d3491dbc8cd3fe389595b09" - ] - ], - [ - [ - "lane.html:md5,c383b0768d9978733d3f5d3b91c15af0", - "laneBarcode.html:md5,48842c23b9a2816aec540177df870968" - ], - [ - - ] - ] - ] - ], - "Report.css:md5,eb7d3eb68fc1539f411404987246b59b", - "index.html:md5,5747c407854ae2c358d0ec201ce622d8", - "tree.html:md5,a1b9bf592973ca829ec69ddf888b7e34" - ] - ] - ] - ], - "5": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - "AdapterTrimming.txt:md5,48ed2b914b1246c0b5d8667525550946", - "ConversionStats.xml:md5,8fe0f57f3f5d256a0762dba75ac62d05", - "DemultiplexingStats.xml:md5,2047ff18f5b9107c084de06e9ff943ad", - "DemuxSummaryF1L1.txt:md5,03e5fd0c1e3079c5f8c7b4d0501b37ff", - "FastqSummaryF1L1.txt:md5,0c6f2d87ee183b84d1051cde9a5643d1", - "Stats.json:md5,8e5f038b8aa9e465599d3575f930e604" - ] - ] - ], - "6": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", - "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", - "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", - "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", - "IndexMetricsOut.bin:md5,9e688c58a5487b8eaf69c9e1005ad0bf", - "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", - "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" - ] - ] - ], - "7": [ - "versions.yml:md5,12f3dca40b6a65cec6ba51c0fd872152" - ], - "fastq": [ - [ - { - "id": "test", - "lane": 1 - }, - "Sample1_S1_L001_R1_001.fastq.gz:md5,0675fb6365322eaafb33c0f8e862b54b" - ] - ], - "fastq_idx": [ - - ], - "interop": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", - "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", - "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", - "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", - "IndexMetricsOut.bin:md5,9e688c58a5487b8eaf69c9e1005ad0bf", - "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", - "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" - ] - ] - ], - "reports": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - [ - [ - [ - [ - [ - "lane.html:md5,794e48287f47a9f22dcb6b6d0c22c3eb", - "laneBarcode.html:md5,2bbdae3ee57151eab520c966597d7438" - ], - [ - - ] - ] - ], - [ - [ - [ - "lane.html:md5,f741870307050dcea79a838f5971770f", - "laneBarcode.html:md5,ffe2e863811c76cb9da27d5d124e0611" - ], - [ - "lane.html:md5,cca97e771d3491dbc8cd3fe389595b09", - "laneBarcode.html:md5,cca97e771d3491dbc8cd3fe389595b09" - ] - ], - [ - [ - "lane.html:md5,c383b0768d9978733d3f5d3b91c15af0", - "laneBarcode.html:md5,48842c23b9a2816aec540177df870968" - ], - [ - - ] - ] - ] - ], - "Report.css:md5,eb7d3eb68fc1539f411404987246b59b", - "index.html:md5,5747c407854ae2c358d0ec201ce622d8", - "tree.html:md5,a1b9bf592973ca829ec69ddf888b7e34" - ] - ] - ] - ], - "stats": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - "AdapterTrimming.txt:md5,48ed2b914b1246c0b5d8667525550946", - "ConversionStats.xml:md5,8fe0f57f3f5d256a0762dba75ac62d05", - "DemultiplexingStats.xml:md5,2047ff18f5b9107c084de06e9ff943ad", - "DemuxSummaryF1L1.txt:md5,03e5fd0c1e3079c5f8c7b4d0501b37ff", - "FastqSummaryF1L1.txt:md5,0c6f2d87ee183b84d1051cde9a5643d1", - "Stats.json:md5,8e5f038b8aa9e465599d3575f930e604" - ] - ] - ], - "undetermined": [ - - ], - "undetermined_idx": [ - - ], - "versions": [ - "versions.yml:md5,12f3dca40b6a65cec6ba51c0fd872152" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-08-05T12:46:23.595844132" - } -} \ No newline at end of file diff --git a/modules/nf-core/bcl2fastq/tests/nextflow.config b/modules/nf-core/bcl2fastq/tests/nextflow.config deleted file mode 100644 index 38ad79af..00000000 --- a/modules/nf-core/bcl2fastq/tests/nextflow.config +++ /dev/null @@ -1,6 +0,0 @@ -process { - - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - - ext.args = "--tiles s_1_1101" -} diff --git a/modules/nf-core/bclconvert/Dockerfile b/modules/nf-core/bclconvert/Dockerfile index eda84168..c5594cf2 100644 --- a/modules/nf-core/bclconvert/Dockerfile +++ b/modules/nf-core/bclconvert/Dockerfile @@ -2,6 +2,24 @@ # Dockerfile to create container with bcl-convert # Push to nfcore/bclconvert: +# Build stage: unpack the RPM file +FROM debian:bullseye-slim AS build +ARG BCLCONVERT_VERSION="4.4.6" + +# Install tools needed to extract RPM +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + rpm2cpio \ + cpio \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Extract bcl-convert from RPM +COPY bcl-convert-4.4.6-2.el8.x86_64.rpm bcl-convert.rpm +RUN rpm2cpio bcl-convert.rpm | cpio -idmv \ + && rm bcl-convert.rpm + +# Final stage: minimal image with only necessary components FROM debian:bullseye-slim ARG BCLCONVERT_VERSION="4.4.6" LABEL org.opencontainers.image.description="Docker image containing bcl-convert" @@ -12,20 +30,16 @@ LABEL org.opencontainers.image.vendor="nf-core" LABEL org.opencontainers.image.license="https://github.com/nf-core/modules/blob/master/modules/nf-core/bclconvert/LICENSE" # Disclaimer: this container is not provided nor supported by Illumina -# 'ps' command is need by some nextflow executions to collect system stats -# Install procps and clean apt cache +# Install procps (for 'ps' command needed by Nextflow) and rclone (for parallel file transfers) RUN apt-get update \ && apt-get install -y --no-install-recommends \ procps \ - rpm2cpio \ - cpio \ + rclone \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* + # Link hostname cmd to fix hardcoded path RUN ln -s /bin/hostname /usr/bin/hostname -# Install bcl-convert -COPY bcl-convert-4.4.6-2.el8.x86_64.rpm bcl-convert.rpm -SHELL ["/bin/bash", "-o", "pipefail", "-c"] -RUN rpm2cpio bcl-convert.rpm | cpio -idmv \ - && rm bcl-convert.rpm -RUN rm -rf /var/log/bcl-convert && ln -sfT /tmp /var/log/bcl-convert + +# Copy bcl-convert executable from build stage +COPY --from=build /usr/bin/bcl-convert /usr/bin/bcl-convert diff --git a/modules/nf-core/bclconvert/bclconvert.diff b/modules/nf-core/bclconvert/bclconvert.diff deleted file mode 100644 index caa6b812..00000000 --- a/modules/nf-core/bclconvert/bclconvert.diff +++ /dev/null @@ -1,107 +0,0 @@ -Changes in component 'nf-core/bclconvert' -'modules/nf-core/bclconvert/LICENSE' is unchanged -'modules/nf-core/bclconvert/Dockerfile' is unchanged -'modules/nf-core/bclconvert/README.md' is unchanged -'modules/nf-core/bclconvert/.gitignore' is unchanged -'modules/nf-core/bclconvert/meta.yml' is unchanged -Changes in 'bclconvert/main.nf': ---- modules/nf-core/bclconvert/main.nf -+++ modules/nf-core/bclconvert/main.nf -@@ -1,5 +1,5 @@ - process BCLCONVERT { -- tag { "$meta.lane" ? "$meta.id"+"."+"$meta.lane" : "$meta.id" } -+ tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } - label 'process_high' - - container "nf-core/bclconvert:4.4.6" -@@ -8,14 +8,14 @@ - tuple val(meta), path(samplesheet), path(run_dir) - - output: -- tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz") , emit: fastq -- tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz") , emit: fastq_idx , optional:true -- tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined , optional:true -- tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional:true -- tuple val(meta), path("output/Reports") , emit: reports -- tuple val(meta), path("output/Logs") , emit: logs -- tuple val(meta), path("output/InterOp/*.bin") , emit: interop , optional:true -- path("versions.yml") , emit: versions -+ tuple val(meta), path("output/**_S[1-9]*_R?_00?.fastq.gz"), emit: fastq -+ tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), emit: fastq_idx, optional: true -+ tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined, optional: true -+ tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional: true -+ tuple val(meta), path("output/Reports/*"), emit: reports -+ tuple val(meta), path("output/Logs/*"), emit: logs -+ tuple val(meta), path("output/InterOp/*.bin"), emit: interop, optional: true -+ path ("versions.yml"), emit: versions - - when: - task.ext.when == null || task.ext.when -@@ -23,7 +23,7 @@ - script: - // Exit if running this module with -profile conda / -profile mamba - if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { -- error "BCLCONVERT module does not support Conda. Please use Docker / Singularity / Podman instead." -+ error("BCLCONVERT module does not support Conda. Please use Docker / Singularity / Podman instead.") - } - def args = task.ext.args ?: '' - def args2 = task.ext.args2 ?: '' -@@ -37,27 +37,27 @@ - - if ${input_tar}; then - ## Ensures --strip-components only applied when top level of tar contents is a directory -- ## If just files or multiple directories, place all in $input_dir -+ ## If just files or multiple directories, place all in ${input_dir} - - if [[ \$(tar -taf ${run_dir} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then - tar \\ -- -C $input_dir --strip-components 1 \\ -+ -C ${input_dir} --strip-components 1 \\ - -xavf \\ -- $args2 \\ -- $run_dir \\ -- $args3 -+ ${args2} \\ -+ ${run_dir} \\ -+ ${args3} - else - tar \\ -- -C $input_dir \\ -+ -C ${input_dir} \\ - -xavf \\ -- $args2 \\ -- $run_dir \\ -- $args3 -+ ${args2} \\ -+ ${run_dir} \\ -+ ${args3} - fi - fi - - bcl-convert \\ -- $args \\ -+ ${args} \\ - --output-directory output \\ - --bcl-input-directory ${input_dir} \\ - --sample-sheet ${samplesheet} -@@ -107,5 +107,4 @@ - bclconvert: \$(bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //') - END_VERSIONS - """ -- - } - -'modules/nf-core/bclconvert/tests/main.nf.test.snap' is unchanged -Changes in 'bclconvert/tests/nextflow.config': ---- modules/nf-core/bclconvert/tests/nextflow.config -+++ modules/nf-core/bclconvert/tests/nextflow.config -@@ -1,5 +1,5 @@ - process { -- withName: "BCLCONVERT" { -+ withName: BCLCONVERT { - ext.args = params.module_args - } - } - -'modules/nf-core/bclconvert/tests/main.nf.test' is unchanged -************************************************************ diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index 6b164908..6f207277 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -12,10 +12,10 @@ process BCLCONVERT { tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), emit: fastq_idx, optional: true tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined, optional: true tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional: true - tuple val(meta), path("output/Reports/*"), emit: reports - tuple val(meta), path("output/Logs/*"), emit: logs + 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 - path ("versions.yml"), emit: versions + tuple val("${task.process}"), val('bclconvert'), eval("bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //'"), topic: versions, emit: versions_bclconvert when: task.ext.when == null || task.ext.when @@ -65,46 +65,83 @@ process BCLCONVERT { # copy the InterOp folder contents to ensure it gets picked up when using fusion mkdir -p output/InterOp/ cp -n **/InterOp/*.bin output/InterOp/ - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bclconvert: \$(bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //') - END_VERSIONS """ stub: """ + mkdir -p output + echo "fake fastq file" | gzip > output/Sample1_S1_L001_R1_001.fastq.gz + echo "fake fastq file" | gzip > output/Undetermined_S0_L001_R1_001.fastq.gz + mkdir -p output/Reports + echo "fake report file" > output/Reports/Adapter_Cycle_Metrics.csv + echo "fake report file" > output/Reports/Adapter_Metrics.csv + echo "fake report file" > output/Reports/Demultiplex_Stats.csv + echo "fake report file" > output/Reports/Demultiplex_Tile_Stats.csv + echo "fake report file" > output/Reports/fastq_list.csv + echo "fake report file" > output/Reports/Index_Hopping_Counts.csv + echo "fake report file" > output/Reports/IndexMetricsOut.bin + echo "fake report file" > output/Reports/Quality_Metrics.csv + echo "fake report file" > output/Reports/Quality_Tile_Metrics.csv + echo "fake report file" > output/Reports/RunInfo.xml + echo "fake report file" > output/Reports/SampleSheet.csv + echo "fake report file" > output/Reports/Top_Unknown_Barcodes.csv + mkdir -p output/Logs - echo "" | gzip > output/Sample1_S1_L001_R1_001.fastq.gz - echo "" | gzip > output/Undetermined_S0_L001_R1_001.fastq.gz - touch output/Reports/Adapter_Cycle_Metrics.csv - touch output/Reports/Adapter_Metrics.csv - touch output/Reports/Demultiplex_Stats.csv - touch output/Reports/Demultiplex_Tile_Stats.csv - touch output/Reports/fastq_list.csv - touch output/Reports/Index_Hopping_Counts.csv - touch output/Reports/IndexMetricsOut.bin - touch output/Reports/Quality_Metrics.csv - touch output/Reports/Quality_Tile_Metrics.csv - touch output/Reports/RunInfo.xml - touch output/Reports/SampleSheet.csv - touch output/Reports/Top_Unknown_Barcodes.csv - touch output/Logs/Errors.log - touch output/Logs/FastqComplete.log - touch output/Logs/Info.log - touch output/Logs/Warnings.log + echo "fake log file" > output/Logs/Errors.log + echo "fake log file" > output/Logs/FastqComplete.log + echo "fake log file" > output/Logs/Info.log + echo "fake log file" > output/Logs/Warnings.log + mkdir -p output/InterOp - touch output/InterOp/ControlMetricsOut.bin - touch output/InterOp/CorrectedIntMetricsOut.bin - touch output/InterOp/ErrorMetricsOut.bin - touch output/InterOp/ExtractionMetricsOut.bin - touch output/InterOp/IndexMetricsOut.bin - touch output/InterOp/QMetricsOut.bin - touch output/InterOp/TileMetricsOut.bin - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bclconvert: \$(bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //') - END_VERSIONS + echo "fake InterOp file" > output/InterOp/ControlMetricsOut.bin + echo "fake InterOp file" > output/InterOp/CorrectedIntMetricsOut.bin + echo "fake InterOp file" > output/InterOp/ErrorMetricsOut.bin + echo "fake InterOp file" > output/InterOp/ExtractionMetricsOut.bin + echo "fake InterOp file" > output/InterOp/IndexMetricsOut.bin + echo "fake InterOp file" > output/InterOp/QMetricsOut.bin + echo "fake InterOp file" > output/InterOp/TileMetricsOut.bin """ } + +def generateReadgroup(ch_fastq_list_csv, ch_fastq) { + return ch_fastq_list_csv + .collect() // make it a value channel + .map { meta, csv_file -> + def fastq_metadata = [] + csv_file + .splitCsv(header: true) + .each { row -> + // Create the readgroup tuple + // RGID,RGSM,RGLB,Lane,Read1File,Read2File + def rg = [:] + // row.RGID is index1.index2.lane + rg.ID = row.RGID + // RGPU is a custom column in the samplesheet containing the flowcell ID + rg.PU = row.RGPU ? row.RGPU : meta.id + "." + row.Lane + rg.SM = row.RGSM + rg.LB = row.RGLB ? row.RGLB : "" + rg.PL = "ILLUMINA" + + // replace the meta id with the sample name + def new_meta = [id: row.RGSM, readgroup: rg] + // Return the new meta with fastq file + fastq_metadata << [new_meta, file(row.Read1File).name] + if (row.Read2File) { + fastq_metadata << [new_meta, file(row.Read2File).name] + } + } + return [meta, fastq_metadata] + } + .join(ch_fastq, by:[0]) // -> [ meta, [fq_meta, fastq_filename], [fastq_file, ...] ] + .transpose(by:[2]) // -> [ meta, [fq_meta, fastq_filename], fastq_file ] + .map { meta, fastq_metadata, fastq_file -> + def fastq_meta = fastq_metadata.find { _meta, filename -> filename == file(fastq_file).name } + return [meta + fastq_meta[0], file(fastq_file)] + } + .groupTuple(by: [0]) + .map { meta, fastq -> + meta.single_end = fastq.size() == 1 + return [meta, fastq.flatten()] + } +} diff --git a/modules/nf-core/bclconvert/meta.yml b/modules/nf-core/bclconvert/meta.yml index e1cd3e01..a483715a 100644 --- a/modules/nf-core/bclconvert/meta.yml +++ b/modules/nf-core/bclconvert/meta.yml @@ -9,7 +9,8 @@ tools: description: "Demultiplex Illumina BCL files" homepage: "https://support.illumina.com/sequencing/sequencing_software/bcl-convert.html" documentation: "https://support-docs.illumina.com/SW/BCL_Convert/Content/SW/FrontPages/BCL_Convert.htm" - licence: ["ILLUMINA"] + licence: + - "ILLUMINA" identifier: "" input: - - meta: @@ -22,7 +23,7 @@ input: description: "Input samplesheet" pattern: "*.{csv}" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 #CSV - run_dir: type: file description: | @@ -39,7 +40,7 @@ output: description: Demultiplexed sample FASTQ files pattern: "**_S*_L00?_R?_00?.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + - edam: http://edamontology.org/format_1930 #FASTQ fastq_idx: - - meta: type: map @@ -49,7 +50,7 @@ output: description: Optional demultiplexed index FASTQ files pattern: "**_S*_L00?_I?_00?.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + - edam: http://edamontology.org/format_1930 #FASTQ undetermined: - - meta: type: map @@ -59,7 +60,7 @@ output: description: Optional undetermined sample FASTQ files pattern: "Undetermined_S0_L00?_R?_00?.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + - edam: http://edamontology.org/format_1930 #FASTQ undetermined_idx: - - meta: type: map @@ -69,43 +70,60 @@ output: description: Optional undetermined index FASTQ files pattern: "Undetermined_S0_L00?_I?_00?.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + - edam: http://edamontology.org/format_1930 #FASTQ reports: - - meta: type: map description: Groovy Map containing sample information - - output/Reports: + - output/Reports/*.{csv,xml,bin}: type: file description: Demultiplexing Reports - pattern: "Reports/*.{csv,xml}" + pattern: "Reports/*.{csv,xml,bin}" ontologies: - - edam: http://edamontology.org/format_3752 # CSV - - edam: http://edamontology.org/format_2332 # XML + - edam: http://edamontology.org/format_3752 #CSV + - edam: http://edamontology.org/format_2332 #XML + - edam: http://edamontology.org/format_2333 #BINARY logs: - - meta: type: map description: Groovy Map containing sample information - - output/Logs: + - output/Logs/*.{log,txt}: type: file - description: Log files + description: Demultiplexing Logs pattern: "Logs/*.{log,txt}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2330 #TEXT interop: - - meta: type: map description: Groovy Map containing sample information - - "output/InterOp/*.bin": + - output/InterOp/*.bin: type: file description: Interop files - pattern: "*.{bin}" - ontologies: [] + pattern: "InterOp/*.bin" + ontologies: + - edam: http://edamontology.org/format_2333 #BINARY + versions_bclconvert: + - - ${task.process}: + type: string + description: The name of the process + - bclconvert: + type: string + description: The name of the tool + - bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - bclconvert: + type: string + description: The name of the tool + - bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //': + type: eval + description: The expression to obtain the version of the tool authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/bclconvert/tests/main.nf.test b/modules/nf-core/bclconvert/tests/main.nf.test index b2971c02..56ec207a 100644 --- a/modules/nf-core/bclconvert/tests/main.nf.test +++ b/modules/nf-core/bclconvert/tests/main.nf.test @@ -33,13 +33,10 @@ nextflow_process { process.out.fastq_idx, process.out.undetermined.collect { meta, fastq -> file(fastq).name }, process.out.undetermined_idx, - process.out.reports, - process.out.logs.collect { meta, logs -> file(logs).list().sort() }, - process.out.interop.collect { meta, interop -> - interop.findAll { interopfile -> - file(interopfile).name != "IndexMetricsOut.bin" } }, - process.out.versions, - path(process.out.versions[0]).yaml + process.out.reports.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.logs.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.interop.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } @@ -75,14 +72,10 @@ nextflow_process { process.out.fastq_idx, process.out.undetermined.collect { meta, fastq -> file(fastq).name }, process.out.undetermined_idx, - process.out.reports, - process.out.logs.collect { meta, logs -> file(logs).list().sort() }, - process.out.interop, - process.out.interop.collect { meta, interop -> - interop.findAll { interopfile -> - file(interopfile).name != "IndexMetricsOut.bin" } }, - process.out.versions, - path(process.out.versions[0]).yaml + process.out.reports.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.logs.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.interop.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } diff --git a/modules/nf-core/bclconvert/tests/main.nf.test.snap b/modules/nf-core/bclconvert/tests/main.nf.test.snap index b7838a5e..43233d59 100644 --- a/modules/nf-core/bclconvert/tests/main.nf.test.snap +++ b/modules/nf-core/bclconvert/tests/main.nf.test.snap @@ -20,24 +20,19 @@ ], [ [ - { - "id": "test" - }, - [ - "Adapter_Cycle_Metrics.csv:md5,05fbe7b2b0acdd557d355b448aa88ace", - "Adapter_Metrics.csv:md5,0fa4ac708955417af9d18cec4955552f", - "Demultiplex_Detailed_Stats.csv:md5,5a6a4d66a96256ff71e4f649927fb112", - "Demultiplex_Stats.csv:md5,4a3f451faa098156623b55b0f2ff27ee", - "Demultiplex_Tile_Stats.csv:md5,f91fb0c7a2c5588ed43c7f9145d004ee", - "IndexMetricsOut.bin:md5,fb16c8a9873e5b5950ae5949126af76c", - "Index_Hopping_Counts.csv:md5,f59474d96afe8218c7590bb240b19690", - "Quality_Metrics.csv:md5,c4622066f85d93b1661c928a46cfc508", - "Quality_Tile_Metrics.csv:md5,e22bc5e2f147695150b02afcccb38c4f", - "RunInfo.xml:md5,f283cb4600235db9261ee1e319b1407e", - "SampleSheet.csv:md5,4113eabae23136cc819c7f15ac5b6aad", - "Top_Unknown_Barcodes.csv:md5,37dbc2860c640fc721820b0217ea0504", - "fastq_list.csv:md5,482cf7fe9b304a900e4ede3bb25b4912" - ] + "Adapter_Cycle_Metrics.csv", + "Adapter_Metrics.csv", + "Demultiplex_Detailed_Stats.csv", + "Demultiplex_Stats.csv", + "Demultiplex_Tile_Stats.csv", + "IndexMetricsOut.bin", + "Index_Hopping_Counts.csv", + "Quality_Metrics.csv", + "Quality_Tile_Metrics.csv", + "RunInfo.xml", + "SampleSheet.csv", + "Top_Unknown_Barcodes.csv", + "fastq_list.csv" ] ], [ @@ -50,62 +45,39 @@ ], [ [ - { - "id": "test" - }, - [ - "BasecallingMetricsOut.bin:md5,7fb651325cba614d497d376eaf43fef4", - "CorrectedIntMetricsOut.bin:md5,dc8d57282ba9ece9e5fc58a92aa2ac52", - "EmpiricalPhasingMetricsOut.bin:md5,1ef4631faf0a3a3beb31b10fc38a734d", - "EventMetricsOut.bin:md5,dee320ce29bdadde44589aa9439f53ab", - "ExtendedTileMetricsOut.bin:md5,f01d1a9cf8445adf719e652ad7304cf2", - "ExtractionMetricsOut.bin:md5,972f4082ad950baaf42a6d28517d28a8", - "FWHMGridMetricsOut.bin:md5,6e297bafcd845bfd0440d08e1bb27685", - "ImageMetricsOut.bin:md5,ac5d1f0a1f611c0c7c9dd8e6b9e701b1", - "IndexMetricsOut.bin:md5,6d95975d5909eb88f824e6dc8066457d", - "OpticalModelMetricsOut.bin:md5,3eaea5fcf2d353950b1e720c73695ccb", - "PFGridMetricsOut.bin:md5,ae469858ee96ffafbcaf3afb814bdab2", - "QMetrics2030Out.bin:md5,438248760db58917b32f4eccc6c64c39", - "QMetricsByLaneOut.bin:md5,e8254cb4a27846710a2a143296be2d8f", - "QMetricsOut.bin:md5,8f6b83028a42be721200a598161ac5c6", - "RegistrationMetricsOut.bin:md5,b5ebd957aed067b6403d851ba2ce0139", - "TileMetricsOut.bin:md5,21388348d81fa9be326d30ef6d348464" - ] - ] - ], - [ - [ - "BasecallingMetricsOut.bin:md5,7fb651325cba614d497d376eaf43fef4", - "CorrectedIntMetricsOut.bin:md5,dc8d57282ba9ece9e5fc58a92aa2ac52", - "EmpiricalPhasingMetricsOut.bin:md5,1ef4631faf0a3a3beb31b10fc38a734d", - "EventMetricsOut.bin:md5,dee320ce29bdadde44589aa9439f53ab", - "ExtendedTileMetricsOut.bin:md5,f01d1a9cf8445adf719e652ad7304cf2", - "ExtractionMetricsOut.bin:md5,972f4082ad950baaf42a6d28517d28a8", - "FWHMGridMetricsOut.bin:md5,6e297bafcd845bfd0440d08e1bb27685", - "ImageMetricsOut.bin:md5,ac5d1f0a1f611c0c7c9dd8e6b9e701b1", - "OpticalModelMetricsOut.bin:md5,3eaea5fcf2d353950b1e720c73695ccb", - "PFGridMetricsOut.bin:md5,ae469858ee96ffafbcaf3afb814bdab2", - "QMetrics2030Out.bin:md5,438248760db58917b32f4eccc6c64c39", - "QMetricsByLaneOut.bin:md5,e8254cb4a27846710a2a143296be2d8f", - "QMetricsOut.bin:md5,8f6b83028a42be721200a598161ac5c6", - "RegistrationMetricsOut.bin:md5,b5ebd957aed067b6403d851ba2ce0139", - "TileMetricsOut.bin:md5,21388348d81fa9be326d30ef6d348464" + "BasecallingMetricsOut.bin", + "CorrectedIntMetricsOut.bin", + "EmpiricalPhasingMetricsOut.bin", + "EventMetricsOut.bin", + "ExtendedTileMetricsOut.bin", + "ExtractionMetricsOut.bin", + "FWHMGridMetricsOut.bin", + "ImageMetricsOut.bin", + "IndexMetricsOut.bin", + "OpticalModelMetricsOut.bin", + "PFGridMetricsOut.bin", + "QMetrics2030Out.bin", + "QMetricsByLaneOut.bin", + "QMetricsOut.bin", + "RegistrationMetricsOut.bin", + "TileMetricsOut.bin" ] ], - [ - "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" - ], { - "BCLCONVERT": { - "bclconvert": "4.4.6" - } + "versions_bclconvert": [ + [ + "BCLCONVERT", + "bclconvert", + "4.4.6" + ] + ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.4" }, - "timestamp": "2025-09-23T10:12:42.943671245" + "timestamp": "2026-02-17T16:59:36.617127" }, "homo_sapiens illumina [bcl] - stub": { "content": [ @@ -116,7 +88,7 @@ "id": "test", "lane": 1 }, - "Sample1_S1_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "Sample1_S1_L001_R1_001.fastq.gz:md5,1495c2d7a9b129c0968b84b149991bfc" ] ], "1": [ @@ -128,7 +100,7 @@ "id": "test", "lane": 1 }, - "Undetermined_S0_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "Undetermined_S0_L001_R1_001.fastq.gz:md5,1495c2d7a9b129c0968b84b149991bfc" ] ], "3": [ @@ -141,18 +113,18 @@ "lane": 1 }, [ - "Adapter_Cycle_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Adapter_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Demultiplex_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Demultiplex_Tile_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "Index_Hopping_Counts.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Quality_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Quality_Tile_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "RunInfo.xml:md5,d41d8cd98f00b204e9800998ecf8427e", - "SampleSheet.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Top_Unknown_Barcodes.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "fastq_list.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + "Adapter_Cycle_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Adapter_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Demultiplex_Stats.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Demultiplex_Tile_Stats.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "IndexMetricsOut.bin:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Index_Hopping_Counts.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Quality_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Quality_Tile_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "RunInfo.xml:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "SampleSheet.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Top_Unknown_Barcodes.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "fastq_list.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656" ] ] ], @@ -163,10 +135,10 @@ "lane": 1 }, [ - "Errors.log:md5,d41d8cd98f00b204e9800998ecf8427e", - "FastqComplete.log:md5,d41d8cd98f00b204e9800998ecf8427e", - "Info.log:md5,d41d8cd98f00b204e9800998ecf8427e", - "Warnings.log:md5,d41d8cd98f00b204e9800998ecf8427e" + "Errors.log:md5,775935cbff2e455fde1d28930143e14f", + "FastqComplete.log:md5,775935cbff2e455fde1d28930143e14f", + "Info.log:md5,775935cbff2e455fde1d28930143e14f", + "Warnings.log:md5,775935cbff2e455fde1d28930143e14f" ] ] ], @@ -177,18 +149,22 @@ "lane": 1 }, [ - "ControlMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "CorrectedIntMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "ErrorMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "ExtractionMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "QMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "TileMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e" + "ControlMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "CorrectedIntMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "ErrorMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "ExtractionMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "IndexMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "QMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "TileMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5" ] ] ], "7": [ - "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" + [ + "BCLCONVERT", + "bclconvert", + "4.4.6" + ] ], "fastq": [ [ @@ -196,7 +172,7 @@ "id": "test", "lane": 1 }, - "Sample1_S1_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "Sample1_S1_L001_R1_001.fastq.gz:md5,1495c2d7a9b129c0968b84b149991bfc" ] ], "fastq_idx": [ @@ -209,13 +185,13 @@ "lane": 1 }, [ - "ControlMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "CorrectedIntMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "ErrorMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "ExtractionMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "QMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "TileMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e" + "ControlMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "CorrectedIntMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "ErrorMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "ExtractionMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "IndexMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "QMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5", + "TileMetricsOut.bin:md5,c38bb88125390922fc469f5c8432b2a5" ] ] ], @@ -226,10 +202,10 @@ "lane": 1 }, [ - "Errors.log:md5,d41d8cd98f00b204e9800998ecf8427e", - "FastqComplete.log:md5,d41d8cd98f00b204e9800998ecf8427e", - "Info.log:md5,d41d8cd98f00b204e9800998ecf8427e", - "Warnings.log:md5,d41d8cd98f00b204e9800998ecf8427e" + "Errors.log:md5,775935cbff2e455fde1d28930143e14f", + "FastqComplete.log:md5,775935cbff2e455fde1d28930143e14f", + "Info.log:md5,775935cbff2e455fde1d28930143e14f", + "Warnings.log:md5,775935cbff2e455fde1d28930143e14f" ] ] ], @@ -240,18 +216,18 @@ "lane": 1 }, [ - "Adapter_Cycle_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Adapter_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Demultiplex_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Demultiplex_Tile_Stats.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "IndexMetricsOut.bin:md5,d41d8cd98f00b204e9800998ecf8427e", - "Index_Hopping_Counts.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Quality_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Quality_Tile_Metrics.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "RunInfo.xml:md5,d41d8cd98f00b204e9800998ecf8427e", - "SampleSheet.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "Top_Unknown_Barcodes.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "fastq_list.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + "Adapter_Cycle_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Adapter_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Demultiplex_Stats.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Demultiplex_Tile_Stats.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "IndexMetricsOut.bin:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Index_Hopping_Counts.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Quality_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Quality_Tile_Metrics.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "RunInfo.xml:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "SampleSheet.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "Top_Unknown_Barcodes.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656", + "fastq_list.csv:md5,f6efb28f2f9dcd1d0cb85b78f33aa656" ] ] ], @@ -261,22 +237,26 @@ "id": "test", "lane": 1 }, - "Undetermined_S0_L001_R1_001.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + "Undetermined_S0_L001_R1_001.fastq.gz:md5,1495c2d7a9b129c0968b84b149991bfc" ] ], "undetermined_idx": [ ], - "versions": [ - "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" + "versions_bclconvert": [ + [ + "BCLCONVERT", + "bclconvert", + "4.4.6" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.4" }, - "timestamp": "2025-09-23T10:12:55.362214653" + "timestamp": "2026-02-17T14:13:11.717962" }, "homo_sapiens illumina [bcl]": { "content": [ @@ -300,25 +280,19 @@ ], [ [ - { - "id": "test", - "lane": 1 - }, - [ - "Adapter_Cycle_Metrics.csv:md5,5a0c88793b4a0885fe3dda16609b576e", - "Adapter_Metrics.csv:md5,989240b8840b2169ac1061f952c90f6c", - "Demultiplex_Detailed_Stats.csv:md5,fda7961f2958545daa94b55b84c99eb1", - "Demultiplex_Stats.csv:md5,93949a8cd96f907d83e0808c1ec2a04b", - "Demultiplex_Tile_Stats.csv:md5,d966f774c438485907ae22ac34b85722", - "IndexMetricsOut.bin:md5,9e688c58a5487b8eaf69c9e1005ad0bf", - "Index_Hopping_Counts.csv:md5,1059369e375fd8f8423c0f6c934be978", - "Quality_Metrics.csv:md5,6614accb1bb414fe312b17b81f5521f7", - "Quality_Tile_Metrics.csv:md5,cdc89fd2962bdd4a24f71e186112118a", - "RunInfo.xml:md5,03038959f4dd181c86bc97ae71fe270a", - "SampleSheet.csv:md5,dc0dffd39541dd6cc5b4801d768a8d2b", - "Top_Unknown_Barcodes.csv:md5,2e2faba761137f228e56bd3428453ccc", - "fastq_list.csv:md5,ae1470cd741e33b87a4ad26f849a50f9" - ] + "Adapter_Cycle_Metrics.csv", + "Adapter_Metrics.csv", + "Demultiplex_Detailed_Stats.csv", + "Demultiplex_Stats.csv", + "Demultiplex_Tile_Stats.csv", + "IndexMetricsOut.bin", + "Index_Hopping_Counts.csv", + "Quality_Metrics.csv", + "Quality_Tile_Metrics.csv", + "RunInfo.xml", + "SampleSheet.csv", + "Top_Unknown_Barcodes.csv", + "fastq_list.csv" ] ], [ @@ -331,27 +305,29 @@ ], [ [ - "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", - "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", - "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", - "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", - "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", - "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" + "ControlMetricsOut.bin", + "CorrectedIntMetricsOut.bin", + "ErrorMetricsOut.bin", + "ExtractionMetricsOut.bin", + "IndexMetricsOut.bin", + "QMetricsOut.bin", + "TileMetricsOut.bin" ] ], - [ - "versions.yml:md5,a7ddd79ad04a69cb254185a11296f1b6" - ], { - "BCLCONVERT": { - "bclconvert": "4.4.6" - } + "versions_bclconvert": [ + [ + "BCLCONVERT", + "bclconvert", + "4.4.6" + ] + ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.4" }, - "timestamp": "2025-09-23T10:12:18.369689549" + "timestamp": "2026-02-17T16:59:10.205948" } } \ No newline at end of file diff --git a/subworkflows/nf-core/bcl_demultiplex/main.nf b/subworkflows/nf-core/bcl_demultiplex/main.nf deleted file mode 100644 index bfe1ae83..00000000 --- a/subworkflows/nf-core/bcl_demultiplex/main.nf +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env nextflow - -// -// 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" - -workflow BCL_DEMULTIPLEX { - take: - ch_flowcell // [[id:"", lane:""], samplesheet.csv, path/to/bcl/files] - demultiplexer // bclconvert or bcl2fastq - - main: - ch_versions = channel.empty() - ch_fastq = channel.empty() - ch_reports = channel.empty() - ch_stats = channel.empty() - ch_interop = channel.empty() - ch_logs = channel.empty() - - // Split flowcells into separate channels containing run as tar and run as path - // https://nextflow.slack.com/archives/C02T98A23U7/p1650963988498929 - ch_flowcell - .branch { _meta, _samplesheet, run -> - tar: run.toString().endsWith(".tar.gz") - dir: true - }.set { ch_flowcells } - - ch_flowcells.tar - .multiMap { meta, samplesheet, run -> - samplesheets: [ meta, samplesheet ] - run_dirs: [ meta, run ] - }.set { ch_flowcells_tar } - - // Runs when run_dir is a tar archive - // Re-join the metadata and the untarred run directory with the samplesheet - ch_flowcells_tar_merged = ch_flowcells_tar - .samplesheets - .join( ch_flowcells_tar.run_dirs ) - - // Merge the two channels back together - ch_flowcells = ch_flowcells.dir.mix(ch_flowcells_tar_merged) - - // MODULE: bclconvert - // Demultiplex the bcl files - if (demultiplexer == "bclconvert") { - BCLCONVERT( ch_flowcells ) - ch_fastq = ch_fastq.mix(BCLCONVERT.out.fastq) - 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_versions = ch_versions.mix(BCLCONVERT.out.versions.first()) - } - - // MODULE: bcl2fastq - // Demultiplex the bcl files - if (demultiplexer == "bcl2fastq") { - BCL2FASTQ( ch_flowcells ) - ch_fastq = ch_fastq.mix(BCL2FASTQ.out.fastq) - 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_versions = ch_versions.mix(BCL2FASTQ.out.versions.first()) - } - - // Generate meta for each fastq - ch_fastq - // reshapes the channel from a single emit of [meta, [fastq, fastq, fastq...]] - // to emits per fastq file like [meta, fastq] - .transpose() - .map { fc_meta, fastq -> - def meta = [:] - meta.id = fastq.getSimpleName().toString() - ~/_R[0-9]_001.*$/ - meta.samplename = fastq.getSimpleName().toString() - ~/_S[0-9]+.*$/ - meta.fcid = fc_meta.id - meta.lane = fc_meta.lane - // The buffered input stream allows reading directly from cloud storage - // It will not make a local copy of the file. - def line = "" - fastq.withInputStream { fq -> - def gzipStream = new java.util.zip.GZIPInputStream(fq) - def decoder = new InputStreamReader(gzipStream, 'ASCII') - def buffered = new BufferedReader(decoder) - line = buffered.readLine() - buffered.close() - } - if ( line != null && line.startsWith('@') ) { - line = line.substring(1) - // expected format is like: - // xx:yy:FLOWCELLID:LANE:... (seven fields) - def fields = line.split(':') - // CASAVA 1.8+ format, from https://support.illumina.com/help/BaseSpace_OLH_009008/Content/Source/Informatics/BS/FileFormat_FASTQ-files_swBS.htm - // "@::::::: :::" - //def sequencer_serial = fields[0] - //def run_nubmer = fields[1] - def fcid = fields[2] - def lane = fields[3] - def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" - def ID = [fcid, lane].join(".") - def PU = [fcid, lane, index].findAll().join(".") - def PL = "ILLUMINA" - def SM = fastq.getSimpleName().toString() - ~/_S[0-9]+.*$/ - meta.readgroup = [ - "ID": ID, - "SM": SM, - "PL": PL, - "PU": PU - ] - meta.empty = false - } else { - println "No reads were found in FASTQ file: ${fastq}" - meta.readgroup = [:] - meta.empty = true - } - return [meta, fastq] - } - // Group by the meta id so that we can find mate pairs if they exist - .groupTuple(by: [0]) - .map { meta, fastq -> - meta.single_end = fastq.size() == 1 - return [meta, fastq.flatten()] - } - .branch { meta, _fastq -> - fastq : meta.empty == false - empty_fastq : meta.empty == true - } - .set{ch_fastq_with_meta} - - emit: - fastq = ch_fastq_with_meta.fastq - empty_fastq = ch_fastq_with_meta.empty_fastq - reports = ch_reports - stats = ch_stats - interop = ch_interop - logs = ch_logs - versions = ch_versions -} diff --git a/subworkflows/nf-core/bcl_demultiplex/meta.yml b/subworkflows/nf-core/bcl_demultiplex/meta.yml deleted file mode 100644 index 856f5204..00000000 --- a/subworkflows/nf-core/bcl_demultiplex/meta.yml +++ /dev/null @@ -1,62 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "bcl_demultiplex" -description: Demultiplex Illumina BCL data using bcl-convert or bcl2fastq -keywords: - - bcl - - bclconvert - - bcl2fastq - - demultiplex - - fastq -components: - - bcl2fastq - - bclconvert -input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'string', lane: int ] - - samplesheet: - type: file - description: | - CSV file containing information about samples to be demultiplexed in Illumina SampleSheet format - - flowcell: - type: file - description: Directory or tar archive containing Illumina BCL data, sequencer output directory - - demultiplexer: - type: string - description: Which demultiplexer to use, bcl2fastq or bclconvert -output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test' ] - - fastq: - type: file - description: Demultiplexed fastq files - pattern: "*.fastq.gz" - - reports: - type: file - description: Demultiplexing reports - pattern: "Reports/*" - - interop: - type: file - description: InterOp files - pattern: "InterOp/*" - - stats: - type: file - description: Demultiplexing statistics (bcl2fastq only) - pattern: "Stats/*" - - logs: - type: file - description: Demultiplexing logs (bclconvert only) - pattern: "Logs/*" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" -authors: - - "@matthdsm" -maintainers: - - "@matthdsm" diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test deleted file mode 100644 index 65a158e9..00000000 --- a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test +++ /dev/null @@ -1,100 +0,0 @@ -// nf-core subworkflows test bcl_demultiplex -nextflow_workflow { - - name "Test Subworkflow test_bcl_demultiplex_bclconvert" - script "../main.nf" - config "./nextflow.config" - workflow "BCL_DEMULTIPLEX" - - tag "subworkflows" - tag "subworkflows_nfcore" - tag "subworkflows/bcl_demultiplex" - tag "bclconvert" - tag "bcl2fastq" - - test("bclconvert") { - - when { - - workflow { - """ - input[0] = Channel.value([ - [id:'HMTFYDRXX', lane:1], - "https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/sarscov2/illumina/bcl/SampleSheet.csv", - "https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/sarscov2/illumina/bcl/200624_A00834_0183_BHMTFYDRXX.tar.gz" - ]) - input[1] = "bclconvert" - """ - } - } - - then { - assertAll( - { assert workflow.success }, - { assert snapshot( - sanitizeOutput(workflow.out, unstableKeys: ["empty_fastq", "logs"]).collectEntries { key, val -> - if (key == "interop") { - return [ key, val.collect { meta, files -> - [ - meta, - files.collect { interop_file -> - if (interop_file.endsWith("IndexMetricsOut.bin")) { - file(interop_file).name - } else { - interop_file - } - } - ] - } ] - } - return [ key, val ] - }, - ).match() - }, - ) - } - } - - test("bcl2fastq") { - - when { - - workflow { - """ - input[0] = Channel.value([ - [id:'test', lane:1 ], - "https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/homo_sapiens/illumina/bcl/flowcell_samplesheet.csv", - "https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/homo_sapiens/illumina/bcl/flowcell.tar.gz" - ]) - input[1] = "bcl2fastq" - """ - } - } - - then { - assertAll( - { assert workflow.success }, - { assert snapshot( - sanitizeOutput(workflow.out).collectEntries { key, val -> - if (key == "interop") { - return [ key, val.collect { meta, files -> - [ - meta, - files.collect { interop_file -> - if (interop_file.endsWith("IndexMetricsOut.bin")) { - file(interop_file).name - } else { - interop_file - } - } - ] - } ] - } - return [ key, val ] - }, - ).match() - }, - ) - } - } -} diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap b/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap deleted file mode 100644 index 537c7efe..00000000 --- a/subworkflows/nf-core/bcl_demultiplex/tests/main.nf.test.snap +++ /dev/null @@ -1,296 +0,0 @@ -{ - "bclconvert": { - "content": [ - { - "empty_fastq": [ - [ - { - "empty": true, - "fcid": "HMTFYDRXX", - "id": "SampleZ_S5_L001", - "lane": 1, - "readgroup": { - - }, - "samplename": "SampleZ", - "single_end": true - }, - [ - "SampleZ_S5_L001_R1_001.fastq.gz" - ] - ] - ], - "fastq": [ - [ - { - "id": "Sample1_S1_L001", - "samplename": "Sample1", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "Sample1", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.GAACTGAGCG+TCGTGGAGCG" - }, - "empty": false, - "single_end": true - }, - [ - "Sample1_S1_L001_R1_001.fastq.gz:md5,b5489d1964db8db5502eb742cc3ef3ec" - ] - ], - [ - { - "id": "Sample23_S3_L001", - "samplename": "Sample23", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "Sample23", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.CGTCTCATAT+TATAGTAGCT" - }, - "empty": false, - "single_end": true - }, - [ - "Sample23_S3_L001_R1_001.fastq.gz:md5,767a1091320320b140288066e29bccc5" - ] - ], - [ - { - "id": "SampleA_S2_L001", - "samplename": "SampleA", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "SampleA", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.AGGTCAGATA+CTACAAGATA" - }, - "empty": false, - "single_end": true - }, - [ - "SampleA_S2_L001_R1_001.fastq.gz:md5,7de2ea88133409f34563f40a0d8c9e55" - ] - ], - [ - { - "id": "sampletest_S4_L001", - "samplename": "sampletest", - "fcid": "HMTFYDRXX", - "lane": 1, - "readgroup": { - "ID": "HMTFYDRXX.1", - "SM": "sampletest", - "PL": "ILLUMINA", - "PU": "HMTFYDRXX.1.ATTCCATAAG+TGCCTGGTGG" - }, - "empty": false, - "single_end": true - }, - [ - "sampletest_S4_L001_R1_001.fastq.gz:md5,c16c7de1b7bffb5e4503f4d94c40f881" - ] - ] - ], - "interop": [ - [ - { - "id": "HMTFYDRXX", - "lane": 1 - }, - [ - "BasecallingMetricsOut.bin:md5,7fb651325cba614d497d376eaf43fef4", - "CorrectedIntMetricsOut.bin:md5,dc8d57282ba9ece9e5fc58a92aa2ac52", - "EmpiricalPhasingMetricsOut.bin:md5,1ef4631faf0a3a3beb31b10fc38a734d", - "EventMetricsOut.bin:md5,dee320ce29bdadde44589aa9439f53ab", - "ExtendedTileMetricsOut.bin:md5,f01d1a9cf8445adf719e652ad7304cf2", - "ExtractionMetricsOut.bin:md5,972f4082ad950baaf42a6d28517d28a8", - "FWHMGridMetricsOut.bin:md5,6e297bafcd845bfd0440d08e1bb27685", - "ImageMetricsOut.bin:md5,ac5d1f0a1f611c0c7c9dd8e6b9e701b1", - "IndexMetricsOut.bin", - "OpticalModelMetricsOut.bin:md5,3eaea5fcf2d353950b1e720c73695ccb", - "PFGridMetricsOut.bin:md5,ae469858ee96ffafbcaf3afb814bdab2", - "QMetrics2030Out.bin:md5,438248760db58917b32f4eccc6c64c39", - "QMetricsByLaneOut.bin:md5,e8254cb4a27846710a2a143296be2d8f", - "QMetricsOut.bin:md5,8f6b83028a42be721200a598161ac5c6", - "RegistrationMetricsOut.bin:md5,b5ebd957aed067b6403d851ba2ce0139", - "TileMetricsOut.bin:md5,21388348d81fa9be326d30ef6d348464" - ] - ] - ], - "logs": [ - [ - { - "id": "HMTFYDRXX", - "lane": 1 - }, - "Logs" - ] - ], - "reports": [ - [ - { - "id": "HMTFYDRXX", - "lane": 1 - }, - [ - "Adapter_Cycle_Metrics.csv:md5,05fbe7b2b0acdd557d355b448aa88ace", - "Adapter_Metrics.csv:md5,0fa4ac708955417af9d18cec4955552f", - "Demultiplex_Detailed_Stats.csv:md5,5a6a4d66a96256ff71e4f649927fb112", - "Demultiplex_Stats.csv:md5,4a3f451faa098156623b55b0f2ff27ee", - "Demultiplex_Tile_Stats.csv:md5,f91fb0c7a2c5588ed43c7f9145d004ee", - "IndexMetricsOut.bin:md5,fb16c8a9873e5b5950ae5949126af76c", - "Index_Hopping_Counts.csv:md5,f59474d96afe8218c7590bb240b19690", - "Quality_Metrics.csv:md5,c4622066f85d93b1661c928a46cfc508", - "Quality_Tile_Metrics.csv:md5,e22bc5e2f147695150b02afcccb38c4f", - "RunInfo.xml:md5,f283cb4600235db9261ee1e319b1407e", - "SampleSheet.csv:md5,4113eabae23136cc819c7f15ac5b6aad", - "Top_Unknown_Barcodes.csv:md5,37dbc2860c640fc721820b0217ea0504", - "fastq_list.csv:md5,482cf7fe9b304a900e4ede3bb25b4912" - ] - ] - ], - "stats": [ - - ], - "versions": [ - "versions.yml:md5,b1427a2b3abad63b04f1dd62c8f40e2e" - ] - } - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" - }, - "timestamp": "2025-11-04T16:13:41.469897018" - }, - "bcl2fastq": { - "content": [ - { - "empty_fastq": [ - - ], - "fastq": [ - [ - { - "id": "Sample1_S1_L001", - "samplename": "Sample1", - "fcid": "test", - "lane": 1, - "readgroup": { - "ID": "000000000-K9H97.1", - "SM": "Sample1", - "PL": "ILLUMINA", - "PU": "000000000-K9H97.1" - }, - "empty": false, - "single_end": true - }, - [ - "Sample1_S1_L001_R1_001.fastq.gz:md5,0675fb6365322eaafb33c0f8e862b54b" - ] - ] - ], - "interop": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - "ControlMetricsOut.bin:md5,6d77b38d0793a6e1ce1e85706e488953", - "CorrectedIntMetricsOut.bin:md5,2bbf84d3be72734addaa2fe794711434", - "ErrorMetricsOut.bin:md5,38c88def138e9bb832539911affdb286", - "ExtractionMetricsOut.bin:md5,7497c3178837eea8f09350b5cd252e99", - "IndexMetricsOut.bin", - "QMetricsOut.bin:md5,7e9f198d53ebdfbb699a5f94cf1ed51c", - "TileMetricsOut.bin:md5,83891751ec1c91a425a524b476b6ca3c" - ] - ] - ], - "logs": [ - - ], - "reports": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - [ - [ - [ - [ - [ - "lane.html:md5,794e48287f47a9f22dcb6b6d0c22c3eb", - "laneBarcode.html:md5,2bbdae3ee57151eab520c966597d7438" - ], - [ - - ] - ] - ], - [ - [ - [ - "lane.html:md5,f741870307050dcea79a838f5971770f", - "laneBarcode.html:md5,ffe2e863811c76cb9da27d5d124e0611" - ], - [ - "lane.html:md5,cca97e771d3491dbc8cd3fe389595b09", - "laneBarcode.html:md5,cca97e771d3491dbc8cd3fe389595b09" - ] - ], - [ - [ - "lane.html:md5,c383b0768d9978733d3f5d3b91c15af0", - "laneBarcode.html:md5,48842c23b9a2816aec540177df870968" - ], - [ - - ] - ] - ] - ], - "Report.css:md5,eb7d3eb68fc1539f411404987246b59b", - "index.html:md5,5747c407854ae2c358d0ec201ce622d8", - "tree.html:md5,a1b9bf592973ca829ec69ddf888b7e34" - ] - ] - ] - ], - "stats": [ - [ - { - "id": "test", - "lane": 1 - }, - [ - "AdapterTrimming.txt:md5,48ed2b914b1246c0b5d8667525550946", - "ConversionStats.xml:md5,8fe0f57f3f5d256a0762dba75ac62d05", - "DemultiplexingStats.xml:md5,2047ff18f5b9107c084de06e9ff943ad", - "DemuxSummaryF1L1.txt:md5,03e5fd0c1e3079c5f8c7b4d0501b37ff", - "FastqSummaryF1L1.txt:md5,0c6f2d87ee183b84d1051cde9a5643d1", - "Stats.json:md5,8e5f038b8aa9e465599d3575f930e604" - ] - ] - ], - "versions": [ - "versions.yml:md5,513271615cb02dbe541a6202d713ef81" - ] - } - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.10.0" - }, - "timestamp": "2025-11-04T15:08:58.666466636" - } -} \ No newline at end of file diff --git a/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config b/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config deleted file mode 100644 index dd8bfa2a..00000000 --- a/subworkflows/nf-core/bcl_demultiplex/tests/nextflow.config +++ /dev/null @@ -1,13 +0,0 @@ -process { - withName: BCLCONVERT { - ext.args = {[ - meta.lane ? "--bcl-only-lane ${meta.lane}" : "", - "--force" - ].join(" ").trim()} - } - withName: BCL2FASTQ { - ext.args = {[ - "--tiles s_1_1101" - ].join(" ").trim()} - } -} diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 3954c603..0702ba02 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -7,6 +7,7 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules +include { BCLCONVERT } from '../modules/nf-core/bclconvert/main' include { FALCO } from '../modules/nf-core/falco/main' include { FASTP } from '../modules/nf-core/fastp/main' include { MD5SUM } from '../modules/nf-core/md5sum/main' @@ -17,11 +18,11 @@ include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverag // Subworkflows include { BAM_QC } from '../subworkflows/local/bam_qc/main' -include { BCL_DEMULTIPLEX } from '../subworkflows/nf-core/bcl_demultiplex/main' include { COVERAGE } from '../subworkflows/local/coverage/main' include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' // Functions +include { generateReadgroup } from '../modules/nf-core/bclconvert/main' include { paramsSummaryMap } from 'plugin/nf-schema' include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' @@ -70,17 +71,16 @@ workflow PREPROCESSING { } .set { ch_illumina_flowcell } - // BCL_DEMULTIPLEX([meta, samplesheet, flowcell], demultiplexer) - BCL_DEMULTIPLEX(ch_illumina_flowcell.flowcell, "bclconvert") - BCL_DEMULTIPLEX.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) + // BCLCONVERT([meta, samplesheet, flowcell]) + BCLCONVERT(ch_illumina_flowcell.flowcell) + BCLCONVERT.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) ch_multiqc_files = ch_multiqc_files.mix( - BCL_DEMULTIPLEX.out.reports, - BCL_DEMULTIPLEX.out.stats, + BCLCONVERT.out.reports, + BCLCONVERT.out.stats, ) - ch_versions = ch_versions.mix(BCL_DEMULTIPLEX.out.versions) - BCL_DEMULTIPLEX.out.fastq - .map { meta, fastq -> [meta.samplename, meta, fastq] } + generateReadgroup(BCLCONVERT.out.fastq) + .map { meta, fastq -> [meta.rg.SM, meta, fastq] } .set { ch_demultiplexed_fastq } ch_illumina_flowcell.info @@ -94,9 +94,6 @@ workflow PREPROCESSING { .combine(ch_sampleinfo, by: 0) .map { samplename, meta, fastq, sampleinfo -> def new_meta = meta + sampleinfo - def readgroup = readgroup_from_fastq(fastq[0]) - readgroup = readgroup + ['SM': samplename, 'LB': new_meta.library ?: ""] - new_meta = new_meta + ['readgroup': readgroup] return [new_meta, fastq] } .groupTuple(by: [0]) @@ -490,8 +487,8 @@ def readgroup_from_fastq(path) { def lane = fields[3] def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" - rg.ID = [fcid, lane].join(".") - rg.PU = [fcid, lane, index].findAll().join(".") + rg.ID = [index, lane].join(".") + rg.PU = [fcid, lane].join(".") rg.PL = "ILLUMINA" } else if (fields.size() == 5) { From f3791089925f255ad443862824a4931c473aa5a7 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 18 Feb 2026 12:47:55 +0100 Subject: [PATCH 204/228] bump falco --- modules.json | 2 +- modules/nf-core/falco/environment.yml | 2 +- modules/nf-core/falco/main.nf | 37 ++--- modules/nf-core/falco/meta.yml | 38 +++-- modules/nf-core/falco/tests/main.nf.test | 60 ++++--- modules/nf-core/falco/tests/main.nf.test.snap | 154 ++++++++++++++---- workflows/preprocessing.nf | 22 +-- 7 files changed, 209 insertions(+), 106 deletions(-) diff --git a/modules.json b/modules.json index 448ec404..b7e85768 100644 --- a/modules.json +++ b/modules.json @@ -42,7 +42,7 @@ }, "falco": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "b2f164ca59b14d6e9ed2dd2a99fa015085396faf", "installed_by": ["modules"] }, "fastp": { diff --git a/modules/nf-core/falco/environment.yml b/modules/nf-core/falco/environment.yml index 59c973a9..1fc00675 100644 --- a/modules/nf-core/falco/environment.yml +++ b/modules/nf-core/falco/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::falco=1.2.1 + - bioconda::falco=1.2.5 diff --git a/modules/nf-core/falco/main.nf b/modules/nf-core/falco/main.nf index a4b343b2..860d52ff 100644 --- a/modules/nf-core/falco/main.nf +++ b/modules/nf-core/falco/main.nf @@ -1,20 +1,19 @@ process FALCO { - tag "$meta.id" + tag "${meta.id}" label 'process_single' - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/falco:1.2.1--h867801b_3': - 'biocontainers/falco:1.2.1--h867801b_3' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://depot.galaxyproject.org/singularity/falco:1.2.5--h077b44d_0' + : 'biocontainers/falco:1.2.5--h077b44d_0'}" input: tuple val(meta), path(reads) output: tuple val(meta), path("*.html"), emit: html - tuple val(meta), path("*.txt") , emit: txt - path "versions.yml" , emit: versions + tuple val(meta), path("*.txt"), emit: txt + tuple val("${task.process}"), val('falco'), eval("falco --version | sed '1!d;s/.* //'"), topic: versions, emit: versions_falco when: task.ext.when == null || task.ext.when @@ -22,23 +21,14 @@ process FALCO { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - if ( reads.toList().size() == 1 ) { + if (reads.toList().size() == 1) { """ - falco $args --threads $task.cpus ${reads} -D ${prefix}_fastqc_data.txt -S ${prefix}_summary.txt -R ${prefix}_report.html - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - falco:\$( falco --version | sed -e "s/falco//g" ) - END_VERSIONS + falco ${args} --threads ${task.cpus} ${reads} -D ${prefix}_fastqc_data.txt -S ${prefix}_summary.txt -R ${prefix}_report.html """ - } else { + } + else { """ - falco $args --threads $task.cpus ${reads} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - falco:\$( falco --version | sed -e "s/falco//g" ) - END_VERSIONS + falco ${args} --threads ${task.cpus} ${reads} """ } @@ -48,10 +38,5 @@ process FALCO { touch ${prefix}_data.txt touch ${prefix}_fastqc_data.html touch ${prefix}_summary.txt - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - falco: \$( falco --version | sed -e "s/falco v//g" ) - END_VERSIONS """ } diff --git a/modules/nf-core/falco/meta.yml b/modules/nf-core/falco/meta.yml index 1450f2da..b8574289 100644 --- a/modules/nf-core/falco/meta.yml +++ b/modules/nf-core/falco/meta.yml @@ -11,7 +11,8 @@ tools: of sequence reads." homepage: "https://falco.readthedocs.io/" documentation: "https://falco.readthedocs.io/" - licence: ["GPL v3"] + licence: + - "GPL v3" identifier: biotools:falco-rna input: - - meta: @@ -24,7 +25,8 @@ input: description: | List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_1930 output: html: - - meta: @@ -36,7 +38,8 @@ output: type: file description: FastQC like report pattern: "*_{fastqc_report.html}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3474 txt: - - meta: type: map @@ -47,14 +50,29 @@ output: type: file description: falco report data pattern: "*_{data.txt}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3474 + versions_falco: + - - ${task.process}: + type: string + description: The name of the process + - falco: + type: string + description: The name of the tool + - falco --version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - falco: + type: string + description: The name of the tool + - falco --version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool authors: - "@lucacozzuto" maintainers: diff --git a/modules/nf-core/falco/tests/main.nf.test b/modules/nf-core/falco/tests/main.nf.test index 816c72ba..cc8ed4bf 100644 --- a/modules/nf-core/falco/tests/main.nf.test +++ b/modules/nf-core/falco/tests/main.nf.test @@ -15,12 +15,7 @@ nextflow_process { """ input[0] = [ [ id: 'test', single_end:true ], - [ - file( - params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], - checkIfExists: true - ), - ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] ] """ } @@ -30,8 +25,9 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.txt, - file(process.out.html.get(0).get(1)).list(), + process.out.txt.collect {meta, files -> files.collect { file(it).name }.sort() }, + file(process.out.html.get(0).get(1)).name, + process.out.findAll { key, val -> key.startsWith("versions") } ).match() }, ) @@ -47,14 +43,8 @@ nextflow_process { input[0] = [ [ id: 'test', single_end:false ], [ - file( - params.test_data['sarscov2']['illumina']['test_1_fastq_gz'], - checkIfExists: true - ), - file( - params.test_data['sarscov2']['illumina']['test_2_fastq_gz'], - checkIfExists: true - ), + 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), ], ] """ @@ -65,8 +55,9 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.txt, - process.out.html.get(0).get(1).collect{ it.split("/")[-1] }.sort(), + process.out.txt.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.html.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.findAll { key, val -> key.startsWith("versions") } ).match() }, ) @@ -81,12 +72,7 @@ nextflow_process { """ input[0] = [ [ id: 'test', single_end:false ], - [ - file( - params.test_data['sarscov2']['illumina']['test_interleaved_fastq_gz'], - checkIfExists: true - ), - ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true)], ] """ } @@ -96,8 +82,9 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.txt, - file(process.out.html.get(0).get(1)).list(), + process.out.txt.collect {meta, files -> files.collect { file(it).name }.sort() }, + file(process.out.html.get(0).get(1)).name, + process.out.findAll { key, val -> key.startsWith("versions") } ).match() }, ) @@ -105,4 +92,25 @@ nextflow_process { } + test("sarscov2 - fastq - single end - stub") { + options "-stub" + when { + process { + """ + input[0] = [ + [ id: 'test', single_end:true ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + } diff --git a/modules/nf-core/falco/tests/main.nf.test.snap b/modules/nf-core/falco/tests/main.nf.test.snap index 34ac64e3..ea31e454 100644 --- a/modules/nf-core/falco/tests/main.nf.test.snap +++ b/modules/nf-core/falco/tests/main.nf.test.snap @@ -3,59 +3,149 @@ "content": [ [ [ - { - "id": "test", - "single_end": true - }, + "test_fastqc_data.txt", + "test_summary.txt" + ] + ], + "test_report.html", + { + "versions_falco": [ [ - "test_fastqc_data.txt:md5,36d989bb9e2d5a632e19452f4e6c2a4e", - "test_summary.txt:md5,a925aec214a83d2f6252847166f2ef3a" + "FALCO", + "falco", + "1.2.5" ] ] - ], - null + } ], - "timestamp": "2024-02-02T16:28:17.756764" + "timestamp": "2026-02-18T11:45:00.791179", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - fastq - paired end": { "content": [ [ [ - { - "id": "test", - "single_end": false - }, - [ - "test_1.fastq.gz_fastqc_data.txt:md5,36d989bb9e2d5a632e19452f4e6c2a4e", - "test_1.fastq.gz_summary.txt:md5,a925aec214a83d2f6252847166f2ef3a", - "test_2.fastq.gz_fastqc_data.txt:md5,ad5c45dfc8f79754dd5d8029456b715b", - "test_2.fastq.gz_summary.txt:md5,d0cb642adefb5635a25e808f1f38780a" - ] + "test_1.fastq.gz_fastqc_data.txt", + "test_1.fastq.gz_summary.txt", + "test_2.fastq.gz_fastqc_data.txt", + "test_2.fastq.gz_summary.txt" ] ], [ - "test_1.fastq.gz_fastqc_report.html", - "test_2.fastq.gz_fastqc_report.html" - ] + [ + "test_1.fastq.gz_fastqc_report.html", + "test_2.fastq.gz_fastqc_report.html" + ] + ], + { + "versions_falco": [ + [ + "FALCO", + "falco", + "1.2.5" + ] + ] + } ], - "timestamp": "2024-02-02T16:22:11.757473" + "timestamp": "2026-02-18T11:45:07.583855", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - fastq - interleaved": { "content": [ [ [ - { - "id": "test", - "single_end": false - }, + "test_fastqc_data.txt", + "test_summary.txt" + ] + ], + "test_report.html", + { + "versions_falco": [ [ - "test_fastqc_data.txt:md5,b5e593f140fe578bdd25ceb84e98fd37", - "test_summary.txt:md5,ca52f458b1223d89db69e2d5e73cf867" + "FALCO", + "falco", + "1.2.5" ] ] - ], - null + } + ], + "timestamp": "2026-02-18T11:45:13.797353", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "sarscov2 - fastq - single end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test_fastqc_data.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test_data.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_summary.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "2": [ + [ + "FALCO", + "falco", + "1.2.5" + ] + ], + "html": [ + [ + { + "id": "test", + "single_end": true + }, + "test_fastqc_data.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "txt": [ + [ + { + "id": "test", + "single_end": true + }, + [ + "test_data.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_summary.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions_falco": [ + [ + "FALCO", + "falco", + "1.2.5" + ] + ] + } ], - "timestamp": "2024-02-02T16:28:36.035899" + "timestamp": "2026-02-18T10:45:44.602269", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 0702ba02..51056ddf 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -76,12 +76,15 @@ workflow PREPROCESSING { BCLCONVERT.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) ch_multiqc_files = ch_multiqc_files.mix( BCLCONVERT.out.reports, - BCLCONVERT.out.stats, + BCLCONVERT.out.logs, ) - generateReadgroup(BCLCONVERT.out.fastq) - .map { meta, fastq -> [meta.rg.SM, meta, fastq] } - .set { ch_demultiplexed_fastq } + generateReadgroup( + BCLCONVERT.out.reports.map { meta, reports -> + return [meta, reports.find { report -> report.name == "fastq_list.csv" }] + }, + BCLCONVERT.out.fastq, + ).map { meta, fastq -> [meta.rg.SM, meta, fastq] }.set { ch_demultiplexed_fastq } ch_illumina_flowcell.info .flatten() @@ -92,7 +95,7 @@ workflow PREPROCESSING { // Merge fastq meta with sample info ch_demultiplexed_fastq .combine(ch_sampleinfo, by: 0) - .map { samplename, meta, fastq, sampleinfo -> + .map { _samplename, meta, fastq, sampleinfo -> def new_meta = meta + sampleinfo return [new_meta, fastq] } @@ -189,7 +192,6 @@ workflow PREPROCESSING { FALCO(ch_fastq_per_sample.other) ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.html) ch_multiqc_files = ch_multiqc_files.mix(FALCO.out.txt) - ch_versions = ch_versions.mix(FALCO.out.versions.first()) // MODULE: fastp // Run QC, trimming and adapter removal @@ -408,9 +410,9 @@ workflow PREPROCESSING { ) emit: - demultiplex_interop = BCL_DEMULTIPLEX.out.interop - demultiplex_reports = BCL_DEMULTIPLEX.out.reports - demultiplex_logs = BCL_DEMULTIPLEX.out.logs + demultiplex_interop = BCLCONVERT.out.interop + demultiplex_reports = BCLCONVERT.out.reports + demultiplex_logs = BCLCONVERT.out.logs demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other falco_html = FALCO.out.html falco_txt = FALCO.out.txt @@ -487,7 +489,7 @@ def readgroup_from_fastq(path) { def lane = fields[3] def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" - rg.ID = [index, lane].join(".") + rg.ID = [index ?: fcid, lane].join(".") rg.PU = [fcid, lane].join(".") rg.PL = "ILLUMINA" } From a31c697bc1158660990191720621993a7c759555 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:02:10 +0100 Subject: [PATCH 205/228] Update all modules to topic and drop versions channel --- modules.json | 16 +- modules/nf-core/biobambam/bamsormadup/main.nf | 48 ++- .../nf-core/biobambam/bamsormadup/meta.yml | 53 +++- .../biobambam/bamsormadup/tests/main.nf.test | 15 +- .../bamsormadup/tests/main.nf.test.snap | 92 +++--- modules/nf-core/bwa/mem/main.nf | 15 +- modules/nf-core/bwa/mem/meta.yml | 67 ++-- modules/nf-core/bwa/mem/tests/main.nf.test | 10 +- .../nf-core/bwa/mem/tests/main.nf.test.snap | 207 ++++++++++--- modules/nf-core/dragmap/align/main.nf | 18 +- modules/nf-core/dragmap/align/meta.yml | 85 +++++- .../nf-core/dragmap/align/tests/main.nf.test | 16 +- .../dragmap/align/tests/main.nf.test.snap | 242 ++++++++++----- modules/nf-core/gnu/sort/tests/main.nf.test | 28 +- modules/nf-core/md5sum/main.nf | 22 +- modules/nf-core/md5sum/meta.yml | 32 +- .../nf-core/md5sum/tests/main.nf.test.snap | 154 +++++++--- modules/nf-core/snapaligner/align/main.nf | 16 +- modules/nf-core/snapaligner/align/meta.yml | 41 ++- .../snapaligner/align/tests/main.nf.test.snap | 66 ++-- modules/nf-core/strobealign/main.nf | 18 +- modules/nf-core/strobealign/meta.yml | 90 ++++-- .../nf-core/strobealign/tests/main.nf.test | 14 +- .../strobealign/tests/main.nf.test.snap | 288 ++++++++++++++---- .../main.nf | 3 - subworkflows/nf-core/fastq_align_dna/main.nf | 12 +- .../fastq_align_dna/tests/main.nf.test | 2 - .../fastq_align_dna/tests/main.nf.test.snap | 98 +++--- workflows/preprocessing.nf | 5 +- 29 files changed, 1172 insertions(+), 601 deletions(-) diff --git a/modules.json b/modules.json index b7e85768..8d39bf4b 100644 --- a/modules.json +++ b/modules.json @@ -12,7 +12,7 @@ }, "biobambam/bamsormadup": { "branch": "master", - "git_sha": "051e7c60dbdcc5d96ce7814c31426ce776f5319b", + "git_sha": "aef75083111cea684bafb6c27cdba8a8d0916638", "installed_by": ["modules"], "patch": "modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff" }, @@ -24,7 +24,7 @@ }, "bwa/mem": { "branch": "master", - "git_sha": "966ba9887e2b04d89d64db06c01508873bde13b1", + "git_sha": "707241c72951f24fd89982c4c80c5983a4c437ef", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwa/mem/bwa-mem.diff" }, @@ -36,7 +36,7 @@ }, "dragmap/align": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "9fd8df2d3e0cd7add065a5c59dd1e9841a907e13", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/dragmap/align/dragmap-align.diff" }, @@ -52,12 +52,12 @@ }, "gnu/sort": { "branch": "master", - "git_sha": "f35fac92470336be03b96bae7547d81d88a3331a", + "git_sha": "5e748ff2b0f990949081c9e49792622eb3fe9ee9", "installed_by": ["modules"] }, "md5sum": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "7df444999424fb148e251c4de5140296c9356f54", "installed_by": ["modules"] }, "mosdepth": { @@ -132,7 +132,7 @@ }, "snapaligner/align": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "cf0eb2bed12c39c5b714d44dd02039a0cefaedb1", "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/snapaligner/align/snapaligner-align.diff" }, @@ -144,7 +144,7 @@ }, "strobealign": { "branch": "master", - "git_sha": "d5cc72b63c4e1565cb66e83f0577b04c0bb54d5c", + "git_sha": "698af1c52555faeba677dfafc6d0197a840ca81f", "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/strobealign/strobealign.diff" } @@ -154,7 +154,7 @@ "nf-core": { "fastq_align_dna": { "branch": "master", - "git_sha": "5dd46a36fca68d6ad1a6b22ec47adc8c6863717d", + "git_sha": "cf0eb2bed12c39c5b714d44dd02039a0cefaedb1", "installed_by": ["subworkflows"], "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" }, diff --git a/modules/nf-core/biobambam/bamsormadup/main.nf b/modules/nf-core/biobambam/bamsormadup/main.nf index 032e718d..804a35c2 100644 --- a/modules/nf-core/biobambam/bamsormadup/main.nf +++ b/modules/nf-core/biobambam/bamsormadup/main.nf @@ -1,21 +1,21 @@ process BIOBAMBAM_BAMSORMADUP { - tag "$meta.id" + tag "${meta.id}" label "process_medium" conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/biobambam:2.0.185--h85de650_1' : - 'biocontainers/biobambam:2.0.185--h85de650_1'}" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://depot.galaxyproject.org/singularity/biobambam:2.0.185--h85de650_1' + : 'biocontainers/biobambam:2.0.185--h85de650_1'}" input: tuple val(meta) , path(bams, stageAs: "?/*"), path(fasta), path(fai) output: - tuple val(meta), path("*.bam") ,optional:true, emit: bam - tuple val(meta), path("*.bam.bai") ,optional:true, emit: bam_index - tuple val(meta), path("*.cram") ,optional:true, emit: cram - tuple val(meta), path("*.metrics.txt") ,emit: metrics - path "versions.yml" ,emit: versions + tuple val(meta), path("*.bam"), optional: true, emit: bam + tuple val(meta), path("*.bam.bai"), optional: true, emit: bam_index + tuple val(meta), path("*.cram"), optional: true, emit: cram + tuple val(meta), path("*.metrics.txt"), emit: metrics + tuple val("${task.process}"), val('biobambam'), eval("bamsormadup --version |& sed '1!d; s/.*version //; s/.\$//'"), topic: versions, emit: versions_biobambam when: task.ext.when == null || task.ext.when @@ -26,7 +26,9 @@ process BIOBAMBAM_BAMSORMADUP { def prefix = task.ext.prefix ?: "${meta.id}" def suffix = args.contains("outputformat=cram") ? "cram" : "bam" def input_string = bams instanceof List ? bams.join(" I=") : bams - if (args.contains("outputformat=cram") && fasta == null) error "Reference required for CRAM output." + if (args.contains("outputformat=cram") && fasta == null) { + error("Reference required for CRAM output.") + } """ bamcat \\ @@ -34,37 +36,25 @@ process BIOBAMBAM_BAMSORMADUP { level=0 \\ | bamcollate2 \\ level=0 \\ - $args2 \\ + ${args2} \\ | bamsormadup \\ - $args \\ + ${args} \\ M=${prefix}.metrics.txt \\ - tmpfile=$prefix \\ - threads=$task.cpus \\ + tmpfile=${prefix} \\ + threads=${task.cpus} \\ > ${prefix}.${suffix} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bamcat: \$(echo \$(bamcat --version 2>&1) | sed 's/^This is biobambam2 version //; s/..biobambam2 is .*\$//' ) - bamcollate2: \$(echo \$(bamcollate2 --version 2>&1) | sed 's/^This is biobambam2 version //; s/..biobambam2 is .*\$//' ) - bamsormadup: \$(echo \$(bamsormadup --version 2>&1) | sed 's/^This is biobambam2 version //; s/..biobambam2 is .*\$//' ) - END_VERSIONS """ stub: def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" def suffix = args.contains("outputformat=cram") ? "cram" : "bam" - if (args.contains("outputformat=cram") && fasta == null) error "Reference required for CRAM output." + if (args.contains("outputformat=cram") && fasta == null) { + error("Reference required for CRAM output.") + } """ touch ${prefix}.${suffix} touch ${prefix}.metrics.txt - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bamcat: \$(echo \$(bamcat --version 2>&1) | sed 's/^This is biobambam2 version //; s/..biobambam2 is .*\$//' ) - bamcollate2: \$(echo \$(bamcollate2 --version 2>&1) | sed 's/^This is biobambam2 version //; s/..biobambam2 is .*\$//' ) - bamsormadup: \$(echo \$(bamsormadup --version 2>&1) | sed 's/^This is biobambam2 version //; s/..biobambam2 is .*\$//' ) - END_VERSIONS """ } diff --git a/modules/nf-core/biobambam/bamsormadup/meta.yml b/modules/nf-core/biobambam/bamsormadup/meta.yml index a863c54a..fbfb0bbd 100644 --- a/modules/nf-core/biobambam/bamsormadup/meta.yml +++ b/modules/nf-core/biobambam/bamsormadup/meta.yml @@ -12,7 +12,8 @@ tools: homepage: https://gitlab.com/german.tischler/biobambam2 documentation: https://gitlab.com/german.tischler/biobambam2/-/blob/master/README.md doi: 10.1186/1751-0473-9-13 - licence: ["GPL v3"] + licence: + - "GPL v3" identifier: "" input: - - meta: @@ -23,7 +24,8 @@ input: - bams: type: file description: List containing 1 or more bam files - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2572 - - meta2: type: map description: | @@ -33,7 +35,14 @@ input: type: file description: Reference genome in FASTA format (optional) pattern: "*.{fa,fasta,fna}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_1929 + - fai: + type: file + description: Reference genome in FASTA index format (optional) + pattern: "*.{fai}" + ontologies: + - edam: http://edamontology.org/format_3673 output: bam: - - meta: @@ -45,7 +54,8 @@ output: type: file description: BAM file with duplicate reads marked/removed pattern: "*.bam" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2572 bam_index: - - meta: type: map @@ -56,7 +66,8 @@ output: type: file description: BAM index file pattern: "*.bai" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3692 cram: - - meta: type: map @@ -67,7 +78,8 @@ output: type: file description: CRAM file with duplicate reads marked/removed pattern: "*.cram" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3674 metrics: - - meta: type: map @@ -78,14 +90,29 @@ output: type: file description: Duplicate metrics file generated by biobambam pattern: "*.{metrics.txt}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3675 + versions_biobambam: + - - ${task.process}: + type: string + description: The name of the process + - biobambam: + type: string + description: The name of the tool + - bamsormadup --version |& sed '1!d; s/.*version //; s/.\$//': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - biobambam: + type: string + description: The name of the tool + - bamsormadup --version |& sed '1!d; s/.*version //; s/.\$//': + type: eval + description: The expression to obtain the version of the tool authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test index 0c4c8498..0b65a21c 100644 --- a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test +++ b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test @@ -22,8 +22,7 @@ nextflow_process { file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) ] ] - input[1] = [[:],[]] - + input[1] = [[:],[],[]] """ } } @@ -36,7 +35,7 @@ nextflow_process { process.out.bam_index, process.out.cram, file(process.out.metrics[0][1]).readLines()[3..5], - process.out.versions.collect{ path(it).yaml } + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -53,8 +52,7 @@ nextflow_process { file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) ] ] - input[1] = [[:],[]] - + input[1] = [[:],[],[]] """ } } @@ -67,7 +65,7 @@ nextflow_process { process.out.bam_index, process.out.cram, file(process.out.metrics[0][1]).readLines()[3..5], - process.out.versions.collect{ path(it).yaml } + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -86,8 +84,7 @@ nextflow_process { file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.bam', checkIfExists: true) ] ] - input[1] = [[:],[]] - + input[1] = [[:],[],[]] """ } } @@ -97,7 +94,7 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out, - process.out.versions.collect{ path(it).yaml } + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } diff --git a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap index b820e405..a56a7949 100644 --- a/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap +++ b/modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap @@ -13,21 +13,21 @@ "lib1\t3\t97\t3\t0\t0\t0\t0\t-1", "" ], - [ - { - "BIOBAMBAM_BAMSORMADUP": { - "bamcat": "2.0.185", - "bamcollate2": "2.0.185", - "bamsormadup": "2.0.185" - } - } - ] + { + "versions_biobambam": [ + [ + "BIOBAMBAM_BAMSORMADUP", + "biobambam", + "2.0.185" + ] + ] + } ], + "timestamp": "2026-02-18T12:29:21.145687", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-06T12:52:41.351378528" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test-biobambam-bamsormadup-multi-input": { "content": [ @@ -43,21 +43,21 @@ "lib1\t3\t97\t3\t0\t0\t0\t0\t-1", "testN\t0\t2820\t2\t0\t828\t0\t0.293617\t3807" ], - [ - { - "BIOBAMBAM_BAMSORMADUP": { - "bamcat": "2.0.185", - "bamcollate2": "2.0.185", - "bamsormadup": "2.0.185" - } - } - ] + { + "versions_biobambam": [ + [ + "BIOBAMBAM_BAMSORMADUP", + "biobambam", + "2.0.185" + ] + ] + } ], + "timestamp": "2026-02-18T12:29:10.9703", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-06T12:52:29.639539709" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test-biobambam-bamsormadup-single-input-stub": { "content": [ @@ -87,7 +87,11 @@ ] ], "4": [ - "versions.yml:md5,a3e9cdb2ef49dc4722663257b23c5cb6" + [ + "BIOBAMBAM_BAMSORMADUP", + "biobambam", + "2.0.185" + ] ], "bam": [ [ @@ -113,24 +117,28 @@ "test.metrics.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,a3e9cdb2ef49dc4722663257b23c5cb6" + "versions_biobambam": [ + [ + "BIOBAMBAM_BAMSORMADUP", + "biobambam", + "2.0.185" + ] ] }, - [ - { - "BIOBAMBAM_BAMSORMADUP": { - "bamcat": "2.0.185", - "bamcollate2": "2.0.185", - "bamsormadup": "2.0.185" - } - } - ] + { + "versions_biobambam": [ + [ + "BIOBAMBAM_BAMSORMADUP", + "biobambam", + "2.0.185" + ] + ] + } ], + "timestamp": "2026-02-18T12:29:25.8377", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-06T13:56:01.80534017" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/bwa/mem/main.nf b/modules/nf-core/bwa/mem/main.nf index a646e9e7..eed1d4c8 100644 --- a/modules/nf-core/bwa/mem/main.nf +++ b/modules/nf-core/bwa/mem/main.nf @@ -16,7 +16,8 @@ process BWA_MEM { tuple val(meta), path("*.cram") , emit: cram, optional: true tuple val(meta), path("*.csi") , emit: csi, optional: true tuple val(meta), path("*.crai") , emit: crai, optional: true - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('bwa'), eval('bwa 2>&1 | sed -n "s/^Version: //p"'), topic: versions, emit: versions_bwa + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), topic: versions, emit: versions_samtools when: task.ext.when == null || task.ext.when @@ -42,12 +43,6 @@ process BWA_MEM { \$INDEX \\ $reads \\ | samtools $samtools_command $args2 ${reference} --threads $task.cpus -o ${prefix}.${extension} - - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bwa: \$(echo \$(bwa 2>&1) | sed 's/^.*Version: //; s/Contact:.*\$//') - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -62,11 +57,5 @@ process BWA_MEM { touch ${prefix}.${extension} touch ${prefix}.csi touch ${prefix}.crai - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bwa: \$(echo \$(bwa 2>&1) | sed 's/^.*Version: //; s/Contact:.*\$//') - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/bwa/mem/meta.yml b/modules/nf-core/bwa/mem/meta.yml index e1265ab7..450a3fe9 100644 --- a/modules/nf-core/bwa/mem/meta.yml +++ b/modules/nf-core/bwa/mem/meta.yml @@ -16,7 +16,8 @@ tools: homepage: http://bio-bwa.sourceforge.net/ documentation: https://bio-bwa.sourceforge.net/bwa.shtml arxiv: arXiv:1303.3997 - licence: ["GPL-3.0-or-later"] + licence: + - "GPL-3.0-or-later" identifier: "biotools:bwa" input: - - meta: @@ -30,8 +31,8 @@ input: List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. ontologies: - - edam: "http://edamontology.org/data_2044" # Sequence - - edam: "http://edamontology.org/format_1930" # FASTQ + - edam: "http://edamontology.org/data_2044" + - edam: "http://edamontology.org/format_1930" - - meta2: type: map description: | @@ -42,7 +43,7 @@ input: description: BWA genome index files pattern: "Directory containing BWA index *.{amb,ann,bwt,pac,sa}" ontologies: - - edam: "http://edamontology.org/data_3210" # Genome index + - edam: "http://edamontology.org/data_3210" - - meta3: type: map description: | @@ -53,8 +54,8 @@ input: description: Reference genome in FASTA format pattern: "*.{fasta,fa}" ontologies: - - edam: "http://edamontology.org/data_2044" # Sequence - - edam: "http://edamontology.org/format_1929" # FASTA + - edam: "http://edamontology.org/data_2044" + - edam: "http://edamontology.org/format_1929" - sort_bam: type: boolean description: use samtools sort (true) or samtools view (false) @@ -69,18 +70,17 @@ output: description: Output BAM file containing read alignments pattern: "*.{bam}" ontologies: - - edam: "http://edamontology.org/format_2572" # BAM + - edam: "http://edamontology.org/format_2572" cram: - - meta: - type: file - description: Output BAM file containing read alignments - ontologies: [] + type: map + description: Groovy Map containing sample information - "*.cram": type: file description: Output CRAM file containing read alignments pattern: "*.{cram}" ontologies: - - edam: "http://edamontology.org/format_3462" # CRAM + - edam: "http://edamontology.org/format_3462" csi: - - meta: type: map @@ -99,13 +99,46 @@ output: description: Optional index file for CRAM file pattern: "*.{crai}" ontologies: [] + versions_bwa: + - - ${task.process}: + type: string + description: The name of the process + - bwa: + type: string + description: The name of the tool + - 'bwa 2>&1 | sed -n "s/^Version: //p"': + type: eval + description: The expression to obtain the version of the tool + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - bwa: + type: string + description: The name of the tool + - 'bwa 2>&1 | sed -n "s/^Version: //p"': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool authors: - "@drpatelh" - "@jeremy1805" diff --git a/modules/nf-core/bwa/mem/tests/main.nf.test b/modules/nf-core/bwa/mem/tests/main.nf.test index d7b69b9e..6486ab00 100644 --- a/modules/nf-core/bwa/mem/tests/main.nf.test +++ b/modules/nf-core/bwa/mem/tests/main.nf.test @@ -48,7 +48,7 @@ nextflow_process { process.out.cram, process.out.csi, process.out.crai, - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions") }, bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -82,7 +82,7 @@ nextflow_process { process.out.cram, process.out.csi, process.out.crai, - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions") }, bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -117,7 +117,7 @@ nextflow_process { process.out.cram, process.out.csi, process.out.crai, - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions") }, bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -152,7 +152,7 @@ nextflow_process { process.out.cram, process.out.csi, process.out.crai, - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions") }, bam(process.out.bam[0][1]).getReadsMD5() ).match() } @@ -187,7 +187,7 @@ nextflow_process { process.out.cram, process.out.csi, process.out.crai, - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions") }, bam(process.out.bam[0][1]).getReadsMD5() ).match() } diff --git a/modules/nf-core/bwa/mem/tests/main.nf.test.snap b/modules/nf-core/bwa/mem/tests/main.nf.test.snap index 70b7b89b..8aca4b23 100644 --- a/modules/nf-core/bwa/mem/tests/main.nf.test.snap +++ b/modules/nf-core/bwa/mem/tests/main.nf.test.snap @@ -10,16 +10,29 @@ [ ], - [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" - ], + { + "versions_bwa": [ + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "versions_samtools": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] + ] + }, "798439cbd7fd81cbcc5078022dc5479d" ], + "timestamp": "2026-02-18T12:42:52.901827", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-01-26T15:16:52.718077761" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "Single-End Sort": { "content": [ @@ -32,16 +45,29 @@ [ ], - [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" - ], + { + "versions_bwa": [ + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "versions_samtools": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] + ] + }, "94fcf617f5b994584c4e8d4044e16b4f" ], + "timestamp": "2026-02-18T12:43:01.149915", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-01-26T15:17:00.554958251" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "Paired-End": { "content": [ @@ -54,16 +80,29 @@ [ ], - [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" - ], + { + "versions_bwa": [ + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "versions_samtools": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] + ] + }, "57aeef88ed701a8ebc8e2f0a381b2a6" ], + "timestamp": "2026-02-18T12:43:09.528042", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-01-26T15:17:08.162122031" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "Paired-End Sort": { "content": [ @@ -76,16 +115,29 @@ [ ], - [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" - ], + { + "versions_bwa": [ + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "versions_samtools": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] + ] + }, "af8628d9df18b2d3d4f6fd47ef2bb872" ], + "timestamp": "2026-02-18T12:43:17.876121", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-01-26T15:17:15.713464923" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "Single-end - stub": { "content": [ @@ -121,7 +173,18 @@ ] ], "4": [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "5": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] ], "bam": [ [ @@ -153,16 +216,27 @@ "test.csi:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + "versions_bwa": [ + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "versions_samtools": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] ] } ], + "timestamp": "2026-02-18T12:43:33.853248", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T11:05:51.638917351" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "Paired-End - no fasta": { "content": [ @@ -175,16 +249,29 @@ [ ], - [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" - ], + { + "versions_bwa": [ + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "versions_samtools": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] + ] + }, "57aeef88ed701a8ebc8e2f0a381b2a6" ], + "timestamp": "2026-02-18T12:43:26.121474", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-01-26T15:17:23.395002931" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "Paired-end - stub": { "content": [ @@ -220,7 +307,18 @@ ] ], "4": [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "5": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] ], "bam": [ [ @@ -252,15 +350,26 @@ "test.csi:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + "versions_bwa": [ + [ + "BWA_MEM", + "bwa", + "0.7.19-r1273" + ] + ], + "versions_samtools": [ + [ + "BWA_MEM", + "samtools", + "1.22.1" + ] ] } ], + "timestamp": "2026-02-18T12:43:42.119907", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T11:05:59.642014144" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/dragmap/align/main.nf b/modules/nf-core/dragmap/align/main.nf index 2529cbca..a0abf087 100644 --- a/modules/nf-core/dragmap/align/main.nf +++ b/modules/nf-core/dragmap/align/main.nf @@ -19,7 +19,9 @@ process DRAGMAP_ALIGN { tuple val(meta), path("*.crai"), emit: crai, optional: true tuple val(meta), path("*.csi"), emit: csi, optional: true tuple val(meta), path('*.log'), emit: log - path "versions.yml", emit: versions + tuple val("${task.process}"), val('dragmap'), eval("dragen-os --version 2>&1"), emit: versions_dragmap, topic: versions + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), emit: versions_samtools, topic: versions + tuple val("${task.process}"), val('pigz'), eval("pigz --version 2>&1 | sed 's/pigz //'"), emit: versions_pigz, topic: versions when: task.ext.when == null || task.ext.when @@ -46,13 +48,6 @@ process DRAGMAP_ALIGN { ${reads_command} \\ 2>| >(tee ${prefix}.dragmap.log >&2) \\ | samtools ${samtools_command} ${args2} --threads ${task.cpus} ${reference} -o ${prefix}.${extension} - - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - dragmap: \$(echo \$(dragen-os --version 2>&1)) - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS """ stub: @@ -77,12 +72,5 @@ process DRAGMAP_ALIGN { touch ${prefix}.${extension} ${create_index} touch ${prefix}.log - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - dragmap: \$(echo \$(dragen-os --version 2>&1)) - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS """ } diff --git a/modules/nf-core/dragmap/align/meta.yml b/modules/nf-core/dragmap/align/meta.yml index ba3ab484..bdb7f00a 100644 --- a/modules/nf-core/dragmap/align/meta.yml +++ b/modules/nf-core/dragmap/align/meta.yml @@ -12,7 +12,8 @@ tools: homepage: https://github.com/Illumina/dragmap documentation: https://github.com/Illumina/dragmap tool_dev_url: https://github.com/Illumina/dragmap#basic-command-line-usage - licence: ["GPL v3"] + licence: + - "GPL v3" identifier: "" input: - - meta: @@ -25,7 +26,8 @@ input: description: | List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_1930 - - meta2: type: map description: | @@ -45,7 +47,8 @@ input: type: file description: Genome fasta reference files pattern: "*.{fa,fasta,fna}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_1929 - sort_bam: type: boolean description: Sort the BAM file @@ -60,7 +63,8 @@ output: type: file description: Output SAM file containing read alignments pattern: "*.{sam}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2571 bam: - - meta: type: map @@ -71,7 +75,8 @@ output: type: file description: Output BAM file containing read alignments pattern: "*.{bam}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2572 cram: - - meta: type: map @@ -82,7 +87,8 @@ output: type: file description: Output CRAM file containing read alignments pattern: "*.{cram}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2573 crai: - - meta: type: map @@ -115,14 +121,67 @@ output: type: file description: Log file pattern: "*.{log}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3888 + versions_dragmap: + - - ${task.process}: + type: string + description: The name of the process + - dragmap: + type: string + description: The name of the tool + - dragen-os --version 2>&1: + type: eval + description: The expression to obtain the version of the tool + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool + versions_pigz: + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - pigz --version 2>&1 | sed 's/pigz //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - dragmap: + type: string + description: The name of the tool + - dragen-os --version 2>&1: + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - pigz --version 2>&1 | sed 's/pigz //': + type: eval + description: The expression to obtain the version of the tool authors: - "@edmundmiller" maintainers: diff --git a/modules/nf-core/dragmap/align/tests/main.nf.test b/modules/nf-core/dragmap/align/tests/main.nf.test index 5abe76f6..5e8b5baa 100644 --- a/modules/nf-core/dragmap/align/tests/main.nf.test +++ b/modules/nf-core/dragmap/align/tests/main.nf.test @@ -45,8 +45,7 @@ nextflow_process { { assert snapshot( file(process.out.bam[0][1]).name, file(process.out.log[0][1]).readLines().findAll { it.startsWith("decompHash") }, - process.out.versions, - path(process.out.versions[0]).yaml + process.out.findAll { key, val -> key.startsWith("versions") }, ).match() } ) } @@ -89,8 +88,7 @@ nextflow_process { { assert snapshot( file(process.out.bam[0][1]).name, file(process.out.log[0][1]).readLines().findAll { it.startsWith("decompHash") }, - process.out.versions, - path(process.out.versions[0]).yaml + process.out.findAll { key, val -> key.startsWith("versions") }, ).match() } ) } @@ -136,8 +134,7 @@ nextflow_process { { assert snapshot( file(process.out.bam[0][1]).name, file(process.out.log[0][1]).readLines().findAll { it.startsWith("decompHash") }, - process.out.versions, - path(process.out.versions[0]).yaml + process.out.findAll { key, val -> key.startsWith("versions") }, ).match() } ) } @@ -183,8 +180,7 @@ nextflow_process { { assert snapshot( file(process.out.bam[0][1]).name, file(process.out.log[0][1]).readLines().findAll { it.startsWith("decompHash") }, - process.out.versions, - path(process.out.versions[0]).yaml + process.out.findAll { key, val -> key.startsWith("versions") }, ).match() } ) } @@ -230,8 +226,7 @@ nextflow_process { { assert snapshot( file(process.out.bam[0][1]).name, file(process.out.log[0][1]).readLines().findAll { it.startsWith("decompHash") }, - process.out.versions, - path(process.out.versions[0]).yaml + process.out.findAll { key, val -> key.startsWith("versions") }, ).match() } ) } @@ -277,7 +272,6 @@ nextflow_process { assertAll ( { assert snapshot( process.out, - path(process.out.versions[0]).yaml ).match() } ) } diff --git a/modules/nf-core/dragmap/align/tests/main.nf.test.snap b/modules/nf-core/dragmap/align/tests/main.nf.test.snap index 9a63fde0..4b355a0a 100644 --- a/modules/nf-core/dragmap/align/tests/main.nf.test.snap +++ b/modules/nf-core/dragmap/align/tests/main.nf.test.snap @@ -10,22 +10,35 @@ "decompHashTableAutoHits...", "decompHashTableSetFlags..." ], - [ - "versions.yml:md5,bec50713b6dac1cc16fe68b731848394" - ], { - "DRAGMAP_ALIGN": { - "dragmap": "1.2.1", - "samtools": "1.19.2", - "pigz": "2.3.4" - } + "versions_dragmap": [ + [ + "DRAGMAP_ALIGN", + "dragmap", + "1.2.1" + ] + ], + "versions_pigz": [ + [ + "DRAGMAP_ALIGN", + "pigz", + "2.3.4" + ] + ], + "versions_samtools": [ + [ + "DRAGMAP_ALIGN", + "samtools", + "1.19.2" + ] + ] } ], + "timestamp": "2026-02-18T13:37:09.601416", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" - }, - "timestamp": "2025-04-10T11:33:50.428894432" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "homo_sapiens - [fastq1, fastq2], hashtable, fasta, true": { "content": [ @@ -38,22 +51,35 @@ "decompHashTableAutoHits...", "decompHashTableSetFlags..." ], - [ - "versions.yml:md5,bec50713b6dac1cc16fe68b731848394" - ], { - "DRAGMAP_ALIGN": { - "dragmap": "1.2.1", - "samtools": "1.19.2", - "pigz": "2.3.4" - } + "versions_dragmap": [ + [ + "DRAGMAP_ALIGN", + "dragmap", + "1.2.1" + ] + ], + "versions_pigz": [ + [ + "DRAGMAP_ALIGN", + "pigz", + "2.3.4" + ] + ], + "versions_samtools": [ + [ + "DRAGMAP_ALIGN", + "samtools", + "1.19.2" + ] + ] } ], + "timestamp": "2026-02-18T13:37:59.385197", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" - }, - "timestamp": "2025-04-10T11:34:27.492548556" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - fastq, hashtable, fasta, true": { "content": [ @@ -66,22 +92,35 @@ "decompHashTableAutoHits...", "decompHashTableSetFlags..." ], - [ - "versions.yml:md5,bec50713b6dac1cc16fe68b731848394" - ], { - "DRAGMAP_ALIGN": { - "dragmap": "1.2.1", - "samtools": "1.19.2", - "pigz": "2.3.4" - } + "versions_dragmap": [ + [ + "DRAGMAP_ALIGN", + "dragmap", + "1.2.1" + ] + ], + "versions_pigz": [ + [ + "DRAGMAP_ALIGN", + "pigz", + "2.3.4" + ] + ], + "versions_samtools": [ + [ + "DRAGMAP_ALIGN", + "samtools", + "1.19.2" + ] + ] } ], + "timestamp": "2026-02-18T13:37:02.623362", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" - }, - "timestamp": "2025-04-10T11:33:39.843877739" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - [fastq1, fastq2], hashtable, fasta, true": { "content": [ @@ -94,22 +133,35 @@ "decompHashTableAutoHits...", "decompHashTableSetFlags..." ], - [ - "versions.yml:md5,bec50713b6dac1cc16fe68b731848394" - ], { - "DRAGMAP_ALIGN": { - "dragmap": "1.2.1", - "samtools": "1.19.2", - "pigz": "2.3.4" - } + "versions_dragmap": [ + [ + "DRAGMAP_ALIGN", + "dragmap", + "1.2.1" + ] + ], + "versions_pigz": [ + [ + "DRAGMAP_ALIGN", + "pigz", + "2.3.4" + ] + ], + "versions_samtools": [ + [ + "DRAGMAP_ALIGN", + "samtools", + "1.19.2" + ] + ] } ], + "timestamp": "2026-02-18T13:37:16.491006", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" - }, - "timestamp": "2025-04-10T11:34:00.702498161" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - [fastq1, fastq2], hashtable, fasta, true - stub": { "content": [ @@ -151,7 +203,25 @@ ] ], "6": [ - "versions.yml:md5,bec50713b6dac1cc16fe68b731848394" + [ + "DRAGMAP_ALIGN", + "dragmap", + "1.2.1" + ] + ], + "7": [ + [ + "DRAGMAP_ALIGN", + "samtools", + "1.19.2" + ] + ], + "8": [ + [ + "DRAGMAP_ALIGN", + "pigz", + "2.3.4" + ] ], "bam": [ [ @@ -189,23 +259,34 @@ "sam": [ ], - "versions": [ - "versions.yml:md5,bec50713b6dac1cc16fe68b731848394" + "versions_dragmap": [ + [ + "DRAGMAP_ALIGN", + "dragmap", + "1.2.1" + ] + ], + "versions_pigz": [ + [ + "DRAGMAP_ALIGN", + "pigz", + "2.3.4" + ] + ], + "versions_samtools": [ + [ + "DRAGMAP_ALIGN", + "samtools", + "1.19.2" + ] ] - }, - { - "DRAGMAP_ALIGN": { - "dragmap": "1.2.1", - "samtools": "1.19.2", - "pigz": "2.3.4" - } } ], + "timestamp": "2026-02-18T13:38:06.245799", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" - }, - "timestamp": "2025-04-10T11:13:17.187912755" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - fastq, hashtable, fasta, false": { "content": [ @@ -218,21 +299,34 @@ "decompHashTableAutoHits...", "decompHashTableSetFlags..." ], - [ - "versions.yml:md5,bec50713b6dac1cc16fe68b731848394" - ], { - "DRAGMAP_ALIGN": { - "dragmap": "1.2.1", - "samtools": "1.19.2", - "pigz": "2.3.4" - } + "versions_dragmap": [ + [ + "DRAGMAP_ALIGN", + "dragmap", + "1.2.1" + ] + ], + "versions_pigz": [ + [ + "DRAGMAP_ALIGN", + "pigz", + "2.3.4" + ] + ], + "versions_samtools": [ + [ + "DRAGMAP_ALIGN", + "samtools", + "1.19.2" + ] + ] } ], + "timestamp": "2026-02-18T13:36:55.869439", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.5" - }, - "timestamp": "2025-04-10T11:33:28.056988229" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/gnu/sort/tests/main.nf.test b/modules/nf-core/gnu/sort/tests/main.nf.test index dbe473d2..9aef3daf 100644 --- a/modules/nf-core/gnu/sort/tests/main.nf.test +++ b/modules/nf-core/gnu/sort/tests/main.nf.test @@ -16,10 +16,9 @@ nextflow_process { process { """ input[0] = [ - [id:'genome_test'], - file(params.test_data['generic']['unsorted_data']['unsorted_text']['genome_file'], - checkIfExists: true) - ] + [id:'genome_test'], + file(params.modules_testdata_base_path + 'generic/unsorted_data/unsorted_text/test.genome', checkIfExists: true) + ] """ } } @@ -39,10 +38,9 @@ nextflow_process { process { """ input[0] = [ - [id:'test'], - file(params.test_data['generic']['unsorted_data']['unsorted_text']['intervals'], - checkIfExists: true) - ] + [id:'test'], + file(params.modules_testdata_base_path + 'generic/unsorted_data/unsorted_text/test.bed', checkIfExists: true) + ] """ } } @@ -63,10 +61,9 @@ nextflow_process { process { """ input[0] = [ - [id:'test'], - file(params.test_data['generic']['unsorted_data']['unsorted_text']['numbers_csv'], - checkIfExists: true) - ] + [id:'test'], + file(params.modules_testdata_base_path + 'generic/unsorted_data/unsorted_text/test.csv', checkIfExists: true) + ] """ } } @@ -88,10 +85,9 @@ nextflow_process { process { """ input[0] = [ - [id:'test'], - file(params.test_data['generic']['unsorted_data']['unsorted_text']['numbers_csv'], - checkIfExists: true) - ] + [id:'test'], + file(params.modules_testdata_base_path + 'generic/unsorted_data/unsorted_text/test.csv', checkIfExists: true) + ] """ } } diff --git a/modules/nf-core/md5sum/main.nf b/modules/nf-core/md5sum/main.nf index ea8cffed..3412281e 100644 --- a/modules/nf-core/md5sum/main.nf +++ b/modules/nf-core/md5sum/main.nf @@ -13,7 +13,7 @@ process MD5SUM { output: tuple val(meta), path("*.md5"), emit: checksum - path "versions.yml", emit: versions + tuple val("${task.process}"), val('md5sum'), eval("md5sum --version | sed '1!d; s/.* //'"), topic: versions, emit: versions_md5sum when: task.ext.when == null || task.ext.when @@ -27,11 +27,6 @@ process MD5SUM { find -L * -maxdepth 0 -type f \\ ! -name '*.md5' \\ -exec sh -c 'md5sum ${args} "\$1" > "\$1.md5"' _ "{}" \\; - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - md5sum: \$( md5sum --version | sed '1!d; s/.* //' ) - END_VERSIONS """ } else { @@ -40,11 +35,6 @@ process MD5SUM { ! -name '*.md5' \\ -exec md5sum ${args} "{}" + \\ > ${prefix}.md5 - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - md5sum: \$( md5sum --version | sed '1!d; s/.* //' ) - END_VERSIONS """ } @@ -55,21 +45,11 @@ process MD5SUM { find -L * -type f \\ ! -name '*.md5' \\ -exec sh -c 'touch "\$1.md5"' _ "{}" \\; - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - md5sum: \$( md5sum --version | sed '1!d; s/.* //' ) - END_VERSIONS """ } else { """ touch ${prefix}.md5 - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - md5sum: \$( md5sum --version | sed '1!d; s/.* //' ) - END_VERSIONS """ } } diff --git a/modules/nf-core/md5sum/meta.yml b/modules/nf-core/md5sum/meta.yml index c1f7e36d..71066a84 100644 --- a/modules/nf-core/md5sum/meta.yml +++ b/modules/nf-core/md5sum/meta.yml @@ -9,7 +9,8 @@ tools: description: Create MD5 (128-bit) checksums for each file homepage: "https://www.gnu.org" documentation: "https://man7.org/linux/man-pages/man1/md5sum.1.html" - licence: ["GPL-3.0-or-later"] + licence: + - "GPL-3.0-or-later" identifier: "" input: - - meta: @@ -19,7 +20,8 @@ input: e.g. [ id:'test', single_end:false ] - files: type: file - description: Any number of files. One md5sum file will be generated for each. + description: Any number of files. One md5sum file will be generated for + each. pattern: "*.*" ontologies: [] - as_separate_files: @@ -39,13 +41,27 @@ output: description: File containing checksum pattern: "*.md5" ontologies: [] + versions_md5sum: + - - ${task.process}: + type: string + description: The name of the process + - md5sum: + type: string + description: The name of the tool + - md5sum --version | sed '1!d; s/.* //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - md5sum: + type: string + description: The name of the tool + - md5sum --version | sed '1!d; s/.* //': + type: eval + description: The expression to obtain the version of the tool authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/md5sum/tests/main.nf.test.snap b/modules/nf-core/md5sum/tests/main.nf.test.snap index 20b59b0b..bf78c29b 100644 --- a/modules/nf-core/md5sum/tests/main.nf.test.snap +++ b/modules/nf-core/md5sum/tests/main.nf.test.snap @@ -14,7 +14,11 @@ ] ], "1": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + [ + "MD5SUM", + "md5sum", + "9.5" + ] ], "checksum": [ [ @@ -27,16 +31,20 @@ ] ] ], - "versions": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + "versions_md5sum": [ + [ + "MD5SUM", + "md5sum", + "9.5" + ] ] } ], + "timestamp": "2026-02-18T14:31:17.339668", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" - }, - "timestamp": "2024-12-13T11:49:35.159607272" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "md5sum on paired fastq, separate": { "content": [ @@ -53,7 +61,11 @@ ] ], "1": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + [ + "MD5SUM", + "md5sum", + "9.5" + ] ], "checksum": [ [ @@ -66,16 +78,20 @@ ] ] ], - "versions": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + "versions_md5sum": [ + [ + "MD5SUM", + "md5sum", + "9.5" + ] ] } ], + "timestamp": "2026-02-18T14:31:11.522274", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" - }, - "timestamp": "2024-12-13T11:49:27.200164144" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "md5sum on hello.txt - stub": { "content": [ @@ -89,7 +105,11 @@ ] ], "1": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + [ + "MD5SUM", + "md5sum", + "9.5" + ] ], "checksum": [ [ @@ -99,16 +119,20 @@ "hello.txt.md5:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + "versions_md5sum": [ + [ + "MD5SUM", + "md5sum", + "9.5" + ] ] } ], + "timestamp": "2026-02-18T14:30:52.301881", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" - }, - "timestamp": "2024-12-13T11:49:01.643624698" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "md5sum on hello.txt": { "content": [ @@ -122,7 +146,11 @@ ] ], "1": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + [ + "MD5SUM", + "md5sum", + "9.5" + ] ], "checksum": [ [ @@ -132,16 +160,20 @@ "hello.txt.md5:md5,5c18e1db5460fb32fed66966483165fd" ] ], - "versions": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + "versions_md5sum": [ + [ + "MD5SUM", + "md5sum", + "9.5" + ] ] } ], + "timestamp": "2026-02-18T14:30:41.089186", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" - }, - "timestamp": "2024-12-13T11:48:47.201714961" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "md5sum on paired fastq, combined": { "content": [ @@ -155,7 +187,11 @@ ] ], "1": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + [ + "MD5SUM", + "md5sum", + "9.5" + ] ], "checksum": [ [ @@ -165,16 +201,20 @@ "test.md5:md5,dfb98e45cbb77a9a63ae7029aee38bd1" ] ], - "versions": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + "versions_md5sum": [ + [ + "MD5SUM", + "md5sum", + "9.5" + ] ] } ], + "timestamp": "2026-02-18T14:30:58.611754", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" - }, - "timestamp": "2024-12-13T11:49:10.207550973" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "md5sum on paired fastq, combined - stub": { "content": [ @@ -188,7 +228,11 @@ ] ], "1": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + [ + "MD5SUM", + "md5sum", + "9.5" + ] ], "checksum": [ [ @@ -198,16 +242,20 @@ "test.md5:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + "versions_md5sum": [ + [ + "MD5SUM", + "md5sum", + "9.5" + ] ] } ], + "timestamp": "2026-02-18T14:31:06.064053", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" - }, - "timestamp": "2024-12-13T11:49:18.36682418" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "md5sum on hello.txt (BSD-style)": { "content": [ @@ -221,7 +269,11 @@ ] ], "1": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + [ + "MD5SUM", + "md5sum", + "9.5" + ] ], "checksum": [ [ @@ -231,15 +283,19 @@ "hello.txt.md5:md5,152a03f5dc7aa8db6612f63154ecbca2" ] ], - "versions": [ - "versions.yml:md5,792d39a2c683575fc644e1bb9087fa5f" + "versions_md5sum": [ + [ + "MD5SUM", + "md5sum", + "9.5" + ] ] } ], + "timestamp": "2026-02-18T14:30:46.389675", "meta": { - "nf-test": "0.9.2", - "nextflow": "24.10.2" - }, - "timestamp": "2024-12-13T11:48:54.672060206" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/snapaligner/align/main.nf b/modules/nf-core/snapaligner/align/main.nf index eacf4644..177d5b82 100644 --- a/modules/nf-core/snapaligner/align/main.nf +++ b/modules/nf-core/snapaligner/align/main.nf @@ -4,8 +4,8 @@ process SNAPALIGNER_ALIGN { 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/21/21f75cd3d97dfe58e62bea51751b04d33a03a16eae3e9947335d569e22962143/data': - 'community.wave.seqera.io/library/snap-aligner:2.0.5--23601d3a3a2ae452' }" + 'https://depot.galaxyproject.org/singularity/snap-aligner:2.0.5--h077b44d_2': + 'biocontainers/snap-aligner:2.0.5--h077b44d_2' }" input: tuple val(meta) , path(reads, stageAs: "?/*"), path(index) @@ -13,7 +13,7 @@ process SNAPALIGNER_ALIGN { output: tuple val(meta), path("*.bam"), emit: bam tuple val(meta), path("*.bai"), optional: true, emit: bai - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('snap-aligner'), eval("snap-aligner 2>&1 | sed 's/^.*version //;s/.\$//;q'"), topic: versions, emit: versions_snapaligner when: task.ext.when == null || task.ext.when @@ -33,21 +33,11 @@ process SNAPALIGNER_ALIGN { -o ${prefix}.bam \\ -t ${task.cpus} \\ $args - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - snapaligner: \$(snap-aligner 2>&1| head -n 1 | sed 's/^.*version //;s/.\$//') - END_VERSIONS """ stub: """ touch test.bam touch test.bam.bai - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - snapaligner: \$(snap-aligner 2>&1| head -n 1 | sed 's/^.*version //;s/.\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/snapaligner/align/meta.yml b/modules/nf-core/snapaligner/align/meta.yml index 66f2fca4..c7aab28d 100644 --- a/modules/nf-core/snapaligner/align/meta.yml +++ b/modules/nf-core/snapaligner/align/meta.yml @@ -14,7 +14,8 @@ tools: documentation: "https://1drv.ms/b/s!AhuEg_0yZD86hcpblUt-muHKYsG8fA?e=R8ogug" tool_dev_url: "https://github.com/amplab/snap" doi: "10.1101/2021.11.23.469039" - licence: ["Apache v2"] + licence: + - "Apache v2" identifier: "" input: - - meta: @@ -24,11 +25,11 @@ input: e.g. [ id:'test', single_end:false ] - reads: type: file - description: List of input fastq files of size 2 for paired fastq or 1 for bam - or single fastq + description: List of input fastq files of size 2 for paired fastq or 1 for + bam or single fastq pattern: "*.{fastq.gz,fq.gz,fastq,fq,bam}" ontologies: - - edam: http://edamontology.org/format_1930 # FASTQ + - edam: http://edamontology.org/format_1930 - - meta2: type: map description: | @@ -50,7 +51,8 @@ output: type: file description: Aligned BAM file pattern: "*.{bam}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2572 bai: - - meta: type: map @@ -61,14 +63,29 @@ output: type: file description: Optional aligned BAM file index pattern: "*.{bai}" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_2572 + versions_snapaligner: + - - ${task.process}: + type: string + description: The name of the process + - snap-aligner: + type: string + description: The name of the tool + - snap-aligner 2>&1 | sed 's/^.*version //;s/.\$//;q': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - snap-aligner: + type: string + description: The name of the tool + - snap-aligner 2>&1 | sed 's/^.*version //;s/.\$//;q': + type: eval + description: The expression to obtain the version of the tool authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/snapaligner/align/tests/main.nf.test.snap b/modules/nf-core/snapaligner/align/tests/main.nf.test.snap index f660cd39..f6107c9c 100644 --- a/modules/nf-core/snapaligner/align/tests/main.nf.test.snap +++ b/modules/nf-core/snapaligner/align/tests/main.nf.test.snap @@ -21,7 +21,11 @@ ] ], "2": [ - "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" + [ + "SNAPALIGNER_ALIGN", + "snap-aligner", + "2.0.5" + ] ], "bai": [ [ @@ -41,16 +45,20 @@ "test.bam:md5,fc98a93036a3c5f7c674d470f7c5515a" ] ], - "versions": [ - "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" + "versions_snapaligner": [ + [ + "SNAPALIGNER_ALIGN", + "snap-aligner", + "2.0.5" + ] ] } ], + "timestamp": "2026-02-18T13:58:48.808573", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T12:01:44.085165306" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_snapaligner_stub": { "content": [ @@ -74,7 +82,11 @@ ] ], "2": [ - "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" + [ + "SNAPALIGNER_ALIGN", + "snap-aligner", + "2.0.5" + ] ], "bai": [ [ @@ -94,16 +106,20 @@ "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" + "versions_snapaligner": [ + [ + "SNAPALIGNER_ALIGN", + "snap-aligner", + "2.0.5" + ] ] } ], + "timestamp": "2026-02-18T13:59:04.153824", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T12:01:58.930050472" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_snapaligner_paired": { "content": [ @@ -127,7 +143,11 @@ ] ], "2": [ - "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" + [ + "SNAPALIGNER_ALIGN", + "snap-aligner", + "2.0.5" + ] ], "bai": [ [ @@ -147,15 +167,19 @@ "test.bam:md5,d4e6df5e063034da268fa4b97db369d3" ] ], - "versions": [ - "versions.yml:md5,dd98393cd432d8472209fcb8f6be362f" + "versions_snapaligner": [ + [ + "SNAPALIGNER_ALIGN", + "snap-aligner", + "2.0.5" + ] ] } ], + "timestamp": "2026-02-18T13:58:57.101052", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T12:01:51.606664577" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/strobealign/main.nf b/modules/nf-core/strobealign/main.nf index 26ab2489..aae11f08 100644 --- a/modules/nf-core/strobealign/main.nf +++ b/modules/nf-core/strobealign/main.nf @@ -19,7 +19,9 @@ process STROBEALIGN { tuple val(meta), path("*.paf.gz") , emit: paf , optional: true tuple val(meta), path("*.tsv.gz") , emit: tsv , optional: true tuple val(meta), path("*.sti") , emit: sti , optional: true - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('strobealign'), eval("strobealign --version"), topic: versions, emit: versions_strobealign + tuple val("${task.process}"), val('samtools'), eval("samtools version | sed '1!d;s/.* //'"), emit: versions_samtools, topic: versions + tuple val("${task.process}"), val('pigz'), eval("pigz --version 2>&1 | sed 's/pigz //'"), emit: versions_pigz, topic: versions when: task.ext.when == null || task.ext.when @@ -65,13 +67,6 @@ process STROBEALIGN { ${fasta} \\ ${reads} \\ | ${output_cmd} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - strobealign: \$(echo \$(strobealign --version)) - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS """ stub: @@ -97,12 +92,5 @@ process STROBEALIGN { echo "" | pigz > ${prefix}.paf.gz echo "" | pigz > ${prefix}.tsv.gz touch ${prefix}.sti - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - strobealign: \$(echo \$(strobealign --version)) - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS """ } diff --git a/modules/nf-core/strobealign/meta.yml b/modules/nf-core/strobealign/meta.yml index e4ede404..f4b85b24 100644 --- a/modules/nf-core/strobealign/meta.yml +++ b/modules/nf-core/strobealign/meta.yml @@ -1,4 +1,3 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: "strobealign" description: "Align short reads using dynamic seed size with strobemers" keywords: @@ -16,9 +15,9 @@ tools: documentation: "https://github.com/ksahlin/strobealign?tab=readme-ov-file#usage" tool_dev_url: "https://github.com/ksahlin/strobealign" doi: "10.1186/s13059-022-02831-7" - licence: ["MIT"] + licence: + - "MIT" identifier: biotools:strobealign - input: - - meta: type: map @@ -31,8 +30,8 @@ input: List of input FastQ files of size 1 and 2 for single-end and paired-end data, respectively. ontologies: - - edam: "http://edamontology.org/data_2044" # Sequence - - edam: "http://edamontology.org/format_1930" # FASTQ + - edam: "http://edamontology.org/data_2044" + - edam: "http://edamontology.org/format_1930" - - meta2: type: map description: | @@ -43,8 +42,8 @@ input: description: Reference genome in FASTA format pattern: "*.{fasta,fa}" ontologies: - - edam: "http://edamontology.org/data_2044" # Sequence - - edam: "http://edamontology.org/format_1929" # FASTA + - edam: "http://edamontology.org/data_2044" + - edam: "http://edamontology.org/format_1929" - - meta3: type: map description: | @@ -55,7 +54,7 @@ input: description: Strobealign genome index file pattern: "*.sti" ontologies: - - edam: "http://edamontology.org/data_3210" # Genome index + - edam: "http://edamontology.org/data_3210" - sort_bam: type: boolean description: use samtools sort (true) or samtools view (false) @@ -70,18 +69,17 @@ output: description: Output BAM file containing read alignments pattern: "*.{bam}" ontologies: - - edam: "http://edamontology.org/format_2572" # BAM + - edam: "http://edamontology.org/format_2572" cram: - - meta: - type: file - description: Output BAM file containing read alignments - ontologies: [] + type: map + description: Groovy Map containing sample information - "*.cram": type: file description: Output CRAM file containing read alignments pattern: "*.{cram}" ontologies: - - edam: "http://edamontology.org/format_3462" # CRAM + - edam: "http://edamontology.org/format_3462" csi: - - meta: type: map @@ -118,7 +116,7 @@ output: description: Output TSV file containing read alignments pattern: "*.{tsv.gz}" ontologies: - - edam: "http://edamontology.org/format_3475" # TSV + - edam: "http://edamontology.org/format_3475" sti: - - meta: type: map @@ -128,13 +126,65 @@ output: description: Optional strobealign index file for fasta reference pattern: "*.{sti}" ontologies: [] + versions_strobealign: + - - ${task.process}: + type: string + description: The name of the process + - strobealign: + type: string + description: The name of the tool + - strobealign --version: + type: eval + description: The expression to obtain the version of the tool + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool + versions_pigz: + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - pigz --version 2>&1 | sed 's/pigz //': + type: eval + description: The expression to obtain the version of the tool +topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - strobealign: + type: string + description: The name of the tool + - strobealign --version: + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - pigz: + type: string + description: The name of the tool + - pigz --version 2>&1 | sed 's/pigz //': + type: eval + description: The expression to obtain the version of the tool authors: - "@matthdsm" maintainers: diff --git a/modules/nf-core/strobealign/tests/main.nf.test b/modules/nf-core/strobealign/tests/main.nf.test index 360637c0..adab50bc 100644 --- a/modules/nf-core/strobealign/tests/main.nf.test +++ b/modules/nf-core/strobealign/tests/main.nf.test @@ -42,7 +42,7 @@ nextflow_process { { assert snapshot( process.out.bam, process.out.csi, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } @@ -78,7 +78,7 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.bam, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } @@ -115,7 +115,7 @@ nextflow_process { { assert snapshot( cram(process.out.cram[0][1], 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/sarscov2/genome/genome.fasta').getReadsMD5(), file(process.out.crai[0][1]).exists(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } @@ -151,7 +151,7 @@ nextflow_process { { assert process.success }, { assert snapshot( cram(process.out.cram[0][1], 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/genomics/sarscov2/genome/genome.fasta').getReadsMD5(), - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } @@ -187,7 +187,7 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.paf, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } @@ -223,7 +223,7 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.tsv, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } @@ -259,7 +259,7 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.sti, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match() } ) } diff --git a/modules/nf-core/strobealign/tests/main.nf.test.snap b/modules/nf-core/strobealign/tests/main.nf.test.snap index 2b8f54dd..7e53f32d 100644 --- a/modules/nf-core/strobealign/tests/main.nf.test.snap +++ b/modules/nf-core/strobealign/tests/main.nf.test.snap @@ -3,15 +3,35 @@ "content": [ "f3a1593b170cf1e9b9008b3afb77cc53", true, - [ - "versions.yml:md5,5de873596967072366007d67fe652250" - ] + { + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ] + } ], + "timestamp": "2026-02-18T14:11:52.319915", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T12:55:51.0954" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "fastq - sti": { "content": [ @@ -24,28 +44,68 @@ "genome.fasta.r150.sti:md5,1fa95f6ba0167a729ddc6a444eb5e8f7" ] ], - [ - "versions.yml:md5,5de873596967072366007d67fe652250" - ] + { + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ] + } ], + "timestamp": "2026-02-18T14:12:18.718682", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T12:31:45.186708" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "fastq - unsorted cram": { "content": [ "57aeef88ed701a8ebc8e2f0a381b2a6", - [ - "versions.yml:md5,5de873596967072366007d67fe652250" - ] + { + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ] + } ], + "timestamp": "2026-02-18T14:11:59.009249", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T12:42:46.49042" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "fastq - tsv": { "content": [ @@ -58,15 +118,35 @@ "test.tsv.gz:md5,1fcb7444ba029b7f41b3a836fec7ecac" ] ], - [ - "versions.yml:md5,5de873596967072366007d67fe652250" - ] + { + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ] + } ], + "timestamp": "2026-02-18T14:12:12.224719", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T12:31:39.58768" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "stub": { "content": [ @@ -129,7 +209,25 @@ ] ], "7": [ - "versions.yml:md5,5de873596967072366007d67fe652250" + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ], + "8": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "9": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] ], "bam": [ [ @@ -188,16 +286,34 @@ "test.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" ] ], - "versions": [ - "versions.yml:md5,5de873596967072366007d67fe652250" + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] ] } ], + "timestamp": "2026-02-18T14:12:25.287429", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T11:56:39.765352" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "fastq - unsorted bam": { "content": [ @@ -210,15 +326,35 @@ "test.bam:md5,740d88010349b3cd487a8b6244c64c0d" ] ], - [ - "versions.yml:md5,5de873596967072366007d67fe652250" - ] + { + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ] + } ], + "timestamp": "2026-02-18T14:11:44.848089", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T12:31:18.225205" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "fastq - paf": { "content": [ @@ -231,15 +367,35 @@ "test.paf.gz:md5,0992a1eb3dff9beca5849b9d1fc66390" ] ], - [ - "versions.yml:md5,5de873596967072366007d67fe652250" - ] + { + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ] + } ], + "timestamp": "2026-02-18T14:12:05.638183", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T12:31:34.790627" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "fastq - sorted bam": { "content": [ @@ -261,14 +417,34 @@ "test.bam.csi:md5,8d53854f92b3f263db0ed27f4bbad054" ] ], - [ - "versions.yml:md5,5de873596967072366007d67fe652250" - ] + { + "versions_pigz": [ + [ + "STROBEALIGN", + "pigz", + "2.8" + ] + ], + "versions_samtools": [ + [ + "STROBEALIGN", + "samtools", + "1.22.1" + ] + ], + "versions_strobealign": [ + [ + "STROBEALIGN", + "strobealign", + "0.16.1" + ] + ] + } ], + "timestamp": "2026-02-18T14:11:38.040997", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-16T12:31:12.870782" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf index 4c65f558..f269c502 100644 --- a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -37,8 +37,6 @@ workflow PIPELINE_INITIALISATION { main: - ch_versions = channel.empty() - // // Print version and exit if required and dump pipeline parameters to JSON file // @@ -86,7 +84,6 @@ workflow PIPELINE_INITIALISATION { emit: samplesheet = ch_samplesheet - versions = ch_versions } /* diff --git a/subworkflows/nf-core/fastq_align_dna/main.nf b/subworkflows/nf-core/fastq_align_dna/main.nf index 3e7cf051..b7d43c3f 100644 --- a/subworkflows/nf-core/fastq_align_dna/main.nf +++ b/subworkflows/nf-core/fastq_align_dna/main.nf @@ -5,12 +5,12 @@ // -include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" -include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' -include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' -include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" -include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' -include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" +include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" +include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' +include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' +include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" +include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' +include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" diff --git a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test index b65eec69..7fc3534b 100644 --- a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test +++ b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test @@ -264,7 +264,6 @@ nextflow_workflow { { assert snapshot( file(workflow.out.bam[0][1]).name, file(workflow.out.reports[0][1]).readLines().findAll { it.startsWith("decompHash") }, - file(workflow.out.versions[0]).name ).match() } ) } @@ -298,7 +297,6 @@ nextflow_workflow { { assert snapshot( file(workflow.out.bam[0][1]).name, file(workflow.out.reports[0][1]).readLines().findAll { it.startsWith("decompHash") }, - file(workflow.out.versions[0]).name ).match() } ) } diff --git a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap index 60e6bea9..ca559836 100644 --- a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap +++ b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap @@ -12,11 +12,11 @@ ] ], + "timestamp": "2026-02-09T16:57:50.690737", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.3" - }, - "timestamp": "2026-02-09T16:57:50.690737" + } }, "test_fastq_align_dragmap_PE": { "content": [ @@ -28,14 +28,13 @@ "decompHashTableExtIndex...", "decompHashTableAutoHits...", "decompHashTableSetFlags..." - ], - "versions.yml" + ] ], + "timestamp": "2026-02-18T13:45:07.40135", "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-14T08:28:25.283436546" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_fastq_align_strobealign_PE": { "content": [ @@ -56,7 +55,7 @@ ], "3": [ - "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ], "bam": [ [ @@ -74,15 +73,15 @@ ], "versions": [ - "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ] } ], + "timestamp": "2026-02-18T14:14:18.839697", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T14:32:08.743821" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_fastq_align_bwa_mem_SE": { "content": [ @@ -94,14 +93,14 @@ ], [ - "versions.yml:md5,315f4ae70b5322c025925d84c887da18" + ] ], + "timestamp": "2025-09-23T11:20:12.631487104", "meta": { "nf-test": "0.9.2", "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T11:20:12.631487104" + } }, "test_fastq_align_bwamem2_SE": { "content": [ @@ -116,11 +115,11 @@ ] ], + "timestamp": "2026-02-09T16:57:37.848527", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.3" - }, - "timestamp": "2026-02-09T16:57:37.848527" + } }, "test_fastq_align_bwa_mem_PE": { "content": [ @@ -132,25 +131,25 @@ ], [ - "versions.yml:md5,315f4ae70b5322c025925d84c887da18" + ] ], + "timestamp": "2025-09-23T11:20:21.322039351", "meta": { "nf-test": "0.9.2", "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T11:20:21.322039351" + } }, "test_fastq_align_bowtie2_SE": { "content": [ "test.bam", null ], + "timestamp": "2026-02-03T15:14:58.560970561", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.3" - }, - "timestamp": "2026-02-03T15:14:58.560970561" + } }, "test_fastq_align_dragmap_SE": { "content": [ @@ -162,25 +161,24 @@ "decompHashTableExtIndex...", "decompHashTableAutoHits...", "decompHashTableSetFlags..." - ], - "versions.yml" + ] ], + "timestamp": "2026-02-18T13:49:05.298349", "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" - }, - "timestamp": "2024-03-14T08:28:12.991034375" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_fastq_align_bowtie2_PE": { "content": [ "test.bam", null ], + "timestamp": "2026-02-03T15:15:05.862448716", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.3" - }, - "timestamp": "2026-02-03T15:15:05.862448716" + } }, "test_fastq_align_snapaligner_PE": { "content": [ @@ -201,7 +199,7 @@ ], "3": [ - "versions.yml:md5,e98be7da5d37b69852090365352c3534" + ], "bam": [ [ @@ -219,15 +217,15 @@ ], "versions": [ - "versions.yml:md5,e98be7da5d37b69852090365352c3534" + ] } ], + "timestamp": "2026-02-18T14:00:43.115798", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T12:03:34.617919741" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_fastq_align_strobealign_SE": { "content": [ @@ -248,7 +246,7 @@ ], "3": [ - "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ], "bam": [ [ @@ -266,15 +264,15 @@ ], "versions": [ - "versions.yml:md5,9d1991417e63455f5e7fe9d67e5985a4" + ] } ], + "timestamp": "2026-02-18T14:14:11.896842", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T14:32:01.424171" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_fastq_align_snapaligner_SE": { "content": [ @@ -295,7 +293,7 @@ ], "3": [ - "versions.yml:md5,e98be7da5d37b69852090365352c3534" + ], "bam": [ [ @@ -313,14 +311,14 @@ ], "versions": [ - "versions.yml:md5,e98be7da5d37b69852090365352c3534" + ] } ], + "timestamp": "2026-02-18T14:00:35.613219", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" - }, - "timestamp": "2025-09-23T12:03:25.88186957" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 51056ddf..f6b202b0 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -42,7 +42,6 @@ workflow PREPROCESSING { genelists // file: directory containing genelist bed files for coverage analysis main: - ch_versions = channel.empty() ch_multiqc_files = channel.empty() ch_samplesheet @@ -323,7 +322,6 @@ workflow PREPROCESSING { ), false, ) - ch_versions = ch_versions.mix(MD5SUM.out.versions.first()) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -350,7 +348,7 @@ workflow PREPROCESSING { "${process}:\n${tool_versions.join('\n')}" } - softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + softwareVersionsToYAML(topic_versions.versions_file) .mix(topic_versions_string) .collectFile( storeDir: "${params.outdir}/pipeline_info", @@ -451,7 +449,6 @@ workflow PREPROCESSING { multiqc_library_report = MULTIQC_LIBRARY.out.report multiqc_library_data = MULTIQC_LIBRARY.out.data multiqc_library_plots = MULTIQC_LIBRARY.out.plots - versions = ch_versions } /* From fde35f7d108db5d0c1a7ae207c07e61d9399f666 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:32:33 +0100 Subject: [PATCH 206/228] update snapshots --- modules.json | 2 +- .../bamsormadup/biobambam-bamsormadup.diff | 8 +- .../fastq_align_dna/fastq_align_dna.diff | 25 +----- .../fastq_align_dna/tests/main.nf.test | 6 -- .../fastq_align_dna/tests/main.nf.test.snap | 86 ++++++------------- .../local/panelcoverage/main.nf.test.snap | 4 +- .../local/bam_qc/main.nf.test.snap | 12 +-- .../local/coverage/main.nf.test.snap | 8 +- .../local/fastq_align_rna/main.nf.test.snap | 8 +- .../fastq_to_aligned_cram/main.nf.test.snap | 20 ++--- tests/workflows/preprocessing.nf.test.snap | 17 ++-- workflows/preprocessing.nf | 16 ++-- 12 files changed, 74 insertions(+), 138 deletions(-) diff --git a/modules.json b/modules.json index 8d39bf4b..7a04dbc8 100644 --- a/modules.json +++ b/modules.json @@ -154,7 +154,7 @@ "nf-core": { "fastq_align_dna": { "branch": "master", - "git_sha": "cf0eb2bed12c39c5b714d44dd02039a0cefaedb1", + "git_sha": "51cf05a850f58964b0d12ab92230348e567819e3", "installed_by": ["subworkflows"], "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" }, diff --git a/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff b/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff index ba8b093d..92881e2c 100644 --- a/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff +++ b/modules/nf-core/biobambam/bamsormadup/biobambam-bamsormadup.diff @@ -5,15 +5,15 @@ Changes in 'biobambam/bamsormadup/main.nf': --- modules/nf-core/biobambam/bamsormadup/main.nf +++ modules/nf-core/biobambam/bamsormadup/main.nf @@ -8,8 +8,7 @@ - 'biocontainers/biobambam:2.0.185--h85de650_1'}" + : 'biocontainers/biobambam:2.0.185--h85de650_1'}" input: -- tuple val(meta) , path(bams, stageAs: "?/*") -- tuple val(meta2), path(fasta) +- tuple val(meta), path(bams, stageAs: "?/*") +- tuple val(meta2), path(fasta), path(fai) + tuple val(meta) , path(bams, stageAs: "?/*"), path(fasta), path(fai) output: - tuple val(meta), path("*.bam") ,optional:true, emit: bam + tuple val(meta), path("*.bam"), optional: true, emit: bam 'modules/nf-core/biobambam/bamsormadup/tests/main.nf.test.snap' is unchanged 'modules/nf-core/biobambam/bamsormadup/tests/main.nf.test' is unchanged diff --git a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff index 5aec63ce..f2a4356b 100644 --- a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff +++ b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff @@ -3,24 +3,7 @@ Changes in component 'nf-core/fastq_align_dna' Changes in 'fastq_align_dna/main.nf': --- subworkflows/nf-core/fastq_align_dna/main.nf +++ subworkflows/nf-core/fastq_align_dna/main.nf -@@ -5,70 +5,75 @@ - // - - --include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" --include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' --include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' --include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" --include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' --include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" -+include { BOWTIE2_ALIGN } from "../../../modules/nf-core/bowtie2/align/main" -+include { BWA_MEM as BWAMEM1_MEM } from '../../../modules/nf-core/bwa/mem/main' -+include { BWAMEM2_MEM as BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' -+include { DRAGMAP_ALIGN } from "../../../modules/nf-core/dragmap/align/main" -+include { SNAPALIGNER_ALIGN as SNAP_ALIGN } from '../../../modules/nf-core/snapaligner/align/main' -+include { STROBEALIGN } from "../../../modules/nf-core/strobealign/main" - - +@@ -16,53 +16,64 @@ workflow FASTQ_ALIGN_DNA { take: @@ -37,7 +20,6 @@ Changes in 'fastq_align_dna/main.nf': - ch_bam_index = Channel.empty() - ch_bam = Channel.empty() - ch_reports = Channel.empty() -- ch_versions = Channel.empty() + ch_bam_index = channel.empty() + ch_bam = channel.empty() + ch_reports = channel.empty() @@ -66,7 +48,6 @@ Changes in 'fastq_align_dna/main.nf': - BWAMEM1_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem - ch_bam = ch_bam.mix(BWAMEM1_MEM.out.bam) - ch_bam_index = ch_bam_index.mix(BWAMEM1_MEM.out.csi) -- ch_versions = ch_versions.mix(BWAMEM1_MEM.out.versions) - } - else if (aligner == 'bwamem2'){ - BWAMEM2_MEM (ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is bwa-mem2 @@ -76,19 +57,16 @@ Changes in 'fastq_align_dna/main.nf': - DRAGMAP_ALIGN(ch_reads, ch_aligner_index, ch_fasta, sort) // If aligner is dragmap - ch_bam = ch_bam.mix(DRAGMAP_ALIGN.out.bam) - ch_reports = ch_reports.mix(DRAGMAP_ALIGN.out.log) -- ch_versions = ch_versions.mix(DRAGMAP_ALIGN.out.versions) - } - else if (aligner == 'snap'){ - SNAP_ALIGN (ch_reads, ch_aligner_index) // If aligner is snap - ch_bam = ch_bam.mix(SNAP_ALIGN.out.bam) - ch_bam_index.mix(SNAP_ALIGN.out.bai) -- ch_versions = ch_versions.mix(SNAP_ALIGN.out.versions) - } - else if (aligner == 'strobealign'){ - STROBEALIGN (ch_reads, ch_fasta, ch_aligner_index, sort) // If aligner is strobealign - ch_bam = ch_bam.mix(STROBEALIGN.out.bam) - ch_bam_index = ch_bam_index.mix(STROBEALIGN.out.csi) -- ch_versions = ch_versions.mix(STROBEALIGN.out.versions) - } - else { - error "Unknown aligner: ${aligner}" @@ -128,7 +106,6 @@ Changes in 'fastq_align_dna/main.nf': - bam = ch_bam // channel: [ [meta], bam ] - bam_index = ch_bam_index // channel: [ [meta], csi/bai ] - reports = ch_reports // channel: [ [meta], log ] -- versions = ch_versions // channel: [ versions.yml ] + bam = ch_bam // channel: [ [meta], bam ] + bam_index = ch_bam_index // channel: [ [meta], csi/bai ] + reports = ch_reports // channel: [ [meta], log ] diff --git a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test index 7fc3534b..b1b3c1c9 100644 --- a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test +++ b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test @@ -52,7 +52,6 @@ nextflow_workflow { { assert workflow.success}, { assert snapshot( file(workflow.out.bam[0][1]).name, - workflow.out.versions[0] ).match() } ) } @@ -86,7 +85,6 @@ nextflow_workflow { { assert workflow.success}, { assert snapshot( file(workflow.out.bam[0][1]).name, - workflow.out.versions[0] ).match() } ) } @@ -121,7 +119,6 @@ nextflow_workflow { file(workflow.out.bam[0][1]).name, workflow.out.bam_index, workflow.out.reports, - workflow.out.versions, ).match() } ) @@ -157,7 +154,6 @@ nextflow_workflow { file(workflow.out.bam[0][1]).name, workflow.out.bam_index, workflow.out.reports, - workflow.out.versions, ).match() } ) @@ -193,7 +189,6 @@ nextflow_workflow { file(workflow.out.bam[0][1]).name, workflow.out.bam_index, workflow.out.reports, - workflow.out.versions, ).match() } ) @@ -229,7 +224,6 @@ nextflow_workflow { file(workflow.out.bam[0][1]).name, workflow.out.bam_index, workflow.out.reports, - workflow.out.versions, ).match() } ) diff --git a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap index ca559836..f002d8a4 100644 --- a/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap +++ b/subworkflows/nf-core/fastq_align_dna/tests/main.nf.test.snap @@ -7,15 +7,12 @@ ], [ - ], - [ - ] ], - "timestamp": "2026-02-09T16:57:50.690737", + "timestamp": "2026-02-18T14:49:11.253548", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nf-test": "0.9.4", + "nextflow": "25.10.4" } }, "test_fastq_align_dragmap_PE": { @@ -53,9 +50,6 @@ ], "2": [ - ], - "3": [ - ], "bam": [ [ @@ -71,13 +65,10 @@ ], "reports": [ - ], - "versions": [ - ] } ], - "timestamp": "2026-02-18T14:14:18.839697", + "timestamp": "2026-02-18T14:49:56.04299", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" @@ -91,15 +82,12 @@ ], [ - ], - [ - ] ], - "timestamp": "2025-09-23T11:20:12.631487104", + "timestamp": "2026-02-18T14:48:28.855536", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.4", + "nextflow": "25.10.4" } }, "test_fastq_align_bwamem2_SE": { @@ -110,15 +98,12 @@ ], [ - ], - [ - ] ], - "timestamp": "2026-02-09T16:57:37.848527", + "timestamp": "2026-02-18T14:48:54.331973", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nf-test": "0.9.4", + "nextflow": "25.10.4" } }, "test_fastq_align_bwa_mem_PE": { @@ -129,26 +114,22 @@ ], [ - ], - [ - ] ], - "timestamp": "2025-09-23T11:20:21.322039351", + "timestamp": "2026-02-18T14:48:37.392571", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.4", + "nextflow": "25.10.4" } }, "test_fastq_align_bowtie2_SE": { "content": [ - "test.bam", - null + "test.bam" ], - "timestamp": "2026-02-03T15:14:58.560970561", + "timestamp": "2026-02-18T14:48:09.863021", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nf-test": "0.9.4", + "nextflow": "25.10.4" } }, "test_fastq_align_dragmap_SE": { @@ -171,13 +152,12 @@ }, "test_fastq_align_bowtie2_PE": { "content": [ - "test.bam", - null + "test.bam" ], - "timestamp": "2026-02-03T15:15:05.862448716", + "timestamp": "2026-02-18T14:48:20.207038", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" + "nf-test": "0.9.4", + "nextflow": "25.10.4" } }, "test_fastq_align_snapaligner_PE": { @@ -197,9 +177,6 @@ ], "2": [ - ], - "3": [ - ], "bam": [ [ @@ -215,13 +192,10 @@ ], "reports": [ - ], - "versions": [ - ] } ], - "timestamp": "2026-02-18T14:00:43.115798", + "timestamp": "2026-02-18T14:49:42.350796", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" @@ -244,9 +218,6 @@ ], "2": [ - ], - "3": [ - ], "bam": [ [ @@ -262,13 +233,10 @@ ], "reports": [ - ], - "versions": [ - ] } ], - "timestamp": "2026-02-18T14:14:11.896842", + "timestamp": "2026-02-18T14:49:49.102483", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" @@ -291,9 +259,6 @@ ], "2": [ - ], - "3": [ - ], "bam": [ [ @@ -309,13 +274,10 @@ ], "reports": [ - ], - "versions": [ - ] } ], - "timestamp": "2026-02-18T14:00:35.613219", + "timestamp": "2026-02-18T14:49:34.584076", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" diff --git a/tests/modules/local/panelcoverage/main.nf.test.snap b/tests/modules/local/panelcoverage/main.nf.test.snap index 4a912279..49122c84 100644 --- a/tests/modules/local/panelcoverage/main.nf.test.snap +++ b/tests/modules/local/panelcoverage/main.nf.test.snap @@ -50,10 +50,10 @@ ] } ], + "timestamp": "2026-02-11T19:45:02.994288", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T19:45:02.994288" + } } } \ No newline at end of file diff --git a/tests/subworkflows/local/bam_qc/main.nf.test.snap b/tests/subworkflows/local/bam_qc/main.nf.test.snap index 5b809485..5c83a450 100644 --- a/tests/subworkflows/local/bam_qc/main.nf.test.snap +++ b/tests/subworkflows/local/bam_qc/main.nf.test.snap @@ -79,11 +79,11 @@ ] } ], + "timestamp": "2026-02-11T20:41:14.126057", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:41:14.126057" + } }, "Bam QC - Samtools": { "content": [ @@ -132,11 +132,11 @@ ] } ], + "timestamp": "2026-02-11T20:27:00.941719", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:27:00.941719" + } }, "Bam QC - WGSmetrics": { "content": [ @@ -218,10 +218,10 @@ ] } ], + "timestamp": "2026-02-11T20:26:15.482881", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:26:15.482881" + } } } \ No newline at end of file diff --git a/tests/subworkflows/local/coverage/main.nf.test.snap b/tests/subworkflows/local/coverage/main.nf.test.snap index 9934ac1f..cb468e45 100644 --- a/tests/subworkflows/local/coverage/main.nf.test.snap +++ b/tests/subworkflows/local/coverage/main.nf.test.snap @@ -248,11 +248,11 @@ ] } ], + "timestamp": "2026-02-11T22:37:17.825377", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T22:37:17.825377" + } }, "Coverage - seqcap": { "content": [ @@ -497,10 +497,10 @@ ] } ], + "timestamp": "2026-02-11T22:36:21.526017", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T22:36:21.526017" + } } } \ No newline at end of file diff --git a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap index 88691d56..900be6c9 100644 --- a/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_align_rna/main.nf.test.snap @@ -96,11 +96,11 @@ ] } ], + "timestamp": "2026-02-11T22:49:27.454517", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T22:49:27.454517" + } }, "fastq align rna - unknown aligner": { "content": [ @@ -108,10 +108,10 @@ "Unsupported aligner woop for sample test" ] ], + "timestamp": "2024-05-28T16:17:08.089796673", "meta": { "nf-test": "0.8.4", "nextflow": "24.04.1" - }, - "timestamp": "2024-05-28T16:17:08.089796673" + } } } \ No newline at end of file diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index eb4e865f..7b141c66 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -36,11 +36,11 @@ ] } ], + "timestamp": "2026-02-11T20:19:51.825749", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:19:51.825749" + } }, "fastq to cram - bwa - bamsormadup": { "content": [ @@ -95,11 +95,11 @@ ] } ], + "timestamp": "2026-02-11T20:10:31.616836", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:10:31.616836" + } }, "fastq to cram - bwa - samtools sormadup": { "content": [ @@ -154,11 +154,11 @@ ] } ], + "timestamp": "2026-02-11T20:15:15.495706", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:15:15.495706" + } }, "fastq to cram - star - bamsormadup": { "content": [ @@ -249,11 +249,11 @@ ] } ], + "timestamp": "2026-02-11T20:13:35.19973", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:13:35.19973" + } }, "fastq to cram - bwa - samtools sort": { "content": [ @@ -292,10 +292,10 @@ ] } ], + "timestamp": "2026-02-11T20:16:26.285299", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T20:16:26.285299" + } } } \ No newline at end of file diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index fc2144f1..1ec63a2b 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -705,11 +705,11 @@ ] } ], + "timestamp": "2026-02-11T21:21:37.068608", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T21:21:37.068608" + } }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -1077,11 +1077,11 @@ ] } ], + "timestamp": "2026-02-11T21:25:53.804729", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T21:25:53.804729" + } }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1687,16 +1687,13 @@ }, "sample1.merged.metrics.txt:md5,01b7286134f5cb6530c3bab2c86fd169" ] - ], - "versions": [ - "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d" ] } ], + "timestamp": "2026-02-18T15:49:18.459258", "meta": { - "nf-test": "0.9.3", + "nf-test": "0.9.4", "nextflow": "25.10.4" - }, - "timestamp": "2026-02-11T22:18:07.06828" + } } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index f6b202b0..6d85647e 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -83,7 +83,7 @@ workflow PREPROCESSING { return [meta, reports.find { report -> report.name == "fastq_list.csv" }] }, BCLCONVERT.out.fastq, - ).map { meta, fastq -> [meta.rg.SM, meta, fastq] }.set { ch_demultiplexed_fastq } + ).map { meta, fastq -> [meta.readgroup.SM, meta, fastq] }.set { ch_demultiplexed_fastq } ch_illumina_flowcell.info .flatten() @@ -386,11 +386,17 @@ workflow PREPROCESSING { library: meta.id != 'main' return [meta, files instanceof List ? files : [files]] } - ch_multiqc_files.main.dump(tag: "MULTIQC files - main", pretty: true) - ch_multiqc_files.library.dump(tag: "MULTIQC files - library", pretty: true) + + + ch_library_multiqc_files = ch_multiqc_files.library.transpose(by: 1).groupTuple() + ch_library_multiqc_files.dump(tag: "MULTIQC files - library", pretty: true) + + + ch_main_multiqc_files = ch_multiqc_files.main.collect().map { files -> [[id: 'main'], files] } + ch_main_multiqc_files.dump(tag: "MULTIQC files - main", pretty: true) MULTIQC_MAIN( - ch_multiqc_files.main.collect().map { files -> [[id: 'main'], files] }, + ch_main_multiqc_files, ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), @@ -399,7 +405,7 @@ workflow PREPROCESSING { ) MULTIQC_LIBRARY( - ch_multiqc_files.library.transpose(by: 1).groupTuple(), + ch_library_multiqc_files, ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), ch_multiqc_logo.toList(), From 88c974a4d067451710234aef5f43272500d67f91 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:38:58 +0100 Subject: [PATCH 207/228] changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aeda298e..d1c950fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 3.0.0dev +- Update pipeline to use topic channels only, deprecation `versions` channels +- Drop `bcl_demultiplex` subworkflow in favour of `bcl-convert` module - Update the output handling to use the new workflow output definitions. - Bump all modules to latest versions. - The workflow now outputs data in a subdirectory per `library`, including a library specific MultiQC report -- Drop support for unaligned cram outputs. +- Drop support for unaligned cram outputs in favor of untrimmed fastq outputs, which are more widely supported and can be used for a wider range of downstream analyses. - Add support for untrimmed fastq outputs for unsupported genomes or when aligner is set to `false`. - Drop support for global `aligner` parameter. The aligner must now be specified per sample in the sample sheet or sample info. - Drop support for global `markdup` and `umi_aware` parameters. Marking duplicates must now be specified per sample in the sample sheet or sample info. From 2ba5c5cacbc2d82f535573466bb5b6f7d226c116 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:39:35 +0100 Subject: [PATCH 208/228] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1c950fb..18e37743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 3.0.0dev +## 3.0.0 - Update pipeline to use topic channels only, deprecation `versions` channels - Drop `bcl_demultiplex` subworkflow in favour of `bcl-convert` module From 32b356508295d2ba83d598c2e63fb6bfafdfd153 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:43:10 +0100 Subject: [PATCH 209/228] update snapshot --- tests/workflows/preprocessing.nf.test.snap | 136 ++++++++++----------- 1 file changed, 65 insertions(+), 71 deletions(-) diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 1ec63a2b..6df9010a 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -3,7 +3,7 @@ "content": [ { "align_reports": [ - + ], "crams": [ [ @@ -36,22 +36,22 @@ ] ], "demultiplex_fastq": [ - + ], "demultiplex_interop": [ - + ], "demultiplex_logs": [ - + ], "demultiplex_reports": [ - + ], "falco_html": [ - + ], "falco_txt": [ - + ], "fastp_html": [ [ @@ -240,7 +240,7 @@ ] ], "mosdepth_per_base_d4": [ - + ], "mosdepth_quantized_bed": [ [ @@ -417,16 +417,16 @@ ] ], "mosdepth_thresholds_bed": [ - + ], "mosdepth_thresholds_csi": [ - + ], "multiqc_library_data": [ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -438,7 +438,7 @@ ], "multiqc_main_plots": [ [ - + ] ], "multiqc_main_report": [ @@ -447,7 +447,7 @@ ] ], "panelcoverage": [ - + ], "picard_hsmetrics": [ [ @@ -547,13 +547,13 @@ ] ], "picard_wgsmetrics": [ - + ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "samtools_coverage": [ [ @@ -699,9 +699,6 @@ }, "sample1.merged.metrics.txt:md5,01b7286134f5cb6530c3bab2c86fd169" ] - ], - "versions": [ - "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d" ] } ], @@ -715,7 +712,7 @@ "content": [ { "align_reports": [ - + ], "crams": [ [ @@ -749,22 +746,22 @@ ] ], "demultiplex_fastq": [ - + ], "demultiplex_interop": [ - + ], "demultiplex_logs": [ - + ], "demultiplex_reports": [ - + ], "falco_html": [ - + ], "falco_txt": [ - + ], "fastp_html": [ [ @@ -869,46 +866,46 @@ ] ], "mosdepth_global": [ - + ], "mosdepth_per_base_bed": [ - + ], "mosdepth_per_base_csi": [ - + ], "mosdepth_per_base_d4": [ - + ], "mosdepth_quantized_bed": [ - + ], "mosdepth_quantized_csi": [ - + ], "mosdepth_regions": [ - + ], "mosdepth_regions_bed": [ - + ], "mosdepth_regions_csi": [ - + ], "mosdepth_summary": [ - + ], "mosdepth_thresholds_bed": [ - + ], "mosdepth_thresholds_csi": [ - + ], "multiqc_library_data": [ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -920,7 +917,7 @@ ], "multiqc_main_plots": [ [ - + ] ], "multiqc_main_report": [ @@ -929,28 +926,28 @@ ] ], "panelcoverage": [ - + ], "picard_hsmetrics": [ - + ], "picard_multiplemetrics": [ - + ], "picard_multiplemetrics_pdf": [ - + ], "picard_wgsmetrics": [ - + ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "samtools_coverage": [ - + ], "samtools_flagstat": [ [ @@ -1071,9 +1068,6 @@ }, "sample1.merged.metrics.txt:md5,01b7286134f5cb6530c3bab2c86fd169" ] - ], - "versions": [ - "versions.yml:md5,c7a35abdd7b3bdda729b3e782bf5f73d" ] } ], @@ -1087,7 +1081,7 @@ "content": [ { "align_reports": [ - + ], "crams": [ [ @@ -1119,22 +1113,22 @@ ] ], "demultiplex_fastq": [ - + ], "demultiplex_interop": [ - + ], "demultiplex_logs": [ - + ], "demultiplex_reports": [ - + ], "falco_html": [ - + ], "falco_txt": [ - + ], "fastp_html": [ [ @@ -1317,7 +1311,7 @@ ] ], "mosdepth_per_base_d4": [ - + ], "mosdepth_quantized_bed": [ [ @@ -1376,13 +1370,13 @@ ] ], "mosdepth_regions": [ - + ], "mosdepth_regions_bed": [ - + ], "mosdepth_regions_csi": [ - + ], "mosdepth_summary": [ [ @@ -1413,16 +1407,16 @@ ] ], "mosdepth_thresholds_bed": [ - + ], "mosdepth_thresholds_csi": [ - + ], "multiqc_library_data": [ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -1434,7 +1428,7 @@ ], "multiqc_main_plots": [ [ - + ] ], "multiqc_main_report": [ @@ -1443,10 +1437,10 @@ ] ], "panelcoverage": [ - + ], "picard_hsmetrics": [ - + ], "picard_multiplemetrics": [ [ @@ -1543,10 +1537,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "samtools_coverage": [ [ @@ -1696,4 +1690,4 @@ "nextflow": "25.10.4" } } -} \ No newline at end of file +} From 92881ae12850bd3347206d11bc9e927dae75934a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 19 Feb 2026 11:10:10 +0100 Subject: [PATCH 210/228] fix snapshots --- .../local/fastq_to_aligned_cram/main.nf.test | 2 +- .../fastq_to_aligned_cram/main.nf.test.snap | 34 ++--- tests/workflows/preprocessing.nf.test.snap | 142 +++++++++--------- 3 files changed, 89 insertions(+), 89 deletions(-) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test index 549854ff..c71d4c34 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test @@ -86,7 +86,7 @@ nextflow_workflow { { assert workflow.success assert snapshot( - sanitizeOutput(workflow.out, unstableKeys:["cram_crai"]) + sanitizeOutput(workflow.out, unstableKeys:["cram_crai","junctions"]) ).match() } ) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index 7b141c66..86cb09c1 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -3,7 +3,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -26,13 +26,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ] } ], @@ -46,7 +46,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -69,10 +69,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -105,7 +105,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -128,10 +128,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -164,7 +164,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -204,7 +204,7 @@ } } }, - "test.Chimeric.out.junction:md5,b560229eb850489cf0cc6f60baee57b5" + "test.Chimeric.out.junction" ] ], "rna_splice_junctions": [ @@ -259,7 +259,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -282,13 +282,13 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ] } ], @@ -298,4 +298,4 @@ "nextflow": "25.10.4" } } -} \ No newline at end of file +} diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index 6df9010a..e6421b43 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -3,7 +3,7 @@ "content": [ { "align_reports": [ - + ], "crams": [ [ @@ -36,22 +36,22 @@ ] ], "demultiplex_fastq": [ - + ], "demultiplex_interop": [ - + ], "demultiplex_logs": [ - + ], "demultiplex_reports": [ - + ], "falco_html": [ - + ], "falco_txt": [ - + ], "fastp_html": [ [ @@ -240,7 +240,7 @@ ] ], "mosdepth_per_base_d4": [ - + ], "mosdepth_quantized_bed": [ [ @@ -417,16 +417,16 @@ ] ], "mosdepth_thresholds_bed": [ - + ], "mosdepth_thresholds_csi": [ - + ], "multiqc_library_data": [ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -438,7 +438,7 @@ ], "multiqc_main_plots": [ [ - + ] ], "multiqc_main_report": [ @@ -447,7 +447,7 @@ ] ], "panelcoverage": [ - + ], "picard_hsmetrics": [ [ @@ -547,13 +547,13 @@ ] ], "picard_wgsmetrics": [ - + ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "samtools_coverage": [ [ @@ -702,17 +702,17 @@ ] } ], - "timestamp": "2026-02-11T21:21:37.068608", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-11T21:21:37.068608" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ { "align_reports": [ - + ], "crams": [ [ @@ -746,22 +746,22 @@ ] ], "demultiplex_fastq": [ - + ], "demultiplex_interop": [ - + ], "demultiplex_logs": [ - + ], "demultiplex_reports": [ - + ], "falco_html": [ - + ], "falco_txt": [ - + ], "fastp_html": [ [ @@ -866,46 +866,46 @@ ] ], "mosdepth_global": [ - + ], "mosdepth_per_base_bed": [ - + ], "mosdepth_per_base_csi": [ - + ], "mosdepth_per_base_d4": [ - + ], "mosdepth_quantized_bed": [ - + ], "mosdepth_quantized_csi": [ - + ], "mosdepth_regions": [ - + ], "mosdepth_regions_bed": [ - + ], "mosdepth_regions_csi": [ - + ], "mosdepth_summary": [ - + ], "mosdepth_thresholds_bed": [ - + ], "mosdepth_thresholds_csi": [ - + ], "multiqc_library_data": [ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -917,7 +917,7 @@ ], "multiqc_main_plots": [ [ - + ] ], "multiqc_main_report": [ @@ -926,28 +926,28 @@ ] ], "panelcoverage": [ - + ], "picard_hsmetrics": [ - + ], "picard_multiplemetrics": [ - + ], "picard_multiplemetrics_pdf": [ - + ], "picard_wgsmetrics": [ - + ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "samtools_coverage": [ - + ], "samtools_flagstat": [ [ @@ -1071,17 +1071,17 @@ ] } ], - "timestamp": "2026-02-11T21:25:53.804729", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-11T21:25:53.804729" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ { "align_reports": [ - + ], "crams": [ [ @@ -1113,22 +1113,22 @@ ] ], "demultiplex_fastq": [ - + ], "demultiplex_interop": [ - + ], "demultiplex_logs": [ - + ], "demultiplex_reports": [ - + ], "falco_html": [ - + ], "falco_txt": [ - + ], "fastp_html": [ [ @@ -1311,7 +1311,7 @@ ] ], "mosdepth_per_base_d4": [ - + ], "mosdepth_quantized_bed": [ [ @@ -1370,13 +1370,13 @@ ] ], "mosdepth_regions": [ - + ], "mosdepth_regions_bed": [ - + ], "mosdepth_regions_csi": [ - + ], "mosdepth_summary": [ [ @@ -1407,16 +1407,16 @@ ] ], "mosdepth_thresholds_bed": [ - + ], "mosdepth_thresholds_csi": [ - + ], "multiqc_library_data": [ "test_data" ], "multiqc_library_plots": [ - + ], "multiqc_library_report": [ "test.html" @@ -1428,7 +1428,7 @@ ], "multiqc_main_plots": [ [ - + ] ], "multiqc_main_report": [ @@ -1437,10 +1437,10 @@ ] ], "panelcoverage": [ - + ], "picard_hsmetrics": [ - + ], "picard_multiplemetrics": [ [ @@ -1537,10 +1537,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "samtools_coverage": [ [ @@ -1684,10 +1684,10 @@ ] } ], - "timestamp": "2026-02-18T15:49:18.459258", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-18T15:49:18.459258" } -} +} \ No newline at end of file From 6fd01c9f9042beb247df34224feae2f7307c9c6d Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 19 Feb 2026 11:36:38 +0100 Subject: [PATCH 211/228] fix snapshots --- .../local/fastq_to_aligned_cram/main.nf.test | 2 +- .../fastq_to_aligned_cram/main.nf.test.snap | 66 +++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test index c71d4c34..65b68c4c 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test @@ -86,7 +86,7 @@ nextflow_workflow { { assert workflow.success assert snapshot( - sanitizeOutput(workflow.out, unstableKeys:["cram_crai","junctions"]) + sanitizeOutput(workflow.out, unstableKeys:["cram_crai","rna_junctions"]) ).match() } ) diff --git a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap index 86cb09c1..e5a3ef5f 100644 --- a/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap +++ b/tests/subworkflows/local/fastq_to_aligned_cram/main.nf.test.snap @@ -3,7 +3,7 @@ "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -26,27 +26,27 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ] } ], - "timestamp": "2026-02-11T20:19:51.825749", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-11T20:19:51.825749" }, "fastq to cram - bwa - bamsormadup": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -69,10 +69,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -95,17 +95,17 @@ ] } ], - "timestamp": "2026-02-11T20:10:31.616836", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-11T20:10:31.616836" }, "fastq to cram - bwa - samtools sormadup": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -128,10 +128,10 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ [ @@ -154,17 +154,17 @@ ] } ], - "timestamp": "2026-02-11T20:15:15.495706", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-11T20:15:15.495706" }, "fastq to cram - star - bamsormadup": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -192,16 +192,16 @@ { "groupSize": 1, "groupTarget": { - "id": "test", - "samplename": "test", - "single_end": false, - "sample_type": "RNA", - "markdup": "bamsormadup", "genome_data": { - "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", "star": "s3://test-data/genomics/homo_sapiens/genome/star/" - } + }, + "id": "test", + "markdup": "bamsormadup", + "sample_type": "RNA", + "samplename": "test", + "single_end": false } }, "test.Chimeric.out.junction" @@ -249,17 +249,17 @@ ] } ], - "timestamp": "2026-02-11T20:13:35.19973", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-19T11:32:22.214357" }, "fastq to cram - bwa - samtools sort": { "content": [ { "align_reports": [ - + ], "cram_crai": [ [ @@ -282,20 +282,20 @@ ] ], "rna_junctions": [ - + ], "rna_splice_junctions": [ - + ], "sormadup_metrics": [ - + ] } ], - "timestamp": "2026-02-11T20:16:26.285299", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-02-11T20:16:26.285299" } -} +} \ No newline at end of file From e12465583328908ce6089e722495eb8086426ac7 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:54:12 +0100 Subject: [PATCH 212/228] small cleanup --- workflows/preprocessing.nf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 6d85647e..e402edc9 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -11,7 +11,6 @@ include { BCLCONVERT } from '../modules/nf-core/bclconvert/main' include { FALCO } from '../modules/nf-core/falco/main' include { FASTP } from '../modules/nf-core/fastp/main' include { MD5SUM } from '../modules/nf-core/md5sum/main' -include { MOSDEPTH } from '../modules/nf-core/mosdepth/main' include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' @@ -38,8 +37,8 @@ include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_ workflow PREPROCESSING { take: ch_samplesheet // channel: samplesheet read in from --input - genomes // map: genome reference files - genelists // file: directory containing genelist bed files for coverage analysis + genomes // map: genome reference files + genelists // file: directory containing genelist bed files for coverage analysis main: ch_multiqc_files = channel.empty() @@ -331,7 +330,8 @@ workflow PREPROCESSING { // // Collate and save software versions // - def topic_versions = channel.topic("versions") + def topic_versions = channel + .topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path From b395ef1fcb5a2438ff44fc7e20e6b089d05ea076 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:23:15 +0100 Subject: [PATCH 213/228] fix bclconvert config --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 0c65d04c..f105629f 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -13,7 +13,7 @@ process { // BCL convert - withName: '.*BCL_DEMULTIPLEX:BCLCONVERT' { + withName: '.*BCLCONVERT' { cpus = 16 memory = { 64.GB * task.attempt } ext.args = { From 000d81cd8f66021b39f70d97406830fd2c26f09c Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:52:00 +0100 Subject: [PATCH 214/228] add demux logging --- workflows/preprocessing.nf | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index e402edc9..f701ddc6 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -77,12 +77,17 @@ workflow PREPROCESSING { BCLCONVERT.out.logs, ) - generateReadgroup( - BCLCONVERT.out.reports.map { meta, reports -> - return [meta, reports.find { report -> report.name == "fastq_list.csv" }] - }, - BCLCONVERT.out.fastq, - ).map { meta, fastq -> [meta.readgroup.SM, meta, fastq] }.set { ch_demultiplexed_fastq } + ch_fastq_with_meta = ch_fastq_with_meta.mix( + generateReadgroup( + BCLCONVERT.out.reports.map { meta, reports -> + return [meta, reports.find { report -> report.name == "fastq_list.csv" }] + }, + BCLCONVERT.out.fastq, + ) + ) + ch_fastq_with_meta.dump(tag: "DEMULTIPLEX: fastq with meta", pretty: true) + + ch_fastq_with_meta.map { meta, fastq -> [meta.readgroup.SM, meta, fastq] }.set { ch_demultiplexed_fastq } ch_illumina_flowcell.info .flatten() From a1355fd7fd8d2e1a9c67df2977488608d151d9cf Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:55:57 +0100 Subject: [PATCH 215/228] typo --- workflows/preprocessing.nf | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index f701ddc6..849d7272 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -37,8 +37,8 @@ include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_ workflow PREPROCESSING { take: ch_samplesheet // channel: samplesheet read in from --input - genomes // map: genome reference files - genelists // file: directory containing genelist bed files for coverage analysis + genomes // map: genome reference files + genelists // file: directory containing genelist bed files for coverage analysis main: ch_multiqc_files = channel.empty() @@ -77,14 +77,12 @@ workflow PREPROCESSING { BCLCONVERT.out.logs, ) - ch_fastq_with_meta = ch_fastq_with_meta.mix( - generateReadgroup( - BCLCONVERT.out.reports.map { meta, reports -> - return [meta, reports.find { report -> report.name == "fastq_list.csv" }] - }, - BCLCONVERT.out.fastq, - ) - ) + generateReadgroup( + BCLCONVERT.out.reports.map { meta, reports -> + return [meta, reports.find { report -> report.name == "fastq_list.csv" }] + }, + BCLCONVERT.out.fastq, + ).set { ch_fastq_with_meta } ch_fastq_with_meta.dump(tag: "DEMULTIPLEX: fastq with meta", pretty: true) ch_fastq_with_meta.map { meta, fastq -> [meta.readgroup.SM, meta, fastq] }.set { ch_demultiplexed_fastq } @@ -335,8 +333,7 @@ workflow PREPROCESSING { // // Collate and save software versions // - def topic_versions = channel - .topic("versions") + def topic_versions = channel.topic("versions") .distinct() .branch { entry -> versions_file: entry instanceof Path From 10247f5b15839785214602f97f5dae9a3899447a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:10:33 +0100 Subject: [PATCH 216/228] fix rg function --- modules/nf-core/bclconvert/main.nf | 35 +++++++++++------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index 6f207277..40be3cdf 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -106,9 +106,9 @@ process BCLCONVERT { def generateReadgroup(ch_fastq_list_csv, ch_fastq) { return ch_fastq_list_csv - .collect() // make it a value channel - .map { meta, csv_file -> - def fastq_metadata = [] + .join(ch_fastq, by: [0]) + .map { meta, csv_file, fastq_list -> + def meta_fastq = [] csv_file .splitCsv(header: true) .each { row -> @@ -123,25 +123,16 @@ def generateReadgroup(ch_fastq_list_csv, ch_fastq) { rg.LB = row.RGLB ? row.RGLB : "" rg.PL = "ILLUMINA" - // replace the meta id with the sample name - def new_meta = [id: row.RGSM, readgroup: rg] - // Return the new meta with fastq file - fastq_metadata << [new_meta, file(row.Read1File).name] - if (row.Read2File) { - fastq_metadata << [new_meta, file(row.Read2File).name] - } + // dereference the fastq files in the csv + def fastq1 = fastq_list.find { fq -> file(fq).name == file(row.Read1File).name } + def fastq2 = row.Read2File ? fastq_list.find { fq -> file(fq).name == file(row.Read2File).name } : null + + // set fastq metadata + def new_meta = meta + [id: row.RGSM, readgroup: rg, single_end: !fastq2] + + meta_fastq << [new_meta, fastq2 ? [fastq1, fastq2] : [fastq1]] } - return [meta, fastq_metadata] - } - .join(ch_fastq, by:[0]) // -> [ meta, [fq_meta, fastq_filename], [fastq_file, ...] ] - .transpose(by:[2]) // -> [ meta, [fq_meta, fastq_filename], fastq_file ] - .map { meta, fastq_metadata, fastq_file -> - def fastq_meta = fastq_metadata.find { _meta, filename -> filename == file(fastq_file).name } - return [meta + fastq_meta[0], file(fastq_file)] - } - .groupTuple(by: [0]) - .map { meta, fastq -> - meta.single_end = fastq.size() == 1 - return [meta, fastq.flatten()] + return meta_fastq } + .flatMap() } From f36dc71316cd29840f1fbb14b31960925e4089ef Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:11:51 +0100 Subject: [PATCH 217/228] fix rg function --- modules.json | 5 ++- modules/nf-core/bclconvert/bclconvert.diff | 51 ++++++++++++++++++++++ modules/nf-core/bclconvert/main.nf | 2 +- 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 modules/nf-core/bclconvert/bclconvert.diff diff --git a/modules.json b/modules.json index 7a04dbc8..6d2aefc7 100644 --- a/modules.json +++ b/modules.json @@ -7,8 +7,9 @@ "nf-core": { "bclconvert": { "branch": "master", - "git_sha": "547b6a0078c2f4499b64d59edb8ae038b31971b2", - "installed_by": ["modules"] + "git_sha": "18e1a9566d76569b8a40dc60184d4eb7413cf6e1", + "installed_by": ["modules"], + "patch": "modules/nf-core/bclconvert/bclconvert.diff" }, "biobambam/bamsormadup": { "branch": "master", diff --git a/modules/nf-core/bclconvert/bclconvert.diff b/modules/nf-core/bclconvert/bclconvert.diff new file mode 100644 index 00000000..e27cb946 --- /dev/null +++ b/modules/nf-core/bclconvert/bclconvert.diff @@ -0,0 +1,51 @@ +Changes in component 'nf-core/bclconvert' +'modules/nf-core/bclconvert/LICENSE' is unchanged +'modules/nf-core/bclconvert/Dockerfile' is unchanged +'modules/nf-core/bclconvert/README.md' is unchanged +'modules/nf-core/bclconvert/.gitignore' is unchanged +'modules/nf-core/bclconvert/meta.yml' is unchanged +Changes in 'bclconvert/main.nf': +--- modules/nf-core/bclconvert/main.nf ++++ modules/nf-core/bclconvert/main.nf +@@ -103,3 +103,36 @@ + echo "fake InterOp file" > output/InterOp/TileMetricsOut.bin + """ + } ++ ++def generateReadgroup(ch_fastq_list_csv, ch_fastq) { ++ return ch_fastq_list_csv ++ .join(ch_fastq, by: [0]) ++ .map { meta, csv_file, fastq_list -> ++ def meta_fastq = [] ++ csv_file ++ .splitCsv(header: true) ++ .each { row -> ++ // Create the readgroup tuple ++ // RGID,RGSM,RGLB,Lane,Read1File,Read2File ++ def rg = [:] ++ // row.RGID is index1.index2.lane ++ rg.ID = row.RGID ++ // RGPU is a custom column in the samplesheet containing the flowcell ID ++ rg.PU = row.RGPU ? row.RGPU : meta.id + "." + row.Lane ++ rg.SM = row.RGSM ++ rg.LB = row.RGLB ? row.RGLB : "" ++ rg.PL = "ILLUMINA" ++ ++ // dereference the fastq files in the csv ++ def fastq1 = fastq_list.find { fq -> file(fq).name == file(row.Read1File).name } ++ def fastq2 = row.Read2File ? fastq_list.find { fq -> file(fq).name == file(row.Read2File).name } : null ++ ++ // set fastq metadata ++ def new_meta = meta + [id: row.RGSM, readgroup: rg, single_end: !fastq2] ++ ++ meta_fastq << [new_meta, fastq2 ? [fastq1, fastq2] : [fastq1]] ++ } ++ return meta_fastq ++ } ++ .flatMap() ++} + +'modules/nf-core/bclconvert/tests/main.nf.test.snap' is unchanged +'modules/nf-core/bclconvert/tests/nextflow.config' is unchanged +'modules/nf-core/bclconvert/tests/main.nf.test' is unchanged +************************************************************ diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index 40be3cdf..1e79e24c 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -1,5 +1,5 @@ process BCLCONVERT { - tag { "${meta.lane}" ? "${meta.id}" + "." + "${meta.lane}" : "${meta.id}" } + tag "${ meta.lane ? meta.id + "." + meta.lane : meta.id }" label 'process_high' container "nf-core/bclconvert:4.4.6" From a51dd1f2754c17ea9edb288c56a6a226366a0d40 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:23:44 +0100 Subject: [PATCH 218/228] catch library from sampleinfo if applicable --- workflows/preprocessing.nf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 849d7272..225c1ba4 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -97,7 +97,12 @@ workflow PREPROCESSING { ch_demultiplexed_fastq .combine(ch_sampleinfo, by: 0) .map { _samplename, meta, fastq, sampleinfo -> - def new_meta = meta + sampleinfo + if (sampleinfo.library) { + new_rg = meta.readgroup + ['LB': sampleinfo.library] + } else { + new_rg = meta.readgroup + } + def new_meta = meta + sampleinfo + ['readgroup': new_rg] return [new_meta, fastq] } .groupTuple(by: [0]) From 8a3742c1776478d2e4ad12ca7dfb9d58cbbe3b0e Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Wed, 25 Feb 2026 11:40:09 +0100 Subject: [PATCH 219/228] fix bclconvert meta.id --- modules/nf-core/bclconvert/bclconvert.diff | 2 +- modules/nf-core/bclconvert/main.nf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nf-core/bclconvert/bclconvert.diff b/modules/nf-core/bclconvert/bclconvert.diff index e27cb946..e850ef91 100644 --- a/modules/nf-core/bclconvert/bclconvert.diff +++ b/modules/nf-core/bclconvert/bclconvert.diff @@ -36,7 +36,7 @@ Changes in 'bclconvert/main.nf': + def fastq2 = row.Read2File ? fastq_list.find { fq -> file(fq).name == file(row.Read2File).name } : null + + // set fastq metadata -+ def new_meta = meta + [id: row.RGSM, readgroup: rg, single_end: !fastq2] ++ def new_meta = meta + [id: fastq1.getSimpleName().toString() - ~/_R[0-9]_001.*$/, readgroup: rg, single_end: !fastq2] + + meta_fastq << [new_meta, fastq2 ? [fastq1, fastq2] : [fastq1]] + } diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index 1e79e24c..7010ce8a 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -128,7 +128,7 @@ def generateReadgroup(ch_fastq_list_csv, ch_fastq) { def fastq2 = row.Read2File ? fastq_list.find { fq -> file(fq).name == file(row.Read2File).name } : null // set fastq metadata - def new_meta = meta + [id: row.RGSM, readgroup: rg, single_end: !fastq2] + def new_meta = meta + [id: fastq1.getSimpleName().toString() - ~/_R[0-9]_001.*$/, readgroup: rg, single_end: !fastq2] meta_fastq << [new_meta, fastq2 ? [fastq1, fastq2] : [fastq1]] } From 620e31c33a05d11ef8aaa4211e58df7d4d740132 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 26 Feb 2026 12:33:01 +0100 Subject: [PATCH 220/228] add cgroup metrics plugin --- nextflow.config | 1 + 1 file changed, 1 insertion(+) diff --git a/nextflow.config b/nextflow.config index a5ceb27d..1a8c1156 100644 --- a/nextflow.config +++ b/nextflow.config @@ -269,6 +269,7 @@ manifest { // Nextflow plugins plugins { id 'nf-schema@2.6.1' + id 'nf-cgroup-metrics@1.0.0' } validation { From df6952a9e38b919735e941cce49d52930325c751 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:54:05 +0100 Subject: [PATCH 221/228] Remove nf-cgroup-metrics plugin from config --- nextflow.config | 1 - 1 file changed, 1 deletion(-) diff --git a/nextflow.config b/nextflow.config index 1a8c1156..a5ceb27d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -269,7 +269,6 @@ manifest { // Nextflow plugins plugins { id 'nf-schema@2.6.1' - id 'nf-cgroup-metrics@1.0.0' } validation { From da7621b29d27ef57ce2a9195e91f708126d67e6a Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:24:15 +0100 Subject: [PATCH 222/228] Feat: MultiQC SAV (#160) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add mqc_sav module * fix bclconvert config * add demux logging * typo * fix rg function * fix rg function * catch library from sampleinfo if applicable * fix bclconvert meta.id * add cgroup metrics plugin * Remove nf-cgroup-metrics plugin from config * update multiqcsav and multiqc * mv rg function to lib * add mqcsav and fix plumbing * changelog * fix syntax error * Replace lib with function in subwf to please linter * update test config, fix issues * ditch conda from CI and update docs a little * fix file staging * fix linting * tinkering with configs * fix nf-test profiles * more work * linting * mqc_sav attempt #1 * Refactor MultiQC summary file handling and improve metadata management * fix test samplesheet * bump mqc_cmgg container * fix mqc output path * update modules + patch * fix multi-lane processing * fix SAV titleé * fix outputs and patch module * fix snap config process selector * set version to 3.0.0 * final fixed for multilane run qc (hopefully) * fix mqc inputs * move bclconvert rg function to subwf * fix final tests * let's hope we're done now... * fix main wf errors * fix tests (again) * test error * f*ck it * f*ck it --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/actions/nf-test/action.yml | 10 - .github/workflows/clean-up.yml | 6 +- .github/workflows/nf-test.yml | 6 +- .gitignore | 1 + .nf-core.yml | 2 +- CHANGELOG.md | 2 + README.md | 1 - assets/multiqc_config.yml | 3 +- conf/modules.config | 26 +-- conf/test.config | 12 +- docs/usage.md | 40 ++-- main.nf | 162 ++++++------- modules.json | 26 ++- modules/nf-core/bclconvert/bclconvert.diff | 51 ---- modules/nf-core/bclconvert/main.nf | 37 +-- modules/nf-core/bclconvert/meta.yml | 8 +- modules/nf-core/bclconvert/tests/main.nf.test | 8 +- .../bclconvert/tests/main.nf.test.snap | 50 +--- modules/nf-core/bowtie2/align/main.nf | 2 + .../bowtie2/align/tests/main.nf.test.snap | 28 +-- modules/nf-core/bwamem2/mem/bwamem2-mem.diff | 8 +- modules/nf-core/bwamem2/mem/main.nf | 47 ++-- modules/nf-core/bwamem2/mem/meta.yml | 19 ++ .../nf-core/bwamem2/mem/tests/main.nf.test | 8 +- .../bwamem2/mem/tests/main.nf.test.snap | 109 ++++----- modules/nf-core/multiqc/main.nf | 28 +-- modules/nf-core/multiqc/meta.yml | 128 +++++----- modules/nf-core/multiqc/multiqc.diff | 27 --- modules/nf-core/multiqc/tests/main.nf.test | 129 +++++++---- .../nf-core/multiqc/tests/main.nf.test.snap | 109 +++++++-- modules/nf-core/multiqcsav/environment.yml | 13 ++ modules/nf-core/multiqcsav/main.nf | 53 +++++ modules/nf-core/multiqcsav/meta.yml | 139 +++++++++++ modules/nf-core/multiqcsav/tests/main.nf.test | 136 +++++++++++ .../multiqcsav/tests/main.nf.test.snap | 96 ++++++++ .../nf-core/picard/collecthsmetrics/main.nf | 40 ++-- .../nf-core/picard/collecthsmetrics/meta.yml | 4 +- .../picard-collecthsmetrics.diff | 27 +-- .../collecthsmetrics/tests/main.nf.test | 25 +- .../collecthsmetrics/tests/main.nf.test.snap | 44 ++-- .../picard/collectmultiplemetrics/main.nf | 27 +-- .../picard/collectmultiplemetrics/meta.yml | 4 +- .../picard-collectmultiplemetrics.diff | 28 +-- .../collectmultiplemetrics/tests/main.nf.test | 144 +++++++++--- .../tests/main.nf.test.snap | 156 ++++++++++++- .../nf-core/picard/collectwgsmetrics/main.nf | 30 +-- .../nf-core/picard/collectwgsmetrics/meta.yml | 5 +- .../picard-collectwgsmetrics.diff | 22 +- .../collectwgsmetrics/tests/main.nf.test | 119 +++++++--- .../collectwgsmetrics/tests/main.nf.test.snap | 74 +++++- modules/nf-core/star/align/meta.yml | 6 - modules/nf-core/star/align/star-align.diff | 20 +- modules/nf-core/star/align/tests/main.nf.test | 20 -- nextflow.config | 12 +- nf-test.config | 2 +- ro-crate-metadata.json | 36 +-- .../main.nf | 95 ++++++++ .../meta.yml | 0 .../fastq_align_dna/fastq_align_dna.diff | 6 +- tests/config/igenomes_test.config | 9 - tests/config/nf-test.config | 9 - tests/default.nf.test | 36 +-- tests/inputs/fastq.yml | 22 -- tests/inputs/fastq_rna.yml | 24 -- tests/inputs/flowcell.yml | 6 - tests/inputs/test.yml | 51 ++++ tests/workflows/preprocessing.nf.test | 129 +++++++++-- tests/workflows/preprocessing.nf.test.snap | 187 +++++++++++---- workflows/preprocessing.nf | 218 +++++++----------- 70 files changed, 1999 insertions(+), 1170 deletions(-) delete mode 100644 modules/nf-core/bclconvert/bclconvert.diff delete mode 100644 modules/nf-core/multiqc/multiqc.diff create mode 100644 modules/nf-core/multiqcsav/environment.yml create mode 100644 modules/nf-core/multiqcsav/main.nf create mode 100644 modules/nf-core/multiqcsav/meta.yml create mode 100644 modules/nf-core/multiqcsav/tests/main.nf.test create mode 100644 modules/nf-core/multiqcsav/tests/main.nf.test.snap create mode 100644 subworkflows/local/utils_nfcmgg_preprocessing_pipeline/main.nf create mode 100644 subworkflows/local/utils_nfcmgg_preprocessing_pipeline/meta.yml delete mode 100644 tests/inputs/fastq.yml delete mode 100644 tests/inputs/fastq_rna.yml delete mode 100644 tests/inputs/flowcell.yml create mode 100644 tests/inputs/test.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e84f2948..d0f648f7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -36,6 +36,6 @@ body: * Nextflow version _(eg. 23.04.0)_ * Hardware _(eg. HPC, Desktop, Cloud)_ * Executor _(eg. slurm, local, awsbatch)_ - * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ + * Container engine: _(e.g. Docker, Singularity, Podman, Shifter, Charliecloud, or Apptainer)_ * OS _(eg. CentOS Linux, macOS, Linux Mint)_ * Version of nf-cmgg/preprocessing _(eg. 1.1, 1.5, 1.8.2)_ diff --git a/.github/actions/nf-test/action.yml b/.github/actions/nf-test/action.yml index 3b9724c7..9c844d5a 100644 --- a/.github/actions/nf-test/action.yml +++ b/.github/actions/nf-test/action.yml @@ -46,16 +46,6 @@ runs: mkdir -p $NXF_SINGULARITY_CACHEDIR mkdir -p $NXF_SINGULARITY_LIBRARYDIR - - name: Conda setup - if: contains(inputs.profile, 'conda') - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3 - with: - auto-update-conda: true - conda-solver: libmamba - channels: conda-forge - channel-priority: strict - conda-remove-defaults: true - - name: Run nf-test shell: bash env: diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml index 6adb0fff..587faa0b 100644 --- a/.github/workflows/clean-up.yml +++ b/.github/workflows/clean-up.yml @@ -12,9 +12,9 @@ jobs: steps: - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10 with: - stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." - stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor. Remove stale label or add a comment if it is still useful." - close-issue-message: "This issue was closed because it has been tagged as awaiting-changes or awaiting-feedback by an nf-core contributor and then staled for 20 days with no activity." + stale-issue-message: "This issue has been tagged as awaiting-changes or awaiting-feedback by an nf-cmgg contributor. Remove stale label or add a comment otherwise this issue will be closed in 20 days." + stale-pr-message: "This PR has been tagged as awaiting-changes or awaiting-feedback by an nf-cmgg contributor. Remove stale label or add a comment if it is still useful." + close-issue-message: "This issue was closed because it has been tagged as awaiting-changes or awaiting-feedback by an nf-cmgg contributor and then staled for 20 days with no activity." days-before-stale: 30 days-before-close: 20 days-before-pr-close: -1 diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index 2288a9b9..f55b0075 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -68,13 +68,11 @@ jobs: fail-fast: false matrix: shard: ${{ fromJson(needs.nf-test-changes.outputs.shard) }} - profile: [conda, docker, singularity] + profile: [docker, singularity] isMain: - ${{ github.base_ref == 'master' || github.base_ref == 'main' }} - # Exclude conda and singularity on dev + # Exclude singularity on dev exclude: - - isMain: false - profile: "conda" - isMain: false profile: "singularity" NXF_VER: diff --git a/.gitignore b/.gitignore index 23b0c7de..980c9ac3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ testing* *.pyc null/ .nf-test* +test_fc diff --git a/.nf-core.yml b/.nf-core.yml index e1b35ad2..d06b88e6 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -35,4 +35,4 @@ template: org: nf-cmgg outdir: . skip_features: ["fastqc"] - version: 3.0.0dev + version: 3.0.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 18e37743..c062310d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 3.0.0 +- Add `MultiQC-SAV` module for Illumina Run QC reports +- Migrate readgroup parsing from `preprocessing.nf` to a local subworkflow - Update pipeline to use topic channels only, deprecation `versions` channels - Drop `bcl_demultiplex` subworkflow in favour of `bcl-convert` module - Update the output handling to use the new workflow output definitions. diff --git a/README.md b/README.md index f867fbba..119479bf 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ [![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) [![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.1) -[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) [![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index cc354c76..3b59662f 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,6 +1,5 @@ report_comment: > - This report has been generated by the nf-cmgg/preprocessing - analysis pipeline. + This report has been generated by the nf-cmgg/preprocessing analysis pipeline. report_section_order: "nf-cmgg-preprocessing-methods-description": order: -1000 diff --git a/conf/modules.config b/conf/modules.config index f105629f..becf78e8 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -104,7 +104,7 @@ process { // -xf 2 : expansion factor for reading compressed data //// SNAP - withName: '.*FASTQ_ALIGN_DNA:SNAPALIGNER_ALIGN' { + withName: '.*FASTQ_ALIGN_DNA:SNAP_ALIGN' { cpus = 16 memory = 64.GB ext.args = { @@ -270,29 +270,27 @@ process { } // MultiQC - withName: '.*MULTIQC_.*$' { - container = "cmgg/multiqc_cmgg:0.0.2-multiqc-v1.33" - cpus = 1 - memory = 4.GB - } - withName: '.*MULTIQC_MAIN' { - ext.prefix = { params.multiqc_title ? params.multiqc_title : "multiqc" } + withName: '.*MULTIQCSAV' { + cpus = 1 + memory = 4.GB + ext.prefix = { params.multiqc_title ? "${params.multiqc_title}_SAV" : "${meta.id}_SAV" } ext.args = { [ - "--template \"cmgg\"", "--no-ai", - params.multiqc_title ? "--title \"${params.multiqc_title}\"" : "", + params.multiqc_title ? "--title \"${params.multiqc_title}\"" : "--title \"${meta.id}\"", ].join(" ").trim() } } - - withName: '.*MULTIQC_LIBRARY' { - ext.prefix = { meta.id ? "${meta.id}" : "multiqc_library" } + withName: '.*MULTIQC' { + container = "cmgg/multiqc_cmgg:0.0.5-multiqc-v1.33" + cpus = 1 + memory = 4.GB + ext.prefix = { params.multiqc_title ? "${params.multiqc_title}_${meta.id}" : "${meta.id}" } ext.args = { [ "--template \"cmgg\"", "--no-ai", - meta.id ? "--title \"${meta.id} - Pool Summary\"" : "", + params.multiqc_title ? "--title \"${params.multiqc_title} - ${meta.id}\"" : "--title \"${meta.id}\"", ].join(" ").trim() } } diff --git a/conf/test.config b/conf/test.config index f4ad2b2b..8b6c7486 100644 --- a/conf/test.config +++ b/conf/test.config @@ -15,7 +15,7 @@ params { config_profile_description = 'Minimal test dataset to check pipeline function' // Input data - input = "${projectDir}/tests/inputs/fastq.yml" + input = "${projectDir}/tests/inputs/test.yml" igenomes_base = "s3://reference-data/genomes" } @@ -25,16 +25,6 @@ process { memory: 6.GB, time: 6.h, ] - - withName: BCLCONVERT { - ext.args = { - [ - meta.lane ? "--bcl-only-lane ${meta.lane}" : "", - "--force", - "--first-tile-only true", - ].join(" ").trim() - } - } } includeConfig "../tests/config/igenomes_test.config" diff --git a/docs/usage.md b/docs/usage.md index 1f1d72d2..32028ecd 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -51,7 +51,7 @@ Following table shows the fields that are used by the `fastq` samplesheet: | `roi` | The path to a BED file containing Regions Of Interest for coverage analysis | :x: | | `aligner` | The aligner to use for this sample. Can be one of these: bowtie2, bwamem, bwamem2, dragmap, strobe and snap. set to `false` to output fastq. | :x: | -An [example samplesheet](../tests/inputs/fastq.yml) has been provided with the pipeline. +An [example samplesheet](../tests/inputs/test.yml) has been provided with the pipeline. ### Flowcell samplesheet @@ -64,22 +64,26 @@ RUN_NAME,RUN_NAME_samplesheet.csv,RUN_NAME_sampleinfo.csv,RUN_NAME_flowcell/ Following table shows the fields that are used by the `flowcell` samplesheet: -| Column | Description | Required | -| ------------- | ------------------------------------------------------------------------------------------------------ | ------------------ | -| `samplesheet` | Illumina flowcell for the flowcell lane | :heavy_check_mark: | -| `sample_info` | CSV file with sample information. See the [flowcell sample info](#flowcell-sample-info) documentation. | :heavy_check_mark: | -| `flowcell` | Illumina flowcell directory | :heavy_check_mark: | -| `lane` | FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :x: | +| Column | Description | Required | +| ------------- | ----------------------------------------------------------------------------------------------------------- | ------------------ | +| `samplesheet` | Illumina flowcell for the flowcell lane | :heavy_check_mark: | +| `sample_info` | JSON/YML file with sample information. See the [flowcell sample info](#flowcell-sample-info) documentation. | :heavy_check_mark: | +| `flowcell` | Illumina flowcell directory | :heavy_check_mark: | +| `lane` | Lane number | :x: | -An [example samplesheet](../tests/inputs/flowcell.yml) has been provided with the pipeline. +An [example samplesheet](../tests/inputs/test.yml) has been provided with the pipeline. ### Flowcell sample info -A `flowcell` sample info CSV file consisting for one sequencing run may look something like the one below. +A `flowcell` sample info JSON/YML file consisting for one sequencing run may look something like the one below. -```csv title="sample_info.csv" -samplename,library,organism,tag -Sample1,test,Homo sapiens,WES +```json title="sample_info.json" +{ + "samplename": "Sample1", + "library": "test", + "organism": "Homo sapiens", + "tag": "WES" +} ``` Following table shows the fields that are used by the `flowcell` samplesheet: @@ -182,11 +186,7 @@ These options are part of Nextflow and use a _single_ hyphen (pipeline parameter Use this parameter to choose a configuration profile. Profiles can give configuration presets for different compute environments. -Several generic profiles are bundled with the pipeline which instruct the pipeline to use software packaged using different methods (Docker, Singularity, Podman, Shifter, Charliecloud, Apptainer, Conda) - see below. - -:::info -We highly recommend the use of Docker or Singularity containers for full pipeline reproducibility, however when this is not possible, Conda is also supported. -::: +Several generic profiles are bundled with the pipeline which instruct the pipeline to use software packaged using different methods (Docker, Singularity, Podman, Shifter, Charliecloud, Apptainer) - see below. The pipeline also dynamically loads configurations from [https://github.com/nf-core/configs](https://github.com/nf-core/configs) when it runs, making multiple config profiles for various institutional clusters available at run time. For more information and to see if your system is available in these configs please see the [nf-core/configs documentation](https://github.com/nf-core/configs#documentation). @@ -210,8 +210,6 @@ If `-profile` is not specified, the pipeline will run locally and expect all sof - A generic configuration profile to be used with [Charliecloud](https://hpc.github.io/charliecloud/) - `apptainer` - A generic configuration profile to be used with [Apptainer](https://apptainer.org/) -- `conda` - - A generic configuration profile to be used with [Conda](https://conda.io/docs/). Please only use Conda as a last resort i.e. when it's not possible to run the pipeline with Docker, Singularity, Podman, Shifter, Charliecloud, or Apptainer. ### `-resume` @@ -233,9 +231,9 @@ To change the resource requests, please see the [max resources](https://nf-co.re ### Custom Containers -In some cases you may wish to change which container or conda environment a step of the pipeline uses for a particular tool. By default nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However in some cases the pipeline specified version maybe out of date. +In some cases you may wish to change which container a step of the pipeline uses for a particular tool. By default nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However in some cases the pipeline specified version maybe out of date. -To use a different container from the default container or conda environment specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/usage/configuration#updating-tool-versions) section of the nf-core website. +To use a different container from the default container specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/usage/configuration#updating-tool-versions) section of the nf-core website. ### Custom Tool Arguments diff --git a/main.nf b/main.nf index aed6d7b5..e2f78c8b 100644 --- a/main.nf +++ b/main.nf @@ -46,6 +46,11 @@ workflow { PIPELINE_INITIALISATION.out.samplesheet, params.genomes, params.genelists, + params.multiqc_config + ? [file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true), file(params.multiqc_config, checkIfExists: true)] + : [file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true)], + params.multiqc_logo ? file(params.multiqc_logo, checkIfExists: true) : [], + params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true), ) // @@ -58,14 +63,14 @@ workflow { params.outdir, params.monochrome_logs, params.hook_url, - PREPROCESSING.out.multiqc_main_report, + PREPROCESSING.out.multiqc_report, ) publish: - demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by: 1) - demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose(by: 1) - demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose(by: 1) + demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose() + demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose() demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() + demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose() falco_html = PREPROCESSING.out.falco_html falco_txt = PREPROCESSING.out.falco_txt fastp_json = PREPROCESSING.out.fastp_json @@ -97,242 +102,211 @@ workflow { picard_wgsmetrics = PREPROCESSING.out.picard_wgsmetrics picard_hsmetrics = PREPROCESSING.out.picard_hsmetrics md5sums = PREPROCESSING.out.md5sums - multiqc_main_report = PREPROCESSING.out.multiqc_main_report - multiqc_main_data = PREPROCESSING.out.multiqc_main_data - multiqc_main_plots = PREPROCESSING.out.multiqc_main_plots - multiqc_library_report = PREPROCESSING.out.multiqc_library_report - multiqc_library_data = PREPROCESSING.out.multiqc_library_data - multiqc_library_plots = PREPROCESSING.out.multiqc_library_plots + multiqc_report = PREPROCESSING.out.multiqc_report + multiqc_data = PREPROCESSING.out.multiqc_data + multiqc_plots = PREPROCESSING.out.multiqc_plots + multiqcsav_report = PREPROCESSING.out.multiqcsav_report + multiqcsav_data = PREPROCESSING.out.multiqcsav_data + multiqcsav_plots = PREPROCESSING.out.multiqcsav_plots } output { - demultiplex_interop { - path { _meta, bin -> - bin >> "Interop/${bin.name}" - } - } demultiplex_reports { path { meta, report -> - def out_path = meta.lane ? "Reports/L00${meta.lane}/${report.name}" as String : "Reports/${report.name}" - report >> out_path + report >> (meta.lane ? "Reports/L00${meta.lane}/${report.name}" : "Reports/${report.name}") } } demultiplex_logs { path { meta, log -> - def out_path = meta.lane ? "Logs/L00${meta.lane}/${log.name}" as String : "Logs/${log.name}" - log >> out_path + log >> (meta.lane ? "Logs/L00${meta.lane}/${log.name}" : "Logs/${log.name}") } } + demultiplex_interop { + path "InterOp/" + } demultiplex_fastq { path { meta, fastq -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" as String : "${meta.samplename}/${fastq.name}" - fastq >> out_path + fastq >> (meta.library ? "${meta.library}/${meta.samplename}/${fastq.name}" : "${meta.samplename}/${fastq.name}") } } falco_html { path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path + html >> (meta.library ? "${meta.library}/${meta.samplename}/${html.name}" : "${meta.samplename}/${html.name}") } } falco_txt { path { meta, txt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" as String : "${meta.samplename}/${txt.name}" - txt >> out_path + txt >> (meta.library ? "${meta.library}/${meta.samplename}/${txt.name}" : "${meta.samplename}/${txt.name}") } } fastp_json { path { meta, json -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${json.name}" as String : "${meta.samplename}/${json.name}" - json >> out_path + json >> (meta.library ? "${meta.library}/${meta.samplename}/${json.name}" : "${meta.samplename}/${json.name}") } } fastp_html { path { meta, html -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${html.name}" as String : "${meta.samplename}/${html.name}" - html >> out_path + html >> (meta.library ? "${meta.library}/${meta.samplename}/${html.name}" : "${meta.samplename}/${html.name}") } } crams { path { meta, cram, crai -> - def out_cram = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" as String : "${meta.samplename}/${meta.samplename}.cram" - def out_crai = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" as String : "${meta.samplename}/${meta.samplename}.cram.crai" - cram >> out_cram - crai >> out_crai + cram >> (meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram" : "${meta.samplename}/${meta.samplename}.cram") + crai >> (meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.cram.crai" : "${meta.samplename}/${meta.samplename}.cram.crai") } } rna_splice_junctions { path { meta, sjt -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" as String : "${meta.samplename}/${sjt.name}" - sjt >> out_path + sjt >> (meta.library ? "${meta.library}/${meta.samplename}/${sjt.name}" : "${meta.samplename}/${sjt.name}") } } rna_junctions { path { meta, junctions -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" as String : "${meta.samplename}/${junctions.name}" - junctions >> out_path + junctions >> (meta.library ? "${meta.library}/${meta.samplename}/${junctions.name}" : "${meta.samplename}/${junctions.name}") } } align_reports { path { meta, log -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${log.name}" as String : "${meta.samplename}/${log.name}" - log >> out_path + log >> (meta.library ? "${meta.library}/${meta.samplename}/${log.name}" : "${meta.samplename}/${log.name}") } } sormadup_metrics { path { meta, metrics -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" as String : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" - metrics >> out_path + metrics >> (meta.library ? "${meta.library}/${meta.samplename}/${meta.samplename}.duplicate_metrics.txt" : "${meta.samplename}/${meta.samplename}.duplicate_metrics.txt") } } mosdepth_global { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_summary { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_regions { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_per_base_d4 { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_per_base_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_per_base_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_regions_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_regions_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_quantized_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_quantized_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_thresholds_bed { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } mosdepth_thresholds_csi { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } samtools_coverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } panelcoverage { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } samtools_stats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } samtools_flagstat { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } samtools_idxstats { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } picard_multiplemetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } picard_multiplemetrics_pdf { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } picard_wgsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } picard_hsmetrics { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } md5sums { path { meta, _file -> - def out_path = meta.library ? "${meta.library}/${meta.samplename}/" as String : "${meta.samplename}/" - return out_path + return (meta.library ? "${meta.library}/${meta.samplename}/" : "${meta.samplename}/") } } - multiqc_main_report { + multiqcsav_report { path "multiqc/" } - multiqc_main_data { + multiqcsav_data { path "multiqc/" } - multiqc_main_plots { + multiqcsav_plots { path "multiqc/" } - multiqc_library_report { - path "multiqc/" + multiqc_report { + path { meta, _file -> + return (meta.id ? "${meta.id}/multiqc/" : "multiqc/") + } } - multiqc_library_data { - path "multiqc/" + multiqc_data { + path { meta, _file -> + return (meta.id ? "${meta.id}/multiqc/" : "multiqc/") + } } - multiqc_library_plots { - path "multiqc/" + multiqc_plots { + path { meta, _file -> + return (meta.id ? "${meta.id}/multiqc/" : "multiqc/") + } } } diff --git a/modules.json b/modules.json index 6d2aefc7..410a4a68 100644 --- a/modules.json +++ b/modules.json @@ -7,9 +7,8 @@ "nf-core": { "bclconvert": { "branch": "master", - "git_sha": "18e1a9566d76569b8a40dc60184d4eb7413cf6e1", - "installed_by": ["modules"], - "patch": "modules/nf-core/bclconvert/bclconvert.diff" + "git_sha": "e4a7e011bee58ded839f4da6bf9bb3fbfbebdebd", + "installed_by": ["modules"] }, "biobambam/bamsormadup": { "branch": "master", @@ -19,7 +18,7 @@ }, "bowtie2/align": { "branch": "master", - "git_sha": "ab146e7909edbf6dcc6459de57eef29dceb61d42", + "git_sha": "92b8df948fd8cdb223e051f5f5e414818a073ee0", "installed_by": ["fastq_align_dna", "modules"], "patch": "modules/nf-core/bowtie2/align/bowtie2-align.diff" }, @@ -31,7 +30,7 @@ }, "bwamem2/mem": { "branch": "master", - "git_sha": "5dd46a36fca68d6ad1a6b22ec47adc8c6863717d", + "git_sha": "8325a8155a77a336a613a504b8e4d6cea7a2344a", "installed_by": ["fastq_align_dna"], "patch": "modules/nf-core/bwamem2/mem/bwamem2-mem.diff" }, @@ -69,25 +68,30 @@ }, "multiqc": { "branch": "master", - "git_sha": "575e1a4b51a9bad7a8cd1316a88fb85684ef7c7b", + "git_sha": "2c73cc8fa92cf48de3da0b643fdf357a8a290b36", "installed_by": ["modules"], "patch": "modules/nf-core/multiqc/multiqc.diff" }, + "multiqcsav": { + "branch": "master", + "git_sha": "2c73cc8fa92cf48de3da0b643fdf357a8a290b36", + "installed_by": ["modules"] + }, "picard/collecthsmetrics": { "branch": "master", - "git_sha": "976ed20e328a92cb24ab6c63a8983ed31bf48469", + "git_sha": "a631e12055f6c23ba2c942d3902b3ed1b9eed859", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff" }, "picard/collectmultiplemetrics": { "branch": "master", - "git_sha": "74ec93d00bef147da3fb1f2262e8d31c14108f88", + "git_sha": "a631e12055f6c23ba2c942d3902b3ed1b9eed859", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff" }, "picard/collectwgsmetrics": { "branch": "master", - "git_sha": "66d5808eaaabd9de8997c4c31a9e8cdd3b56c080", + "git_sha": "a631e12055f6c23ba2c942d3902b3ed1b9eed859", "installed_by": ["modules"], "patch": "modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff" }, @@ -139,7 +143,7 @@ }, "star/align": { "branch": "master", - "git_sha": "d6419d592de78e193625b209c1d0a5cc09206df3", + "git_sha": "cebe21bbd158c15c8fab172e37cfe97a239f4b77", "installed_by": ["modules"], "patch": "modules/nf-core/star/align/star-align.diff" }, @@ -155,7 +159,7 @@ "nf-core": { "fastq_align_dna": { "branch": "master", - "git_sha": "51cf05a850f58964b0d12ab92230348e567819e3", + "git_sha": "9afa0584136287aa20fc18296f45f103c0c4e69a", "installed_by": ["subworkflows"], "patch": "subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff" }, diff --git a/modules/nf-core/bclconvert/bclconvert.diff b/modules/nf-core/bclconvert/bclconvert.diff deleted file mode 100644 index e850ef91..00000000 --- a/modules/nf-core/bclconvert/bclconvert.diff +++ /dev/null @@ -1,51 +0,0 @@ -Changes in component 'nf-core/bclconvert' -'modules/nf-core/bclconvert/LICENSE' is unchanged -'modules/nf-core/bclconvert/Dockerfile' is unchanged -'modules/nf-core/bclconvert/README.md' is unchanged -'modules/nf-core/bclconvert/.gitignore' is unchanged -'modules/nf-core/bclconvert/meta.yml' is unchanged -Changes in 'bclconvert/main.nf': ---- modules/nf-core/bclconvert/main.nf -+++ modules/nf-core/bclconvert/main.nf -@@ -103,3 +103,36 @@ - echo "fake InterOp file" > output/InterOp/TileMetricsOut.bin - """ - } -+ -+def generateReadgroup(ch_fastq_list_csv, ch_fastq) { -+ return ch_fastq_list_csv -+ .join(ch_fastq, by: [0]) -+ .map { meta, csv_file, fastq_list -> -+ def meta_fastq = [] -+ csv_file -+ .splitCsv(header: true) -+ .each { row -> -+ // Create the readgroup tuple -+ // RGID,RGSM,RGLB,Lane,Read1File,Read2File -+ def rg = [:] -+ // row.RGID is index1.index2.lane -+ rg.ID = row.RGID -+ // RGPU is a custom column in the samplesheet containing the flowcell ID -+ rg.PU = row.RGPU ? row.RGPU : meta.id + "." + row.Lane -+ rg.SM = row.RGSM -+ rg.LB = row.RGLB ? row.RGLB : "" -+ rg.PL = "ILLUMINA" -+ -+ // dereference the fastq files in the csv -+ def fastq1 = fastq_list.find { fq -> file(fq).name == file(row.Read1File).name } -+ def fastq2 = row.Read2File ? fastq_list.find { fq -> file(fq).name == file(row.Read2File).name } : null -+ -+ // set fastq metadata -+ def new_meta = meta + [id: fastq1.getSimpleName().toString() - ~/_R[0-9]_001.*$/, readgroup: rg, single_end: !fastq2] -+ -+ meta_fastq << [new_meta, fastq2 ? [fastq1, fastq2] : [fastq1]] -+ } -+ return meta_fastq -+ } -+ .flatMap() -+} - -'modules/nf-core/bclconvert/tests/main.nf.test.snap' is unchanged -'modules/nf-core/bclconvert/tests/nextflow.config' is unchanged -'modules/nf-core/bclconvert/tests/main.nf.test' is unchanged -************************************************************ diff --git a/modules/nf-core/bclconvert/main.nf b/modules/nf-core/bclconvert/main.nf index 7010ce8a..1b83e5df 100644 --- a/modules/nf-core/bclconvert/main.nf +++ b/modules/nf-core/bclconvert/main.nf @@ -12,8 +12,8 @@ process BCLCONVERT { tuple val(meta), path("output/**_S[1-9]*_I?_00?.fastq.gz"), emit: fastq_idx, optional: true tuple val(meta), path("output/**Undetermined_S0*_R?_00?.fastq.gz"), emit: undetermined, optional: true tuple val(meta), path("output/**Undetermined_S0*_I?_00?.fastq.gz"), emit: undetermined_idx, optional: true - 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/Reports"), emit: reports + tuple val(meta), path("output/Logs"), emit: logs tuple val(meta), path("output/InterOp/*.bin"), emit: interop, optional: true tuple val("${task.process}"), val('bclconvert'), eval("bcl-convert -V 2>&1 | head -n 1 | sed 's/^.*Version //'"), topic: versions, emit: versions_bclconvert @@ -103,36 +103,3 @@ process BCLCONVERT { echo "fake InterOp file" > output/InterOp/TileMetricsOut.bin """ } - -def generateReadgroup(ch_fastq_list_csv, ch_fastq) { - return ch_fastq_list_csv - .join(ch_fastq, by: [0]) - .map { meta, csv_file, fastq_list -> - def meta_fastq = [] - csv_file - .splitCsv(header: true) - .each { row -> - // Create the readgroup tuple - // RGID,RGSM,RGLB,Lane,Read1File,Read2File - def rg = [:] - // row.RGID is index1.index2.lane - rg.ID = row.RGID - // RGPU is a custom column in the samplesheet containing the flowcell ID - rg.PU = row.RGPU ? row.RGPU : meta.id + "." + row.Lane - rg.SM = row.RGSM - rg.LB = row.RGLB ? row.RGLB : "" - rg.PL = "ILLUMINA" - - // dereference the fastq files in the csv - def fastq1 = fastq_list.find { fq -> file(fq).name == file(row.Read1File).name } - def fastq2 = row.Read2File ? fastq_list.find { fq -> file(fq).name == file(row.Read2File).name } : null - - // set fastq metadata - def new_meta = meta + [id: fastq1.getSimpleName().toString() - ~/_R[0-9]_001.*$/, readgroup: rg, single_end: !fastq2] - - meta_fastq << [new_meta, fastq2 ? [fastq1, fastq2] : [fastq1]] - } - return meta_fastq - } - .flatMap() -} diff --git a/modules/nf-core/bclconvert/meta.yml b/modules/nf-core/bclconvert/meta.yml index a483715a..27f9b1db 100644 --- a/modules/nf-core/bclconvert/meta.yml +++ b/modules/nf-core/bclconvert/meta.yml @@ -75,10 +75,10 @@ output: - - meta: type: map description: Groovy Map containing sample information - - output/Reports/*.{csv,xml,bin}: + - output/Reports: type: file description: Demultiplexing Reports - pattern: "Reports/*.{csv,xml,bin}" + pattern: "Reports" ontologies: - edam: http://edamontology.org/format_3752 #CSV - edam: http://edamontology.org/format_2332 #XML @@ -87,10 +87,10 @@ output: - - meta: type: map description: Groovy Map containing sample information - - output/Logs/*.{log,txt}: + - output/Logs: type: file description: Demultiplexing Logs - pattern: "Logs/*.{log,txt}" + pattern: "Logs" ontologies: - edam: http://edamontology.org/format_2330 #TEXT interop: diff --git a/modules/nf-core/bclconvert/tests/main.nf.test b/modules/nf-core/bclconvert/tests/main.nf.test index 56ec207a..b1b7acab 100644 --- a/modules/nf-core/bclconvert/tests/main.nf.test +++ b/modules/nf-core/bclconvert/tests/main.nf.test @@ -33,8 +33,8 @@ nextflow_process { process.out.fastq_idx, process.out.undetermined.collect { meta, fastq -> file(fastq).name }, process.out.undetermined_idx, - process.out.reports.collect {meta, files -> files.collect { file(it).name }.sort() }, - process.out.logs.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.reports.collect {meta, dir -> file(dir).name }, + process.out.logs.collect {meta, dir -> file(dir).name }, process.out.interop.collect {meta, files -> files.collect { file(it).name }.sort() }, process.out.findAll { key, val -> key.startsWith("versions") } ).match() } @@ -72,8 +72,8 @@ nextflow_process { process.out.fastq_idx, process.out.undetermined.collect { meta, fastq -> file(fastq).name }, process.out.undetermined_idx, - process.out.reports.collect {meta, files -> files.collect { file(it).name }.sort() }, - process.out.logs.collect {meta, files -> files.collect { file(it).name }.sort() }, + process.out.reports.collect {meta, dir -> file(dir).name }, + process.out.logs.collect {meta, dir -> file(dir).name }, process.out.interop.collect {meta, files -> files.collect { file(it).name }.sort() }, process.out.findAll { key, val -> key.startsWith("versions") } ).match() } diff --git a/modules/nf-core/bclconvert/tests/main.nf.test.snap b/modules/nf-core/bclconvert/tests/main.nf.test.snap index 43233d59..b228a5b2 100644 --- a/modules/nf-core/bclconvert/tests/main.nf.test.snap +++ b/modules/nf-core/bclconvert/tests/main.nf.test.snap @@ -19,29 +19,10 @@ ], [ - [ - "Adapter_Cycle_Metrics.csv", - "Adapter_Metrics.csv", - "Demultiplex_Detailed_Stats.csv", - "Demultiplex_Stats.csv", - "Demultiplex_Tile_Stats.csv", - "IndexMetricsOut.bin", - "Index_Hopping_Counts.csv", - "Quality_Metrics.csv", - "Quality_Tile_Metrics.csv", - "RunInfo.xml", - "SampleSheet.csv", - "Top_Unknown_Barcodes.csv", - "fastq_list.csv" - ] + "Reports" ], [ - [ - "Errors.log", - "FastqComplete.txt", - "Info.log", - "Warnings.log" - ] + "Logs" ], [ [ @@ -77,7 +58,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-17T16:59:36.617127" + "timestamp": "2026-03-04T20:03:26.54479" }, "homo_sapiens illumina [bcl] - stub": { "content": [ @@ -279,29 +260,10 @@ ], [ - [ - "Adapter_Cycle_Metrics.csv", - "Adapter_Metrics.csv", - "Demultiplex_Detailed_Stats.csv", - "Demultiplex_Stats.csv", - "Demultiplex_Tile_Stats.csv", - "IndexMetricsOut.bin", - "Index_Hopping_Counts.csv", - "Quality_Metrics.csv", - "Quality_Tile_Metrics.csv", - "RunInfo.xml", - "SampleSheet.csv", - "Top_Unknown_Barcodes.csv", - "fastq_list.csv" - ] + "Reports" ], [ - [ - "Errors.log", - "FastqComplete.txt", - "Info.log", - "Warnings.log" - ] + "Logs" ], [ [ @@ -328,6 +290,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-17T16:59:10.205948" + "timestamp": "2026-03-04T20:02:51.80369" } } \ No newline at end of file diff --git a/modules/nf-core/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index 86aa8bef..36383249 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -31,6 +31,7 @@ process BOWTIE2_ALIGN { def args = task.ext.args ?: "" def args2 = task.ext.args2 ?: "" def prefix = task.ext.prefix ?: "${meta.id}" + def rg = args.contains("--rg-id") ? "" : "--rg-id ${prefix} --rg SM:${prefix}" def unaligned = "" def reads_args = "" @@ -59,6 +60,7 @@ process BOWTIE2_ALIGN { $reads_args \\ --threads $task.cpus \\ $unaligned \\ + $rg \\ $args \\ 2>| >(tee ${prefix}.bowtie2.log >&2) \\ | samtools $samtools_command $args2 --threads $task.cpus ${reference} -o ${prefix}.${extension} - diff --git a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap index c8c6d4b5..b1df41e7 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap @@ -47,11 +47,11 @@ "sarscov2 - fastq, index, fasta, false, false - sam2": { "content": [ [ - "ERR5069949.2151832\t16\tMT192765.1\t17453\t42\t150M\t*\t0\t0\tACGCACATTGCTAACTAAGGGCACACTAGAACCAGAATATTTCAATTCAGTGTGTAGACTTATGAAAACTATAGGTCCAGACATGTTCCTCGGAACTTGTCGGCGTTGTCCTGCTGAAATTGTTGACACTGTGAGTGCTTTGGTTTATGA\tAAAA 0 ? extension_matcher[0][2].toLowerCase() : "bam" - def reference = fasta && extension=="cram" ? "--reference ${fasta}" : "" - if (!fasta && extension=="cram") error "Fasta reference is required for CRAM output" - + def reference = fasta && extension == "cram" ? "--reference ${fasta}" : "" + if (!fasta && extension == "cram") { + error("Fasta reference is required for CRAM output") + } """ INDEX=`find -L ./ -name "*.amb" | sed 's/\\.amb\$//'` bwa-mem2 \\ mem \\ - $args \\ - -t $task.cpus \\ + ${args} \\ + -t ${task.cpus} \\ \$INDEX \\ - $reads \\ - | samtools $samtools_command $args2 -@ $task.cpus ${reference} -o ${prefix}.${extension} - + ${reads} \\ + | samtools ${samtools_command} ${args2} -@ ${task.cpus} ${reference} -o ${prefix}.${extension} - """ stub: - def args2 = task.ext.args2 ?: '' def prefix = task.ext.prefix ?: "${meta.id}" def extension_pattern = /(--output-fmt|-O)+\s+(\S+)/ - def extension_matcher = (args2 =~ extension_pattern) + def extension_matcher = (args2 =~ extension_pattern) def extension = extension_matcher.getCount() > 0 ? extension_matcher[0][2].toLowerCase() : "bam" - if (!fasta && extension=="cram") error "Fasta reference is required for CRAM output" + if (!fasta && extension == "cram") { + error("Fasta reference is required for CRAM output") + } def create_index = "" if (extension == "cram") { create_index = "touch ${prefix}.crai" - } else if (extension == "bam") { + } + else if (extension == "bam") { create_index = "touch ${prefix}.csi" } - """ touch ${prefix}.${extension} ${create_index} diff --git a/modules/nf-core/bwamem2/mem/meta.yml b/modules/nf-core/bwamem2/mem/meta.yml index bcfd006d..a60d6788 100644 --- a/modules/nf-core/bwamem2/mem/meta.yml +++ b/modules/nf-core/bwamem2/mem/meta.yml @@ -129,6 +129,16 @@ output: - bwa-mem2 version | grep -o -E "[0-9]+(\.[0-9]+)+": type: eval description: The expression to obtain the version of the tool + versions_samtools: + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The 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}: @@ -140,6 +150,15 @@ topics: - bwa-mem2 version | grep -o -E "[0-9]+(\.[0-9]+)+": type: eval description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - samtools: + type: string + description: The name of the tool + - samtools version | sed '1!d;s/.* //': + type: eval + description: The expression to obtain the version of the tool authors: - "@maxulysse" - "@matthdsm" diff --git a/modules/nf-core/bwamem2/mem/tests/main.nf.test b/modules/nf-core/bwamem2/mem/tests/main.nf.test index 20e37254..be33a3a7 100644 --- a/modules/nf-core/bwamem2/mem/tests/main.nf.test +++ b/modules/nf-core/bwamem2/mem/tests/main.nf.test @@ -50,7 +50,6 @@ nextflow_process { ).match() } ) } - } test("sarscov2 - fastq, index, fasta, true") { @@ -79,7 +78,6 @@ nextflow_process { ).match() } ) } - } test("sarscov2 - [fastq1, fastq2], index, fasta, false") { @@ -111,7 +109,6 @@ nextflow_process { ).match() } ) } - } test("sarscov2 - [fastq1, fastq2], index, fasta, true") { @@ -143,7 +140,6 @@ nextflow_process { ).match() } ) } - } test("sarscov2 - [fastq1, fastq2], index, fasta, true - stub") { @@ -170,10 +166,8 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } - } diff --git a/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap b/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap index 74763935..06d854b0 100644 --- a/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap +++ b/modules/nf-core/bwamem2/mem/tests/main.nf.test.snap @@ -10,52 +10,25 @@ "bwamem2", "2.2.1" ] + ], + "versions_samtools": [ + [ + "BWAMEM2_MEM", + "samtools", + "1.22.1" + ] ] } ], + "timestamp": "2026-02-19T11:51:27.481278728", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-09T16:25:00.500092" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - [fastq1, fastq2], index, fasta, true - stub": { "content": [ { - "0": [ - - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - [ - { - "id": "test", - "single_end": false - }, - "test.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "5": [ - [ - "BWAMEM2_MEM", - "bwamem2", - "2.2.1" - ] - ], "bam": [ [ { @@ -89,14 +62,21 @@ "bwamem2", "2.2.1" ] + ], + "versions_samtools": [ + [ + "BWAMEM2_MEM", + "samtools", + "1.22.1" + ] ] } ], + "timestamp": "2026-02-19T11:54:06.902806102", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-09T16:25:22.004027" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - [fastq1, fastq2], index, fasta, true": { "content": [ @@ -109,14 +89,21 @@ "bwamem2", "2.2.1" ] + ], + "versions_samtools": [ + [ + "BWAMEM2_MEM", + "samtools", + "1.22.1" + ] ] } ], + "timestamp": "2026-02-19T11:51:40.483217643", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-09T16:25:14.131056" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - fastq, index, fasta, false": { "content": [ @@ -129,14 +116,21 @@ "bwamem2", "2.2.1" ] + ], + "versions_samtools": [ + [ + "BWAMEM2_MEM", + "samtools", + "1.22.1" + ] ] } ], + "timestamp": "2026-02-19T11:51:02.459481643", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-09T16:24:34.624533" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - fastq, index, fasta, true": { "content": [ @@ -149,13 +143,20 @@ "bwamem2", "2.2.1" ] + ], + "versions_samtools": [ + [ + "BWAMEM2_MEM", + "samtools", + "1.22.1" + ] ] } ], + "timestamp": "2026-02-19T11:51:15.170720681", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-09T16:24:47.191245" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 25c2a503..5376aea1 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,26 +1,21 @@ process MULTIQC { - tag "$meta.id" + tag "${meta.id}" 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' }" + 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(multiqc_files, stageAs: "?/*") - path(multiqc_config) - path(extra_multiqc_config) - path(multiqc_logo) - path(replace_names) - path(sample_names) + tuple val(meta), path(multiqc_files, stageAs: "?/*"), path(multiqc_config, stageAs: "?/*"), 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"'), emit: versions + tuple val(meta), path("*.html"), emit: report + tuple val(meta), path("*_data"), emit: data + tuple val(meta), path("*_plots"), emit: plots, optional: true // 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 + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions when: task.ext.when == null || task.ext.when @@ -28,8 +23,7 @@ process MULTIQC { 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 config = multiqc_config ? multiqc_config instanceof List ? "--config ${multiqc_config.join(' --config ')}" : "--config ${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}" : '' @@ -39,7 +33,6 @@ process MULTIQC { ${args} \\ ${config} \\ ${prefix} \\ - ${extra_config} \\ ${logo} \\ ${replace} \\ ${samples} \\ @@ -51,6 +44,7 @@ process MULTIQC { mkdir multiqc_data touch multiqc_data/.stub mkdir multiqc_plots + touch multiqc_plots/.stub touch multiqc_report.html """ } diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index 9fd34f37..ef434a9a 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,6 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into - a single report +description: Aggregate results from bioinformatics analyses across many samples + into a single report keywords: - QC - bioinformatics tools @@ -12,67 +12,81 @@ tools: 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"] + licence: + - "GPL-3.0-or-later" identifier: biotools:multiqc input: - - multiqc_files: - type: file - description: | - List of reports / files recognised 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": + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - multiqc_files: type: file - description: MultiQC report file - pattern: ".html" + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC ontologies: [] - data: - - "*_data": - type: directory - description: MultiQC data dir - pattern: "multiqc_data" - plots: - - "*_plots": + - multiqc_config: type: file - description: Plots created by MultiQC - pattern: "*_plots" + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + ontologies: + - edam: http://edamontology.org/format_3750 + - 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 + - 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 +output: + report: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*.html": + type: file + description: MultiQC report file + pattern: ".html" + ontologies: [] + data: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + plots: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_plots" + ontologies: [] versions: - - ${task.process}: type: string diff --git a/modules/nf-core/multiqc/multiqc.diff b/modules/nf-core/multiqc/multiqc.diff deleted file mode 100644 index f0991afe..00000000 --- a/modules/nf-core/multiqc/multiqc.diff +++ /dev/null @@ -1,27 +0,0 @@ -Changes in component 'nf-core/multiqc' -'modules/nf-core/multiqc/environment.yml' is unchanged -'modules/nf-core/multiqc/meta.yml' is unchanged -Changes in 'multiqc/main.nf': ---- modules/nf-core/multiqc/main.nf -+++ modules/nf-core/multiqc/main.nf -@@ -1,4 +1,5 @@ - process MULTIQC { -+ tag "$meta.id" - label 'process_single' - - conda "${moduleDir}/environment.yml" -@@ -7,7 +8,7 @@ - 'community.wave.seqera.io/library/multiqc:1.33--ee7739d47738383b' }" - - input: -- path multiqc_files, stageAs: "?/*" -+ tuple val(meta), path(multiqc_files, stageAs: "?/*") - path(multiqc_config) - path(extra_multiqc_config) - path(multiqc_logo) - -'modules/nf-core/multiqc/tests/main.nf.test.snap' is unchanged -'modules/nf-core/multiqc/tests/nextflow.config' is unchanged -'modules/nf-core/multiqc/tests/main.nf.test' is unchanged -'modules/nf-core/multiqc/tests/custom_prefix.config' is unchanged -************************************************************ diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index d1ae8b06..0e422eaa 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -15,25 +15,28 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { + assert process.success 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() } + { assert snapshot( + file(process.out.report[0][1]).name, + file(process.out.data[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") + }).match() } ) } - } test("sarscov2 single-end [fastqc] - custom prefix") { @@ -42,24 +45,28 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/custom_prefix.html" }, - { assert process.out.data[0] ==~ ".*/custom_prefix_data" } + { assert snapshot( + file(process.out.report[0][1]).name, + file(process.out.data[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") + }).match() } ) } - } test("sarscov2 single-end [fastqc] [config]") { @@ -67,22 +74,60 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true), + [], + [], + [] + ]) """ } } then { + assert process.success 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() } + { assert snapshot( + file(process.out.report[0][1]).name, + file(process.out.data[0][1]).name, + file(process.out.plots[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") + }).match() } + ) + } + } + + test("sarscov2 single-end [fastqc] [multiple configs]") { + + when { + process { + """ + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [ + file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true), + file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true) + ], + [], + [], + [] + ]) + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.report[0][1]).name, + file(process.out.data[0][1]).name, + file(process.out.plots[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") + }).match() } ) } } @@ -94,25 +139,23 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out.report.collect { file(it).getName() } + - process.out.data.collect { file(it).getName() } + - process.out.plots.collect { file(it).getName() } + - process.out.findAll { key, val -> key.startsWith("versions")} ).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index d72d35b7..c022701f 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,6 +1,9 @@ { - "sarscov2 single-end [fastqc]": { + "sarscov2 single-end [fastqc] [multiple configs]": { "content": [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", { "versions": [ [ @@ -13,35 +16,81 @@ ], "meta": { "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nextflow": "25.10.4" + }, + "timestamp": "2026-02-26T20:21:35.851707" + }, + "sarscov2 single-end [fastqc]": { + "content": [ + "multiqc_report.html", + "multiqc_data", + { + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" }, - "timestamp": "2025-12-09T10:10:43.020315838" + "timestamp": "2026-02-26T15:10:36.019680076" }, "sarscov2 single-end [fastqc] - stub": { "content": [ - [ - "multiqc_report.html", - "multiqc_data", - "multiqc_plots", - { - "versions": [ + { + "data": [ + [ + { + "id": "FASTQC" + }, [ - "MULTIQC", - "multiqc", - "1.33" + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" ] ] - } - ] + ], + "plots": [ + [ + { + "id": "FASTQC" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "report": [ + [ + { + "id": "FASTQC" + }, + "multiqc_report.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } ], "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nf-test": "0.9.4", + "nextflow": "25.10.4" }, - "timestamp": "2025-12-09T10:11:14.131950776" + "timestamp": "2026-02-26T15:14:39.789193051" }, "sarscov2 single-end [fastqc] [config]": { "content": [ + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", { "versions": [ [ @@ -53,9 +102,29 @@ } ], "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + }, + "timestamp": "2026-02-26T15:21:29.116129274" + }, + "sarscov2 single-end [fastqc] - custom prefix": { + "content": [ + "custom_prefix.html", + "custom_prefix_data", + { + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" }, - "timestamp": "2025-12-09T10:11:07.15692209" + "timestamp": "2026-02-26T15:10:43.419877592" } } \ No newline at end of file diff --git a/modules/nf-core/multiqcsav/environment.yml b/modules/nf-core/multiqcsav/environment.yml new file mode 100644 index 00000000..092076ff --- /dev/null +++ b/modules/nf-core/multiqcsav/environment.yml @@ -0,0 +1,13 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + # renovate: datasource=conda depName=bioconda/multiqc + - bioconda::multiqc=1.33 + # renovate: datasource=conda depName=bioconda/multiqc_sav + - bioconda::multiqc_sav=0.2.0 + - pip=25.3 + - pip: + - interop==1.9.0 diff --git a/modules/nf-core/multiqcsav/main.nf b/modules/nf-core/multiqcsav/main.nf new file mode 100644 index 00000000..833ad6df --- /dev/null +++ b/modules/nf-core/multiqcsav/main.nf @@ -0,0 +1,53 @@ +process MULTIQCSAV { + tag "${meta.id}" + 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'}" + + 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) + + output: + tuple val(meta), path("*.html"), emit: report + tuple val(meta), path("*_data"), emit: data + tuple val(meta), path("*_plots"), emit: plots, optional: true + // 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 + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions + tuple val("${task.process}"), val('multiqcsav'), eval('python -c "import multiqc_sav; print(multiqc_sav.__version__)"'), emit: versions_multiqcsav + tuple val("${task.process}"), val('interop'), eval('python -c "import interop; print(interop.__version__)"'), emit: versions_interop + + 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 ? multiqc_config instanceof List ? "--config ${multiqc_config.join(' --config ')}" : "--config ${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}" : '' + """ + export TMPDIR="\$PWD/tmp" + multiqc \\ + --force \\ + ${args} \\ + ${config} \\ + ${prefix} \\ + ${logo} \\ + ${replace} \\ + ${samples} \\ + . + """ + + stub: + """ + mkdir multiqc_data + touch multiqc_data/.stub + mkdir multiqc_plots + touch multiqc_plots/.stub + touch multiqc_report.html + """ +} diff --git a/modules/nf-core/multiqcsav/meta.yml b/modules/nf-core/multiqcsav/meta.yml new file mode 100644 index 00000000..86545841 --- /dev/null +++ b/modules/nf-core/multiqcsav/meta.yml @@ -0,0 +1,139 @@ +name: multiqcsav +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 ] + - xml: + type: file + description: xml files from an Illumina sequencing run + pattern: "*.xml" + ontologies: + - edam: http://edamontology.org/format_2332 + - interop_bin: + type: file + description: Illumina InterOp binary files + pattern: "InterOp/*.bin" + ontologies: + - edam: http://edamontology.org/format_2333 + - extra_multiqc_files: + type: file + description: | + List of reports / files recognised 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 + - 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 + - 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 +output: + report: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*.html": + type: file + description: MultiQC report file + pattern: ".html" + ontologies: [] + data: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + plots: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_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 + versions_interop: + - - ${task.process}: + type: string + description: The process the versions were collected from + - interop: + type: string + description: The tool name + - python -c "import interop; print(interop.__version__)": + type: eval + description: The expression to obtain the version of the tool + versions_multiqcsav: + - - ${task.process}: + type: string + description: The process the versions were collected from + - multiqcsav: + type: string + description: The name of the tool + - python -c "import multiqc_sav; print(multiqc_sav.__version__)": + type: eval + description: The expression to obtain the version of the tool +authors: + - "@matthdsm" + - "@delfiterradas" +maintainers: + - "@matthdsm" diff --git a/modules/nf-core/multiqcsav/tests/main.nf.test b/modules/nf-core/multiqcsav/tests/main.nf.test new file mode 100644 index 00000000..3f48121e --- /dev/null +++ b/modules/nf-core/multiqcsav/tests/main.nf.test @@ -0,0 +1,136 @@ +nextflow_process { + + name "Test Process MULTIQCSAV" + script "../main.nf" + process "MULTIQCSAV" + + tag "modules" + tag "modules_nfcore" + tag "untar" + tag "multiqcsav" + + 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.fileName.toString() == 'RunInfo.xml') { + xml << file + } + } + + def interop = [] + untar.eachFileRecurse { file -> + if (file.parent.name == 'InterOp' && file.fileName.toString().endsWith(".bin")) { + interop << file + } + } + + return [ + meta, + xml, + interop, + [], + [], + [], + [], + [] + ] + } + + input[0] = ch_sav_in + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.report[0][1]).name, + file(process.out.data[0][1]).name, + process.out.findAll { key, val -> key.startsWith("versions") + }).match() } + ) + } + } + + test("NovaSeq6000 - stub") { + + options "-stub" + + 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.fileName.toString() == 'RunInfo.xml') { + xml << file + } + } + + def interop = [] + untar.eachFileRecurse { file -> + if (file.parent.name == 'InterOp' && file.fileName.toString().endsWith(".bin")) { + interop << file + } + } + + return [ + meta, + xml, + interop, + [], + [], + [], + [], + [] + ] + } + + input[0] = ch_sav_in + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } +} diff --git a/modules/nf-core/multiqcsav/tests/main.nf.test.snap b/modules/nf-core/multiqcsav/tests/main.nf.test.snap new file mode 100644 index 00000000..3f3783a1 --- /dev/null +++ b/modules/nf-core/multiqcsav/tests/main.nf.test.snap @@ -0,0 +1,96 @@ +{ + "NovaSeq6000": { + "content": [ + "multiqc_report.html", + "multiqc_data", + { + "versions": [ + [ + "MULTIQCSAV", + "multiqc", + "1.33" + ] + ], + "versions_interop": [ + [ + "MULTIQCSAV", + "interop", + "1.9.0" + ] + ], + "versions_multiqcsav": [ + [ + "MULTIQCSAV", + "multiqcsav", + "0.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + }, + "timestamp": "2026-02-26T15:17:26.065765698" + }, + "NovaSeq6000 - stub": { + "content": [ + { + "data": [ + [ + { + "id": "NovaSeq6000" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "plots": [ + [ + { + "id": "NovaSeq6000" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "report": [ + [ + { + "id": "NovaSeq6000" + }, + "multiqc_report.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + [ + "MULTIQCSAV", + "multiqc", + "1.33" + ] + ], + "versions_interop": [ + [ + "MULTIQCSAV", + "interop", + "1.9.0" + ] + ], + "versions_multiqcsav": [ + [ + "MULTIQCSAV", + "multiqcsav", + "0.2.0" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + }, + "timestamp": "2026-02-26T15:18:42.648653899" + } +} \ No newline at end of file diff --git a/modules/nf-core/picard/collecthsmetrics/main.nf b/modules/nf-core/picard/collecthsmetrics/main.nf index 22d95d57..2b9b7588 100644 --- a/modules/nf-core/picard/collecthsmetrics/main.nf +++ b/modules/nf-core/picard/collecthsmetrics/main.nf @@ -1,18 +1,18 @@ process PICARD_COLLECTHSMETRICS { - tag "$meta.id" + tag "${meta.id}" 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/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' : - 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' + : 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6'}" input: tuple val(meta), path(bam), path(bai), path(bait_intervals, stageAs: "bait/*"), path(target_intervals, stageAs: "target/*") ,path(fasta) ,path(fai) ,path(dict) output: - tuple val(meta), path("*_metrics") , emit: metrics - tuple val("${task.process}"), val('picard'), eval("picard CollectHsMetrics --version 2>&1 | sed -n 's/^Version:*//p'"), topic: versions, emit: versions_picard + tuple val(meta), path("*_metrics"), emit: metrics + tuple val("${task.process}"), val('picard'), eval("picard CollectHsMetrics --version 2>&1 | sed -n 's/.*Version://p'"), topic: versions, emit: versions_picard when: task.ext.when == null || task.ext.when @@ -24,40 +24,38 @@ process PICARD_COLLECTHSMETRICS { def avail_mem = 3072 if (!task.memory) { - log.info '[Picard CollectHsMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.' - } else { - avail_mem = (task.memory.mega*0.8).intValue() + log.info('[Picard CollectHsMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() } def bait_interval_list = bait_intervals def bait_intervallist_cmd = "" - if (bait_intervals =~ /.(bed|bed.gz)$/){ + if (bait_intervals =~ /.(bed|bed.gz)$/) { bait_interval_list = bait_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." } def target_interval_list = target_intervals def target_intervallist_cmd = "" - if (target_intervals =~ /.(bed|bed.gz)$/){ + if (target_intervals =~ /.(bed|bed.gz)$/) { target_interval_list = target_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." } - - """ export TMP=\$PWD - - $bait_intervallist_cmd - $target_intervallist_cmd + ${bait_intervallist_cmd} + ${target_intervallist_cmd} picard \\ -Xmx${avail_mem}M \\ CollectHsMetrics \\ - $args \\ - $reference \\ - --BAIT_INTERVALS $bait_interval_list \\ - --TARGET_INTERVALS $target_interval_list \\ - --INPUT $bam \\ + ${args} \\ + ${reference} \\ + --BAIT_INTERVALS ${bait_interval_list} \\ + --TARGET_INTERVALS ${target_interval_list} \\ + --INPUT ${bam} \\ --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics \\ --TMP_DIR . """ diff --git a/modules/nf-core/picard/collecthsmetrics/meta.yml b/modules/nf-core/picard/collecthsmetrics/meta.yml index a21aa6ec..89bc502c 100644 --- a/modules/nf-core/picard/collecthsmetrics/meta.yml +++ b/modules/nf-core/picard/collecthsmetrics/meta.yml @@ -106,7 +106,7 @@ output: - picard: type: string description: The tool name - - "picard CollectHsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + - "picard CollectHsMetrics --version 2>&1 | sed -n 's/.*Version://p'": type: string description: The command used to generate the version of the tool @@ -118,7 +118,7 @@ topics: - picard: type: string description: The tool name - - "picard CollectHsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + - "picard CollectHsMetrics --version 2>&1 | sed -n 's/.*Version://p'": type: string description: The command used to generate the version of the tool authors: diff --git a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff index f4bf1eda..f9b0281a 100644 --- a/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff +++ b/modules/nf-core/picard/collecthsmetrics/picard-collecthsmetrics.diff @@ -5,18 +5,18 @@ Changes in 'picard/collecthsmetrics/main.nf': --- modules/nf-core/picard/collecthsmetrics/main.nf +++ modules/nf-core/picard/collecthsmetrics/main.nf @@ -8,11 +8,7 @@ - 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" + : 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6'}" input: - tuple val(meta), path(bam), path(bai), path(bait_intervals, stageAs: "baits/*"), path(target_intervals, stageAs: 'targets/*') - tuple val(meta2), path(ref) - tuple val(meta3), path(ref_fai) - tuple val(meta4), path(ref_dict) -- tuple val(meta5), path(ref_gzi) // ref_gzi only required if reference is gzipped +- tuple val(meta5), path(ref_gzi) + tuple val(meta), path(bam), path(bai), path(bait_intervals, stageAs: "bait/*"), path(target_intervals, stageAs: "target/*") ,path(fasta) ,path(fai) ,path(dict) output: - tuple val(meta), path("*_metrics") , emit: metrics + tuple val(meta), path("*_metrics"), emit: metrics @@ -24,7 +20,7 @@ script: def args = task.ext.args ?: '' @@ -26,9 +26,9 @@ Changes in 'picard/collecthsmetrics/main.nf': def avail_mem = 3072 if (!task.memory) { -@@ -37,18 +33,19 @@ +@@ -38,16 +34,17 @@ def bait_intervallist_cmd = "" - if (bait_intervals =~ /.(bed|bed.gz)$/){ + if (bait_intervals =~ /.(bed|bed.gz)$/) { bait_interval_list = bait_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") - bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." + bait_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${bait_intervals} --OUTPUT ${bait_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." @@ -36,24 +36,21 @@ Changes in 'picard/collecthsmetrics/main.nf': def target_interval_list = target_intervals def target_intervallist_cmd = "" - if (target_intervals =~ /.(bed|bed.gz)$/){ + if (target_intervals =~ /.(bed|bed.gz)$/) { target_interval_list = target_intervals.toString().replaceAll(/.(bed|bed.gz)$/, ".interval_list") - target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${ref_dict} --TMP_DIR ." + target_intervallist_cmd = "picard -Xmx${avail_mem}M BedToIntervalList --INPUT ${target_intervals} --OUTPUT ${target_interval_list} --SEQUENCE_DICTIONARY ${dict} --TMP_DIR ." } - - """ + export TMP=\$PWD + ${bait_intervallist_cmd} + ${target_intervallist_cmd} - $bait_intervallist_cmd - $target_intervallist_cmd -@@ -61,8 +58,8 @@ - --BAIT_INTERVALS $bait_interval_list \\ - --TARGET_INTERVALS $target_interval_list \\ - --INPUT $bam \\ +@@ -59,7 +56,8 @@ + --BAIT_INTERVALS ${bait_interval_list} \\ + --TARGET_INTERVALS ${target_interval_list} \\ + --INPUT ${bam} \\ - --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics -- + --OUTPUT ${prefix}.CollectHsMetrics.coverage_metrics \\ + --TMP_DIR . """ diff --git a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test index 07a9ccf4..d7366111 100644 --- a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test +++ b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test @@ -40,11 +40,9 @@ nextflow_process { size, lines, process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } - } test("sarscov2 - bam - gzippedfa") { @@ -78,17 +76,13 @@ nextflow_process { size, lines, process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } - } test("sarscov2 - bam - stub") { - options "-stub" - when { process { """ @@ -110,10 +104,9 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } test("sarscov2 - bam - nofasta") { @@ -147,11 +140,9 @@ nextflow_process { size, lines, process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } - } test("sarscov2 - bam - bed") { @@ -186,11 +177,9 @@ nextflow_process { size, lines, process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } - } test("sarscov2 - bam - samebed") { @@ -225,10 +214,8 @@ nextflow_process { size, lines, process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } - } } diff --git a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap index 74d9441f..43385314 100644 --- a/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collecthsmetrics/tests/main.nf.test.snap @@ -115,31 +115,15 @@ ] } ], + "timestamp": "2026-01-05T17:03:29.566021877", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-05T17:03:29.566021877" + } }, "sarscov2 - bam - stub": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.CollectHsMetrics.coverage_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - "PICARD_COLLECTHSMETRICS", - "picard", - "3.4.0" - ] - ], "metrics": [ [ { @@ -158,11 +142,11 @@ ] } ], + "timestamp": "2026-02-19T17:36:03.822502867", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-01-05T17:03:13.333276975" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "sarscov2 - bam - gzippedfa": { "content": [ @@ -280,11 +264,11 @@ ] } ], + "timestamp": "2026-01-05T17:03:04.382110367", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-05T17:03:04.382110367" + } }, "sarscov2 - bam - samebed": { "content": [ @@ -402,11 +386,11 @@ ] } ], + "timestamp": "2026-01-05T17:13:22.872920293", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-05T17:13:22.872920293" + } }, "sarscov2 - bam": { "content": [ @@ -524,11 +508,11 @@ ] } ], + "timestamp": "2026-01-05T17:02:47.615784738", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-05T17:02:47.615784738" + } }, "sarscov2 - bam - bed": { "content": [ @@ -646,10 +630,10 @@ ] } ], + "timestamp": "2026-01-05T17:13:02.812282052", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-01-05T17:13:02.812282052" + } } } \ No newline at end of file diff --git a/modules/nf-core/picard/collectmultiplemetrics/main.nf b/modules/nf-core/picard/collectmultiplemetrics/main.nf index 11b00464..59842bdd 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/main.nf +++ b/modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -1,19 +1,19 @@ process PICARD_COLLECTMULTIPLEMETRICS { - tag "$meta.id" + tag "${meta.id}" 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/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' : - 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' + : 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6'}" input: tuple val(meta) , path(bam), path(bai), path(intervals), path(fasta) ,path(fai), path(dict) output: tuple val(meta), path("*_metrics"), emit: metrics - tuple val(meta), path("*.pdf") , emit: pdf, optional: true - tuple val("${task.process}"), val('picard'), eval("picard CollectMultipleMetrics --version 2>&1 | sed -n 's/^Version:*//p'"), topic: versions, emit: versions_picard + tuple val(meta), path("*.pdf"), emit: pdf, optional: true + tuple val("${task.process}"), val('picard'), eval("picard CollectMultipleMetrics --version 2>&1 | sed -n 's/.*Version://p'"), topic: versions, emit: versions_picard when: task.ext.when == null || task.ext.when @@ -25,21 +25,22 @@ process PICARD_COLLECTMULTIPLEMETRICS { def reference_cmd = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" def avail_mem = 3072 if (!task.memory) { - log.info '[Picard CollectMultipleMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.' - } else { - avail_mem = (task.memory.mega*0.8).intValue() + log.info('[Picard CollectMultipleMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() } """ export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectMultipleMetrics \\ - $args \\ - --INPUT $bam \\ + ${args} \\ + --INPUT ${bam} \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ --TMP_DIR . \\ - $reference_cmd \\ - $intervals_cmd + ${reference_cmd} \\ + ${intervals_cmd} """ stub: diff --git a/modules/nf-core/picard/collectmultiplemetrics/meta.yml b/modules/nf-core/picard/collectmultiplemetrics/meta.yml index 1ea47244..213d600b 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/meta.yml +++ b/modules/nf-core/picard/collectmultiplemetrics/meta.yml @@ -81,7 +81,7 @@ output: - picard: type: string description: The tool name - - "picard CollectMultipleMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + - "picard CollectMultipleMetrics --version 2>&1 | sed -n 's/.*Version://p'": type: string description: The command used to generate the version of the tool @@ -93,7 +93,7 @@ topics: - picard: type: string description: The tool name - - "picard CollectMultipleMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + - "picard CollectMultipleMetrics --version 2>&1 | sed -n 's/.*Version://p'": type: string description: The command used to generate the version of the tool diff --git a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff index 1d7cbf60..780c0862 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff +++ b/modules/nf-core/picard/collectmultiplemetrics/picard-collectmultiplemetrics.diff @@ -5,10 +5,10 @@ Changes in 'picard/collectmultiplemetrics/main.nf': --- modules/nf-core/picard/collectmultiplemetrics/main.nf +++ modules/nf-core/picard/collectmultiplemetrics/main.nf @@ -8,9 +8,7 @@ - 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" + : 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6'}" input: -- tuple val(meta) , path(bam), path(bai) +- tuple val(meta), path(bam), path(bai) - tuple val(meta2), path(fasta) - tuple val(meta3), path(fai) + tuple val(meta) , path(bam), path(bai), path(intervals), path(fasta) ,path(fai), path(dict) @@ -24,33 +24,25 @@ Changes in 'picard/collectmultiplemetrics/main.nf': + def reference_cmd = fasta ? "--REFERENCE_SEQUENCE ${fasta}" : "" def avail_mem = 3072 if (!task.memory) { - log.info '[Picard CollectMultipleMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.' -@@ -31,14 +30,16 @@ - avail_mem = (task.memory.mega*0.8).intValue() + log.info('[Picard CollectMultipleMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') +@@ -32,13 +31,16 @@ + avail_mem = (task.memory.mega * 0.8).intValue() } """ + export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectMultipleMetrics \\ - $args \\ - --INPUT $bam \\ + ${args} \\ + --INPUT ${bam} \\ --OUTPUT ${prefix}.CollectMultipleMetrics \\ -- $reference -- +- ${reference} + --TMP_DIR . \\ -+ $reference_cmd \\ -+ $intervals_cmd ++ ${reference_cmd} \\ ++ ${intervals_cmd} """ stub: -@@ -54,6 +55,5 @@ - touch ${prefix}.CollectMultipleMetrics.quality_by_cycle.pdf - touch ${prefix}.CollectMultipleMetrics.insert_size_histogram.pdf - touch ${prefix}.CollectMultipleMetrics.quality_distribution_metrics -- - """ - } 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test index 08456941..0037acab 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test +++ b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test @@ -16,16 +16,15 @@ nextflow_process { process { """ input[0] = [ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ] - input[1] = [ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - input[2] = [[id:'genome'],[]] - + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [[id:'genome'],[]] """ } } @@ -37,8 +36,7 @@ nextflow_process { process.out.metrics[0][1].collect { file(it).name }.toSorted(), process.out.pdf[0][1].collect { file(it).name }.toSorted(), process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } } @@ -49,13 +47,12 @@ nextflow_process { process { """ input[0] = [ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ] - input[1] = [[id:'genome'],[]] + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) + ] + input[1] = [[id:'genome'],[]] input[2] = [[id:'genome'],[]] - """ } } @@ -67,8 +64,7 @@ nextflow_process { process.out.metrics[0][1].collect { file(it).name }.toSorted(), process.out.pdf[0][1].collect { file(it).name }.toSorted(), process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } } @@ -79,19 +75,18 @@ nextflow_process { process { """ input[0] = [ - [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) - ] - input[1] = [ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - input[2] = [ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) - ] - + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] """ } } @@ -103,10 +98,89 @@ nextflow_process { process.out.metrics[0][1].collect { file(it).name }.toSorted(), process.out.pdf[0][1].collect { file(it).name }.toSorted(), process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} + ) + } + } + + test("test-picard-collectmultiplemetrics - stub") { + options "-stub" + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [[id:'genome'],[]] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + test("test-picard-collectmultiplemetrics-nofasta - stub") { + options "-stub" + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) + ] + input[1] = [[id:'genome'],[]] + input[2] = [[id:'genome'],[]] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } ) } } + test("test-picard-collectmultiplemetrics-cram - stub") { + options "-stub" + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true) + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } } diff --git a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap index 1acf3776..393ed100 100644 --- a/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collectmultiplemetrics/tests/main.nf.test.snap @@ -25,11 +25,107 @@ ] } ], + "timestamp": "2026-02-02T10:22:21.230301646", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-02-02T10:22:21.230301646" + } + }, + "test-picard-collectmultiplemetrics - stub": { + "content": [ + { + "metrics": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.alignment_summary_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.insert_size_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_by_cycle_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_distribution_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "pdf": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.insert_size_histogram.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_by_cycle.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_distribution.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.read_length_histogram.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions_picard": [ + [ + "PICARD_COLLECTMULTIPLEMETRICS", + "picard", + "3.4.0" + ] + ] + } + ], + "timestamp": "2026-02-20T10:32:38.701455244", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "test-picard-collectmultiplemetrics-nofasta - stub": { + "content": [ + { + "metrics": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.alignment_summary_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.insert_size_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_by_cycle_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_distribution_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "pdf": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.insert_size_histogram.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_by_cycle.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_distribution.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.read_length_histogram.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions_picard": [ + [ + "PICARD_COLLECTMULTIPLEMETRICS", + "picard", + "3.4.0" + ] + ] + } + ], + "timestamp": "2026-02-20T10:32:48.923918624", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test-picard-collectmultiplemetrics-cram": { "content": [ @@ -57,11 +153,11 @@ ] } ], + "timestamp": "2026-02-02T10:23:52.23446844", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-02-02T10:23:52.23446844" + } }, "test-picard-collectmultiplemetrics-nofasta": { "content": [ @@ -89,10 +185,58 @@ ] } ], + "timestamp": "2026-02-02T10:23:27.387621193", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.2" - }, - "timestamp": "2026-02-02T10:23:27.387621193" + } + }, + "test-picard-collectmultiplemetrics-cram - stub": { + "content": [ + { + "metrics": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.alignment_summary_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.base_distribution_by_cycle_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.insert_size_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_by_cycle_metrics:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_distribution_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "pdf": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.CollectMultipleMetrics.base_distribution_by_cycle.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.insert_size_histogram.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_by_cycle.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.quality_distribution.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "test.CollectMultipleMetrics.read_length_histogram.pdf:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions_picard": [ + [ + "PICARD_COLLECTMULTIPLEMETRICS", + "picard", + "3.4.0" + ] + ] + } + ], + "timestamp": "2026-02-20T10:32:57.11686549", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/picard/collectwgsmetrics/main.nf b/modules/nf-core/picard/collectwgsmetrics/main.nf index b8d1ee42..8048b2b6 100644 --- a/modules/nf-core/picard/collectwgsmetrics/main.nf +++ b/modules/nf-core/picard/collectwgsmetrics/main.nf @@ -1,11 +1,11 @@ process PICARD_COLLECTWGSMETRICS { - tag "$meta.id" + tag "${meta.id}" 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/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' : - 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/08/0861295baa7c01fc593a9da94e82b44a729dcaf8da92be8e565da109aa549b25/data' + : 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6'}" input: tuple val(meta), path(bam), path(bai) ,path(fasta) ,path(fai), path(dict) @@ -13,32 +13,33 @@ process PICARD_COLLECTWGSMETRICS { output: tuple val(meta), path("*_metrics"), emit: metrics - tuple val("${task.process}"), val('picard'), eval("picard CollectWgsMetrics --version 2>&1 | sed -n 's/^Version:*//p'"), topic: versions, emit: versions_picard + tuple val("${task.process}"), val('picard'), eval("picard CollectWgsMetrics --version 2>&1 | sed -n 's/.*Version://p'"), topic: versions, emit: versions_picard when: task.ext.when == null || task.ext.when script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" def avail_mem = 3072 - def interval = intervallist ? "--INTERVALS ${intervallist}" : '' + def interval = intervallist ? "--INTERVALS ${intervallist}" : '' if (!task.memory) { - log.info '[Picard CollectWgsMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.' - } else { - avail_mem = (task.memory.mega*0.8).intValue() + log.info('[Picard CollectWgsMetrics] Available memory not known - defaulting to 3GB. Specify process memory requirements to change this.') + } + else { + avail_mem = (task.memory.mega * 0.8).intValue() } """ export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectWgsMetrics \\ - $args \\ - --INPUT $bam \\ + ${args} \\ + --INPUT ${bam} \\ --OUTPUT ${prefix}.CollectWgsMetrics.coverage_metrics \\ --REFERENCE_SEQUENCE ${fasta} \\ --TMP_DIR . \\ - $interval + ${interval} """ @@ -46,6 +47,5 @@ process PICARD_COLLECTWGSMETRICS { def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.CollectWgsMetrics.coverage_metrics - """ } diff --git a/modules/nf-core/picard/collectwgsmetrics/meta.yml b/modules/nf-core/picard/collectwgsmetrics/meta.yml index c59811d5..c5afe2e7 100644 --- a/modules/nf-core/picard/collectwgsmetrics/meta.yml +++ b/modules/nf-core/picard/collectwgsmetrics/meta.yml @@ -76,10 +76,9 @@ output: - picard: type: string description: The tool name - - "picard CollectWgsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + - "picard CollectWgsMetrics --version 2>&1 | sed -n 's/.*Version://p'": type: string description: The command used to generate the version of the tool - topics: versions: - - ${task.process}: @@ -88,7 +87,7 @@ topics: - picard: type: string description: The tool name - - "picard CollectWgsMetrics --version 2>&1 | sed -n 's/^Version:*//p'": + - "picard CollectWgsMetrics --version 2>&1 | sed -n 's/.*Version://p'": type: string description: The command used to generate the version of the tool authors: diff --git a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff index c1389e4e..5de262d0 100644 --- a/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff +++ b/modules/nf-core/picard/collectwgsmetrics/picard-collectwgsmetrics.diff @@ -4,33 +4,37 @@ Changes in component 'nf-core/picard/collectwgsmetrics' Changes in 'picard/collectwgsmetrics/main.nf': --- modules/nf-core/picard/collectwgsmetrics/main.nf +++ modules/nf-core/picard/collectwgsmetrics/main.nf -@@ -8,9 +8,7 @@ - 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6' }" +@@ -8,10 +8,8 @@ + : 'community.wave.seqera.io/library/picard:3.4.0--e9963040df0a9bf6'}" input: - tuple val(meta), path(bam), path(bai) - tuple val(meta2), path(fasta) - tuple val(meta3), path(fai) +- path intervallist + tuple val(meta), path(bam), path(bai) ,path(fasta) ,path(fai), path(dict) - path intervallist ++ path intervallist output: -@@ -31,6 +29,7 @@ - avail_mem = (task.memory.mega*0.8).intValue() + tuple val(meta), path("*_metrics"), emit: metrics +@@ -32,6 +30,7 @@ + avail_mem = (task.memory.mega * 0.8).intValue() } """ + export TMP=\$PWD picard \\ -Xmx${avail_mem}M \\ CollectWgsMetrics \\ -@@ -38,6 +37,7 @@ - --INPUT $bam \\ +@@ -39,7 +38,9 @@ + --INPUT ${bam} \\ --OUTPUT ${prefix}.CollectWgsMetrics.coverage_metrics \\ --REFERENCE_SEQUENCE ${fasta} \\ + --TMP_DIR . \\ - $interval - + ${interval} ++ """ + + stub: 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap' is unchanged 'modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test' is unchanged diff --git a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test index d6a60e6b..1bda5980 100644 --- a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test +++ b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test @@ -16,19 +16,18 @@ nextflow_process { process { """ input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), - ] - input[1] = [ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - input[2] = [ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) - ] - input[3] = [] - + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ] + input[3] = [] """ } } @@ -37,10 +36,9 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - file(process.out.metrics[0][1]).text.contains('coverage high_quality_coverage_count'), + file(process.out.metrics[0][1]).text.contains('coverage high_quality_coverage_count'), process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } } @@ -51,19 +49,18 @@ nextflow_process { process { """ input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), - [] - ] - input[1] = [ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - input[2] = [ - [id:'genome'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) - ] - input[3] = file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/picard/baits.interval_list', checkIfExists: true) - + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + [] + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ] + input[3] = file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/picard/baits.interval_list', checkIfExists: true) """ } } @@ -72,12 +69,70 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - file(process.out.metrics[0][1]).text.contains('coverage high_quality_coverage_count'), + file(process.out.metrics[0][1]).text.contains('coverage high_quality_coverage_count'), process.out.findAll { key, val -> key.startsWith("versions") } - ).match() - } + ).match()} ) } } + test("test-picard-collectwgsmetrics - stub") { + options "-stub" + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true), + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ] + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + test("test-picard-collectwgsmetrics-with-interval - stub") { + options "-stub" + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + [] + ] + input[1] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + input[2] = [ + [id:'genome'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) + ] + input[3] = file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/picard/baits.interval_list', checkIfExists: true) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } } diff --git a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap index 375c2ef9..79f1145f 100644 --- a/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap +++ b/modules/nf-core/picard/collectwgsmetrics/tests/main.nf.test.snap @@ -1,7 +1,34 @@ { + "test-picard-collectwgsmetrics-with-interval - stub": { + "content": [ + { + "metrics": [ + [ + { + "id": "test", + "single_end": false + }, + "test.CollectWgsMetrics.coverage_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_picard": [ + [ + "PICARD_COLLECTWGSMETRICS", + "picard", + "3.4.0" + ] + ] + } + ], + "timestamp": "2026-02-20T10:35:04.636691319", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, "test-picard-collectwgsmetrics-with-interval": { "content": [ - true, + false, { "versions_picard": [ [ @@ -12,15 +39,42 @@ ] } ], + "timestamp": "2026-02-20T10:34:45.059411647", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "test-picard-collectwgsmetrics - stub": { + "content": [ + { + "metrics": [ + [ + { + "id": "test", + "single_end": false + }, + "test.CollectWgsMetrics.coverage_metrics:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_picard": [ + [ + "PICARD_COLLECTWGSMETRICS", + "picard", + "3.4.0" + ] + ] + } + ], + "timestamp": "2026-02-20T10:34:54.347278951", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-02-02T14:52:55.091876466" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test-picard-collectwgsmetrics": { "content": [ - true, + false, { "versions_picard": [ [ @@ -31,10 +85,10 @@ ] } ], + "timestamp": "2026-02-20T10:34:25.744978033", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.2" - }, - "timestamp": "2026-02-02T14:52:11.334274481" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/star/align/meta.yml b/modules/nf-core/star/align/meta.yml index d1441570..3df5cfe7 100644 --- a/modules/nf-core/star/align/meta.yml +++ b/modules/nf-core/star/align/meta.yml @@ -49,12 +49,6 @@ input: - star_ignore_sjdbgtf: type: boolean description: Ignore annotation GTF file - - seq_platform: - type: string - description: Sequencing platform - - seq_center: - type: string - description: Sequencing center output: log_final: - - meta: diff --git a/modules/nf-core/star/align/star-align.diff b/modules/nf-core/star/align/star-align.diff index 0c9c6621..07d96b66 100644 --- a/modules/nf-core/star/align/star-align.diff +++ b/modules/nf-core/star/align/star-align.diff @@ -4,7 +4,7 @@ Changes in component 'nf-core/star/align' Changes in 'star/align/main.nf': --- modules/nf-core/star/align/main.nf +++ modules/nf-core/star/align/main.nf -@@ -8,10 +8,7 @@ +@@ -8,10 +8,9 @@ 'community.wave.seqera.io/library/htslib_samtools_star_gawk:ae438e9a604351a4' }" input: @@ -13,18 +13,24 @@ Changes in 'star/align/main.nf': - tuple val(meta3), path(gtf) - val star_ignore_sjdbgtf + tuple val(meta), path(reads, stageAs: "input*/*"), path(index), path(gtf) - val seq_platform - val seq_center ++ val seq_platform ++ val seq_center -@@ -46,7 +43,7 @@ + output: + tuple val(meta), path('*Log.final.out') , emit: log_final +@@ -44,8 +43,10 @@ def reads1 = [] def reads2 = [] meta.single_end ? [reads].flatten().each{ read -> reads1 << read} : reads.eachWithIndex{ v, ix -> ( ix & 1 ? reads2 : reads1) << v } - def ignore_gtf = star_ignore_sjdbgtf ? '' : "--sjdbGTFfile $gtf" +- attrRG = args.contains("--outSAMattrRGline") ? "" : "--outSAMattrRGline 'ID:$prefix' 'SM:$prefix'" + def ignore_gtf = gtf ? "--sjdbGTFfile $gtf" : '' - def seq_platform_arg = seq_platform ? "'PL:$seq_platform'" : "" - def seq_center_arg = seq_center ? "'CN:$seq_center'" : "" - attrRG = args.contains("--outSAMattrRGline") ? "" : "--outSAMattrRGline 'ID:$prefix' $seq_center_arg 'SM:$prefix' $seq_platform_arg" ++ def seq_platform_arg = seq_platform ? "'PL:$seq_platform'" : "" ++ def seq_center_arg = seq_center ? "'CN:$seq_center'" : "" ++ attrRG = args.contains("--outSAMattrRGline") ? "" : "--outSAMattrRGline 'ID:$prefix' $seq_center_arg 'SM:$prefix' $seq_platform_arg" + def out_sam_type = (args.contains('--outSAMtype')) ? '' : '--outSAMtype BAM Unsorted' + mv_unsorted_bam = (args.contains('--outSAMtype BAM Unsorted SortedByCoordinate')) ? "mv ${prefix}.Aligned.out.bam ${prefix}.Aligned.unsort.out.bam" : '' + """ 'modules/nf-core/star/align/tests/main.nf.test.snap' is unchanged 'modules/nf-core/star/align/tests/nextflow.arriba.config' is unchanged diff --git a/modules/nf-core/star/align/tests/main.nf.test b/modules/nf-core/star/align/tests/main.nf.test index da0cc07e..d7c6ccbd 100644 --- a/modules/nf-core/star/align/tests/main.nf.test +++ b/modules/nf-core/star/align/tests/main.nf.test @@ -43,8 +43,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -108,8 +106,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -173,8 +169,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -237,8 +231,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -304,8 +296,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -367,8 +357,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -419,8 +407,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -471,8 +457,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -523,8 +507,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } @@ -577,8 +559,6 @@ nextflow_process { [ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.gtf', checkIfExists: true) ] ]) input[3] = false - input[4] = 'illumina' - input[5] = false """ } } diff --git a/nextflow.config b/nextflow.config index a5ceb27d..c3e162e8 100644 --- a/nextflow.config +++ b/nextflow.config @@ -14,6 +14,7 @@ params { // References genome = null + genomes = [:] igenomes_base = '/references/' igenomes_ignore = false @@ -64,7 +65,6 @@ includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ profiles { debug { - dumpHashes = true process.beforeScript = 'echo $HOSTNAME' cleanup = false nextflow.enable.configProcessNamesValidation = true @@ -108,7 +108,7 @@ profiles { singularity.ociAutoPull = true wave.enabled = true wave.freeze = true - wave.strategy = 'conda,container' + wave.strategy = ["conda", "container"] } emulate_amd64 { docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' @@ -165,7 +165,7 @@ profiles { singularity.ociAutoPull = true wave.enabled = true wave.freeze = true - wave.strategy = 'conda,container' + wave.strategy = ["conda", "container"] } gpu { docker.runOptions = '-u $(id -u):$(id -g) --gpus all' @@ -211,7 +211,7 @@ env { } // Set bash options -process.shell = ["bash", "-C", "-e", "-u", "-o", "pipefail"] +process.shell = ["bash", "-C", "-e", "-u", "-o", "pipefail"].join(' ') // Disable process selector warnings by default. Use debug profile to enable warnings. nextflow.enable.configProcessNamesValidation = false @@ -234,7 +234,7 @@ trace { dag { enabled = true overwrite = true - file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${params.trace_report_suffix}.mmd" } manifest { @@ -262,7 +262,7 @@ manifest { mainScript = 'main.nf' defaultBranch = 'main' nextflowVersion = '!>=25.10.0' - version = '3.0.0dev' + version = '3.0.0' doi = '' } diff --git a/nf-test.config b/nf-test.config index c5d343b4..bda04274 100644 --- a/nf-test.config +++ b/nf-test.config @@ -12,7 +12,7 @@ config { ignore = ['modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*'] // run all test with defined profile(s) from the main nextflow.config - profile = "test" + profile = "test,s3_ugent" // list of filenames or patterns that should be trigger a full test run triggers = ['nextflow.config', 'nf-test.config', 'conf/test.config', 'tests/nextflow.config', 'tests/.nftignore'] diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 1d3d46af..40119c7b 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -21,9 +21,9 @@ { "@id": "./", "@type": "Dataset", - "creativeWorkStatus": "InProgress", - "datePublished": "2026-02-09T13:16:20+00:00", - "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.1)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,aligner,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,bwamem,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag,aligner\nfc_sample1,test,Homo sapiens,WES,bwamem\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "creativeWorkStatus": "Stable", + "datePublished": "2026-03-04T08:40:34+00:00", + "description": "# nf-cmgg/preprocessing\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/nf-cmgg/preprocessing)\n[![GitHub Actions CI Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-cmgg/preprocessing/actions/workflows/linting.yml)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.5.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.5.1)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-cmgg/preprocessing)\n\n## Introduction\n\n**nf-cmgg/preprocessing** is a bioinformatics pipeline that demultiplexes and aligns raw sequencing data.\nIt also performs basic QC and coverage analysis.\n\nThe pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible.\n\nSteps inlcude:\n\n1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html)\n2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp)\n3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq\n4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html)\n5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html)\n6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics)\n7. QC aggregation using [`multiqc`](https://multiqc.info/)\n\n![metro map](docs/images/metro_map.png)\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\nThe full documentation can be found [here](docs/README.md)\n\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv` for fastq inputs:\n\n```csv\nid,samplename,organism,library,aligner,fastq_1,fastq_2\nsample1,sample1,Homo sapiens,Library_Name,bwamem,reads1.fq.gz,reads2.fq.gz\n```\n\n`samplesheet.csv` for flowcell inputs:\n\n```csv\nid,samplesheet,lane,flowcell,sample_info\nflowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv\n```\n\n`sampleinfo.csv` for use with flowcell inputs:\n\n```csv\nsamplename,library,organism,tag,aligner\nfc_sample1,test,Homo sapiens,WES,bwamem\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-cmgg/preprocessing \\\n -profile \\\n --igenomes_base /path/to/genomes \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_;\n> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files).\n\n## Credits\n\nnf-cmgg/preprocessing was originally written by the CMGG ICT team.\n\n## Support\n\nThis pipeline uses code and infrastructure developed and maintained by the [nf-core](https://nf-co.re) community, reused here under the [MIT license](https://github.com/nf-core/tools/blob/master/LICENSE).\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" @@ -105,7 +105,7 @@ }, "mentions": [ { - "@id": "#e939b96d-700d-40a2-9ff8-added4e0ade4" + "@id": "#a7d7e3e1-4abb-45b6-8465-8056924d5808" } ], "name": "nf-cmgg/preprocessing" @@ -134,14 +134,14 @@ ], "creator": [ { - "@id": "https://orcid.org/0000-0003-2555-3114" + "@id": "https://orcid.org/0009-0003-5619-1555" }, { - "@id": "https://orcid.org/0009-0003-5619-1555" + "@id": "https://orcid.org/0000-0003-2555-3114" } ], "dateCreated": "", - "dateModified": "2026-02-09T14:16:20Z", + "dateModified": "2026-03-04T09:40:34Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "image": { "@id": "docs/images/metro_map.png" @@ -169,10 +169,10 @@ }, "url": [ "https://github.com/nf-cmgg/preprocessing", - "https://nf-co.re/nf-cmgg/preprocessing/dev/" + "https://nf-co.re/nf-cmgg/preprocessing/3.0.0/" ], "version": [ - "3.0.0dev" + "3.0.0" ] }, { @@ -196,11 +196,11 @@ "name": "Workflow diagram" }, { - "@id": "#e939b96d-700d-40a2-9ff8-added4e0ade4", + "@id": "#a7d7e3e1-4abb-45b6-8465-8056924d5808", "@type": "TestSuite", "instance": [ { - "@id": "#a6c6a5a5-b7e8-4825-8dce-3f467dbc2c91" + "@id": "#61347af5-7167-4ebd-a8c0-2b36f46308d1" } ], "mainEntity": { @@ -209,7 +209,7 @@ "name": "Test suite for nf-cmgg/preprocessing" }, { - "@id": "#a6c6a5a5-b7e8-4825-8dce-3f467dbc2c91", + "@id": "#61347af5-7167-4ebd-a8c0-2b36f46308d1", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-cmgg/preprocessing", "resource": "repos/nf-cmgg/preprocessing/actions/workflows/nf-test.yml", @@ -342,17 +342,17 @@ "name": "nf-core", "url": "https://nf-co.re/" }, - { - "@id": "https://orcid.org/0000-0003-2555-3114", - "@type": "Person", - "email": "11850640+matthdsm@users.noreply.github.com", - "name": "Matthias De Smet" - }, { "@id": "https://orcid.org/0009-0003-5619-1555", "@type": "Person", "email": "101190534+nvnieuwk@users.noreply.github.com", "name": "Nicolas Vannieuwkerke" + }, + { + "@id": "https://orcid.org/0000-0003-2555-3114", + "@type": "Person", + "email": "11850640+matthdsm@users.noreply.github.com", + "name": "Matthias De Smet" } ] } \ No newline at end of file diff --git a/subworkflows/local/utils_nfcmgg_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcmgg_preprocessing_pipeline/main.nf new file mode 100644 index 00000000..a20d0849 --- /dev/null +++ b/subworkflows/local/utils_nfcmgg_preprocessing_pipeline/main.nf @@ -0,0 +1,95 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBWORKFLOWS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// Mock subworkflow to please linting +workflow UTILS_NFCMGG_PREPROCESSING_PIPELINE { +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + FUNCTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +// +// Generate readgroup information from FASTQ header +// +def getReadgroupFromFastq(fastq, SM, LB, CN) { + // expected format: + // xx:yy:FLOWCELLID:LANE:... (seven fields) + // or + // FLOWCELLID:LANE:xx:... (five fields) + def line + fastq.withInputStream { fq -> + def isGzip = fastq.name.toString().endsWith('.gz') + def stream = isGzip ? new java.util.zip.GZIPInputStream(fq) as InputStream : fq as InputStream + def decoder = new InputStreamReader(stream, 'ASCII') + def buffered = new BufferedReader(decoder) + line = buffered.readLine() + } + assert line.startsWith('@') + line = line.substring(1) + def fields = line.split(':') + def rg = [:] + rg.LB = LB ?: '' + rg.CN = CN ?: '' + rg.PL = 'ILLUMINA' + rg.SM = SM ?: fastq.name.toString() - ~/_R[0-9]_001.*$/ + if (fields.size() >= 7) { + // CASAVA 1.8+ format, from https://support.illumina.com/help/BaseSpace_OLH_009008/Content/Source/Informatics/BS/FileFormat_FASTQ-files_swBS.htm + // "@::::::: :::" + // def sequencer_serial = fields[0] + // def run_number = fields[1] + def fcid = fields[2] + def lane = fields[3] + def index = fields[-1] ==~ /^[GATCN+-]+$/ ? fields[-1] : '' + rg.ID = [index ?: fcid, lane].join('.') + rg.PU = [fcid, lane].join('.') + } + else if (fields.size() == 5) { + def fcid = fields[0] + def lane = fields[1] + rg.ID = [fcid, lane].join('.') + rg.PU = [fcid, lane].join('.') + } + return rg +} + +// +// Generate readgroup from bclconvert outputs +// +def getReadgroupsFromBclconvert(ch_fastq_list_csv, ch_fastq) { + return ch_fastq_list_csv + .join(ch_fastq, by: [0]) + .map { meta, csv_file, fastq_list -> + def meta_fastq = [] + csv_file + .splitCsv(header: true) + .each { row -> + // Create the readgroup tuple + // RGID,RGSM,RGLB,Lane,Read1File,Read2File + def rg = [:] + // row.RGID is index1.index2.lane + rg.ID = row.RGID + // RGPU is a custom column in the samplesheet containing the flowcell ID + rg.PU = row.RGPU ? row.RGPU : meta.id + "." + row.Lane + rg.SM = row.RGSM + rg.LB = row.RGLB ? row.RGLB : "" + rg.PL = "ILLUMINA" + + // dereference the fastq files in the csv + def fastq1 = fastq_list.find { fq -> file(fq).name == file(row.Read1File).name } + def fastq2 = row.Read2File ? fastq_list.find { fq -> file(fq).name == file(row.Read2File).name } : null + + // set fastq metadata + def new_meta = meta + [id: fastq1.getSimpleName().toString() - ~/_R[0-9]_001.*$/, readgroup: rg, single_end: !fastq2] + + meta_fastq << [new_meta, fastq2 ? [fastq1, fastq2] : [fastq1]] + } + return meta_fastq + } + .flatMap() +} diff --git a/subworkflows/local/utils_nfcmgg_preprocessing_pipeline/meta.yml b/subworkflows/local/utils_nfcmgg_preprocessing_pipeline/meta.yml new file mode 100644 index 00000000..e69de29b diff --git a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff index f2a4356b..2f585e04 100644 --- a/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff +++ b/subworkflows/nf-core/fastq_align_dna/fastq_align_dna.diff @@ -17,9 +17,9 @@ Changes in 'fastq_align_dna/main.nf': main: -- ch_bam_index = Channel.empty() -- ch_bam = Channel.empty() -- ch_reports = Channel.empty() +- ch_bam_index = channel.empty() +- ch_bam = channel.empty() +- ch_reports = channel.empty() + ch_bam_index = channel.empty() + ch_bam = channel.empty() + ch_reports = channel.empty() diff --git a/tests/config/igenomes_test.config b/tests/config/igenomes_test.config index 5ecb24af..e71fec6f 100644 --- a/tests/config/igenomes_test.config +++ b/tests/config/igenomes_test.config @@ -11,12 +11,3 @@ params { } } } - -aws { - client { - endpoint = "https://s3.ugent.be" - protocol = "https" - s3PathStyleAccess = true - connectionTimeout = 60000 - } -} diff --git a/tests/config/nf-test.config b/tests/config/nf-test.config index c24e5c2f..88f7efd5 100644 --- a/tests/config/nf-test.config +++ b/tests/config/nf-test.config @@ -5,12 +5,3 @@ process { time: 6.h, ] } - -aws { - client { - endpoint = "https://s3.ugent.be" - protocol = "https" - s3PathStyleAccess = true - connectionTimeout = 60000 - } -} diff --git a/tests/default.nf.test b/tests/default.nf.test index 66a790d4..d32cc960 100644 --- a/tests/default.nf.test +++ b/tests/default.nf.test @@ -7,43 +7,11 @@ nextflow_pipeline { tag "pipeline" tag "pipeline/main" - test("main - fastq input") { + test("main") { when { params { - input = "${projectDir}/tests/inputs/fastq.yml" - igenomes_base = "s3://reference-data/genomes" - outdir = "$outputDir" - } - } - - then { - assert workflow.success - } - - } - - test("main - flowcell input") { - - when { - params { - input = "${projectDir}/tests/inputs/flowcell.yml" - igenomes_base = "s3://reference-data/genomes" - outdir = "$outputDir" - } - } - - then { - assert workflow.success - } - - } - - test("main - fastq RNA input") { - - when { - params { - input = "${projectDir}/tests/inputs/fastq_rna.yml" + input = "${projectDir}/tests/inputs/test.yml" igenomes_base = "s3://reference-data/genomes" outdir = "$outputDir" } diff --git a/tests/inputs/fastq.yml b/tests/inputs/fastq.yml deleted file mode 100644 index 8195b58b..00000000 --- a/tests/inputs/fastq.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -# fastq inputs -- id: sample1_L001 - samplename: fastq_paired1 - library: test_library - organism: Homo sapiens - tag: WES - aligner: bwamem - markdup: bamsormadup - run_coverage: true - fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz - fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz -- id: sample1_L002 - samplename: fastq_paired1 - library: test_library - organism: Homo sapiens - tag: WES - aligner: bwamem - markdup: bamsormadup - run_coverage: true - fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz - fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/tests/inputs/fastq_rna.yml b/tests/inputs/fastq_rna.yml deleted file mode 100644 index 3945eb53..00000000 --- a/tests/inputs/fastq_rna.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -# fastq inputs -- id: sample1_L001 - samplename: fastq_paired1 - library: test_library - organism: Homo sapiens - tag: WES - sample_type: RNA - aligner: star - markdup: bamsormadup - run_coverage: true - fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz - fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz -- id: sample1_L002 - samplename: fastq_paired1 - library: test_library - organism: Homo sapiens - tag: WES - sample_type: RNA - aligner: star - markdup: bamsormadup - run_coverage: true - fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz - fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/tests/inputs/flowcell.yml b/tests/inputs/flowcell.yml deleted file mode 100644 index 4711c5b9..00000000 --- a/tests/inputs/flowcell.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- id: 200624_A00834_0183_BHMTFYDRXX - samplesheet: https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleSheet_2.csv - lane: 1 - flowcell: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/200624_A00834_0183_BHMTFYDRXX.tar.gz - sample_info: https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleInfo_2.json diff --git a/tests/inputs/test.yml b/tests/inputs/test.yml new file mode 100644 index 00000000..3a432b4b --- /dev/null +++ b/tests/inputs/test.yml @@ -0,0 +1,51 @@ +--- +# flowcell inputs +- id: 200624_A00834_0183_BHMTFYDRXX + samplesheet: https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleSheet_2.csv + lane: 1 + flowcell: s3://test-data/genomics/homo_sapiens/illumina/bcl/ + sample_info: https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleInfo_2.json +# DNA fastq inputs +- id: DNA1_L001 + samplename: DNA_paired1 + library: test_library + organism: Homo sapiens + tag: WES + aligner: bwamem + markdup: bamsormadup + run_coverage: true + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz +- id: DNA1_L002 + samplename: DNA_paired1 + library: test_library + organism: Homo sapiens + tag: WES + aligner: bwamem + markdup: bamsormadup + run_coverage: true + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz +# RNA fastq inputs +- id: RNA1_L001 + samplename: RNA_paired1 + library: test_library + organism: Homo sapiens + tag: WES + sample_type: RNA + aligner: star + markdup: bamsormadup + run_coverage: true + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz +- id: RNA1_L002 + samplename: RNA_paired1 + library: test_library + organism: Homo sapiens + tag: WES + sample_type: RNA + aligner: star + markdup: bamsormadup + run_coverage: true + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/main/data/genomics/homo_sapiens/illumina/fastq/test_R2.fastq.gz diff --git a/tests/workflows/preprocessing.nf.test b/tests/workflows/preprocessing.nf.test index 4d5e52cc..d8bac5f5 100644 --- a/tests/workflows/preprocessing.nf.test +++ b/tests/workflows/preprocessing.nf.test @@ -49,6 +49,12 @@ nextflow_workflow { ] // genelists input[2] = null + // mqc_config + input[3] = [file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true)] + // mqc_logo + input[4] = [] + // mqc methods description + input[5] = null """ } } @@ -57,12 +63,12 @@ nextflow_workflow { assert workflow.success assert snapshot( sanitizeOutput(workflow.out, unstableKeys:[ - "multiqc_main_report", - "multiqc_main_data", - "multiqc_main_plots", - "multiqc_library_report", - "multiqc_library_data", - "multiqc_library_plots", + "multiqc_report", + "multiqc_data", + "multiqc_plots", + "multiqcsav_report", + "multiqcsav_data", + "multiqcsav_plots", "md5sums", "fastp_html", "crams", @@ -119,6 +125,12 @@ nextflow_workflow { ] // genelists input[2] = null + // mqc_config + input[3] = [file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true)] + // mqc_logo + input[4] = [] + // mqc methods description + input[5] = null """ } } @@ -127,12 +139,12 @@ nextflow_workflow { assert workflow.success assert snapshot( sanitizeOutput(workflow.out, unstableKeys:[ - "multiqc_main_report", - "multiqc_main_data", - "multiqc_main_plots", - "multiqc_library_report", - "multiqc_library_data", - "multiqc_library_plots", + "multiqc_report", + "multiqc_data", + "multiqc_plots", + "multiqcsav_report", + "multiqcsav_data", + "multiqcsav_plots", "md5sums", "fastp_html", "crams", @@ -194,6 +206,12 @@ nextflow_workflow { ] // genelists input[2] = null + // mqc_config + input[3] = [file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true)] + // mqc_logo + input[4] = [] + // mqc methods description + input[5] = null """ } } @@ -202,12 +220,12 @@ nextflow_workflow { assert workflow.success assert snapshot( sanitizeOutput(workflow.out, unstableKeys:[ - "multiqc_main_report", - "multiqc_main_data", - "multiqc_main_plots", - "multiqc_library_report", - "multiqc_library_data", - "multiqc_library_plots", + "multiqc_report", + "multiqc_data", + "multiqc_plots", + "multiqcsav_report", + "multiqcsav_data", + "multiqcsav_plots", "md5sums", "fastp_html", "crams", @@ -222,4 +240,79 @@ nextflow_workflow { ).match() } } + + test("preprocessing - flowcell - bwa - bamsormadup - roi") { + when { + workflow { + """ + // ch_samplesheet + input[0] = Channel.of( + [ + [ // meta + id: "200624_A00834_0183_BHMTFYDRXX", + lane: 1, + ], + [], // fastq_1 + [], // fastq_2 + file("https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleSheet_2.csv", checkIfExists: true), + file("https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleInfo_2.json", checkIfExists: true), + file("s3://test-data/genomics/homo_sapiens/illumina/bcl", checkIfExists: true) + + ] + ) + // genomes + input[1] = [ + GRCh38: [ + fasta: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + fai: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + dict: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + bwamem: "s3://test-data/genomics/homo_sapiens/genome/bwa/", + gtf: "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + ] + ] + // genelists + input[2] = null + // mqc_config + input[3] = [file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true)] + // mqc_logo + input[4] = [] + // mqc methods description + input[5] = null + """ + } + } + + then { + assert workflow.success + assert snapshot( + sanitizeOutput(workflow.out, unstableKeys:[ + "demultiplex_logs", + "demultiplex_reports", + "multiqc_report", + "multiqc_data", + "multiqc_plots", + "multiqcsav_report", + "multiqcsav_data", + "multiqcsav_plots", + "md5sums", + "fastp_html", + "crams", + "picard_wgsmetrics", + "picard_multiplemetrics_pdf", + "picard_multiplemetrics", + "picard_hsmetrics", + "samtools_flagstat", + "samtools_coverage", + "samtools_stats" + ]).collectEntries { key, value -> + if (key in ["demultiplex_logs", "demultiplex_reports"]) { + [ key: value.sort() ] + } else { + [ key: value ] + } + } + ).match() + } + } + } diff --git a/tests/workflows/preprocessing.nf.test.snap b/tests/workflows/preprocessing.nf.test.snap index e6421b43..f1d096fa 100644 --- a/tests/workflows/preprocessing.nf.test.snap +++ b/tests/workflows/preprocessing.nf.test.snap @@ -71,7 +71,7 @@ "markdup": "bamsormadup", "organism": "Homo sapiens", "readgroup": { - "CN": "CMGG", + "CN": "", "ID": "H5T2YDSX3.1", "LB": "test", "PL": "ILLUMINA", @@ -103,12 +103,12 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "readgroup": { - "CN": "CMGG", - "ID": "H5T2YDSX3.1", - "PU": "H5T2YDSX3.1", + "LB": "test", + "CN": "", "PL": "ILLUMINA", "SM": "sample1", - "LB": "test" + "ID": "H5T2YDSX3.1", + "PU": "H5T2YDSX3.1" }, "genome": "GRCh38", "genome_data": { @@ -422,28 +422,38 @@ "mosdepth_thresholds_csi": [ ], - "multiqc_library_data": [ - "test_data" + "multiqc_data": [ + [ + { + "id": "test" + }, + "test_data" + ] ], - "multiqc_library_plots": [ + "multiqc_plots": [ ], - "multiqc_library_report": [ - "test.html" + "multiqc_report": [ + [ + { + "id": "test" + }, + "test.html" + ] ], - "multiqc_main_data": [ + "multiqcsav_data": [ [ - "multiqc_data" + ] ], - "multiqc_main_plots": [ + "multiqcsav_plots": [ [ ] ], - "multiqc_main_report": [ + "multiqcsav_report": [ [ - "multiqc.html" + ] ], "panelcoverage": [ @@ -706,7 +716,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-11T21:21:37.068608" + "timestamp": "2026-03-05T14:04:31.848677" }, "preprocessing - fastq - bwa - bamsormadup - roi - no coverage/no picard": { "content": [ @@ -782,7 +792,7 @@ "markdup": "bamsormadup", "organism": "Homo sapiens", "readgroup": { - "CN": "CMGG", + "CN": "", "ID": "H5T2YDSX3.1", "LB": "test", "PL": "ILLUMINA", @@ -815,12 +825,12 @@ "roi": "/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/regions/roi_chr21.bed", "single_end": false, "readgroup": { - "CN": "CMGG", - "ID": "H5T2YDSX3.1", - "PU": "H5T2YDSX3.1", + "LB": "test", + "CN": "", "PL": "ILLUMINA", "SM": "sample1", - "LB": "test" + "ID": "H5T2YDSX3.1", + "PU": "H5T2YDSX3.1" }, "genome": "GRCh38", "genome_data": { @@ -901,28 +911,38 @@ "mosdepth_thresholds_csi": [ ], - "multiqc_library_data": [ - "test_data" + "multiqc_data": [ + [ + { + "id": "test" + }, + "test_data" + ] ], - "multiqc_library_plots": [ + "multiqc_plots": [ ], - "multiqc_library_report": [ - "test.html" + "multiqc_report": [ + [ + { + "id": "test" + }, + "test.html" + ] ], - "multiqc_main_data": [ + "multiqcsav_data": [ [ - "multiqc_data" + ] ], - "multiqc_main_plots": [ + "multiqcsav_plots": [ [ ] ], - "multiqc_main_report": [ + "multiqcsav_report": [ [ - "multiqc.html" + ] ], "panelcoverage": [ @@ -1075,7 +1095,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-11T21:25:53.804729" + "timestamp": "2026-03-05T14:08:24.880945" }, "preprocessing - fastq - bwa - bamsormadup - no roi": { "content": [ @@ -1148,7 +1168,7 @@ "markdup": "bamsormadup", "organism": "Homo sapiens", "readgroup": { - "CN": "CMGG", + "CN": "", "ID": "H5T2YDSX3.1", "LB": "test", "PL": "ILLUMINA", @@ -1178,12 +1198,12 @@ "run_coverage": true, "single_end": false, "readgroup": { - "CN": "CMGG", - "ID": "H5T2YDSX3.1", - "PU": "H5T2YDSX3.1", + "LB": "test", + "CN": "", "PL": "ILLUMINA", "SM": "sample1", - "LB": "test" + "ID": "H5T2YDSX3.1", + "PU": "H5T2YDSX3.1" }, "genome": "GRCh38", "genome_data": { @@ -1412,28 +1432,38 @@ "mosdepth_thresholds_csi": [ ], - "multiqc_library_data": [ - "test_data" + "multiqc_data": [ + [ + { + "id": "test" + }, + "test_data" + ] ], - "multiqc_library_plots": [ + "multiqc_plots": [ ], - "multiqc_library_report": [ - "test.html" + "multiqc_report": [ + [ + { + "id": "test" + }, + "test.html" + ] ], - "multiqc_main_data": [ + "multiqcsav_data": [ [ - "multiqc_data" + ] ], - "multiqc_main_plots": [ + "multiqcsav_plots": [ [ ] ], - "multiqc_main_report": [ + "multiqcsav_report": [ [ - "multiqc.html" + ] ], "panelcoverage": [ @@ -1685,9 +1715,68 @@ } ], "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-03-05T14:07:05.010944" + }, + "preprocessing - flowcell - bwa - bamsormadup - roi": { + "content": [ + { + "key": [ + [ + { + "groupSize": 1, + "groupTarget": { + "single_end": true, + "samplename": "Sample1", + "sample_type": "DNA", + "library": "test", + "tag": "WES", + "purpose": [ + + ], + "organism": "Homo sapiens", + "genome": "GRCh38", + "vivar_project": [ + + ], + "binsize": [ + + ], + "panels": [ + + ], + "aligner": "bwamem", + "markdup": "bamsormadup", + "umi_aware": false, + "skip_trimming": false, + "trim_front": 0, + "trim_tail": 0, + "adapter_R1": null, + "adapter_R2": null, + "run_coverage": true, + "disable_picard_metrics": true, + "roi": null, + "genome_data": { + "fasta": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna", + "fai": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.fna.fai", + "dict": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.dict", + "bwamem": "s3://test-data/genomics/homo_sapiens/genome/bwa/", + "gtf": "s3://test-data/genomics/homo_sapiens/genome/seq/GCA_000001405.15_GRCh38_full_plus_hs38d1_analysis_set_chr21.gtf" + }, + "id": "Sample1" + } + }, + "Sample1.merged.metrics.txt:md5,f23933cc5957694d2286bdae22039097" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-02-18T15:49:18.459258" + "timestamp": "2026-03-05T14:02:04.847019" } } \ No newline at end of file diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index 225c1ba4..d654dfd5 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -1,4 +1,4 @@ -include { samplesheetToList } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -7,26 +7,27 @@ include { samplesheetToList } from 'plugin/nf-schema' */ // Modules -include { BCLCONVERT } from '../modules/nf-core/bclconvert/main' -include { FALCO } from '../modules/nf-core/falco/main' -include { FASTP } from '../modules/nf-core/fastp/main' -include { MD5SUM } from '../modules/nf-core/md5sum/main' -include { MULTIQC as MULTIQC_LIBRARY } from '../modules/nf-core/multiqc/main' -include { MULTIQC as MULTIQC_MAIN } from '../modules/nf-core/multiqc/main' -include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage/main' +include { BCLCONVERT } from '../modules/nf-core/bclconvert' +include { FALCO } from '../modules/nf-core/falco' +include { FASTP } from '../modules/nf-core/fastp' +include { MD5SUM } from '../modules/nf-core/md5sum' +include { MULTIQC } from '../modules/nf-core/multiqc' +include { MULTIQCSAV } from '../modules/nf-core/multiqcsav' +include { SAMTOOLS_COVERAGE } from '../modules/nf-core/samtools/coverage' // Subworkflows -include { BAM_QC } from '../subworkflows/local/bam_qc/main' -include { COVERAGE } from '../subworkflows/local/coverage/main' -include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram/main' +include { BAM_QC } from '../subworkflows/local/bam_qc' +include { COVERAGE } from '../subworkflows/local/coverage' +include { FASTQ_TO_CRAM } from '../subworkflows/local/fastq_to_aligned_cram' // Functions -include { generateReadgroup } from '../modules/nf-core/bclconvert/main' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' -include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' -include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { getReadgroupsFromBclconvert } from '../subworkflows/local/utils_nfcmgg_preprocessing_pipeline' +include { getReadgroupFromFastq } from '../subworkflows/local/utils_nfcmgg_preprocessing_pipeline' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' +include { getGenomeAttribute } from '../subworkflows/local/utils_nfcore_preprocessing_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -39,6 +40,9 @@ workflow PREPROCESSING { ch_samplesheet // channel: samplesheet read in from --input genomes // map: genome reference files genelists // file: directory containing genelist bed files for coverage analysis + multiqc_config // file(s): MultiQC config file(s) + multiqc_logo // file: MultiQC logo file + multiqc_methods_description // file: custom methods description for MultiQC report main: ch_multiqc_files = channel.empty() @@ -46,7 +50,7 @@ workflow PREPROCESSING { ch_samplesheet .branch { meta, fastq_1, fastq_2, samplesheet, sampleinfo, flowcell -> illumina_flowcell: (flowcell && samplesheet && sampleinfo) && !(fastq_1 || fastq_2) - return [meta, samplesheet, sampleinfo, flowcell] + return [["id": meta.id, "lane": meta.lane], samplesheet, sampleinfo, flowcell] fastq: (fastq_1) && !(flowcell || samplesheet || sampleinfo) return [meta, [fastq_1, fastq_2].findAll()] other: true @@ -72,34 +76,50 @@ workflow PREPROCESSING { // BCLCONVERT([meta, samplesheet, flowcell]) BCLCONVERT(ch_illumina_flowcell.flowcell) BCLCONVERT.out.fastq.dump(tag: "DEMULTIPLEX: fastq", pretty: true) - ch_multiqc_files = ch_multiqc_files.mix( - BCLCONVERT.out.reports, - BCLCONVERT.out.logs, - ) - generateReadgroup( + getReadgroupsFromBclconvert( BCLCONVERT.out.reports.map { meta, reports -> - return [meta, reports.find { report -> report.name == "fastq_list.csv" }] + return [meta, file(reports).resolve("fastq_list.csv")] }, BCLCONVERT.out.fastq, - ).set { ch_fastq_with_meta } - ch_fastq_with_meta.dump(tag: "DEMULTIPLEX: fastq with meta", pretty: true) + ).dump(tag: "DEMULTIPLEX: fastq with meta", pretty: true).map { meta, fastq -> [meta.readgroup.SM, meta, fastq] }.set { ch_demultiplexed_fastq } + + // Run QC + ch_mqcsav_input = ch_illumina_flowcell.flowcell + .map { meta, _samplesheet, flowcell -> + def interop = files(flowcell.resolve("InterOp/*.bin"), checkIfExists: true) + def xml = files(flowcell.resolve("*.xml"), checkIfExists: true) + return [meta, xml, interop] + } + .join(BCLCONVERT.out.reports, by: 0) + .map { meta, xml, interop, reports -> + return [meta - meta.subMap(['lane']), xml, interop, reports] + } + .groupTuple(by: [0]) + .map { meta, xml, interop, reports -> + return [meta, xml.flatten().unique(), interop.flatten().unique(), reports.flatten(), multiqc_config, multiqc_logo, [], []] + } + .dump(tag: "MULTIQC SAV input", pretty: true) - ch_fastq_with_meta.map { meta, fastq -> [meta.readgroup.SM, meta, fastq] }.set { ch_demultiplexed_fastq } + MULTIQCSAV( + ch_mqcsav_input + ) + // Merge fastq meta with sample info ch_illumina_flowcell.info .flatten() .transpose() .map { sampleinfo -> [sampleinfo.samplename, sampleinfo] } .set { ch_sampleinfo } - // Merge fastq meta with sample info ch_demultiplexed_fastq .combine(ch_sampleinfo, by: 0) .map { _samplename, meta, fastq, sampleinfo -> + def new_rg = [:] if (sampleinfo.library) { new_rg = meta.readgroup + ['LB': sampleinfo.library] - } else { + } + else { new_rg = meta.readgroup } def new_meta = meta + sampleinfo + ['readgroup': new_rg] @@ -114,6 +134,7 @@ workflow PREPROCESSING { other: true } .set { ch_demultiplexed_fastq_with_sampleinfo } + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PROCESS FASTQ INPUTS @@ -125,15 +146,9 @@ workflow PREPROCESSING { // if no fastq_2, then single-end def single_end = fastq[1] ? false : true // add readgroup metadata - def rg = readgroup_from_fastq(fastq[0]) // if the sample name starts with "snp_", remove it so the sampletracking works later on. def samplename = meta.samplename.startsWith("snp_") ? meta.samplename.substring(4) : meta.samplename - rg = rg + [ - 'SM': samplename, - 'LB': meta.library ?: "", - 'PL': meta.platform ?: rg.PL, - 'ID': meta.readgroup ?: rg.ID, - ] + def rg = getReadgroupFromFastq(fastq[0], samplename, meta.library, meta.platform) def meta_with_readgroup = meta + ['single_end': single_end, 'readgroup': rg] return [meta_with_readgroup, fastq] } @@ -363,67 +378,50 @@ workflow PREPROCESSING { sort: true, newLine: true, ) - .map { file -> [[id: 'main'], file] } .set { ch_collated_versions } // // MODULE: MultiQC // - ch_multiqc_config = channel.fromPath("${projectDir}/assets/multiqc_config.yml", checkIfExists: true) - ch_multiqc_custom_config = params.multiqc_config ? channel.fromPath(params.multiqc_config, checkIfExists: true) : channel.empty() - ch_multiqc_logo = params.multiqc_logo ? channel.fromPath(params.multiqc_logo, checkIfExists: true) : channel.empty() - + // summary files without meta, e.g. versions, params summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") ch_workflow_summary = channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml').map { file -> [[id: 'main'], file] }) + ch_methods_description = channel.value(multiqc_methods_description ? methodsDescriptionText(multiqc_methods_description) : "") - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) - ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_summary_files = channel.empty() + .mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + .mix(ch_collated_versions) + .mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true)) + .toList() + .map { files -> [files] } + .dump(tag: "Summary files for MultiQC", pretty: true) - ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true).map { file -> [[id: 'main'], file] }) - - ch_multiqc_files = ch_multiqc_files + ch_multiqc_input = ch_multiqc_files .map { meta, files -> - return [meta.library ? [id: meta.library] : [id: 'main'], files] + def new_meta = meta.library ? [id: meta.library] : [id: 'multiqc'] + return [new_meta, files] } - .branch { meta, files -> - main: meta.id == 'main' - return files - library: meta.id != 'main' - return [meta, files instanceof List ? files : [files]] + .groupTuple(by: 0) + .combine(ch_summary_files) + .map { meta, multiqc_files, summary_files -> + return [meta, (multiqc_files + summary_files).flatten(), multiqc_config.flatten(), multiqc_logo, [], []] } + .dump(tag: "MULTIQC files", pretty: true) - - ch_library_multiqc_files = ch_multiqc_files.library.transpose(by: 1).groupTuple() - ch_library_multiqc_files.dump(tag: "MULTIQC files - library", pretty: true) - - - ch_main_multiqc_files = ch_multiqc_files.main.collect().map { files -> [[id: 'main'], files] } - ch_main_multiqc_files.dump(tag: "MULTIQC files - main", pretty: true) - MULTIQC_MAIN( - ch_main_multiqc_files, - ch_multiqc_config.toList(), - ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList(), - [], - [], - ) - - MULTIQC_LIBRARY( - ch_library_multiqc_files, - ch_multiqc_config.toList(), - ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList(), - [], - [], - ) + // MULTIQC([meta, multiqc_files, multiqc_config, multiqc_logo, replace_names, sample_names]) + MULTIQC(ch_multiqc_input) emit: - demultiplex_interop = BCLCONVERT.out.interop - demultiplex_reports = BCLCONVERT.out.reports - demultiplex_logs = BCLCONVERT.out.logs + demultiplex_reports = BCLCONVERT.out.reports.map { meta, reports -> + return [meta, files(reports.resolve("*"))] + } + demultiplex_logs = BCLCONVERT.out.logs.map { meta, logs -> + return [meta, files(logs.resolve("*"))] + } + demultiplex_interop = ch_illumina_flowcell.flowcell.map { meta, _samplesheet, flowcell -> + return [meta, files(flowcell.resolve("InterOp/*.bin"))] + } demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other falco_html = FALCO.out.html falco_txt = FALCO.out.txt @@ -456,56 +454,10 @@ workflow PREPROCESSING { picard_wgsmetrics = BAM_QC.out.picard_wgsmetrics picard_hsmetrics = BAM_QC.out.picard_hsmetrics md5sums = MD5SUM.out.checksum - multiqc_main_report = MULTIQC_MAIN.out.report.toList() - multiqc_main_data = MULTIQC_MAIN.out.data.toList() - multiqc_main_plots = MULTIQC_MAIN.out.plots.toList() - multiqc_library_report = MULTIQC_LIBRARY.out.report - multiqc_library_data = MULTIQC_LIBRARY.out.data - multiqc_library_plots = MULTIQC_LIBRARY.out.plots -} - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - FUNCTIONS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -// https://github.com/nf-core/sarek/blob/7ba61bde8e4f3b1932118993c766ed33b5da465e/workflows/sarek.nf#L1014-L1040 -def readgroup_from_fastq(path) { - // expected format: - // xx:yy:FLOWCELLID:LANE:... (seven fields) - // or - // FLOWCELLID:LANE:xx:... (five fields) - def line - - path.withInputStream { fq -> - def gzipStream = new java.util.zip.GZIPInputStream(fq) as InputStream - def decoder = new InputStreamReader(gzipStream, 'ASCII') - def buffered = new BufferedReader(decoder) - line = buffered.readLine() - } - assert line.startsWith('@') - line = line.substring(1) - def fields = line.split(':') - def rg = [:] - rg.CN = "CMGG" - - if (fields.size() >= 7) { - // CASAVA 1.8+ format, from https://support.illumina.com/help/BaseSpace_OLH_009008/Content/Source/Informatics/BS/FileFormat_FASTQ-files_swBS.htm - // "@::::::: :::" - // def sequencer_serial = fields[0] - // def run_number = fields[1] - def fcid = fields[2] - def lane = fields[3] - def index = fields[-1] =~ /[GATC+-]/ ? fields[-1] : "" - - rg.ID = [index ?: fcid, lane].join(".") - rg.PU = [fcid, lane].join(".") - rg.PL = "ILLUMINA" - } - else if (fields.size() == 5) { - def fcid = fields[0] - rg.ID = fcid - } - return rg + multiqcsav_report = MULTIQCSAV.out.report.toList() + multiqcsav_data = MULTIQCSAV.out.data.toList() + multiqcsav_plots = MULTIQCSAV.out.plots.toList() + multiqc_report = MULTIQC.out.report + multiqc_data = MULTIQC.out.data + multiqc_plots = MULTIQC.out.plots } From 75d9460d25ef33a4c1d6f5b3c32d3b62707daad4 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:39:11 +0100 Subject: [PATCH 223/228] restore InterOp output --- main.nf | 6 ++++-- workflows/preprocessing.nf | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/main.nf b/main.nf index e2f78c8b..b98a9eeb 100644 --- a/main.nf +++ b/main.nf @@ -70,7 +70,7 @@ workflow { demultiplex_reports = PREPROCESSING.out.demultiplex_reports.transpose() demultiplex_logs = PREPROCESSING.out.demultiplex_logs.transpose() demultiplex_fastq = PREPROCESSING.out.demultiplex_fastq.transpose() - demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose() + demultiplex_interop = PREPROCESSING.out.demultiplex_interop.transpose(by: 1) falco_html = PREPROCESSING.out.falco_html falco_txt = PREPROCESSING.out.falco_txt fastp_json = PREPROCESSING.out.fastp_json @@ -122,7 +122,9 @@ output { } } demultiplex_interop { - path "InterOp/" + path { _meta, bin -> + bin >> "Interop/${bin.name}" + } } demultiplex_fastq { path { meta, fastq -> diff --git a/workflows/preprocessing.nf b/workflows/preprocessing.nf index d654dfd5..5337ae93 100644 --- a/workflows/preprocessing.nf +++ b/workflows/preprocessing.nf @@ -419,9 +419,7 @@ workflow PREPROCESSING { demultiplex_logs = BCLCONVERT.out.logs.map { meta, logs -> return [meta, files(logs.resolve("*"))] } - demultiplex_interop = ch_illumina_flowcell.flowcell.map { meta, _samplesheet, flowcell -> - return [meta, files(flowcell.resolve("InterOp/*.bin"))] - } + demultiplex_interop = BCLCONVERT.out.interop demultiplex_fastq = ch_demultiplexed_fastq_with_sampleinfo.other falco_html = FALCO.out.html falco_txt = FALCO.out.txt From 6620a298d7f2316d0f7691504e65a073fad3c695 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 5 Mar 2026 19:50:18 +0100 Subject: [PATCH 224/228] Bump modules (#161) * bump modules * update subwf, include nf-teams * fix errors --- assets/adaptivecard.json | 67 ------------------- assets/slackreport.json | 34 ---------- main.nf | 1 - modules.json | 4 +- modules/nf-core/samtools/coverage/main.nf | 7 +- .../samtools/coverage/tests/main.nf.test.snap | 18 ++--- nextflow.config | 10 +++ .../main.nf | 5 -- .../nf-core/utils_nfcore_pipeline/main.nf | 64 ------------------ .../{main.workflow.nf.test => main.nf.test} | 0 ...orkflow.nf.test.snap => main.nf.test.snap} | 0 11 files changed, 22 insertions(+), 188 deletions(-) delete mode 100644 assets/adaptivecard.json delete mode 100644 assets/slackreport.json rename subworkflows/nf-core/utils_nfcore_pipeline/tests/{main.workflow.nf.test => main.nf.test} (100%) rename subworkflows/nf-core/utils_nfcore_pipeline/tests/{main.workflow.nf.test.snap => main.nf.test.snap} (100%) diff --git a/assets/adaptivecard.json b/assets/adaptivecard.json deleted file mode 100644 index 92ed5f06..00000000 --- a/assets/adaptivecard.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "type": "message", - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.adaptive", - "contentUrl": null, - "content": { - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "msteams": { - "width": "Full" - }, - "type": "AdaptiveCard", - "version": "1.2", - "body": [ - { - "type": "TextBlock", - "size": "Large", - "weight": "Bolder", - "color": "<% if (success) { %>Good<% } else { %>Attention<%} %>", - "text": "nf-cmgg/preprocessing v${version} - ${runName}", - "wrap": true - }, - { - "type": "TextBlock", - "spacing": "None", - "text": "Completed at ${dateComplete} (duration: ${duration})", - "isSubtle": true, - "wrap": true - }, - { - "type": "TextBlock", - "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors. The full error message was: ${errorReport}.<% } %>", - "wrap": true - }, - { - "type": "TextBlock", - "text": "The command used to launch the workflow was as follows:", - "wrap": true - }, - { - "type": "TextBlock", - "text": "${commandLine}", - "isSubtle": true, - "wrap": true - } - ], - "actions": [ - { - "type": "Action.ShowCard", - "title": "Pipeline Configuration", - "card": { - "type": "AdaptiveCard", - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "body": [ - { - "type": "FactSet", - "facts": [<% out << summary.collect{ k,v -> "{\"title\": \"$k\", \"value\" : \"$v\"}"}.join(",\n") %> - ] - } - ] - } - } - ] - } - } - ] -} diff --git a/assets/slackreport.json b/assets/slackreport.json deleted file mode 100644 index 84fc115a..00000000 --- a/assets/slackreport.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "attachments": [ - { - "fallback": "Plain-text summary of the attachment.", - "color": "<% if (success) { %>good<% } else { %>danger<%} %>", - "author_name": "nf-cmgg/preprocessing ${version} - ${runName}", - "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", - "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", - "fields": [ - { - "title": "Command used to launch the workflow", - "value": "```${commandLine}```", - "short": false - } - <% - if (!success) { %> - , - { - "title": "Full error message", - "value": "```${errorReport}```", - "short": false - }, - { - "title": "Pipeline configuration", - "value": "<% out << summary.collect{ k,v -> k == "hook_url" ? "_${k}_: (_hidden_)" : ( ( v.class.toString().contains('Path') || ( v.class.toString().contains('String') && v.contains('/') ) ) ? "_${k}_: `${v}`" : (v.class.toString().contains('DateTime') ? ("_${k}_: " + v.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM))) : "_${k}_: ${v}") ) }.join(",\n") %>", - "short": false - } - <% } - %> - ], - "footer": "Completed at <% out << dateComplete.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM)) %> (duration: ${duration})" - } - ] -} diff --git a/main.nf b/main.nf index b98a9eeb..64e8d3db 100644 --- a/main.nf +++ b/main.nf @@ -62,7 +62,6 @@ workflow { params.plaintext_email, params.outdir, params.monochrome_logs, - params.hook_url, PREPROCESSING.out.multiqc_report, ) diff --git a/modules.json b/modules.json index 410a4a68..5f13e2ed 100644 --- a/modules.json +++ b/modules.json @@ -103,7 +103,7 @@ }, "samtools/coverage": { "branch": "master", - "git_sha": "b2e78932ef01165fd85829513eaca29eff8e640a", + "git_sha": "440edf75d8782913115a7b72a88392a227f72cc1", "installed_by": ["modules"], "patch": "modules/nf-core/samtools/coverage/samtools-coverage.diff" }, @@ -170,7 +170,7 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "65f5e638d901a51534c68fd5c1c19e8112fb4df1", + "git_sha": "f0b535b3ae20080f8db03dd5388876ad1ec29d70", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { diff --git a/modules/nf-core/samtools/coverage/main.nf b/modules/nf-core/samtools/coverage/main.nf index 25754d35..ff566999 100644 --- a/modules/nf-core/samtools/coverage/main.nf +++ b/modules/nf-core/samtools/coverage/main.nf @@ -37,11 +37,6 @@ process SAMTOOLS_COVERAGE { stub: def prefix = task.ext.prefix ?: "${meta.id}" """ - touch ${prefix}.txt - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//' ) - END_VERSIONS + echo "#rname\tstartpos\tendpos\tnumreads\tcovbases\tcoverage\tmeandepth\tmeanbaseq\tmeanmapq" > ${prefix}.txt """ } diff --git a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap index 256c6507..0d72500a 100644 --- a/modules/nf-core/samtools/coverage/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/coverage/tests/main.nf.test.snap @@ -7,7 +7,7 @@ { "id": "test" }, - "test.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + "test.txt:md5,ea885d54c0223dff86e2e44f5bc08374" ] ], "versions_samtools": [ @@ -19,11 +19,11 @@ ] } ], + "timestamp": "2026-03-03T16:16:25.616671578", "meta": { - "nf-test": "0.9.3", - "nextflow": "25.10.3" - }, - "timestamp": "2026-02-10T15:27:27.16473081" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, "test_samtools_coverage_bam": { "content": [ @@ -45,11 +45,11 @@ ] } ], + "timestamp": "2026-02-10T15:27:06.759689511", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.3" - }, - "timestamp": "2026-02-10T15:27:06.759689511" + } }, "test_samtools_coverage_cram": { "content": [ @@ -86,10 +86,10 @@ ] } ], + "timestamp": "2026-02-10T15:27:12.949845604", "meta": { "nf-test": "0.9.3", "nextflow": "25.10.3" - }, - "timestamp": "2026-02-10T15:27:12.949845604" + } } } \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index c3e162e8..44d9698c 100644 --- a/nextflow.config +++ b/nextflow.config @@ -269,6 +269,7 @@ manifest { // Nextflow plugins plugins { id 'nf-schema@2.6.1' + id 'nf-teams@0.1.0' } validation { @@ -276,6 +277,15 @@ validation { monochromeLogs = params.monochrome_logs } +// TODO remove this once minimal nf-version is 26.0X with strict syntax. +teams { + enabled = true + webHook { + url = params.hook_url ? params.hook_url : System.getenv('TEAMS_WEBHOOK_URL') + } + onComplete.enabled = true +} + // Load modules.config for DSL2 module specific options includeConfig 'conf/modules.config' diff --git a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf index f269c502..d7b7103b 100644 --- a/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_preprocessing_pipeline/main.nf @@ -14,7 +14,6 @@ include { samplesheetToList } from 'plugin/nf-schema' include { paramsHelp } from 'plugin/nf-schema' include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' @@ -99,7 +98,6 @@ workflow PIPELINE_COMPLETION { plaintext_email // boolean: Send plain-text email instead of HTML outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output - hook_url // string: hook URL for notifications multiqc_report // string: Path to MultiQC report main: @@ -123,9 +121,6 @@ workflow PIPELINE_COMPLETION { } completionSummary(monochrome_logs) - if (hook_url) { - imNotification(summary_params, hook_url) - } } workflow.onError { diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index 2f30e9a4..bf568a08 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test similarity index 100% rename from subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test rename to subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap similarity index 100% rename from subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap rename to subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap From d396daee5d2f8654f9575f3c2ebf84afa7cc56af Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:00:11 +0100 Subject: [PATCH 225/228] Update/docs (#162) * fix download test * Update parameters docs * Update output docs * drop conda profiles * update usage docs --- .github/workflows/download_pipeline.yml | 4 +- docs/output.md | 11 ++-- docs/parameters.md | 69 ++++++++++++------------- docs/usage.md | 20 ++++--- nextflow.config | 20 ------- 5 files changed, 50 insertions(+), 74 deletions(-) diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 6d94bcbf..d9970752 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -95,14 +95,14 @@ jobs: env: NXF_SINGULARITY_CACHEDIR: ./singularity_container_images NXF_SINGULARITY_HOME_MOUNT: true - run: nextflow run ./${{needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results + run: nextflow run ./${{needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -stub -profile test,singularity,s3_ugent --outdir ./results - name: Run the downloaded pipeline (stub run not supported) id: run_pipeline if: ${{ steps.stub_run_pipeline.outcome == 'failure' }} env: NXF_SINGULARITY_CACHEDIR: ./singularity_container_images NXF_SINGULARITY_HOME_MOUNT: true - run: nextflow run ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -profile test,singularity --outdir ./results + run: nextflow run ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -profile test,singularity,s3_ugent --outdir ./results - name: Count the downloaded number of container images id: count_afterwards diff --git a/docs/output.md b/docs/output.md index e57580fc..ed562aa8 100644 --- a/docs/output.md +++ b/docs/output.md @@ -10,7 +10,7 @@ The directories listed below will be created in the results directory after the ### Sample information -A separate directory will be created in the output directory for each sample containing all output files for that sample. +A separate directory will be created in the output directory for each sample containing all output files for that sample. If a library name is given in the samplesheet, the sample directories will be nested within a library directory.
    Output files @@ -44,6 +44,7 @@ A separate directory will be created in the output directory for each sample con - `SAMPLE.regions.bed.gz`: The regional BED file, showing how well covered the requested regions are, calculated by `mosdepth` (only when a ROI BED file has been given) - `SAMPLE.regions.bed.gz.csi`: The index of the regional BED file - `SAMPLE.stats`: General statistics for the sample + - `multiqc/`: Directory containing the MultiQC report for the sample or library
    ### Extra outputs for flowcell inputs @@ -70,9 +71,9 @@ Some additional files will be created when a flowcell input has been used. -[MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. +[MultiQC](https://seqera.io/multiqc/) is a visualization tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. -Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQC. The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. For more information about how to use MultiQC reports, see . +Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQC. The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. For more information about how to use MultiQC reports, see . ### Pipeline information @@ -80,10 +81,8 @@ Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQ Output files - `pipeline_info/` - - Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. + - Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.mmd`. - Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. - - Reformatted samplesheet files used as input to the pipeline: `samplesheet.valid.csv`. - - Parameters used by the pipeline run: `params.json`. diff --git a/docs/parameters.md b/docs/parameters.md index 18c594f1..700a2292 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -12,51 +12,50 @@ Define where the pipeline should find input data and save output data. | `outdir` | The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure. | `string` | | True | | | `email` | Email address for completion summary.
    HelpSet this parameter to your e-mail address to get a summary e-mail with details of the run sent to you when the workflow exits. If set in your user config file (`~/.nextflow/config`) then you don't need to specify this on the command line for every run.
    | `` | | | | | `multiqc_title` | MultiQC report title. Printed as page header, used for filename if not otherwise specified. | `string` | | | | +| `genomes` | | `object` | | | True | ## Pipeline options -| Parameter | Description | Type | Default | Required | Hidden | -| ------------------------ | ----------------------------------------------------------------------- | --------- | ----------- | -------- | ------ | -| `markdup` | Which alignment postprocessor to use | `string` | bamsormadup | | | -| `run_coverage` | Run coverage analysis steps | `boolean` | True | | | -| `skip_trimming` | Skip adapter trimming | `boolean` | False | | | -| `split_fastq` | Number of reads per FastQ split (0 to disable splitting) | `integer` | 100000000 | | | -| `trim_front` | Number of bases to trim from the front of the read | `integer` | 0 | | | -| `trim_tail` | Number of bases to trim from the tail of the read | `integer` | 0 | | | -| `adapter_R1` | Adapter sequence to be trimmed | `string` | None | | | -| `adapter_R2` | Adapter sequence to be trimmed | `string` | None | | | -| `disable_picard_metrics` | Disable the calculation of (slow) Picard metrics | `boolean` | False | | | -| `roi` | Region of interest for coverage analysis to be applied to all samples | `string` | None | | | -| `genelists` | Directory containing gene list bed files for granular coverage analysis | `string` | None | | | +| Parameter | Description | Type | Default | Required | Hidden | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | --------- | -------- | ------ | +| `split_fastq` | Specify how many reads each split of a FastQ file contains. Set 0 to turn off splitting at all.
    HelpUse the the tool FastP to split FASTQ file by number of reads. This parallelizes across fastq file shards speeding up mapping. Note although the minimum value is 250 reads, if you have fewer than 250 reads a single FASTQ shard will still be created.
    | `integer` | 100000000 | | | +| `genelists` | Directory containing gene list bed files for granular coverage analysis | `string` | None | | | ## Institutional config options Parameters used to describe centralised config profiles. These should not be edited. -| Parameter | Description | Type | Default | Required | Hidden | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------- | -------- | ------ | -| `custom_config_version` | Git commit id for Institutional configs. | `string` | master | | True | -| `custom_config_base` | Base directory for Institutional configs.
    HelpIf you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.
    | `string` | https://raw.githubusercontent.com/nf-core/configs/master | | True | -| `config_profile_name` | Institutional config name. | `string` | | | True | -| `config_profile_description` | Institutional config description. | `string` | | | True | -| `config_profile_contact` | Institutional config contact information. | `string` | | | True | -| `config_profile_url` | Institutional config URL link. | `string` | | | True | +| Parameter | Description | Type | Default | Required | Hidden | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------ | -------- | ------ | +| `custom_config_version` | Git commit id for Institutional configs. | `string` | main | | True | +| `custom_config_base` | Base directory for custom configs.
    HelpIf you're running offline, Nextflow will not be able to fetch the custom config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.
    | `string` | https://raw.githubusercontent.com/nf-cmgg/configs/main | | True | +| `config_profile_name` | Institutional config name. | `string` | | | True | +| `config_profile_description` | Institutional config description. | `string` | | | True | +| `config_profile_contact` | Institutional config contact information. | `string` | | | True | +| `config_profile_url` | Institutional config URL link. | `string` | | | True | ## Generic options Less common options for the pipeline, typically set in a config file. -| Parameter | Description | Type | Default | Required | Hidden | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | ------- | -------- | ------ | -| `help` | Display help text. | `boolean` | | | True | -| `version` | Display version and exit. | `boolean` | | | True | -| `publish_dir_mode` | Method used to save pipeline results to output directory.
    HelpThe Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.
    | `string` | copy | | True | -| `email_on_fail` | Email address for completion summary, only when pipeline fails.
    HelpAn email address to send a summary email to when the pipeline is completed - ONLY sent if the pipeline does not exit successfully.
    | `string` | | | True | -| `plaintext_email` | Send plain-text email instead of HTML. | `boolean` | | | True | -| `max_multiqc_email_size` | File size limit when attaching MultiQC reports to summary emails. | `string` | 25.MB | | True | -| `monochrome_logs` | Do not use coloured log outputs. | `boolean` | | | True | -| `hook_url` | Incoming hook URL for messaging service
    HelpIncoming hook URL for messaging service. Currently, MS Teams and Slack are supported.
    | `string` | | | True | -| `multiqc_config` | Custom config file to supply to MultiQC. | `string` | | | True | -| `multiqc_logo` | Custom logo file to supply to MultiQC. File name must also be set in the MultiQC config file | `string` | | | True | -| `multiqc_methods_description` | Custom MultiQC yaml file containing HTML including a methods description. | `string` | | | | -| `validate_params` | Boolean whether to validate parameters against the schema at runtime | `boolean` | True | | True | +| Parameter | Description | Type | Default | Required | Hidden | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | -------------------------------------------------------- | -------- | ------ | +| `version` | Display version and exit. | `boolean` | | | True | +| `publish_dir_mode` | Method used to save pipeline results to output directory. (accepted: `symlink`\|`rellink`\|`link`\|`copy`\|`copyNoFollow`\|`move`)
    HelpThe Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.
    | `string` | copy | | True | +| `email_on_fail` | Email address for completion summary, only when pipeline fails.
    HelpAn email address to send a summary email to when the pipeline is completed - ONLY sent if the pipeline does not exit successfully.
    | `string` | | | True | +| `plaintext_email` | Send plain-text email instead of HTML. | `boolean` | | | True | +| `max_multiqc_email_size` | File size limit when attaching MultiQC reports to summary emails. | `string` | 25.MB | | True | +| `monochrome_logs` | Do not use coloured log outputs. | `boolean` | | | True | +| `hook_url` | Incoming hook URL for messaging service
    HelpIncoming hook URL for messaging service. Currently, MS Teams and Slack are supported.
    | `string` | | | True | +| `multiqc_config` | Custom config file to supply to MultiQC. | `string` | | | True | +| `multiqc_logo` | Custom logo file to supply to MultiQC. File name must also be set in the MultiQC config file | `string` | | | True | +| `multiqc_methods_description` | Custom MultiQC yaml file containing HTML including a methods description. | `string` | | | | +| `validate_params` | Boolean whether to validate parameters against the schema at runtime | `boolean` | True | | True | +| `pipelines_testdata_base_path` | Base URL or local path to location of pipeline test dataset files | `string` | https://raw.githubusercontent.com/nf-core/test-datasets/ | | True | +| `trace_report_suffix` | Suffix to add to the trace report filename. Default is the date and time in the format yyyy-MM-dd_HH-mm-ss. | `string` | | | True | +| `help` | Display the help message. | `['boolean', 'string']` | | | | +| `help_full` | Display the full detailed help message. | `boolean` | | | | +| `show_hidden` | Display hidden parameters in the help message (only works when --help or --help_full are provided). | `boolean` | | | | +| `igenomes_base` | Directory / URL base for iGenomes references. | `string` | /references/ | | True | +| `igenomes_ignore` | Do not load the iGenomes reference config.
    HelpDo not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`.
    | `boolean` | | | True | +| `genome` | Name of iGenomes reference.
    HelpIf using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`.

    See the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details.
    | `string` | | | | diff --git a/docs/usage.md b/docs/usage.md index 32028ecd..c44bccca 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -116,7 +116,7 @@ CONTROL_REP1,AEG588A1_S1_L004_R1_001.fastq.gz,AEG588A1_S1_L004_R2_001.fastq.gz The typical command for running the pipeline is as follows: ```bash -nextflow run nf-cmgg/preprocessing --input ./samplesheet.csv --outdir ./results -profile docker +nextflow run nf-cmgg/preprocessing --input ./samplesheet. --outdir ./results -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -195,6 +195,12 @@ They are loaded in sequence, so later profiles can overwrite earlier profiles. If `-profile` is not specified, the pipeline will run locally and expect all software to be installed and available on the `PATH`. This is _not_ recommended, since it can lead to different results on different machines dependent on the computer enviroment. +- `debug` + - A generic profile with settings to help with debugging the pipeline. It will use more verbose logging. +- `arm64` + - A generic profile with settings to run the pipeline on ARM64 architecture machines (eg. Apple Silicon). It will use software containers built for ARM64 where available. +- `emulate_amd64` + - A generic profile with settings to run the pipeline on ARM64 architecture machines (eg. Apple Silicon) using AMD64 software containers. This is for when ARM64 containers are not available but you still want to run the pipeline on an ARM64 machine. Note that this will be slower than using ARM64 containers. - `test` - A profile with a complete configuration for automated testing - Includes links to test data so needs no other parameters @@ -241,22 +247,14 @@ A pipeline might not always support every possible argument or option of a parti To learn how to provide additional arguments to a particular tool of the pipeline, please see the [customising tool arguments](https://nf-co.re/docs/usage/configuration#customising-tool-arguments) section of the nf-core website. -### nf-core/configs +### nf-core/configs and nf-cmgg/configs -In most cases, you will only need to create a custom config as a one-off but if you and others within your organisation are likely to be running nf-core pipelines regularly and need to use the same settings regularly it may be a good idea to request that your custom config file is uploaded to the `nf-core/configs` git repository. Before you do this please can you test that the config file works with your pipeline of choice using the `-c` parameter. You can then create a pull request to the `nf-core/configs` repository with the addition of your config file, associated documentation file (see examples in [`nf-core/configs/docs`](https://github.com/nf-core/configs/tree/master/docs)), and amending [`nfcore_custom.config`](https://github.com/nf-core/configs/blob/master/nfcore_custom.config) to include your custom profile. +In most cases, you will only need to create a custom config as a one-off but if you and others within your organisation are likely to be running nf-cmgg pipelines regularly and need to use the same settings regularly it may be a good idea to request that your custom config file is uploaded to the `nf-core/configs` git repository. Before you do this please can you test that the config file works with your pipeline of choice using the `-c` parameter. You can then create a pull request to the `nf-core/configs` repository with the addition of your config file, associated documentation file (see examples in [`nf-core/configs/docs`](https://github.com/nf-core/configs/tree/master/docs)), and amending [`nfcore_custom.config`](https://github.com/nf-core/configs/blob/master/nfcore_custom.config) to include your custom profile. See the main [Nextflow documentation](https://www.nextflow.io/docs/latest/config.html) for more information about creating your own configuration files. If you have any questions or issues please send us a message on [Slack](https://nf-co.re/join/slack) on the [`#configs` channel](https://nfcore.slack.com/channels/configs). -## Azure Resource Requests - -To be used with the `azurebatch` profile by specifying the `-profile azurebatch`. -We recommend providing a compute `params.vm_type` of `Standard_D16_v3` VMs by default but these options can be changed if required. - -Note that the choice of VM size depends on your quota and the overall workload during the analysis. -For a thorough list, please refer the [Azure Sizes for virtual machines in Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/sizes). - ## Running in the background Nextflow handles job submissions and supervises the running jobs. The Nextflow process must run until the pipeline is finished. diff --git a/nextflow.config b/nextflow.config index 44d9698c..990ff21a 100644 --- a/nextflow.config +++ b/nextflow.config @@ -69,26 +69,6 @@ profiles { cleanup = false nextflow.enable.configProcessNamesValidation = true } - conda { - conda.enabled = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - conda.channels = ['conda-forge', 'bioconda'] - apptainer.enabled = false - } - mamba { - conda.enabled = true - conda.useMamba = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false - } docker { docker.enabled = true conda.enabled = false From 2a732449a476cdc01c45885d7eb90e624a1ceed8 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 6 Mar 2026 09:54:51 +0100 Subject: [PATCH 226/228] add plugins untill NF 26.XX is in prod --- nextflow.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nextflow.config b/nextflow.config index 990ff21a..61685c2d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -248,6 +248,8 @@ manifest { // Nextflow plugins plugins { + id 'nf-cgroup-metrics@1.0.1' + id 'nf-cmgg@0.1.0' id 'nf-schema@2.6.1' id 'nf-teams@0.1.0' } @@ -258,6 +260,10 @@ validation { } // TODO remove this once minimal nf-version is 26.0X with strict syntax. +cmgg { + samplesheets.enabled = true + done.enabled = true +} teams { enabled = true webHook { From 6064f40407dde76fcf29bbb29e2db41086844340 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 6 Mar 2026 10:07:34 +0100 Subject: [PATCH 227/228] Remove download_pipeline workflow file --- .github/workflows/download_pipeline.yml | 134 ------------------------ 1 file changed, 134 deletions(-) delete mode 100644 .github/workflows/download_pipeline.yml diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml deleted file mode 100644 index d9970752..00000000 --- a/.github/workflows/download_pipeline.yml +++ /dev/null @@ -1,134 +0,0 @@ -name: Test successful pipeline download with 'nf-core pipelines download' - -# Run the workflow when: -# - dispatched manually -# - when a PR is opened or reopened to main/master branch -# - the head branch of the pull request is updated, i.e. if fixes for a release are pushed last minute to dev. -on: - workflow_dispatch: - inputs: - testbranch: - description: "The specific branch you wish to utilize for the test execution of nf-core pipelines download." - required: true - default: "dev" - pull_request: - branches: - - main - - master - -env: - NXF_ANSI_LOG: false - -jobs: - configure: - runs-on: ubuntu-latest - outputs: - REPO_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPO_LOWERCASE }} - REPOTITLE_LOWERCASE: ${{ steps.get_repo_properties.outputs.REPOTITLE_LOWERCASE }} - REPO_BRANCH: ${{ steps.get_repo_properties.outputs.REPO_BRANCH }} - steps: - - name: Get the repository name and current branch - id: get_repo_properties - run: | - echo "REPO_LOWERCASE=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" - echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> "$GITHUB_OUTPUT" - echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> "$GITHUB_OUTPUT" - - download: - runs-on: ubuntu-latest - needs: configure - steps: - - name: Install Nextflow - uses: nf-core/setup-nextflow@v2 - - - name: Disk space cleanup - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 - - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 - with: - python-version: "3.14" - architecture: "x64" - - - name: Setup Apptainer - uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0 - with: - apptainer-version: 1.3.4 - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install git+https://github.com/nf-core/tools.git - - - name: Make a cache directory for the container images - run: | - mkdir -p ./singularity_container_images - - - name: Download the pipeline - env: - NXF_SINGULARITY_CACHEDIR: ./singularity_container_images - run: | - nf-core pipelines download ${{ needs.configure.outputs.REPO_LOWERCASE }} \ - --revision ${{ needs.configure.outputs.REPO_BRANCH }} \ - --outdir ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} \ - --compress "none" \ - --container-system 'singularity' \ - --container-library "quay.io" -l "docker.io" -l "community.wave.seqera.io/library/" \ - --container-cache-utilisation 'amend' \ - --download-configuration 'yes' - - - name: Inspect download - run: tree ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }} - - - name: Inspect container images - run: tree ./singularity_container_images | tee ./container_initial - - - name: Count the downloaded number of container images - id: count_initial - run: | - image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) - echo "Initial container image count: $image_count" - echo "IMAGE_COUNT_INITIAL=$image_count" >> "$GITHUB_OUTPUT" - - - name: Run the downloaded pipeline (stub) - id: stub_run_pipeline - continue-on-error: true - env: - NXF_SINGULARITY_CACHEDIR: ./singularity_container_images - NXF_SINGULARITY_HOME_MOUNT: true - run: nextflow run ./${{needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -stub -profile test,singularity,s3_ugent --outdir ./results - - name: Run the downloaded pipeline (stub run not supported) - id: run_pipeline - if: ${{ steps.stub_run_pipeline.outcome == 'failure' }} - env: - NXF_SINGULARITY_CACHEDIR: ./singularity_container_images - NXF_SINGULARITY_HOME_MOUNT: true - run: nextflow run ./${{ needs.configure.outputs.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ needs.configure.outputs.REPO_BRANCH }}) -profile test,singularity,s3_ugent --outdir ./results - - - name: Count the downloaded number of container images - id: count_afterwards - run: | - image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) - echo "Post-pipeline run container image count: $image_count" - echo "IMAGE_COUNT_AFTER=$image_count" >> "$GITHUB_OUTPUT" - - - name: Compare container image counts - id: count_comparison - run: | - if [ "${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }}" -ne "${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }}" ]; then - initial_count=${{ steps.count_initial.outputs.IMAGE_COUNT_INITIAL }} - final_count=${{ steps.count_afterwards.outputs.IMAGE_COUNT_AFTER }} - difference=$((final_count - initial_count)) - echo "$difference additional container images were \n downloaded at runtime . The pipeline has no support for offline runs!" - tree ./singularity_container_images > ./container_afterwards - diff ./container_initial ./container_afterwards - exit 1 - else - echo "The pipeline can be downloaded successfully!" - fi - - - name: Upload Nextflow logfile for debugging purposes - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: nextflow_logfile.txt - path: .nextflow.log* - include-hidden-files: true From 6981bdc2da8daec7953698784b372b93c6891c92 Mon Sep 17 00:00:00 2001 From: Matthias De Smet <11850640+matthdsm@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:55:38 +0100 Subject: [PATCH 228/228] Fix docs and new metro map --- CHANGELOG.md | 2 +- README.md | 51 +- assets/schema_input.json | 4 +- docs/images/metro_map.png | Bin 212847 -> 0 bytes docs/images/metro_map.svg | 1263 ----------------- docs/images/metro_map_dark.md | 45 + docs/images/metro_map_dark.svg | 99 ++ docs/images/metro_map_light.md | 45 + docs/images/metro_map_light.svg | 104 ++ .../nf-cmgg-preprocessing_logo_dark.png | Bin 78416 -> 65764 bytes .../nf-cmgg-preprocessing_logo_dark.svg | 16 +- .../nf-cmgg-preprocessing_logo_light.png | Bin 79022 -> 65952 bytes .../nf-cmgg-preprocessing_logo_light.svg | 14 +- docs/output.md | 8 +- docs/parameters.md | 8 +- docs/usage.md | 141 +- 16 files changed, 409 insertions(+), 1391 deletions(-) delete mode 100644 docs/images/metro_map.png delete mode 100644 docs/images/metro_map.svg create mode 100644 docs/images/metro_map_dark.md create mode 100644 docs/images/metro_map_dark.svg create mode 100644 docs/images/metro_map_light.md create mode 100644 docs/images/metro_map_light.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index c062310d..34cc5393 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## v2.0.2 -- Drop unsed params +- Drop unused params - Set aligner to `star` for RNA-seq - Finetune resources - Fix some bugs for different input tags diff --git a/README.md b/README.md index 119479bf..2d6849f9 100644 --- a/README.md +++ b/README.md @@ -18,17 +18,23 @@ It also performs basic QC and coverage analysis. The pipeline is built using Nextflow, a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It comes with docker containers making installation trivial and results highly reproducible. -Steps inlcude: +Steps include: -1. Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html) -2. Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp) -3. Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq -4. Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html) -5. Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html) -6. Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollecHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics) -7. QC aggregation using [`multiqc`](https://multiqc.info/) +- Demultiplexing using [`BCLconvert`](https://emea.support.illumina.com/sequencing/sequencing_software/bcl-convert.html) +- Run QC using [`MultiQC SAV`](https://github.com/MultiQC/MultiQC_SAV) +- Read QC and trimming using [`fastp`](https://github.com/OpenGene/fastp) or [`falco`](https://github.com/smithlabcode/falco) +- Alignment using either [`bwa`](https://github.com/lh3/bwa), [`bwa-mem2`](https://github.com/bwa-mem2/bwa-mem2), [`bowtie2`](https://github.com/BenLangmead/bowtie2), [`dragmap`](https://github.com/Illumina/DRAGMAP), [`snap`](https://github.com/amplab/snap) or [`strobe`](https://github.com/ksahlin/strobealign) for DNA-seq and [`STAR`](https://github.com/alexdobin/STAR) for RNA-seq +- Duplicate marking using [`bamsormadup`](https://gitlab.com/german.tischler/biobambam2) or [`samtools markdup`](http://www.htslib.org/doc/samtools-markdup.html) +- Coverage analysis using [`mosdepth`](https://github.com/brentp/mosdepth) and [`samtools coverage`](http://www.htslib.org/doc/samtools-coverage.html) +- Alignment QC using [`samtools flagstat`](http://www.htslib.org/doc/samtools-flagstat.html), [`samtools stats`](http://www.htslib.org/doc/samtools-stats.html), [`samtools idxstats`](http://www.htslib.org/doc/samtools-idxstats.html) and [`picard CollectHsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectHsMetrics), [`picard CollectWgsMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectWgsMetrics), [`picard CollectMultipleMetrics`](https://broadinstitute.github.io/picard/command-line-overview.html#CollectMultipleMetrics) +- QC aggregation using [`multiqc`](https://multiqc.info/) -![metro map](docs/images/metro_map.png) + + + + + Fallback image description + ## Usage @@ -37,36 +43,15 @@ Steps inlcude: The full documentation can be found [here](docs/README.md) -First, prepare a samplesheet with your input data that looks as follows: - -`samplesheet.csv` for fastq inputs: - -```csv -id,samplename,organism,library,aligner,fastq_1,fastq_2 -sample1,sample1,Homo sapiens,Library_Name,bwamem,reads1.fq.gz,reads2.fq.gz -``` - -`samplesheet.csv` for flowcell inputs: - -```csv -id,samplesheet,lane,flowcell,sample_info -flowcell_id,/path/to/illumina_samplesheet.csv,1,/path/to/sequencer_uploaddir,/path/to/sampleinfo.csv -``` - -`sampleinfo.csv` for use with flowcell inputs: - -```csv -samplename,library,organism,tag,aligner -fc_sample1,test,Homo sapiens,WES,bwamem -``` +First, prepare a samplesheet with your input data. Check the [usage docs](docs/usage.md) for details on the required format and example files. Now, you can run the pipeline using: ```bash nextflow run nf-cmgg/preprocessing \ - -profile \ + -profile \ --igenomes_base /path/to/genomes \ - --input samplesheet.csv \ + --input samplesheet. \ --outdir ``` diff --git a/assets/schema_input.json b/assets/schema_input.json index a6cd4941..4a7bd527 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -160,10 +160,10 @@ }, "anyOf": [ { - "required": ["id", "samplename", "organism", "aligner", "tag", "fastq_1", "fastq_2"] + "required": ["id", "samplename", "organism", "aligner", "fastq_1", "fastq_2"] }, { - "required": ["id", "samplename", "genome", "aligner", "tag", "fastq_1", "fastq_2"] + "required": ["id", "samplename", "genome", "aligner", "fastq_1", "fastq_2"] }, { "required": ["id", "samplesheet", "sample_info", "flowcell"] diff --git a/docs/images/metro_map.png b/docs/images/metro_map.png deleted file mode 100644 index f2057abd01142a8e04fa59717a1e315d464c56fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212847 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≫Kd11KWU0&gh*IgwHF1 z?yHhEPsCnmDOF|`xnG&<`cW4BN!vQfY0H^RG(f(dc zW2XSbAxbw2JA9525V7^A95qy!We-L+7lL)*(;0&5ENN~HFp+v>G{GZB_JD^D+*TNC zJTy`?OUcK+JfPJG%6vIbgd>%~?@FEg>pLI^8+JRc)NFDXt?v$$XB6_+;zm}WGr;mT z-+G&Q;I6G3Ss}SP17vgCvFoAp4>1t30em_2z9#}F;0RmAqmSzWb9>}6jQ8J`pBCm< z`kQ+E-kq+IK20Tq@LhA@ic2hvX5afI@=}WFTY2>Q7hx_jtTULS5@8N5d0@Pu2VyEg zEJ?gDM-=?nyx=g=w+@&raDNOd?xAi1kE^l6VJr6QBJHfY3)Ure>(u9^LzF*Lc4 zz!G>3;W+^(mm>^Du)=J5?qK`)8>Oa>ju3$G6sx6wcDAA>NXf0SMd0_U2RBPxW(e^b z1rWiEMy1<+gdawgt$Xs9*#+LA*b=oJW=3cr+72YW)7z@@sSP&D=trT3 zRW7xie<&qb`zT|#MtK~|*TwKMXh2bNy3e4oRh0u^h{IF@oVHN@~{ zSiKjfmT{%oxhK(NsdxE{kf2~`LxU0(umHw%anTLxYgJNW&9^*crgtCiR&sb0??8yj zXq&OUh4k^L!(flC-lZ^wH%xE|6skzZ$eJ2Fj0G69fU<*`tQc_^jhjUtp9 zG(J&Qs67eqE?65FOX!5 z(*nJBQ^wWPMUxCP`w(K^^cJ)p@H;Z=pgnQYWD^gEap9v^Ksd7XE9l&3SXZ7w$V%b! z>$(_)&%#Yc-lrB`ljnaZi{^WPFO6 zlqg*&=;~xJS$vKkL%OTPd>S)9Vh|1_bL*ii6tevcQc@gexZ_4XO;|*zLmm7W5%eW- zNdV6Y<0`}<)s12>v=u`209nPz!$q7vTs}|q2;abrLE-Wf_&$7*u{z5J+9}kiq}2u7 zUEBQE?jSXF#er6NHk+KhEjBlJvd6;(ZwAmA9c>2`N~reOKxp*xkuHHlwwxstq|etS z&sXSN)6BTrf7PJ)cP>&THac6`*ua)M2$*{#RLEj?e%GPGz>31%NIRg6KgAj;MrP(1 z8{S&7LIS82c$&m;9*6W(j;ShEqt{?k;SWn*^eKIaO{9joV7v~ctQ=T8rKP3lXngTV zKE*1q64EndrqK7la#>zN)#{Gxt`c9r%<$*W-@nlyKjkDUzAO7bE`Vt>tt&2^6-=U0 zSGm<~CVFS0J_q)C>=uK3b-oTr80QX;&lyKd%z1|pVISTIc4!(YPt3VsuVECVC2GkU z8@RbULU6KAi7S%XQ0DCsm3=I-4U!dtwXJe0G3LUD1Z$QIYC`KkAIC6*LO>K8y-#Mj zM4eCXTNj&w`lT*Z^eNsw>EiLWvCZ*_ISZbKlu@TAP6&BJ#o!Phc|>?#C_jm)5x<1E zeqgJ675SdryDKbJP_6cnh6t7R9CIPjBb<}_Y3{_*Cme%ZA&7H?Jv&j%lN6W8|yA%&?P|{$16g6(6#(Q{`tNo*>~3fSej8fQAcK z#uX*l`9-kJhYCNN9PW6wYWPWQd3oIl2Y@0i+XE0p>~}=s{2(G>lPSgE;7LpDa>u#S z7$F5Qc-q3)P)dT*e?lz^dgEKTR8KGfy|HzXxbbeQ>W6;ZJ&SKZHn0l`>DE=J-T#I39uqI=a#W8L znTlk{TJbsL`0`8jY{9fE$}c0|Uj3?Qr?zWm49E;bJSsDM#`+*XNt z=ZxZ_-uw9*C5tSn8p&~ERTHIaI8YEa09x?^R0a%RIoWNa@ z3KK@6a0M7KHNCYM4k2XvIaa*jk6u9)iMwcoj9&!>nE?JS&HmUpWfd;If55F5YZNu)jFsj0Kc%!STQ!B^u&o;K~u&No?$%%UB|WC}lrGMsTzJ z!FrHfyho}42tybPQ}amh5ZCSi#&3-N9@aCPK{@Dlnz@WRAa$_V3!n{vLU|-O!f2p? zH}DM~l`O@DqW~jtVGy^s9x-Ev@LB8^H#au{xqv@_ga$_cki}SZs~K=IdSDp60Llo! z6(BKxrt7T(!Xi9!lyGKkrzrq4v4DGTnDIX)OoR#b7<~piF4QhzFTn8%Al6Yq)fNbm z-LdYw?g;IF3mQ&iEV6fHTBX2wCt{p;%B6PU+!2<*qt=26zi#AH+1RE-G%9rUy@!RW z0H8B3)SA8Dzn9|tt;0quoa52%qD!f&a6urcE`JP%IE}R6@j&DQF>6wW(j|8ksb~OT zJ7HEJNn8QL3BMKN*Uav_m`V_`H%`Hi>;{SEx5ZaVsgU?c>Oe&shr^5VGz`CKC^T@s z{`eS~{e^Oz7u?9qX_Gz-v`rIemv$a>IUrxo4JW6!WFY_%ehCW4Tb(Y`9mb%4Z-gcY zxsFg(p;`HyC~W@u0El4VRnV#@sX;PIB_JRGc4vziJe9B-m?&Ivv>bpNVtMF3T#=(d za%ydQPD3X_LObji`ML?qDrn#>?@-LO*ptE&*@u|w6G0uoZlVh| zh`GM+1pqR9ahqd-CI;5AVPxtZXJm!_2kFS2?f zr&l3#eX5z0S^ul`58Y}XE&R1|aEHKTM{3~vK^z?-aln8FW5>Cl@e#x!0HrH%ogat{ zNbes}#u2v^RADDon9)Zo;8nqMVa+!*Ze&jc4)su7yB`KE2nu8phJLRC6Vjp1-2K4b z7+`Z<+TOlZMg@`zE+DK(*pfE?z&-hZ!UZ_&A%d(En=F7a^EvMibdtN?j4T%HjDy+SI4U-*M%$q>iJJk_Z_E@ zLJE91Zjhx!5Wx?j*CeewqCM`$?~t+Yz@EtWK-Eh2FM+0X8dnc{z*6SP9qX^v2i~$FBQm0Hq)b8DAG|!kp2y);X7tz zON${K%0#_^M~^K(sm-?ud^Zjv`#5$dASDk!$R}<|=scmhI~CsrjRe-tDZAGkK%1+w zQLScJ;PBzYN@KMcByM0{1^63gBT467FrfI3UCFA{GF3YD|0c~{fiX72ChCatY65g% zi5e-~;EG4VjF424WQ#8b|5!}2K~l10kk+RoGbd;D6|gJ`!DSFhk8?dYrW#T09Zo+u zw{;wN!E0)uXnL*eS=99cyXUik9-;f`oYFNT*EV8wc;t*YhHSX86<@vp812ls(Ideu za}^{JJc*H9TN|5ZyUW-n2_}3iwJ*GgVE9$u-Mte|F;mHeJ_&kJUwaSYbXD!CD3|G= zRy~cSkEkzzC*CspO#$uXmbJH0Q2_pp;lefeF$v5jk)3eU)JCu;D;zs}$C28Fuyu^A zSs2O0pM(N+!{%l^RMcc2#&b!R;`3tL$h?M!BYhpGPmo8;daCGfrx%I7XLoE8in1Q% z5#{!aNdI*;bg(3tCr$G%4W8%vBtobrxI47wSfo{2U(W#D6hW7vnf8A0p!%q09o)4K zfNqE8Bn$jTi}Z^L%A6M$`(|80+{%1e)@ZpNGV z+q1mH3Pu7BTp7OM)7_2<0~&Sy zPtPi*#r@uMx>~gKACBVs#IJ5badYAuCe{D=pi;&qfD;6n)m(6YPh?D3DGrFh4apw( zc9m@jK6VABvj}COVR~s!Ie?QPBT9BSl8qvXaC^cIlW+eW1q5!%V1dF(Sp1Xm4_xlZ zi_W>;^#V=Mz}+(q*XNjrpu}=Husa{pnSMgJ%wZ ze%`Bpp)zBs>8aNC;`Cjf8vlxV-M9>BeW5JCRZ-f&g4#+7D1=s?#Ws*Bn~(qb%!r}% zhxhOAZIqam8f0$5xds9)rLA4h;aGS^i)X;-*GDzx`xq9J(Rr9X?hY{zQIeRG?uuAz zHP(Fs0A^G%ytc@8PGe*s(x@PQgkbcOg`lkCH-eOBf6@ZfI12F6f?*6Ob=5basrK2h z?7gtt*u*B~VzIR9!y}&jDVp2zUcT;IGq*$g&t5k!3hMX|RaI+cRBkcctQPwv{B}=* zC-AR+0KsINAf76bNMNcXgWSFiY&5XpMej^dL7emeC>Rkwl9kzS-yR2pI|lDXY>I?8 z0NPsrNz+J(0@(-tV`P=+MuVMHD3A^y37W#{juIwjs}JyrjJtvNxmVf}jp0!X!tXL^ zP1*tjNXLn49$W}T0i_tEjM1~h>+wPur$mB6c%mEG#<@RgM!%B&xj5S+VWiv>cKM}H zdTHc8hRnN9q*N+FRR;Q^u`z-uD_MZXk%|f(azZ~+MJTr1B728icrJ-?D7fQ zNeCh^!DuD}=Ql|I=oTI#c>l~<28_3so*ou`?xZjTqmEhT70PX~Uq9e!kAn_~94I{T zM8S9WmW}2FO9{e%ve!GTC>Yfc(GZe~2tn6)VJBwvgw+g+hMH0+%;E@;22%v0T0ow^ z`zyCCe2yJWB(#E)H2)~a%=@o+bKA7TbW)_-cED>=b#Jc$I(=2_FHSi`r(ph8ivW0x0P=Zs^(J-a+ z>AOUutyH%#v&p!1L{G5rPS0!p_Z7WYK&#zdc27P$Q!WdR=nOtw5%0LIXhLYufo+$H zd`lN~oR}*L6)tT^)3e~Eb6gf3)s9%mJ0W?GNtk|xu)I0>%feq!}{QD1iy;%{_h1@Fcis^ zmodAKwAp0D72s6_D#k*jNiy*RdDb9eS35zkwx-zD=TQu?K+ z*C@CT$C)+%oNsH>alTvoZK;UeJS(O8%)=uUquKfYXnm45y1NPI;`cyJwgTmB`n@+^ zctMRhVEwtLs~VF+w~VQ0*J4V$Q|3?otB?Y*Kez4%`8!@%4AbcvjNR*|pB5(J^a2!# zAfkH)y$!~20T2jtI873XG1+iS8Ypldh(8&sVweY9_>!)fNrilbDkc6I;VNJbuzCA- z1vC?6mmsL*<@E>uj@?3!4M{o==0d;)#Kpw{sI9>jT73mLCpvUNNM$Lgy)_ZIQBw8c zkBPkry8H3Zmu`Fl=pQ!oG(5Z>DW#*x;TVX;(DrS>Bn{>G)??S%F%owA6re`KMcWT2a-eU3jL`vA~+iOGss7O#>c;*>ijp^tYpRkD7PF~s*@9t9|UB= z-UAnacnBey5dAD#hFc$+(PNMT24k8BP&@-`hD|mTnvV%6Em{Ap1+Y`-an3poBli0| zqL*u}?$9!rm@jPMl!H!Gk;k*Mo;yrJk}bgn?wZD$ZgCdpsP$W2rX)c#q*B2W&}3v+oKCwT zdt|Dz_5Jvs6m6NS|3V@}wmNV&%WRP?*{*}-Ccv9fW!F#*!UpK?_#HFvZnX#-7UVL2K}HOh~9*Bf=(aX z{T>nzk2Z{I&mg-H4|dcTx8U3f^eD1*Ak?7+CYpn`*p>uZi@5#dT35htaDj^xzP3&o z&Pf07r~DaXo_mh|Vc#jo3u&F|nSz5w!!&osWo7mo4}9h@uv(IF?R$85p5xNHxDl5v z?IOCo>zL^S_r5f~Y7n@vZ1(bqIeM*Q1a!fR>P6xuSPQN@HIXDDRx|+On8T((J4|IT zeu;<6w;kJ$X1K+r()ugarkz8C`$GoHy|GWy?k848c`Mc1jkPw{ym&c&RdLNjdJ(HX zx0A}An_aeU-K+SrKG0@l{B2&kRON+lyOkXiLteZ}}Zm@Qdt20vyJ z6$rM1a58M&RG6fZ$_Bt3F4#WBUMvz~96{Ozd_ZJ_{6PT#y~)7^iwg1{pw z1dSr|>^D)o@CAduB|4i!P=Hu^;&lvR7z!}w2VyB1+7hG1|Mx>M3sF~``5oVPUG`JU znKHTD9XI)cO7tE@$hp(@*e{y)D{}|)Zz(PuudQW0Bp*53v>nh7#BrqfL_10bL>Nvz z$5?;@;Y%#)P%>#AoFy$cGb7z8hrOAM~U#`RdNcMer1g*-Acsq^xB z3Pk{DKYymDKeUV3Op9}KyMy#WT(J=n0uXvYr!TGl?ZPwb>EZF{`SUX%n=;5;WW^XtvV`zk$WB4>TD=Xx(#4`iDefL|31!2uV= zWjlhFDgB3s+%vu4h;1@TU!FWn8l0q(4RT=ptruVUy`z9(>+;mL54rSLIv#$_f4Wi) z^#<*Yhw5ZWy<(5@>I6eow~wiN^`ojSYy9hS*p}sYeh3@6I(M<)Mw_MgO0819|2$?S zoZyWC!C()$7WPH{+|3s#r3q8{GOqqSG~O+ru7U^WR&lJZ=Q%icvUGi4iR9^TzrW@_F0()u zTKi|CHCqy6?|m`mkawQ@@7Q#u#a%ut+rlU2*4sQ`FK-sq)ZgB2O{EdH=dbhM=a(Au zw~3!UT&NhlYCLh}i+VKfAunpMho4;++{jc-f&Idt{! zJy~^;>w79#e$ewR9xg*NA&dGPw=8zYothI>UeX&(SzfeYs4 z7<#~iSJ{V3^8VLq+sL6`8gJS`=;-I)q1pUTb@XE`K2Kn_xv1^2mT}sJ{Ovn=sm|%_ zb|cCl&Ts`hc4@bXfY%N8XTSDen6&0soY`ln*XT{BhknNS`q5`7_cvUB8mDMn_jAiv zC8tmuLrdC!ede>SVosEgU$*IDc7af}n-tYF1D);$ORvM9di>KZ_sU%>UnQ7Kcd7pDzFe!sd8cte zpY_&}FHao5nag(4yUWvgRjhUXZjF^s zvUlZ^=$8e({i=BW*z4lUXE)Qf*7dA21wTHDi@c3RxKxolhT`p@pOPswjs>t20hL+^6?@xQNMG|w!T)F(EFN7L|m z(5kG}dcl>`(Z*G#`Qhlp%(~~LTSu<+UOQCQzE_yG?9j7nZQiDbp1jqYVq;`{>0*Di z6gay~9-j%#w@FeR_Pr^|5%AZlyKUjk*n)k}jlr&kH^C#lR=N+2D-1=fl>X*0>N6dR zb)wc}``PkJ{f0!Xn4|0YxT9<%JFO5a8&>8M|F{qxCNo~)N;(4E)!K>`MRk!Wy z?5gkhCDDIGdG`gGr%1kzT{rr1{cvMcKJ|{wqt2sZ)JAVUum#WY9b^p9HCWs~J19Ob zelh!fv~h1(2YbzTD-m{vc#UuMTwY~~f`62JlXCw}7R}p_XQkSC_48wYAOF@Y& zbBbWZ*G-MduTDsqd{4@B)*P_(h>@d~p?Rn0_F{`Q$EqQd@GN(H4Sa?*|9u2bR@HFs zJtflD76tQ+4z)I?o%Ze4W$6ew_0nF0Z6y750muETJT*IH6|J^wovy{t;VBf>S{Xks z`>yuVQES`zy(X_OGDrn{kR9r*N?_o(fBR{R!gxvjQ%)xHfphU&2CiJx&oBzQbeLxJ zZSg(Z|2;+Zm8Y1bI37L7+juC!@0IlWF^xD|i%(yaE}5#H%emR6xoq5gLA)(UEp_N; z8TA+PiSfXgzH0SZiL^!~sQEVr4zi7G%oTJp{>!Hktn_8QXOLTn>>ImH{OndHTDei% zH(LDnMdOYB`?S9Fd@maI9TooU<{LYZ$k}Z>nR{zo=J>}M)}`Kdy8A(*y+(en&wiPe z3QfW9vllJksH&P;Ow`jSPpBYIz-a0nD0C_+M|~D`hHnBmGbK8U{C4>1MMy1HOJq!M5&*`Xo#RiZlhp2x4!;| zHXkJv)d9^6%7w(7ypKOtp0FzYf4`T>n(7|MiRLpGcT>$DOV_JpS-fMa+CcZ4g+XLN zBuT!j^25AHSKKb_O}_-+jzn@d;|&m%V5`O)L^l#+*NY-?7PvvHnEyDk}BF1vxL4 zr241=n#S_D^A_A(kP5O=b_K~39x7JBGruNJrTQ3=%{gFxI&0uWO5eqoIFPTG~NS4LtGju3=1}{_HX)MDX|V0S3xJQC3s) zARK`zhLr#%(*NISKYKEfT~LV*-NCVDFWVEv7c-AO@3423wcky(WHHm!)WBk!zgpGq zMig8mVe`Er?SPDm9UsJ8Z45Klkmv%8Rw1IN#z?6$KEhesumfG%H((jqK(-02%T*LK zlqs1%{)=f|EANC_Kb$#IEv-W#|B|povgV~*N6a@Y%&U(rQ@cif);M+Y@0*(};G9`O z!9Z~Z1dln+s=(uZbV-|sWJB;5WslX=${o>?7Xu%J;`;0v3oHzur_RmI9m%@?-*vvj zBFgShD{WZZc&6c;()PT)^R^Zr-`>9?{E_R$hmf|@_d+h5uN8ZtwI2J#FlJj77++!1 z9Jc`kt3zh}MhqI_bg z)iJqj@w?~!{Dy^6dyZFs+uIe%{rLck)|uK5{d(p4@7~ykp^0qRIbD>I!3at?rdIEw z<(6sN?dB)>AmmEAoNqnZgtj+p43qL?jT2l;5s%93EFl@q7{nZf3Kw%<%LY2S_ppQ| zGDYItRSm6Jh$F!4*Epfe_kV_p=|lK8stcyZwC&5X#J%Ed`w$KTy&8N~bmBTTwbc8q zA8CJaC%}Fawa76GFZ!Ryl3R+JQaIzJzpi1^UiHR4_qqc5nT69gfI_41rK^{OND)0a zmGW=3ea}42Y9PKPE{w1qg_SM`M#6Vt0j%({6gkfkf44gZo7vYgH6MbxhfevN%rOax zo#6AXah)jTsu0F<6Jb$`-!#9?VQv9|jb!aYCFtUY3Ns@J3D#z?20~|evxUkSY|X_VlalHreLa<9NN~@^d9IL$m;Zzs_JStMCkq3jEyUA;RVy<15sQ- zb$bem!gc_L(k3Rnw`^^{|NQv?y;Rm;Jba@bVvKjMhj&ah6q6WQ2KEH5K`Rm4T0nNI z6`HnyU$7mordOd{G&G;__W^5>Q2Dd<`#+s&_#AlL*H(u5GM_fvrEe#@f9$gzJDjx9 zAse>}W_Iea^&rv+f*t8*f$n&pJ$w{YFF6CMBXejB!d}J4lNLWOM)3fPFb^Z6>=kt* z+;H_yR260%{U<&`vW21VeXL_eD8LReV$sxMx*+WV|B81Ql3{#6+)Us-L`MHan|N*v z$lbk2O;`w5A`;$&Y7a!<$dr`zn6AA8VdW17>RIAhlt&>Ue0M*PuSPgV;C5j0K+Kmg zkJ*6xqjA$eJ3IRi0JL7r)bE0X?7bFRAH4NatUkbcwy|k9(234PNQCVG1hN)t46*`KZQq7dv~nE9Zi*8>JqxW*Ix0va#iH_N+@Oep@Cy&bAbs z+5H~F7n*hifKP3Fuop`qJ)BP}z}WD_;0t~^6e&CTo&9g{njQc}%7$>%g0TDy z4Gm{Uvm2iO!{G(gaSGeVBE#zH&H=~xfv%qH5Qu>yNEPAs-fg(}aBKD^pP|oz9nHy3 zPD<6sk22tfLIBJJ{eS2z@L~f0Qgyj3&3QSEHN`sCo;Ee*lMUF(|2o3QehlnnK&;<^ zW*xBIq`Wk`6Sm$XU+~uvlP0pPhK~LS{gX;N;qNacMcB{ZkLgG8WD=LYf!cCOBvGOB zth)Q@1n&C6omV;|{ZkW<15@?ETpOcS1{0X#f!ggsM6n=Ze!#FyFW(L~naUsgPT035 zs`(&;(cja75dmXGMTPC>C7?U2{q=G0GC-WbiIQc!thJ5n9_Gtnw2cK3S0@rSUcY5d(HNHI0(!ak-#KfP% z$i&2X=H#Rhj^KR|^pV^?K@fQKQajGMBUm}@fZjoB^oBZ*{Nw09aH4J!+MyJvwc~i% zbi-3XlE8;OgtZQ2CP2x6gU0}`eC!2qYPNxLVw|0g*R%D6{b6exn~o_mIu-SSDhSLX zL6FwHq4qKx(;F<*`Y*_Gips>Y{X8Pr>t;Fp;&xLU+t1imValZ6aQlllWMkS^fb=6r z(GsX_?%$Juhv0=`14JcS)HBRmwvdYioX{&EKq)Mz1dguLT}@4!2z3Mn9EE}R>D`-N;lx@L zIO9OU{dCpo)29&$UwmBR^WWl-3%1My3^ysf8@Z;jDhL|^bz;MyCL^NbAl1Goj49Q% zeh*_M0)YK*H~_R14-bz>K!=3vCL}COBOFMQ55s=t@V471nMScWYs$jZ4CJGmP@RJe z!^y+5h7^A&=7{q&G|(AB(4-N1(kcpA*IUK!X4Fhsb?;nhRQB!8*AzC+eB~D7&;R|f zaEnFWp{_F=)(;Nq9ew}ZYN>(v{ouV;`EOZx5PN|StphQU+ALLYTI*uHK1S&a-6bwA z1H4qkeXv!`7d^z)o;{n^fj_oOM1aLNM3se!>D6Z~P*wKXeAdoiI#$BZ#EJ0(BH+E- z<@%Xdmh+>WBfqM=bzT$$hfA$ftJtw%*VgA;LRigk7{}EM6fZ9P0PNV5`Ch^miYwV0 zb~z_KTEMCLju1U6!q4yLbg@pe8!N!7VYT}_dMyR%$$*+RG=K9-j-j*D)|qmap(Lc& za_q5HblSl^RJ-neZ%y>Nnw;{xNgJMPBvqjM$gRYw4Qb|P@g=0-0V&?&r-6lHfq_)C zY;H-qww+$6evh6^C0)3r%R%1sLb-9nee#0D&u{v&p5E3WKX0|p>e|}moE;TS^}(iX zX< zLPGQDmpm)KTkVT^eNH!bldHX$wynjwHIzDqwbl0OUf}|dybDOHzSN+sdv9NGE!o_Y z+`6BizXG8F!mC2<{8w-YMuByZvP(ij*XsP^`a#3MV22m*S;v@c%jX{4-CS$_RIqN< z1J`I2gaJyuii5Nzk9g|B=_=#`4F+b{{K-xYCa5%;=nLMwNm`x#X|>EQ4jTN9(>Qyr z!}}(N_sKo`hzF#lwQU5t@l6JXhU#A!>R(cmV)i^%uBeB%DY^NxG=xpLxH%`XzbN0c zKd>eBudas1id7DbQ??4~ONZsDZ^j*8%g@jM%sN^OEIA6M{Z(~!(qMyq`~90?N7##B z)gXKF5my|OPh6#02N(uR;7j&e{&0N_5gUbx_(Eg^7n)TRTsStQVsPOJ!Hlh!H{UOtF3t0En@8RNSVb1=8_Mn;hTi?|tmJWOvy zyEZr&>f10;ABapKF?!J{bRkhKqwuJxs8)t?CMbiXcBl;w2@CTRD4so~EQfS~3b}ph zd_QkKPVPG#EJ3JLDXz%uFTeK{h9SBB)c|bnjrsH{-k!c+-@c94*oMQzK7b=Qo@*A? zHj$|xT^IyZ_X*r#p|{Q&?>$RPXD!6J-*MIHY|qAHf?k<2swQV|?Ml=)-5r0sQGlO1 z(y!?&RiGhjG9Gr!+rS+= z1g&0>qc2`{*%}T<<*P@@nCXrMnR#>VXVjtDzL+rNm{O)hOm>li5?#I zjjuWlQOnWvYgM3=>qRHGPuK#^zam-seA{W3buf@7dsti-?1YTF4abr0O$$DGwMEv{=8RDuZOK;wq$uR0PAQHkThib zMMIB;VZ$J#L{}Rk$*E4&J$rUtNJxlaQG>(+WZ6W!ZUDW*xsunfHODR9VqK-|G~ow< zp2N#aOdARBy$V@ND+CSF6E82h`wi+81Bizv0X?lA#2~4m9!1PL^1m`|@T>cJdoP$C zuW`cW@yoA1(t)F%fJnA)3I&7WxIf|fo-Dwu?CF`^7x-8KQQQKL^sKhF_Lk0ln;s0I zN4h$XugHZhyIYE|5at4+NBbWnkt1({LyxVI2zsA*l;981*j?o3o|*Z_JTJj$>-O#0 ze(eHYVb0t6`1uX(hRBrwTb!*G{0LuESG{nHOL+6KmrK0Rk-=9WqU=sB%MVz2lw(>R ziB>H-Pc#Xp`P*S0-ZDttEfgOb1362;+na-b?Z0aje?*LZ^Dk^MXn_Q-Y-e12F&ke(RO zO?yh@Jh&CA}&000ztv=4r*ns z2KBL&bVO)Vb^(!q;e|<4%sSXB+=C1|QT#Mkb!6gu<6K~$IU|~i3h<=Ksu-5_@qitZ zj`{yJ`unCx{d_AR5qTx0c$AAOn9pvXat`_T&(R(oYFCL%1RWjS;k4tNoF@&-hY?x> zA3ci9OGS^8#S|477)Uo#Ut1fEpH$Zj5JHQbu9lw^Qh^?bSQ3F0+cMAVtf9dI*8pYI z22Zi<1GWzF`1O9nFzAfK`1z5}!F1*LjEqMh1oMLJ{zL0A{@BOQFBbm?;Y!~L(I862 z&JatxAbQVfdMvFdfw_4c2svtRo%|o+@y>(BaP|O8Nz)?scCtRa-bRZA(FblYf;~uv zJa}}h52U#!CMGuh<4^)SAHZS+3j73c9$K(g02;ha4-dFNEz$z@+ijf-7f!);W)FpV z+qUXH*yV5%0}XF)LV5v}$>7QrDWV^N5mO_~i63~I0Dyqs^zPXr__RDh>525_gXWb4 zEdzc1Q@FM1lVVuMB9Gqs@ZIrmY*VVJtEwUBgfXEau2B?V2u2F_MX)y$e*Rht9@JhN zYilmbEo?R4dkNbbw6wHTZr&7RVxn2S`jIpj=bANZ@O`3)B^CwT$C1@Xi5d}SlgH&DzxC-!TToKCI$cDB^YU0YU7;jzoDX90qooD#3bnH(i2Wo;Yem z7Gtf+BLGXV*k}ZShkOryo>`a`Bt%BKf`+7o=(*Z8<^msVPp~nKc;cWh-2M2B=JpGT zf#k7+R*(zON&$2h9!pEhIJ96VUI-ie``FmRnhlTZ!Y8OW(yo}A$kg}3_$9^q7rYKy z5Uutt+y*NuMS!_}3Wq#o6sn*&yuHj|TQJh!I4v9nE5ZkmuvQ7N)c^La9+LgmoABx& ztg0&y9!$_5V)_Iq!W1nha66vYp73+KAS+ATjO`pplV^Z_yn>eP3AR(MiUgy5?K3J< zb93P?@R~F_SRsC!giNdOiE7k8aB$;XU0wHm=}+Jh5KubA`!|UL*sT~cNNW4u;M%kM zf}Ws-4Fg518u0Wv3NM;Q@0#GpWIr(8J1^RxpE!`dSo+*SX@wA7G6{RRjxXaYT|nuD zpBH+GUwBqd&WnLVqHYoulqu|1_D#>t&OXA*;N$+@-n)=}h)}#kstE;30`xz90|Of0 zZEFmK*g(%gjQj-Rp?azW*FKJ_Pfbl+$YpO}jrCLjn-M67>^?*Kv53z2^9~>%gnCcH95gTOT05MYLXMY5Q2s>aMDU}q=Vo^xm zj2rp&i$CLWS)w8=pHJy$0{a-2=9Yc93uCXOi(@^p3#j~ zmP)v6nW3m8X~;-f*)yV~5TP;~GBS!%lE{pR2$fZGA(v4~R!T-9^?M%f$M?VA_i=yk z`{HVx=jVLCkMVlFj@J?SI|Gv=3N__kih#%js!)|*XsowzL&Ewpl~wkAHJ#G_Rtj@! z_W(aFF8adqXDA~Zco|(Nm(TM`HMh&8tkGWE2_^o`xG^8t=-jN+;5{IUS?n1yyBiTP zzBc`K?$)BB84~?t{krn$FdO}12a@bvfq|B>9@3z{ta5B0Jj9G{w#^;)H1FZMySC78 zjj^x*vM|_XWx+sUn|FxATPv7F)@;?P`uA_#F50mBIW(t49wrI#uqfokzS_cqGZ!a; ztywk)1f}=)cNpi4Km7ox@}K1;#C2E#r@fEYKC^ZnWf+!A+2W)b`=NrU-dcf(Ji@$| z;ehMC^-zW@?D3{=)ru3hMO=u*gKBy6KY#w<<+S?SxA%_c7L~kx>tJWsTohxVJI~II zvao2WC}97m`C9TYr_pJ`Cbnbbq0$eEUvo}|DDNE@Vvd0_@Kafc!VDIlg)OXVOHU9XD@T8b!)HihOl$*S;{fE)o zemCy}L2ucTJsQ}p{C;t8`z{_+u)Z8&QPSH4RK%kaQbujp>N#J4C~f1?qHGPrPPfg? zj?bRdhaiJ#LiU3PZ5Q7EK^h4Ns5g*($zlJS@cLwWiBX2>(>s%fIxuq;*43@vlM|C} z%%bLqCf{nj5DD#;jrVo!uZDN+-hDfz4>eK3tsHws{HGRbKVgC`mjG)z(KF7xdn8Lg zl}V^$|LJ|AhHaw0ukRDHFeJ$i9V7qXYdlFBy#yP`#RC_*!@^2&D+xnaI@gIaf) z|DQO88=jtccXm?^2{MX@bYEMx7$K`x*rR95ym^x}9L;s^09xM7_2N#mhr$YZQBC2a zs4aF@r*xGR=a~I}U-tC$22if-@+T}+=Q=m&l{xKj#!29*mWmG;hTFW7JR1?2HR~vI zfJN%sSl%k8SG3U8rRhB%wdY2{BARqA&?9E<=Ay?ti;-6W9K#>%up$=M2es0;QUAZR z>!NZ0a{jr$b?_Gic8A>FcTb3Ry`u0!)%zII&h!0Sysd@T>IR{zd?l z*Kf@sFRX#{0D}@+mmcXg^%PcP$3DI@+j6^}!nDVZ=;+QvQ8(kc(Lfn%2m^S$IngjRv|ivd(C%2EtwkUm4sj`+66J zjv)My2wI%Gq6!k((*EWLFviV%ifLKp$rR zv@vgibs71mCO!?T+eZ0zW~OD!!JKO~UUM7euR6NG$AuIu<4?E!d0`y0%V0F! zRor5(-M-z3FKKA+e+WxLXSJZwyjzC+(Mme(s=_QY@9LYS^MlFJzRh9u3f2z_S@I8H zoj6yXf@&Y^_etDiq^iW5CYlpPE3Ufy8%w5KfYk|VUVXBu<6e8S}-R;FC zC58B`nYKN`NCZTmZhYb;qtWh;+iQ;P>{>N$(xklw1Jzr-QWSdOYFPj0g%&1{oRMue zZ=U>VO+-Y*bk={Fcm`Pn46FTFpWf;5#gp8;BH>~<2xpcr;3kFg|%IKG`8b{n@i;qUDD2GXB|Y6i=QZIfKI! z&X48oqv3B*QLYf%O6Bpt^O2xj*FEZnG0qU}1vay09WAiRrKGo@=h*9b>|!ndEQ@z; zb8+h*uKD#SFHb%mh7?k2P2iXjsEXgxbsY!79QR}cgW4(!?FZaf?KE`F7CYpOjXyb_yCJ!$H=azMm*f9o}qMi&;} znbqt1!YNQKzfXE!cYN1IL!Xb2-K2ihKn%79O;Q6Qd8mCZgtfE8Ynf%3$1j?pE(-@Z6`k zTqh=<3yyuibm>xaE2}Ms4-jnL08U-!(C@YF`SBc1He0oa9sFZRWw(Pdn%4rGo|%Tx z76Kio>b0Hll!3|Y-Q_WZsfwqnjXmIqGOuc5Y)1YYg?AmBkS8P@`3bTkPSLbGN%qGs zUTjCXHEQ9)6R!^vtJFceW%b;%^2ZElBO{O*Ve0B%`#s`OpcdOyK4#fr$>zQ(v~*Vcpk^R{8Zy6w5* zbjN)$cv?qb(17;ODH!D?k%=8&?Gd!$Snt)Y7|sicHwros90RcbptI+ekv;H5JV02G#$HN&1j z!~rs}^=K*spa7xbX&@OGvZxC!?+yv$zy$A&XaCFPGg=zV!9!QT#%bl@wS5oQ)Xf79 zq~vYD_w8QZ)5OH)^p)rnqK25LdCR|f|NpTgjct>ITQYLQE7 z-v79v$4I{o?5xjVocbTCWD52XByX@}MRug>rPNeflEZlM4)CuTfTV(DK8=GcVpguT zTZAdc^&ifDU_X52U4|HB^P^0RGS;&UFE3{N&FxpBp}^lrNnz@i){YBhfqH~Aq%z*BvrwMvfuo&BcHnltB&!7^2f-4J%AwN%JUS)bEv$t-dk>F|^Tjt9c5e@9Hop4Ct1PTRdXA{Wt#KTp1az*TIwaaQFDz&-)O|YcA zo5rpZ6YJvo_3AP8ec0t>UAh$pKH2``01~mazvB6VPU$9|h~fjgez1|`4813N?kxFQZbl|10ZbT&eJ^|7 zmb&cIsuN<}dy3F3d;4f8CSF}*24htC`SbnRKSh*OTH1)4G5i@vJz;Rz78N?8Q50Hx z?{a-bQo@;AN(db6`=cpIG?S)E|6Lf3U6ZI`hu8ebW#F&G?d*al&FKYZpLuXC-FE;5 zb<+7BW`wk_`+SBh^BS;WAD>Y%PKg!tLZ7c!d@?sWb{mR?S4$AI|0gv<7RVA;6?(+ zvuawUeYnY-oBudiU#)TbcJ1(EdGQVbqeIZB-Cjy5x)F)u|mpZ-HZWouXhZ(g3dE<@ULDR_!iUupmAGxHrEQXnQ{MO^f?LZ}w zg{-*5RL^9`r}()`SO+pc*|>r;-}tY&3r14+WY~$ zIX9thZ8OX5BTB}3=@v`~)D1|e#Qb9de|`BT@o3`e#`hD&5RL@;N>m;`U7=+=fbnfd z1veV7GWogY{Xqd+tTx;mi=cKU2(BuN3lt?|g3!eL+}F*)1K&}TGsZmVzLbsoCnu!G z$4hAAsHxp)qN%E>lAx_AB0zX zg0)M>v`vnFoVEt7TZg$cH@aDv)f128eyq{%bIbdbBF8P=KBJr1?Q0>6zTvZ> z(6^0Q)T)+Vb{RRtE!-k7?dc4Pq?2>!j(ygH+tulpwR;STrO(N^{$@4VH-=uq_pi^%>xd#*=H z#BE#(0*16x7G??slXL7u(^j4J^_4|4gPN!*v?_)X9Y_Jr?QO@x7{fz8`-1WaU^WDK zk=Fb7?=iNqSh@22>-I1eUTubD0QZ%Zcc=8EiD*U91AkzpuZH0xt7JMcKxuM4X+V^T z&y~b!W>IyWh_v6Rcve@uUO(+Y;r^ST8_qvYv6*Gbxq?x+x;PbFWbl}`YRnA2GSN*Bws zQvL9U`17oqA~6@H&nf#Ho+L1m$|Z0+<{Y&N&$ojE;Blk!jWx4QwVgh`dw1#$4Q_nW zm@gPwqX>_UiwjLkS`@gN7?X74^0n&Zj5&OKljF#O=Z1E5dLEziB7Tehl#XBrNb`^1 zA%-kS+E%CL!-qm$0 z0TN4&w1!u*3M+<$aQ%WVc^IABTl$H(faG?s`Rs)Y?^c?7ZseSc&^kCIq(KVjclhYh z$Nnw&dsvlHUAM!G=^7cSU~isD^b;|L%wgZXz5tSI@yoOzp1k~fDl}zGJKV`hU7>Q`-^k$;;i?I-Y9!Pa7By~VR3W0HO52bY zHK@5FXCz@DYUb&fer6@{ANSMcAv3!$;X`uS@9_v;IP`^x%#&yQJ7_o<8?Q-R;xI&M z!Hxy*7lz9Q)cHWF*Msf^8o;eCBRgA_#`)74G_%r|;6@f!_S+Ev#&nBjlDWIPc9S-y z({A%$>nwDq-=;69r@(8v=UyyUbCQn7#s<=lFvW0ii1;+-7o|5++&s<^l~ zKK#Pjv+BwzJt16`RUA#fyEGs12>Z6-T0OKALpC-GKXxa+G5y5`pu}~RirFIcM@mV_ zr$qH~!tKhXQQtjZF8X=UvbhMjIcJ+)yKe?C5WhkK!xNhqeDptIb~Yn z16D0`-_w8#a&80kX2G|9*=GJM9o&eK*o29jE4M}mP}bRasE&3>JrJ3bw#Ie*%jwIP ze^teeA2F{k5*C7^?2m1wrL_&*vSllzDWV#?@$6aZt@}o$FJ$cG7MZiNTF}m@DA$ic zj}8s?3E=Q#z{P>)s7Prc1u3YPA!II^EoD{$x*qv`7Txdpth$o(wqwV-XT7W&NZqgz zkrNWR`?EmB+Vxx5PQJ2iX{p6VAiJjA9!IkaNVwRb@%ZV#*sAtf@=}wKGXUFIO7C2_ z$e%xdnoqf0^B^07ZYi=xS?pG}4WdtW8j7(g24?jY$duLt3-KoQHZZrbw!Y5D(XKsv zR7gbBT3S4+dL0qEY!}rRo2rzQlyG)hPrQQU=)B8HfCGNME*fJ>Z$75Y*bJU{mDQLU>lVnxbhJfyP+i}u z(n_jxj;d&-=$>AG_;5U>K!;2VR|U;|8xFn#0zu-#^XF5_a{6rkYWRpS31XyB@GW9nnC8%oOV3v5EAiqRL_;4CVpUTX2Ei#=!D?W>~%~y zyPY~8_TIU%o*$KNJ@YPhQSql1vN|sF_H9Sb_V;aTgTTohZEUi;K5=YK$6&+;#k{K~ z-MYncKOK>}gaN>fM`|Ui0a(6>GMSgA&xJ0MQ^(qoaX_|D?)-}tT4J;0MT-~PF=O>G zzPWA;abX`cT)`zA`^*V=k1n2EwU^u+UpA6T7m70F*7r2;F9C?Slg?9dbX`sT*Yz2N zfDLlMd>-FwkObkrEOcA>tX`c`w}S(typG~_l9}btDiV0lXFN$*$&@-hRtXxCs*&9e z;ic?|orcTf)oTr56~(2Ndl`!UjPhfbLMr$7{C_@6h5!Br&^ySCscGKh?fvl`0QMip zktv4S5QTwy5PyBxz2v!SRTtnj`B8i90JpO;GXtXz97v#)CW>01rV&z~ zByYO}Nf4d(Xo@ZnR7)TeJ>K9i3^J7$4Kys_pIL?9^c17Hwr9i>BWeYu`Wgmtg zn5Qzb96ef&&s4lwciPQ_>pu6mENYc9+TZy2c&oB8B?Nf1UE6r;)Y>6gSY(Xi(+wC1 zhLu3U8c+#57>?lq0P6gYEt)qsjPY!Ah6==%B6+#|2BpJPuvbPs`376RlX`-!$q&Ur z89=}9@i`c~@$tmz9%A{f*?<8mv%ulv$a9Trtw@aPiMD7(Aa8^Y=UV7+BI}tW8t4*J z*(i;R`g+F;jz|Na4%$OjTPWVqf2n_SAyCR|=FQ&0omH`OqUi*m)CsKg3p(7rWXD9) zH~@v6IBj$_b$4~OML~Fk;6bEA2Oz4x*N?fu7(jw}p-C=A-N1#v%j zD37^=Juji#tW4WHqT<`LeE)$1W5G#}@prwh0JgSLRDS>N(fkKV=xIm+&pLYrG={ZW z(8gK4CI$Mng)T(G(Fd0uo8J?)04NLq-?H!B^B}PFvH_aAEn*NwacSx8S$tz>#aWi@ z8HR*}93h9Tbe%lehTPEw7UsHnKv-CqjUS3({Wc-al{c3SNNzng%2HPs4d?Y&bG;4) zM`co`o=$&}t-Z_YXy`F-_Jl;77v1;uYvFPCi)eHn|J#4&t){xVvJo)0Y#&*uVZ{K= zu`-Da>H?d&4tbb`$YUCpjIptiN5RH4J1ol?C^Ego`X3)(UyPFuzK#X+-7cFAaOpk5 zRim=j#1MI}s9wmYE1-1hnGgH(t#zV%&t5N%jnnSczrV=3#v@oR!>nh>&IKP#fyi?K zGv;AIB$t}-(TA7~(YtljnU$)2yxIW$$5VXGTCiXYejRf3MHxJU9V^}QQ_n9o7bqKxOZ^K z6rHtSiW(4vRz8@?;%NnqUCZ&+OJ+kv7JvMh)36r=p%v{$hO+`nI2_D`1rA-6rk(lD zn3TRk$kp{%Gg2?Jz{q?t&xYq}5L2lXDhdVZHVb~!ib%xxcQX(|x>KSY+gA%1x@~ zQ3|1%4~PJau&vPu7W_IY3HP!Eua|xZrnIsrOeb(V_~51_EMB_wpJq6jz*;;#ll$=D zPQj9B1`bnH#U*|+EqL}UmrEdWGg6MyVQP;&(5c7gmxK9n5A~ql)`u}1<(hr>uKK%8 zn>Y9V&GVe}UNw< z>F`JnoTB6TT}@1M>({S;J{+CoR-_g08H`CjWowyZetn`S&i!E8ed4Kgpj;>s(=#rqKRG(MwL^Ql5cRXsOWSk-WPG?E z&{e7B-OBLYyB)w5MF^B1p9J!SDNK@ySD)iwTLoFLoL+ZZ!P|ITUPcn*&#fNz7wkD* zMy;-Fo;eTtO$Wi-E59nORuMhAx-^|AYNPGjo73ZLgVw%3>ho`wud-9BW&Uy&v5S_D z{dy6tmNf{DXv7t59sd3McjvuddKepbrtqAc?mwhetBx0?GDrng9ZDi?9eyDtCB|&| zTa^!v1Dt_NBF%@QWS-B;tAe4wnFJM$9eURVX=}bh1aV0$kzUT<HrQX!`8^?Z1Br^ysHIkRWY(lIpLr1kOR$HZ+#lPDzF z5Z0dDGm09}|94q`+O7_0R%NdOe1c=_0cRO%v^$XRy3OtXv;YGWl(%@dhporeO#@$m z&iJQp0L$R0YBAN0W}l%Dr`$3|YF?vCeyb3=$B<|?f~>!5-@fC!{?OUpqT7Xohm>24I>VA3W^I|az2zz6ED zuV^wi99|t6OElqFOsARP+Q#X0pMdsxMoso|4>YpD|wq*9rndq@-(Kcaq$?7*#mzN46egdOErdVdKH&uKe zugOt*?aeEd;cf0di+mK+R)g34Y>6ri$)Lu&`Sa!_Db*@y#IlR^{>@yrf z2Yjf*`(O**J$v@##~*MRj@EYfO0&8l-1mfV(E1sOC*eodqo2un#ZuI6Ry&p=T*VJx zkPgn%W~gGBZxr2-WBobd@tdnNTz~#rRew|28Zb9UP=3(`M)_^rX|52EmMCdYihooo(^N!O% zYd_FQ4Pj;K4jc^r*{j>@0}!HezqC(#N=iyPqjr8hK&b>2U4O>?8Hju7ISj`gbWJ#N z#HvN5=O8|Pl=263Orl-8k6y9j?6il8=nP0kLR*}oy~C^PT*mo6vDBFDhWX2CRzYoO z{AQ4m_W)YovWsWb88b)HYZt3Sp44yWei5$fw`%;kN?f69 z7Bg&kDpC$UXG!&&u+w$7Umm#qc+Za(nssOA8(7;|>TkRinl$~>vy|p3Hy6%5vEg+7 z#9JFXA1ORtzUj1GyOgGeGuIkU%2rFVF&dwD^}vVPKe@@j-w%kmtJC{r)yI;O6$d_E z{ao&MX!qA4Pu?=;7#Z1?)H@5TMp$Fke6cjaasF@1j=PYj7%!SI<)B3gtk{Ht0T+(; zAH##88{Z7K1pz*a=?-Du$W<)6tcfjs`0u|Ho*ikfdZC{2NeVWm$X>^mMHEv&u#iP` zov|;2xhyrYKWdvZX({IifvJQf-{*@vy=punRMlq4sAD$H16P!1u6ksMz4y;HNB&e1 zUS`05h{x^;_w-H=l5(=PdOHj-IZ-9vyWv+$ z`)91>3oC~h-zoHR%%Y*eL#Ho6I6`d&Q5VUKOZIpEol4`zyCTzDu*HY2-s7zKv}uR4 z{kHv;^G>z1V%X*<)S@hNW#lz7`3g1%Cpr%rv>(}Q_+;_=q$5i$wdd}P8I#j%*w(H= zn>IDvw{IUK1UViw;*g&gZ~kH;Pxb>`by@ZKKiLHz`{S-^M*824_H3$Km-b?ZPTCTS z6r*tC&YeZnYvgyl20m%`rSul+&EHIBF91w?F_UnL%8uuXeD5fUOf4>M6Z8TAjAu2B zo?D0g+}gZ@voo1*-YH!`%a#&Kk?c;xGs5OdyAraytYZoa4h{`_MnGOhml8XSQIc=3 z(TZMw^{OtSbsQj<0&#G03dJ=x{!d)ymwNF{GZ{A=ylO>Z?Tv|@UR@nAyQprP>j zVcXoCTYpR3@0gj=eD<~}6{&vB3ic%|4lqsYL?A&-5c1~U!7n;LT0L9UDXeO6NZQR6 z`j$!^MqQda;nC>lDXIgT*?yVZdlx>*?!KBpxjJmiW3Wt=cvSs236le8AyF;73F&dw z{`eALa6oL-5Ep6&9mP+dEo-uwvDd78+H+hKLZhN=@lB*Ki%MIza=h*j2w)hN6TO=D zVFU(2X~dx~Z8vWoIB1Z-K0~XETLVg310#Cl=qN1(afv+(Qx_+*g3d;J1i8Ky!&0={ z37*Y=y7wsN4w+$9!?J|wqy`(W@87ro^)-r0o8t4z9K$)gu*9lt; zZgy?4$l1kZ4&OtP382d48UKW$f`DxXmf@K2iUtv(QWlv8XqJ<#m!C8xl3=p?cT_;d zxV}IVEbg?=ovtz>P%SIQJ`Qe^92rED2*6SzM1ikw*KHftVnZk+y!-^lm7)_8vIu-u z=Rn3K>q5rdhE~W%M z1|GlG=b%X4sSohK)3$bDbyH<0eHeMg? z(ZZ+SEZ^!@mKATQe^&FMKPFTP&L3=s1%TWfC--uc9^CoIO~Vnkn|>a9|sHs~bEp zCMsVe`~WB{0z=HNKY-c(h{7+l8Ye)GJ+^yMHb1@Ol~}WW96~JT)dNDXKXiUywQEGQ zj;ZNZo=(KX^gC#*WEhP0n9^8MTbj?;@V8EO2M6yBsP}lh0!;5VMN4e~R4^TeCliJF zj~~mLJZk7z8gowvx0?_dlw2bJ5=a-JJ2bdQtzB#7;Vo;2zi8SO|c2L-)?m<+=$R+q1>V}Wv0W&kmrY{!BWM&x>2 z(BQb!b(M6UB5mpa(5`=gr5NHJ3w6U)5q=^Q`dtWjAuq1(Zd>}aMoWAM2onFX-I>1d?q%%M*Tv`VSpmRdHz>KfSDN?G5LiaC0`C5_8t*t zQ*PP4S5jd6X2(C&mV8wy>0O+mws`Q4)$^{@*P8w4?1zv0j~S(z!MV&ppM-dmMT{lE z%|~Z#*7j#{xq+yXw1Rb10_=wqmeazBA-41*b)Nj8lkTK77q-m$@~TU}e!F?s>6I<3 zFAUcY3E<1y4Kh^We>HAqWYlZYBqX@`5euZACQq{Sxx?SNNpC<1scr)^F}~5J;QSJK zEJr0{zhS85@Rod{P8g}C#EfjYvAtC!Zglhj{Yv&+)v zcXw5Jy*g>#;g&0BwrH{A$$29;pK}YJIoP#PV&o%$VLjr=n#5%)897^&^8S7`&tp9~ zQ-sb?S}`MADI4$;dEIUyNaN|dZ2tRiD(}Mx#-|zBw z%Gv*@iN?54edZ>wQDt=KKZC3+;{}{uTMb(NT0DqZt#Uw>k07UU|6bQayQBmq65;YYs4H&O&=lg%WQ>ABYYt z;*J;GA>)=FeC$z7o~>J_fRPYrVZ4z#+iQZDzW7p8y__*g>>mE%{5zXHA?9K9Gm36OOo&&`{ zeAEe`+s(XT88HRyNM#y|jQ@|6K$w1Vld-}6mm zdTV~YKPKsxh_)F7<23$tPg-F+%UhYjKFfn^W!e0H%y5`l-!l{tt*SZY#90Hna(G9r2!J@y)k zB%9xf5Fa2V8z{=*pO{^>NA#r@#>RIi#yahIqR;~h364an_mdQwX!XYZu_hKP+QsKE3N9)am;Po3gl}R3V(>pKhv&VJ1fRaz%AZ#Lg&t} zEgvWAUwPa+hxOdSI4MOm8D#^3TPZLoo0h(sur4}F1v=>7jHVfb#D#{P;dC87<Rvm|%aWQ8cp-o1Z6o?T%)s)pC70w$fE+e!-g7!?`z$mh_6 zI`r+^mk&LJ^rzr--k{GG=e))uATvPB?^UNr7B5 zX#4ir0ImGUhfJz6RL5kx@%MumsVqYd!Md~_U4j)f2j-#rkjzc5aq-}IuRngQv1(OS z(-bb{SQw>XPM-{a`qd~vm&oUyqbmhv~6l1#M z)iHNgJ(e`^w4zpFPWN$gVdwT#tpfKR|o(M|_ZCNl@aVwVOw z%$_0Clg+;o{m8g?!9fxxoiUWj^^P59;jH630uOdmL6e9;0Um5k?lKc=ahgi2O4dK_kJnff7f zPVv=3tBtFMLkV%I#Z9jym7YRYo2B+Y5q}{W48!I-ANA4|EA)9#V0FZ=F;MGd2j!iu z_sgw7$VyA9T3W1;+$hj`LhguunQzEzl=Y($28;5ickjFR?kUOWJgxsRG8H){kXEp> zwHi|=(R3r8F_Ze_Gk_ImQwBH4#NjB2bek(n*fB;wkzne;L2X`>e4#h}6sT>)0^@tK zmYSEdhr0+gb(kN==vWXcjMzQywvyYn&^J&96#*wutHXR=YwNydI5UdHmK!MO$Gf;3 zBTbbAkEZS!{pq@qle(N49hDL;YXhAgO&#^AsX3s>zx{aj^r<~I;IWrvvpbk6u`3T# z5SD~n<3s+Gb?_fPeDLgLXswo-dR%*i0H<6ev*}~)>a~8a6>>qade9P z0BugqbmU-p@DZ>g;_Ht{)}(O)F$>LrP1z!R1W6iE2M&z6vIG^~Tz0yLV-&QP;PZ&x zL}qVWuyx7f&f-Zji%Y=|o^T!3fN@MuxO}tOd^2BqY{gxQ>h~ClF&v{uC3)lK&5dkh zqtiN3+2LP|n*Qs0MKz#ewt=Bx9+jc^KT4F*{aXb^yYi_q2mYFFrLrQ2&Rk@q{{B}T z)F$-l^UabHPGO{8_wn3N?+P8xK^&9`v0V{3#GA`Y%i74uwiB|m+oXc<(1$UF(FO(~ zu|o3kC9n2yVMg5vc8L+MkjXdVn)Hqsnv;kB3JfFa6akceg7V zs%>w{MgoX8Pu=RGfAu_4nc612R6e1RM16p9j8XaWz2V^-(L&@s%nvqIdd?Mk5BiwPn>TL$zIM!zmC?ed_mt4$wt zq_S#>tbE$0BS&^R8Cb;oI2OQ2TQd?0{%jLull!9`(;>46Nb*wV%oz>Hefq+M$d3&g zHl%{nYf)nARy(7Jq3e;PsEE+X#3NZDNa9CO!&<}bQkYI1$DhgPQVPNO^&~ip-Vb&a z@YdVgJKX2h><0($QTWYc@hU;k5D_X3G)4vjF52%o`ttIs76jB3_l+}_ffRqi&uzy1 z`PsCo7b$EhSR#Cf@!$7Y_=lTqEMp04s!Jke0)Q99EbT~WA(jvqBf+9#ba=l{L$!fK zpUliy*Dopo74xMu!!(H4ZCurp$f2mrm=aLYZ_D4BjG1M?W2!oF93uLO*Brs<8^Q}R zYkdUs_tw^aJ)~CE(6r#=QlM`hR!`_eaV(LuqBa!Bq`T`y5t++kLL|!MOLkayUXr9F ztL{+polLoQ7vWFI;~^oCnJMVxVtvA2vdx|;Z0LuXyj!rghmhL5&&uprSvW$P0@>(= zt&m4#e@3@hQ5Av#F`=%kys*$>fj-rMZVDU;8!~ z{&UVRiq*Z4vi27X-sPM>?$cJ?AcT_r_VeeLV{Wv1**a#<-)g!PEwLJ*3xf+=1jgK< zo40Q-hl{ze&uB#9&IyAC4ccWSL9$%y^tElYauxU6Gqeiy2s^VL-xZ{9K&Y#JGS&HN zwJE_2DcHB9LoSr+Elu{l``fm?G^0u@zguKN06O_j{*7|I*Ne)Zh6n!d3;E~T z?=roWd`eSIO*hil$LEjUTm80Wdl~N>FRI?}A0D&ir3vZw`0G0x*Y^Hj1n2eD%@>V6 zXUkw{f1rR1n)hC{MuEU^pF+46Xj(LDHF^_PXw>@L{Ksjy(Pq*TlCBM~8>F7&@0R|3 zAx6i5KX&gks_n=S$U1l_rxooo(!=S5*G7SMPG7iiD^37NM7+C}IvJ_c(#!r19_*`Z zGk0gA+8TE_xT(2?(w}DxV#j-O%t-Gyctbkmc2=o#n9=Td#ST%0Db!)2u6SLGW}HFX`RTjK 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 HE!? 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 B#s~la diff --git a/docs/images/metro_map.svg b/docs/images/metro_map.svg deleted file mode 100644 index cfd9b083..00000000 --- a/docs/images/metro_map.svg +++ /dev/null @@ -1,1263 +0,0 @@ - - - -nf-cmgg/preprocessingfastqflowcellfastqORfastqfastqbclbclbclbclbclFastP trimming,QC andadapterremovalAlignbowtie2, bwamem,bwamem2, snapdragmap or starcramMultiQCreportindexfastaORMandatory process(es)Supported genomes flowReport filesLegendsOptional process(es)Additional outputs/inputsUnsupported genomes flowCreate indexwhen index ismissing Sort & mark duplicatessamtools sormadup or bamsormadupsamtools convertbam -> crambedmosdepthsamtools importfastq -> ucramPicard metricspicard CollectMultipleMetrics,picard CollectWgsMetrics andpicard CollectHsMetrics--disable_picard_metrics falsesamtools metricssamtools stats,samtools flagstat andsamtools idxstatsucramreportsAll generatedreportssamtools catmerge ucramsfrom same samplebcl-convertbcl -> fastqinteropdetermine coveragein genelist panelssamtoolscoveragebed diff --git a/docs/images/metro_map_dark.md b/docs/images/metro_map_dark.md new file mode 100644 index 00000000..65349f39 --- /dev/null +++ b/docs/images/metro_map_dark.md @@ -0,0 +1,45 @@ +```mermaid +%%metro logo: ./nf-cmgg-preprocessing_logo_dark.png +%%metro style: dark +%%metro line: main | Alignment and Postprocessing | #00ff00 +%%metro line: qc | Quality control | #ff0000 +%%metro file: BCL_IN | BCL +%%metro file: FASTQ_IN | FASTQ +%%metro file: CRAM_OUT | CRAM +%%metro file: MULTIQC_LIBRARY | HTML +%%metro file: MULTIQC_SAV | HTML +%%metro compact_offsets: true + +graph TD + + BCL_IN[] + FASTQ_IN[] + MULTIQC_SAV[] + CRAM_OUT[] + MULTIQC_LIBRARY[] + + BCL_IN -->|main | BCLCONVERT + BCL_IN -->|qc| MULTIQC_SAV + BCLCONVERT -->|qc| MULTIQC_SAV + + FASTQ_IN[] + FASTQ_IN -->|qc,main| FASTP + BCLCONVERT -->|qc| FALCO + BCLCONVERT -->|qc,main| FASTP + FALCO -->|qc| MULTIQC_LIBRARY + FASTP -->|qc| MULTIQC_LIBRARY + + FASTP -->|main| ALIGN + ALIGN -->|main| MARKDUP + MARKDUP -->|main| CRAM_OUT + + CRAM_OUT -->|qc| MOSDEPTH + CRAM_OUT -->|qc| SAMTOOLS_COV + MOSDEPTH -->|qc| MULTIQC_LIBRARY + SAMTOOLS_COV -->|qc| MULTIQC_LIBRARY + + CRAM_OUT -->|qc| SAMTOOLS_QC + CRAM_OUT -->|qc| PICARD + SAMTOOLS_QC -->|qc| MULTIQC_LIBRARY + PICARD -->|qc| MULTIQC_LIBRARY +``` diff --git a/docs/images/metro_map_dark.svg b/docs/images/metro_map_dark.svg new file mode 100644 index 00000000..0f452bc5 --- /dev/null +++ b/docs/images/metro_map_dark.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +BCL + + + + + +HTML + + + + +FASTQ + + + + + + +HTML + + + + + + +CRAM + + + + +BCL_IN +FASTQ_IN +BCLCONVERT +MULTIQC_SAV +FASTP +FALCO +ALIGN +MARKDUP +CRAM_OUT +MOSDEPTH +SAMTOOLS_COV +SAMTOOLS_QC +PICARD +MULTIQC_LIBRARY + + + +Alignment and Postprocessing + +Quality control +created with nf-metro v0.5.4 + diff --git a/docs/images/metro_map_light.md b/docs/images/metro_map_light.md new file mode 100644 index 00000000..5cd6a5b0 --- /dev/null +++ b/docs/images/metro_map_light.md @@ -0,0 +1,45 @@ +```mermaid +%%metro logo: ./nf-cmgg-preprocessing_logo_light.png +%%metro style: light +%%metro line: main | Alignment and Postprocessing | #00ff00 +%%metro line: qc | Quality control | #ff0000 +%%metro file: BCL_IN | BCL +%%metro file: FASTQ_IN | FASTQ +%%metro file: CRAM_OUT | CRAM +%%metro file: MULTIQC_LIBRARY | HTML +%%metro file: MULTIQC_SAV | HTML +%%metro compact_offsets: true + +graph TD + + BCL_IN[] + FASTQ_IN[] + MULTIQC_SAV[] + CRAM_OUT[] + MULTIQC_LIBRARY[] + + BCL_IN -->|main | BCLCONVERT + BCL_IN -->|qc| MULTIQC_SAV + BCLCONVERT -->|qc| MULTIQC_SAV + + FASTQ_IN[] + FASTQ_IN -->|qc,main| FASTP + BCLCONVERT -->|qc| FALCO + BCLCONVERT -->|qc,main| FASTP + FALCO -->|qc| MULTIQC_LIBRARY + FASTP -->|qc| MULTIQC_LIBRARY + + FASTP -->|main| ALIGN + ALIGN -->|main| MARKDUP + MARKDUP -->|main| CRAM_OUT + + CRAM_OUT -->|qc| MOSDEPTH + CRAM_OUT -->|qc| SAMTOOLS_COV + MOSDEPTH -->|qc| MULTIQC_LIBRARY + SAMTOOLS_COV -->|qc| MULTIQC_LIBRARY + + CRAM_OUT -->|qc| SAMTOOLS_QC + CRAM_OUT -->|qc| PICARD + SAMTOOLS_QC -->|qc| MULTIQC_LIBRARY + PICARD -->|qc| MULTIQC_LIBRARY +``` diff --git a/docs/images/metro_map_light.svg b/docs/images/metro_map_light.svg new file mode 100644 index 00000000..ac3be697 --- /dev/null +++ b/docs/images/metro_map_light.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +BCL + + + + + +HTML + + + + +FASTQ + + + + + + +HTML + + + + + + +CRAM + + + + +BCL_IN +FASTQ_IN +BCLCONVERT +MULTIQC_SAV +FASTP +FALCO +ALIGN +MARKDUP +CRAM_OUT +MOSDEPTH +SAMTOOLS_COV +SAMTOOLS_QC +PICARD +MULTIQC_LIBRARY + + + +Alignment and Postprocessing + +Quality control +created with nf-metro v0.5.4 + diff --git a/docs/images/nf-cmgg-preprocessing_logo_dark.png b/docs/images/nf-cmgg-preprocessing_logo_dark.png index 2f4bd13f419811091ec85f16b0267bfe21c79f3c..d91e637970729ada5a11e67dc057fab103f24166 100644 GIT binary patch literal 65764 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

    0f`9eO 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.st0{fill:#24af63}.st1{font-family:Arial, Helvetica, sans-serif;;font-weight:"bold"}.st2{font-size:209.8672px}.st4{fill:#ecdc86}.st7{fill:#396e35}nf-nf-cmgg/preprocessingpreprocZt3oLhx>k> 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�kc{-+4bKpbyyJ(&qIUdYyzY{7}vI1#y5^u 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 XTZ%L%oEjz$TZGUuyoJ}afB3%uAlg6z literal 79022 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.st0{fill:#24af63}.st1{font-family:Arial, Helvetica, sans-serif;font-weight:bold;}.st2{font-size:209.8672px}.st4{fill:#ecdc86}.st7{fill:#396e35}nf-nf-cmgg/preprocessingpreproc diff --git a/docs/parameters.md b/docs/parameters.md index 700a2292..0f7220fc 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -16,10 +16,10 @@ Define where the pipeline should find input data and save output data. ## Pipeline options -| Parameter | Description | Type | Default | Required | Hidden | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | --------- | -------- | ------ | -| `split_fastq` | Specify how many reads each split of a FastQ file contains. Set 0 to turn off splitting at all.

    HelpUse the the tool FastP to split FASTQ file by number of reads. This parallelizes across fastq file shards speeding up mapping. Note although the minimum value is 250 reads, if you have fewer than 250 reads a single FASTQ shard will still be created.
    | `integer` | 100000000 | | | -| `genelists` | Directory containing gene list bed files for granular coverage analysis | `string` | None | | | +| Parameter | Description | Type | Default | Required | Hidden | +| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------- | -------- | ------ | +| `split_fastq` | Specify how many reads each split of a FastQ file contains. Set 0 to turn off splitting at all.
    HelpUse the tool FastP to split FASTQ file by number of reads. This parallelizes across fastq file shards speeding up mapping. Note although the minimum value is 250 reads, if you have fewer than 250 reads a single FASTQ shard will still be created.
    | `integer` | 100000000 | | | +| `genelists` | Directory containing gene list bed files for granular coverage analysis | `string` | None | | | ## Institutional config options diff --git a/docs/usage.md b/docs/usage.md index c44bccca..f59c809a 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -14,42 +14,56 @@ You will need to create a samplesheet with information about the samples you wou The pipeline supports two types of samplesheets to be used as input: [`fastq`](#fastq-samplesheet) and [`flowcell`](#flowcell-samplesheet) samplesheets. The type will be automatically detected and applied by the pipeline. The pipeline will also auto-detect whether a sample is single- or paired-end using the information provided in the samplesheet. The samplesheet can have as many columns as you desire. -### Common samplesheet fields - -This table shows all samplesheet fields that can be used by both the [`fastq`](#fastq-samplesheet) and the [`flowcell`](#flowcell-samplesheet) samplesheet types. - -| Column | Description | Required for Fastq | Required for Flowcell | -| ------ | ---------------------------------------------------------------------------------- | ------------------ | --------------------- | -| `id` | Unique samplesheet/flowcell ID. Can only contain letters, numbers and underscores. | :heavy_check_mark: | :heavy_check_mark: | - ### Fastq samplesheet -A `fastq` samplesheet file consisting of both single- and paired-end data may look something like the one below. This is for 6 samples, where `TREATMENT_REP3` has been sequenced twice. - -```csv title="samplesheet.csv" -id,samplename,fastq_1,fastq_2,genome,tag -CONTROL_REP1,CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz,GRCh38,WES -CONTROL_REP2,CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz,GRCh38,WES -CONTROL_REP3,CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz,GRCh38,WES -TREATMENT_REP1,TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz,,GRCh38,WES -TREATMENT_REP2,TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz,,GRCh38,WES -TREATMENT_REP3,TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz,,GRCh38,WES -TREATMENT_REP3,TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz,,GRCh38,WES +A `fastq` samplesheet file consisting of paired-end data may look something like the one below. + +```yml +- id: DNA1_L001 + samplename: DNA_paired1 + library: test_library + genome: GRCh38 + aligner: bwamem + markdup: bamsormadup + umi_aware: false + skip_trimming: false + trim_front: 0 + trim_tail: 0 + adapter_R1: AGATCGGAAGAGCACACGTCTGAACTCCTTA + adapter_R2: AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT + run_coverage: true + disable_picard_metrics: false + roi: null + tag: WES + sample_type: DNA + fastq_1: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R1.fastq.gz + fastq_2: https://github.com/nf-cmgg/test-datasets/raw/preprocessing/data/genomics/homo_sapiens/illumina/fastq/sample1_R2.fastq.gz ``` Following table shows the fields that are used by the `fastq` samplesheet: -| Column | Description | Required | -| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | -| `fastq_1` | FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :heavy_check_mark: | -| `fastq_2` | FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :x: | -| `samplename` | The sample name corresponding to the sample in the Fastq file(s) | :heavy_check_mark: | -| `genome` | The genome build to use for the analysis. Currently supports GRCh38, GRCm39 and GRCz11 | :heavy_check_mark: (unless `organism` is given) | -| `organism` | Full name of the organism. Currently supports "Homo sapiens", "Mus musculus" and "Danio rerio" | :heavy_check_mark: (unless `genome` is given) | -| `library` | Sample library name | :x: | -| `tag` | The tag used by the sample. Can be one of WES, WGS or coPGT-M | :heavy_check_mark: | -| `roi` | The path to a BED file containing Regions Of Interest for coverage analysis | :x: | -| `aligner` | The aligner to use for this sample. Can be one of these: bowtie2, bwamem, bwamem2, dragmap, strobe and snap. set to `false` to output fastq. | :x: | +| Column | Description | Required | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | +| `id` | Unique sample identifier | :heavy_check_mark: | +| `samplename` | The sample name corresponding to the sample in the Fastq file(s) | :heavy_check_mark: | +| `genome` | The genome build to use for the analysis. Currently supports `GRCh38`, `GRCm39` and `GRCz11` | :heavy_check_mark: (unless `organism` is given) | +| `organism` | Full name of the organism. Currently supports `Homo sapiens`, `Mus musculus` and `Danio rerio` | :heavy_check_mark: (unless `genome` is given) | +| `library` | Sample library name | :x: | +| `tag` | The tag used by the sample. Can be one of `WES`, `WGS`, `SeqCap` and `coPGT-M` | :x: | +| `aligner` | The aligner to use for this sample. Can be one of these: `bowtie2`, `bwamem`, `bwamem2`, `dragmap`, `strobe` and `snap`. Set to `false` to output fastq. | :heavy_check_mark: | +| `markdup` | Markdup algorithm to use for duplicate marking. Can be set to `bamsormadup`, `samtools` or `false` | :x: | +| `umi_aware` | Whether UMI-aware processing should be used. Only applies when `markdup` is set to `samtools` | :x: | +| `skip_trimming` | Skip adapter trimming step | :x: | +| `trim_front` | Number of bases to trim from the front of reads | :x: | +| `trim_tail` | Number of bases to trim from the tail of reads | :x: | +| `adapter_R1` | Adapter sequence for read 1 | :x: | +| `adapter_R2` | Adapter sequence for read 2 | :x: | +| `run_coverage` | Run coverage analysis | :x: | +| `disable_picard_metrics` | Disable Picard metrics collection | :x: | +| `roi` | The path to a BED file containing Regions Of Interest for coverage analysis | :x: | +| `sample_type` | Sample type (e.g., `DNA`, `RNA`) | :x: | +| `fastq_1` | FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :heavy_check_mark: | +| `fastq_2` | FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz' | :x: | An [example samplesheet](../tests/inputs/test.yml) has been provided with the pipeline. @@ -57,9 +71,12 @@ An [example samplesheet](../tests/inputs/test.yml) has been provided with the pi A `flowcell` samplesheet file consisting of one sequencing run may look something like the one below. -```csv title="samplesheet.csv" -id,samplesheet,sample_info,flowcell -RUN_NAME,RUN_NAME_samplesheet.csv,RUN_NAME_sampleinfo.csv,RUN_NAME_flowcell/ +```yml +- id: 200624_A00834_0183_BHMTFYDRXX + samplesheet: https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleSheet_2.csv + lane: 1 + flowcell: s3://test-data/genomics/homo_sapiens/illumina/bcl/ + sample_info: https://github.com/nf-cmgg/test-datasets/raw/refs/heads/preprocessing/data/genomics/homo_sapiens/illumina/flowcell/SampleInfo_2.json ``` Following table shows the fields that are used by the `flowcell` samplesheet: @@ -77,38 +94,24 @@ An [example samplesheet](../tests/inputs/test.yml) has been provided with the pi A `flowcell` sample info JSON/YML file consisting for one sequencing run may look something like the one below. -```json title="sample_info.json" -{ - "samplename": "Sample1", - "library": "test", - "organism": "Homo sapiens", - "tag": "WES" -} -``` - -Following table shows the fields that are used by the `flowcell` samplesheet: - -| Column | Description | Required | -| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | -| `samplename` | The sample name | :heavy_check_mark: | -| `library` | The library name | :x: | -| `tag` | Sample tag. Has to be one of these: WES, WGS, coPGT-M | :heavy_check_mark: | -| `organism` | The organism of the sample. Has to be one of these: "Homo sapiens", "Mus musculus" or "Danio rerio" | :heavy_check_mark: | -| `vivar_project` | The vivar project name (currently not used by the pipeline) | :x: | -| `binsize` | The binsize for CNV analysis (currently not used by the pipeline) | :x: | -| `panels` | A list of panels for coverage analysis | :x: | -| `roi` | Region of interest BED file for coverage analysis | :x: | -| `aligner` | The aligner to use for this sample. Can be one of these: bowtie2, bwamem, bwamem2, dragmap, strobe and snap. Set to `false` to output fastq. | :x: | - -### Multiple runs of the same sample - -The `sample` identifiers have to be the same when you have re-sequenced the same sample more than once e.g. to increase sequencing depth. The pipeline will concatenate the raw reads before performing any downstream analysis. Below is an example for the same sample sequenced across 3 lanes: - -```csv title="samplesheet.csv" -sample,fastq_1,fastq_2 -CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz -CONTROL_REP1,AEG588A1_S1_L003_R1_001.fastq.gz,AEG588A1_S1_L003_R2_001.fastq.gz -CONTROL_REP1,AEG588A1_S1_L004_R1_001.fastq.gz,AEG588A1_S1_L004_R2_001.fastq.gz +```yml +- id: DNA1_L001 + samplename: DNA_paired1 + library: test_library + genome: GRCh38 + aligner: bwamem + markdup: bamsormadup + umi_aware: false + skip_trimming: false + trim_front: 0 + trim_tail: 0 + adapter_R1: AGATCGGAAGAGCACACGTCTGAACTCCTTA + adapter_R2: AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT + run_coverage: true + disable_picard_metrics: false + roi: null + tag: WES + sample_type: DNA ``` ## Running the pipeline @@ -170,7 +173,7 @@ First, go to the [nf-cmgg/preprocessing releases page](https://github.com/nf-cmg This version number will be logged in reports when you run the pipeline, so that you'll know what you used when you look back in the future. For example, at the bottom of the MultiQC reports. -To further assist in reproducbility, you can use share and re-use [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. +To further assist in reproducibility, you can use share and re-use [parameter files](#running-the-pipeline) to repeat pipeline runs with the same settings without having to write out a command with every single parameter. :::tip If you wish to share such profile (such as upload as supplementary material for academic publications), make sure to NOT include cluster specific paths to files, nor institutional specific profiles. @@ -193,7 +196,7 @@ The pipeline also dynamically loads configurations from [https://github.com/nf-c Note that multiple profiles can be loaded, for example: `-profile test,docker` - the order of arguments is important! They are loaded in sequence, so later profiles can overwrite earlier profiles. -If `-profile` is not specified, the pipeline will run locally and expect all software to be installed and available on the `PATH`. This is _not_ recommended, since it can lead to different results on different machines dependent on the computer enviroment. +If `-profile` is not specified, the pipeline will run locally and expect all software to be installed and available on the `PATH`. This is _not_ recommended, since it can lead to different results on different machines dependent on the computer environment. - `debug` - A generic profile with settings to help with debugging the pipeline. It will use more verbose logging. @@ -237,7 +240,7 @@ To change the resource requests, please see the [max resources](https://nf-co.re ### Custom Containers -In some cases you may wish to change which container a step of the pipeline uses for a particular tool. By default nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However in some cases the pipeline specified version maybe out of date. +In some cases you may wish to change which container a step of the pipeline uses for a particular tool. By default nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However in some cases the pipeline specified version may be out of date. To use a different container from the default container specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/usage/configuration#updating-tool-versions) section of the nf-core website. @@ -262,7 +265,7 @@ Nextflow handles job submissions and supervises the running jobs. The Nextflow p The Nextflow `-bg` flag launches Nextflow in the background, detached from your terminal so that the workflow does not stop if you log out of your session. The logs are saved to a file. Alternatively, you can use `screen` / `tmux` or similar tool to create a detached session which you can log back into at a later time. -Some HPC setups also allow you to run nextflow within a cluster job submitted your job scheduler (from where it submits more jobs). +Some HPC setups also allow you to run nextflow within a cluster job submitted to your job scheduler (from where it submits more jobs). ## Nextflow memory requirements