From 84fcab9b917663546d6de7f3f7ce13af942b491f Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 29 Sep 2025 17:16:13 +0200 Subject: [PATCH 01/55] Update main.nf files paths --- modules/local/{split_cooler_dump.nf => split_cooler_dump/main.nf} | 0 subworkflows/local/{compartments.nf => compartments/main.nf} | 0 subworkflows/local/{cooler.nf => cooler/main.nf} | 0 subworkflows/local/{hicpro.nf => hicpro/main.nf} | 0 subworkflows/local/{hicpro_mapping.nf => hicpro_mapping/main.nf} | 0 subworkflows/local/{pairtools.nf => pairtools/main.nf} | 0 subworkflows/local/{prepare_genome.nf => prepare_genome/main.nf} | 0 subworkflows/local/{tads.nf => tads/main.nf} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename modules/local/{split_cooler_dump.nf => split_cooler_dump/main.nf} (100%) rename subworkflows/local/{compartments.nf => compartments/main.nf} (100%) rename subworkflows/local/{cooler.nf => cooler/main.nf} (100%) rename subworkflows/local/{hicpro.nf => hicpro/main.nf} (100%) rename subworkflows/local/{hicpro_mapping.nf => hicpro_mapping/main.nf} (100%) rename subworkflows/local/{pairtools.nf => pairtools/main.nf} (100%) rename subworkflows/local/{prepare_genome.nf => prepare_genome/main.nf} (100%) rename subworkflows/local/{tads.nf => tads/main.nf} (100%) diff --git a/modules/local/split_cooler_dump.nf b/modules/local/split_cooler_dump/main.nf similarity index 100% rename from modules/local/split_cooler_dump.nf rename to modules/local/split_cooler_dump/main.nf diff --git a/subworkflows/local/compartments.nf b/subworkflows/local/compartments/main.nf similarity index 100% rename from subworkflows/local/compartments.nf rename to subworkflows/local/compartments/main.nf diff --git a/subworkflows/local/cooler.nf b/subworkflows/local/cooler/main.nf similarity index 100% rename from subworkflows/local/cooler.nf rename to subworkflows/local/cooler/main.nf diff --git a/subworkflows/local/hicpro.nf b/subworkflows/local/hicpro/main.nf similarity index 100% rename from subworkflows/local/hicpro.nf rename to subworkflows/local/hicpro/main.nf diff --git a/subworkflows/local/hicpro_mapping.nf b/subworkflows/local/hicpro_mapping/main.nf similarity index 100% rename from subworkflows/local/hicpro_mapping.nf rename to subworkflows/local/hicpro_mapping/main.nf diff --git a/subworkflows/local/pairtools.nf b/subworkflows/local/pairtools/main.nf similarity index 100% rename from subworkflows/local/pairtools.nf rename to subworkflows/local/pairtools/main.nf diff --git a/subworkflows/local/prepare_genome.nf b/subworkflows/local/prepare_genome/main.nf similarity index 100% rename from subworkflows/local/prepare_genome.nf rename to subworkflows/local/prepare_genome/main.nf diff --git a/subworkflows/local/tads.nf b/subworkflows/local/tads/main.nf similarity index 100% rename from subworkflows/local/tads.nf rename to subworkflows/local/tads/main.nf From 45e415ffa88e958ab4714181a3bdfafd37443637 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 29 Sep 2025 17:16:56 +0200 Subject: [PATCH 02/55] Update nf-core modules --- modules.json | 46 +-- modules/nf-core/bowtie2/align/environment.yml | 14 +- modules/nf-core/bowtie2/align/main.nf | 7 +- modules/nf-core/bowtie2/align/meta.yml | 163 +++++--- .../nf-core/bowtie2/align/tests/main.nf.test | 90 ++--- .../bowtie2/align/tests/main.nf.test.snap | 96 ++--- modules/nf-core/bowtie2/align/tests/tags.yml | 2 - modules/nf-core/bowtie2/build/environment.yml | 12 +- modules/nf-core/bowtie2/build/main.nf | 4 +- modules/nf-core/bowtie2/build/meta.yml | 49 ++- .../nf-core/bowtie2/build/tests/main.nf.test | 4 +- .../bowtie2/build/tests/main.nf.test.snap | 8 +- modules/nf-core/bowtie2/build/tests/tags.yml | 2 - modules/nf-core/bwa/index/environment.yml | 12 +- modules/nf-core/bwa/index/main.nf | 12 +- modules/nf-core/bwa/index/meta.yml | 54 ++- .../nf-core/bwa/index/tests/main.nf.test.snap | 10 +- modules/nf-core/bwa/index/tests/tags.yml | 2 - modules/nf-core/bwa/mem/environment.yml | 13 +- modules/nf-core/bwa/mem/main.nf | 6 +- modules/nf-core/bwa/mem/meta.yml | 126 ++++-- modules/nf-core/bwa/mem/tests/main.nf.test | 139 ++----- .../nf-core/bwa/mem/tests/main.nf.test.snap | 213 ++++++++-- modules/nf-core/bwa/mem/tests/tags.yml | 3 - modules/nf-core/calder2/environment.yml | 6 +- modules/nf-core/calder2/main.nf | 36 +- modules/nf-core/calder2/meta.yml | 60 +-- modules/nf-core/calder2/tests/main.nf.test | 135 +++++++ .../nf-core/calder2/tests/main.nf.test.snap | 113 ++++++ modules/nf-core/calder2/tests/nextflow.config | 3 + .../nf-core/cooler/balance/environment.yml | 6 +- modules/nf-core/cooler/balance/main.nf | 19 +- modules/nf-core/cooler/balance/meta.yml | 57 +-- .../nf-core/cooler/balance/tests/main.nf.test | 63 +++ .../cooler/balance/tests/main.nf.test.snap | 57 +++ modules/nf-core/cooler/cload/environment.yml | 6 +- modules/nf-core/cooler/cload/main.nf | 29 +- modules/nf-core/cooler/cload/meta.yml | 76 ++-- .../nf-core/cooler/cload/tests/main.nf.test | 170 ++++++++ .../cooler/cload/tests/main.nf.test.snap | 89 +++++ .../cooler/cload/tests/nextflow.config | 5 + modules/nf-core/cooler/dump/environment.yml | 6 +- modules/nf-core/cooler/dump/main.nf | 23 +- modules/nf-core/cooler/dump/meta.yml | 57 +-- .../nf-core/cooler/dump/tests/main.nf.test | 59 +++ .../cooler/dump/tests/main.nf.test.snap | 78 ++++ .../nf-core/cooler/makebins/environment.yml | 6 +- modules/nf-core/cooler/makebins/main.nf | 16 +- modules/nf-core/cooler/makebins/meta.yml | 43 +- .../cooler/makebins/tests/main.nf.test | 59 +++ .../cooler/makebins/tests/main.nf.test.snap | 68 ++++ .../nf-core/cooler/zoomify/environment.yml | 7 +- modules/nf-core/cooler/zoomify/main.nf | 4 +- modules/nf-core/cooler/zoomify/meta.yml | 51 +-- .../nf-core/cooler/zoomify/tests/main.nf.test | 67 ++++ .../cooler/zoomify/tests/main.nf.test.snap | 57 +++ .../cooler/zoomify/tests/nextflow.config | 5 + .../custom/getchromsizes/environment.yml | 11 +- modules/nf-core/custom/getchromsizes/main.nf | 4 +- modules/nf-core/custom/getchromsizes/meta.yml | 81 ++-- .../getchromsizes/tests/main.nf.test.snap | 40 +- .../custom/getchromsizes/tests/tags.yml | 2 - modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 4 +- .../nf-core/multiqc/tests/main.nf.test.snap | 18 +- modules/nf-core/multiqc/tests/tags.yml | 2 - modules/nf-core/pairix/environment.yml | 4 +- modules/nf-core/pairix/meta.yml | 56 ++- modules/nf-core/pairix/tests/main.nf.test | 32 ++ .../nf-core/pairix/tests/main.nf.test.snap | 39 ++ .../nf-core/pairtools/dedup/environment.yml | 4 +- modules/nf-core/pairtools/dedup/meta.yml | 64 +-- .../pairtools/dedup/tests/main.nf.test | 39 ++ .../pairtools/dedup/tests/main.nf.test.snap | 30 ++ .../pairtools/dedup/tests/nextflow.config | 5 + .../nf-core/pairtools/merge/environment.yml | 4 +- modules/nf-core/pairtools/merge/meta.yml | 49 ++- .../pairtools/merge/tests/main.nf.test | 37 ++ .../pairtools/merge/tests/main.nf.test.snap | 21 + .../nf-core/pairtools/parse/environment.yml | 4 +- modules/nf-core/pairtools/parse/meta.yml | 67 ++-- .../pairtools/parse/tests/main.nf.test | 40 ++ .../pairtools/parse/tests/main.nf.test.snap | 30 ++ .../pairtools/parse/tests/nextflow.config | 5 + .../pairtools/restrict/environment.yml | 4 +- modules/nf-core/pairtools/restrict/meta.yml | 50 ++- .../pairtools/restrict/tests/main.nf.test | 40 ++ .../restrict/tests/main.nf.test.snap | 21 + .../pairtools/restrict/tests/nextflow.config | 5 + .../nf-core/pairtools/select/environment.yml | 4 +- modules/nf-core/pairtools/select/meta.yml | 64 +-- .../pairtools/select/tests/main.nf.test | 39 ++ .../pairtools/select/tests/main.nf.test.snap | 28 ++ .../pairtools/select/tests/nextflow.config | 5 + .../nf-core/pairtools/sort/environment.yml | 4 +- modules/nf-core/pairtools/sort/meta.yml | 49 ++- .../nf-core/pairtools/sort/tests/main.nf.test | 38 ++ .../pairtools/sort/tests/main.nf.test.snap | 21 + .../pairtools/sort/tests/nextflow.config | 5 + .../nf-core/pairtools/stats/environment.yml | 4 +- modules/nf-core/pairtools/stats/meta.yml | 49 ++- .../pairtools/stats/tests/main.nf.test | 33 ++ .../pairtools/stats/tests/main.nf.test.snap | 37 ++ .../nf-core/samtools/flagstat/environment.yml | 10 +- modules/nf-core/samtools/flagstat/main.nf | 19 +- modules/nf-core/samtools/flagstat/meta.yml | 63 +-- .../samtools/flagstat/tests/main.nf.test | 28 +- .../samtools/flagstat/tests/main.nf.test.snap | 78 +++- .../nf-core/samtools/flagstat/tests/tags.yml | 2 - .../nf-core/samtools/index/environment.yml | 10 +- modules/nf-core/samtools/index/main.nf | 13 +- modules/nf-core/samtools/index/meta.yml | 80 ++-- .../nf-core/samtools/index/tests/main.nf.test | 87 +++- .../samtools/index/tests/main.nf.test.snap | 264 ++++++++++--- modules/nf-core/samtools/index/tests/tags.yml | 2 - modules/nf-core/samtools/sort/environment.yml | 10 +- modules/nf-core/samtools/sort/main.nf | 55 ++- modules/nf-core/samtools/sort/meta.yml | 144 ++++--- .../nf-core/samtools/sort/tests/main.nf.test | 260 +++++++++++- .../samtools/sort/tests/main.nf.test.snap | 371 ++++++++++++++++-- .../samtools/sort/tests/nextflow.config | 1 - .../samtools/sort/tests/nextflow_cram.config | 8 + modules/nf-core/samtools/sort/tests/tags.yml | 3 - 123 files changed, 4128 insertions(+), 1197 deletions(-) delete mode 100644 modules/nf-core/bowtie2/align/tests/tags.yml delete mode 100644 modules/nf-core/bowtie2/build/tests/tags.yml delete mode 100644 modules/nf-core/bwa/index/tests/tags.yml delete mode 100644 modules/nf-core/bwa/mem/tests/tags.yml create mode 100644 modules/nf-core/calder2/tests/main.nf.test create mode 100644 modules/nf-core/calder2/tests/main.nf.test.snap create mode 100644 modules/nf-core/calder2/tests/nextflow.config create mode 100644 modules/nf-core/cooler/balance/tests/main.nf.test create mode 100644 modules/nf-core/cooler/balance/tests/main.nf.test.snap create mode 100644 modules/nf-core/cooler/cload/tests/main.nf.test create mode 100644 modules/nf-core/cooler/cload/tests/main.nf.test.snap create mode 100644 modules/nf-core/cooler/cload/tests/nextflow.config create mode 100644 modules/nf-core/cooler/dump/tests/main.nf.test create mode 100644 modules/nf-core/cooler/dump/tests/main.nf.test.snap create mode 100644 modules/nf-core/cooler/makebins/tests/main.nf.test create mode 100644 modules/nf-core/cooler/makebins/tests/main.nf.test.snap create mode 100644 modules/nf-core/cooler/zoomify/tests/main.nf.test create mode 100644 modules/nf-core/cooler/zoomify/tests/main.nf.test.snap create mode 100644 modules/nf-core/cooler/zoomify/tests/nextflow.config delete mode 100644 modules/nf-core/custom/getchromsizes/tests/tags.yml delete mode 100644 modules/nf-core/multiqc/tests/tags.yml create mode 100644 modules/nf-core/pairix/tests/main.nf.test create mode 100644 modules/nf-core/pairix/tests/main.nf.test.snap create mode 100644 modules/nf-core/pairtools/dedup/tests/main.nf.test create mode 100644 modules/nf-core/pairtools/dedup/tests/main.nf.test.snap create mode 100644 modules/nf-core/pairtools/dedup/tests/nextflow.config create mode 100644 modules/nf-core/pairtools/merge/tests/main.nf.test create mode 100644 modules/nf-core/pairtools/merge/tests/main.nf.test.snap create mode 100644 modules/nf-core/pairtools/parse/tests/main.nf.test create mode 100644 modules/nf-core/pairtools/parse/tests/main.nf.test.snap create mode 100644 modules/nf-core/pairtools/parse/tests/nextflow.config create mode 100644 modules/nf-core/pairtools/restrict/tests/main.nf.test create mode 100644 modules/nf-core/pairtools/restrict/tests/main.nf.test.snap create mode 100644 modules/nf-core/pairtools/restrict/tests/nextflow.config create mode 100644 modules/nf-core/pairtools/select/tests/main.nf.test create mode 100644 modules/nf-core/pairtools/select/tests/main.nf.test.snap create mode 100644 modules/nf-core/pairtools/select/tests/nextflow.config create mode 100644 modules/nf-core/pairtools/sort/tests/main.nf.test create mode 100644 modules/nf-core/pairtools/sort/tests/main.nf.test.snap create mode 100644 modules/nf-core/pairtools/sort/tests/nextflow.config create mode 100644 modules/nf-core/pairtools/stats/tests/main.nf.test create mode 100644 modules/nf-core/pairtools/stats/tests/main.nf.test.snap delete mode 100644 modules/nf-core/samtools/flagstat/tests/tags.yml delete mode 100644 modules/nf-core/samtools/index/tests/tags.yml create mode 100644 modules/nf-core/samtools/sort/tests/nextflow_cram.config delete mode 100644 modules/nf-core/samtools/sort/tests/tags.yml diff --git a/modules.json b/modules.json index 655e4f0f..0a33033d 100644 --- a/modules.json +++ b/modules.json @@ -7,57 +7,57 @@ "nf-core": { "bowtie2/align": { "branch": "master", - "git_sha": "e4bad511789f16d0df39ee306b2cd50418365048", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "bowtie2/build": { "branch": "master", - "git_sha": "1fea64f5132a813ec97c1c6d3a74e0aee7142b6d", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "bwa/index": { "branch": "master", - "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", + "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", "installed_by": ["modules"] }, "bwa/mem": { "branch": "master", - "git_sha": "e0ff65e1fb313677de09f5f477ae3da30ce19b7b", + "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", "installed_by": ["modules"] }, "calder2": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "cooler/balance": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "679deaa32d2862bec641ddaf463e8d8fd9119baf", "installed_by": ["modules"] }, "cooler/cload": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "e36263e74125f9c7c400f4a0faafa006408f57ed", "installed_by": ["modules"] }, "cooler/dump": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "cooler/makebins": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "679deaa32d2862bec641ddaf463e8d8fd9119baf", "installed_by": ["modules"] }, "cooler/zoomify": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "528e4142f86093d92c72f90d40bff9b5131747ca", "installed_by": ["modules"] }, "custom/getchromsizes": { "branch": "master", - "git_sha": "1ceaa8ba4d0fd886dbca0e545815d905b7407de7", + "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"] }, "fastqc": { @@ -67,62 +67,62 @@ }, "multiqc": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e10b76ca0c66213581bec2833e30d31f239dec0b", "installed_by": ["modules"] }, "pairix": { "branch": "master", - "git_sha": "3f5420aa22e00bd030a2556dfdffc9e164ec0ec5", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "pairtools/dedup": { "branch": "master", - "git_sha": "4d3743f71f43cc40505dee2bc0747dca2df5f69a", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "pairtools/merge": { "branch": "master", - "git_sha": "4d3743f71f43cc40505dee2bc0747dca2df5f69a", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "pairtools/parse": { "branch": "master", - "git_sha": "4d3743f71f43cc40505dee2bc0747dca2df5f69a", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "pairtools/restrict": { "branch": "master", - "git_sha": "4d3743f71f43cc40505dee2bc0747dca2df5f69a", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "pairtools/select": { "branch": "master", - "git_sha": "4d3743f71f43cc40505dee2bc0747dca2df5f69a", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "pairtools/sort": { "branch": "master", - "git_sha": "4d3743f71f43cc40505dee2bc0747dca2df5f69a", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "pairtools/stats": { "branch": "master", - "git_sha": "4d3743f71f43cc40505dee2bc0747dca2df5f69a", + "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", "installed_by": ["modules"] }, "samtools/flagstat": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", + "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", "installed_by": ["modules"] }, "samtools/index": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", + "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"] }, "samtools/sort": { "branch": "master", - "git_sha": "04fbbc7c43cebc0b95d5b126f6d9fe4effa33519", + "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", "installed_by": ["modules"] } } diff --git a/modules/nf-core/bowtie2/align/environment.yml b/modules/nf-core/bowtie2/align/environment.yml index d2796359..066ff52e 100644 --- a/modules/nf-core/bowtie2/align/environment.yml +++ b/modules/nf-core/bowtie2/align/environment.yml @@ -1,9 +1,13 @@ -name: bowtie2_align +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::bowtie2=2.5.2 - - bioconda::samtools=1.18 - - conda-forge::pigz=2.6 + # renovate: datasource=conda depName=bioconda/bowtie2 + - bioconda::bowtie2=2.5.4 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.21 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.21 + - conda-forge::pigz=2.8 diff --git a/modules/nf-core/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index 809525ad..631d0bf7 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -4,8 +4,8 @@ process BOWTIE2_ALIGN { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:f70b31a2db15c023d641c32f433fb02cd04df5a6-0' : - 'biocontainers/mulled-v2-ac74a7f02cebcfcc07d8e8d1d750af9c83b4d45a:f70b31a2db15c023d641c32f433fb02cd04df5a6-0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/b4/b41b403e81883126c3227fc45840015538e8e2212f13abc9ae84e4b98891d51c/data' : + 'community.wave.seqera.io/library/bowtie2_htslib_samtools_pigz:edeb13799090a2a6' }" input: tuple val(meta) , path(reads) @@ -60,7 +60,7 @@ process BOWTIE2_ALIGN { --threads $task.cpus \\ $unaligned \\ $args \\ - 2> >(tee ${prefix}.bowtie2.log >&2) \\ + 2>| >(tee ${prefix}.bowtie2.log >&2) \\ | samtools $samtools_command $args2 --threads $task.cpus ${reference} -o ${prefix}.${extension} - if [ -f ${prefix}.unmapped.fastq.1.gz ]; then @@ -90,7 +90,6 @@ process BOWTIE2_ALIGN { } else { create_unmapped = save_unaligned ? "touch ${prefix}.unmapped_1.fastq.gz && touch ${prefix}.unmapped_2.fastq.gz" : "" } - def reference = fasta && extension=="cram" ? "--reference ${fasta}" : "" if (!fasta && extension=="cram") error "Fasta reference is required for CRAM output" def create_index = "" diff --git a/modules/nf-core/bowtie2/align/meta.yml b/modules/nf-core/bowtie2/align/meta.yml index 38610e0e..f38da12e 100644 --- a/modules/nf-core/bowtie2/align/meta.yml +++ b/modules/nf-core/bowtie2/align/meta.yml @@ -16,35 +16,39 @@ tools: documentation: http://bowtie-bio.sourceforge.net/bowtie2/manual.shtml doi: 10.1038/nmeth.1923 licence: ["GPL-3.0-or-later"] + identifier: "" 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. - - meta2: - type: map - description: | - Groovy Map containing reference information - e.g. [ id:'test', single_end:false ] - - index: - type: file - description: Bowtie2 genome index files - pattern: "*.ebwt" - - meta3: - type: map - description: | - Groovy Map containing reference information - e.g. [ id:'test', single_end:false ] - - fasta: - type: file - description: Bowtie2 genome fasta file - pattern: "*.fasta" + - - 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: [] + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test', single_end:false ] + - index: + type: file + description: Bowtie2 genome index files + pattern: "*.ebwt" + ontologies: [] + - - meta3: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Bowtie2 genome fasta file + pattern: "*.fasta" + ontologies: [] - save_unaligned: type: boolean description: | @@ -55,38 +59,77 @@ input: description: use samtools sort (true) or samtools view (false) pattern: "true or false" output: - - sam: - type: file - description: Output SAM file containing read alignments - pattern: "*.sam" - - bam: - type: file - description: Output BAM file containing read alignments - pattern: "*.bam" - - cram: - type: file - description: Output CRAM file containing read alignments - pattern: "*.cram" - - csi: - type: file - description: Output SAM/BAM index for large inputs - pattern: "*.csi" - - crai: - type: file - description: Output CRAM index - pattern: "*.crai" - - log: - type: file - description: Aligment log - pattern: "*.log" - - fastq: - type: file - description: Unaligned FastQ files - pattern: "*.fastq.gz" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + sam: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.sam": + type: file + description: Output SAM file containing read alignments + pattern: "*.sam" + ontologies: [] + bam: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.bam": + type: file + description: Output BAM file containing read alignments + pattern: "*.bam" + ontologies: [] + cram: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.cram": + type: file + description: Output CRAM file containing read alignments + pattern: "*.cram" + ontologies: [] + csi: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.csi": + type: file + description: Output SAM/BAM index for large inputs + pattern: "*.csi" + ontologies: [] + crai: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.crai": + type: file + description: Output CRAM index + pattern: "*.crai" + ontologies: [] + log: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.log": + type: file + description: Alignment log + pattern: "*.log" + ontologies: [] + fastq: + - - meta: + type: map + description: Groovy Map containing sample information + - "*fastq.gz": + type: file + description: Unaligned FastQ files + pattern: "*.fastq.gz" + 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/main.nf.test b/modules/nf-core/bowtie2/align/tests/main.nf.test index 03aeaf9e..0de5950f 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test @@ -18,7 +18,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -30,10 +30,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - 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) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -64,7 +64,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -76,10 +76,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - 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) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -110,7 +110,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -122,10 +122,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - 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) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -155,7 +155,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -167,10 +167,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - 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) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -200,7 +200,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -213,12 +213,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - 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) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -248,7 +248,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -261,12 +261,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - 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) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -297,7 +297,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -309,10 +309,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - 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) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -343,7 +343,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -356,12 +356,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - 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) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -391,7 +391,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -404,12 +404,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - 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) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -439,7 +439,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -451,10 +451,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - 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) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -486,7 +486,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -499,12 +499,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - 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) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = true //sort """ @@ -533,7 +533,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -546,12 +546,12 @@ nextflow_process { input[0] = [ [ id:'test', single_end:false ], // meta map [ - 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) ] ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ @@ -583,7 +583,7 @@ nextflow_process { """ input[0] = [ [ id:'test'], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } @@ -595,10 +595,10 @@ nextflow_process { """ input[0] = [ [ id:'test', single_end:true ], // meta map - 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) ] input[1] = BOWTIE2_BUILD.out.index - input[2] = [[ id:'test'], file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true)] + input[2] = [[ id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true)] input[3] = false //save_unaligned input[4] = false //sort """ 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 028e7da6..4ffd62e9 100644 --- a/modules/nf-core/bowtie2/align/tests/main.nf.test.snap +++ b/modules/nf-core/bowtie2/align/tests/main.nf.test.snap @@ -15,14 +15,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:19:25.337323" + "timestamp": "2025-03-24T12:45:59.038637" }, "sarscov2 - fastq, index, fasta, false, false - sam2": { "content": [ @@ -46,14 +46,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.5" }, - "timestamp": "2024-03-18T12:31:40.337129939" + "timestamp": "2025-03-25T08:28:51.065380563" }, "sarscov2 - [fastq1, fastq2], index, fasta, true, true - cram": { "content": [ @@ -82,14 +82,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T12:58:55.482166476" + "timestamp": "2025-03-24T11:38:12.222762" }, "sarscov2 - fastq, index, fasta, true, false - bam": { "content": [ @@ -107,14 +107,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:19:55.741244" + "timestamp": "2025-03-24T12:46:12.766061" }, "sarscov2 - fastq, large_index, fasta, false, false - bam": { "content": [ @@ -132,14 +132,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:19:09.604979" + "timestamp": "2025-03-24T11:24:03.499074" }, "sarscov2 - fastq, index, fasta, false, true - bam": { "content": [ @@ -157,14 +157,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:18:22.547322" + "timestamp": "2025-03-24T11:08:30.329879" }, "sarscov2 - fastq, index, fasta, true, false - stub": { "content": [ @@ -175,14 +175,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:02:09.557518106" + "timestamp": "2025-03-24T13:48:54.684859" }, "sarscov2 - [fastq1, fastq2], index, fasta, false, false - bam": { "content": [ @@ -200,14 +200,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:18:38.78064" + "timestamp": "2025-03-24T11:13:41.815354" }, "sarscov2 - [fastq1, fastq2], index, fasta, false, false - stub": { "content": [ @@ -218,14 +218,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:20:26.047111" + "timestamp": "2025-03-24T13:06:00.821232" }, "sarscov2 - fastq, index, fasta, false, false - sam": { "content": [ @@ -249,14 +249,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.5" }, - "timestamp": "2024-03-18T12:31:26.668053751" + "timestamp": "2025-03-25T08:28:26.086145568" }, "sarscov2 - [fastq1, fastq2], index, fasta, true, false - bam": { "content": [ @@ -274,14 +274,14 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:19:40.606135" + "timestamp": "2025-03-24T12:46:05.840695" }, "sarscov2 - [fastq1, fastq2], index, fasta, false, true - bam": { "content": [ @@ -299,13 +299,13 @@ ], [ - "versions.yml:md5,01d18ab035146ea790e9a0f70adb758f" + "versions.yml:md5,2768d626cdb54c9a9b5ed7aecbc3ca11" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "24.10.4" }, - "timestamp": "2024-03-18T13:18:54.194648" + "timestamp": "2025-03-24T11:18:52.825034" } } \ No newline at end of file diff --git a/modules/nf-core/bowtie2/align/tests/tags.yml b/modules/nf-core/bowtie2/align/tests/tags.yml deleted file mode 100644 index ac47d1c8..00000000 --- a/modules/nf-core/bowtie2/align/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -bowtie2/align: - - modules/nf-core/bowtie2/align/** diff --git a/modules/nf-core/bowtie2/build/environment.yml b/modules/nf-core/bowtie2/build/environment.yml index 22bbfc37..066ff52e 100644 --- a/modules/nf-core/bowtie2/build/environment.yml +++ b/modules/nf-core/bowtie2/build/environment.yml @@ -1,7 +1,13 @@ -name: bowtie2_build +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::bowtie2=2.5.2 + # renovate: datasource=conda depName=bioconda/bowtie2 + - bioconda::bowtie2=2.5.4 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.21 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.21 + - conda-forge::pigz=2.8 diff --git a/modules/nf-core/bowtie2/build/main.nf b/modules/nf-core/bowtie2/build/main.nf index 9e2e0e5e..fb7effec 100644 --- a/modules/nf-core/bowtie2/build/main.nf +++ b/modules/nf-core/bowtie2/build/main.nf @@ -4,8 +4,8 @@ process BOWTIE2_BUILD { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bowtie2:2.5.2--py39h6fed5c7_0' : - 'biocontainers/bowtie2:2.5.2--py39h6fed5c7_0' }" + 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/b4/b41b403e81883126c3227fc45840015538e8e2212f13abc9ae84e4b98891d51c/data' : + 'community.wave.seqera.io/library/bowtie2_htslib_samtools_pigz:edeb13799090a2a6' }" input: tuple val(meta), path(fasta) diff --git a/modules/nf-core/bowtie2/build/meta.yml b/modules/nf-core/bowtie2/build/meta.yml index 2d687991..3e83ecb4 100644 --- a/modules/nf-core/bowtie2/build/meta.yml +++ b/modules/nf-core/bowtie2/build/meta.yml @@ -15,29 +15,36 @@ tools: documentation: http://bowtie-bio.sourceforge.net/bowtie2/manual.shtml doi: 10.1038/nmeth.1923 licence: ["GPL-3.0-or-later"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing reference information - e.g. [ id:'test', single_end:false ] - - fasta: - type: file - description: Input genome fasta file + - - meta: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Input genome fasta file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing reference information - e.g. [ id:'test', single_end:false ] - - index: - type: file - description: Bowtie2 genome index files - pattern: "*.bt2" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + index: + - - meta: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test', single_end:false ] + - bowtie2: + type: file + description: Bowtie2 genome index files + pattern: "*.bt2" + 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/bowtie2/build/tests/main.nf.test b/modules/nf-core/bowtie2/build/tests/main.nf.test index 16376025..ee94c19c 100644 --- a/modules/nf-core/bowtie2/build/tests/main.nf.test +++ b/modules/nf-core/bowtie2/build/tests/main.nf.test @@ -1,7 +1,7 @@ nextflow_process { name "Test Process BOWTIE2_BUILD" - script "modules/nf-core/bowtie2/build/main.nf" + script "../main.nf" process "BOWTIE2_BUILD" tag "modules" tag "modules_nfcore" @@ -15,7 +15,7 @@ nextflow_process { """ input[0] = [ [ id:'test' ], - file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] """ } diff --git a/modules/nf-core/bowtie2/build/tests/main.nf.test.snap b/modules/nf-core/bowtie2/build/tests/main.nf.test.snap index 6875e021..ea5711e4 100644 --- a/modules/nf-core/bowtie2/build/tests/main.nf.test.snap +++ b/modules/nf-core/bowtie2/build/tests/main.nf.test.snap @@ -18,7 +18,7 @@ ] ], "1": [ - "versions.yml:md5,1df11e9b82891527271c889c880d3974" + "versions.yml:md5,d136fb9c16f0a9fb2ae804b2a5fbc09c" ], "index": [ [ @@ -36,10 +36,14 @@ ] ], "versions": [ - "versions.yml:md5,1df11e9b82891527271c889c880d3974" + "versions.yml:md5,d136fb9c16f0a9fb2ae804b2a5fbc09c" ] } ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.02.1" + }, "timestamp": "2023-11-23T11:51:01.107681997" } } \ No newline at end of file diff --git a/modules/nf-core/bowtie2/build/tests/tags.yml b/modules/nf-core/bowtie2/build/tests/tags.yml deleted file mode 100644 index 81aa61da..00000000 --- a/modules/nf-core/bowtie2/build/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -bowtie2/build: - - modules/nf-core/bowtie2/build/** diff --git a/modules/nf-core/bwa/index/environment.yml b/modules/nf-core/bwa/index/environment.yml index 126e0034..54e67949 100644 --- a/modules/nf-core/bwa/index/environment.yml +++ b/modules/nf-core/bwa/index/environment.yml @@ -1,7 +1,13 @@ -name: bwa_index +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults + dependencies: - - bioconda::bwa=0.7.18 + # renovate: datasource=conda depName=bioconda/bwa + - bioconda::bwa=0.7.19 + # 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/bwa/index/main.nf b/modules/nf-core/bwa/index/main.nf index 2e48b6ca..1860ecfa 100644 --- a/modules/nf-core/bwa/index/main.nf +++ b/modules/nf-core/bwa/index/main.nf @@ -1,18 +1,20 @@ process BWA_INDEX { tag "$fasta" - label 'process_single' + // NOTE requires 5.37N memory where N is the size of the database + // source: https://bio-bwa.sourceforge.net/bwa.shtml#8 + memory { 6.B * fasta.size() } conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/bwa:0.7.18--he4a0461_0' : - 'biocontainers/bwa:0.7.18--he4a0461_0' }" + '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(fasta) output: - tuple val(meta), path(bwa) , emit: index - path "versions.yml" , emit: versions + tuple val(meta), path("bwa") , emit: index + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-core/bwa/index/meta.yml b/modules/nf-core/bwa/index/meta.yml index 6bbc87a6..1781586f 100644 --- a/modules/nf-core/bwa/index/meta.yml +++ b/modules/nf-core/bwa/index/meta.yml @@ -14,29 +14,41 @@ tools: documentation: https://bio-bwa.sourceforge.net/bwa.shtml arxiv: arXiv:1303.3997 licence: ["GPL-3.0-or-later"] + identifier: "biotools:bwa" input: - - meta: - type: map - description: | - Groovy Map containing reference information. - e.g. [ id:'test', single_end:false ] - - fasta: - type: file - description: Input genome fasta file + - - meta: + type: map + description: | + Groovy Map containing reference information. + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Input genome fasta file + ontologies: + - edam: "http://edamontology.org/data_2044" # Sequence + - edam: "http://edamontology.org/format_1929" # FASTA output: - - meta: - type: map - description: | - Groovy Map containing reference information. - e.g. [ id:'test', single_end:false ] - - index: - type: file - description: BWA genome index files - pattern: "*.{amb,ann,bwt,pac,sa}" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + index: + - - meta: + type: map + description: | + Groovy Map containing reference information. + e.g. [ id:'test', single_end:false ] + - bwa: + type: map + description: | + Groovy Map containing reference information. + e.g. [ id:'test', single_end:false ] + pattern: "*.{amb,ann,bwt,pac,sa}" + ontologies: + - edam: "http://edamontology.org/data_3210" # Genome index + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" - "@maxulysse" diff --git a/modules/nf-core/bwa/index/tests/main.nf.test.snap b/modules/nf-core/bwa/index/tests/main.nf.test.snap index 7c8f0465..8fdb482a 100644 --- a/modules/nf-core/bwa/index/tests/main.nf.test.snap +++ b/modules/nf-core/bwa/index/tests/main.nf.test.snap @@ -17,7 +17,7 @@ ] ], "1": [ - "versions.yml:md5,a64462ac7dfb21f4ade9b02e7f65c5bb" + "versions.yml:md5,9a94c646009e4e01912bde135de16400" ], "index": [ [ @@ -34,14 +34,14 @@ ] ], "versions": [ - "versions.yml:md5,a64462ac7dfb21f4ade9b02e7f65c5bb" + "versions.yml:md5,9a94c646009e4e01912bde135de16400" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-16T11:40:09.925307" + "timestamp": "2025-09-23T11:05:03.657185748" } } \ No newline at end of file diff --git a/modules/nf-core/bwa/index/tests/tags.yml b/modules/nf-core/bwa/index/tests/tags.yml deleted file mode 100644 index 28bb483c..00000000 --- a/modules/nf-core/bwa/index/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -bwa/index: - - modules/nf-core/bwa/index/** diff --git a/modules/nf-core/bwa/mem/environment.yml b/modules/nf-core/bwa/mem/environment.yml index 3aa9f0cc..54e67949 100644 --- a/modules/nf-core/bwa/mem/environment.yml +++ b/modules/nf-core/bwa/mem/environment.yml @@ -1,10 +1,13 @@ -name: bwa_mem +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults + dependencies: - - bwa=0.7.18 + # renovate: datasource=conda depName=bioconda/bwa + - bioconda::bwa=0.7.19 + # renovate: datasource=conda depName=bioconda/htslib + - bioconda::htslib=1.22.1 # renovate: datasource=conda depName=bioconda/samtools - - samtools=1.20 - - htslib=1.20.0 + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/bwa/mem/main.nf b/modules/nf-core/bwa/mem/main.nf index 9c815f0c..6893b047 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://depot.galaxyproject.org/singularity/mulled-v2-fe8faa35dbf6dc65a0f7f5d4ea12e31a79f73e40:1bd8542a8a0b42e0981337910954371d0230828e-0' : - 'biocontainers/mulled-v2-fe8faa35dbf6dc65a0f7f5d4ea12e31a79f73e40:1bd8542a8a0b42e0981337910954371d0230828e-0' }" + '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) @@ -53,10 +53,8 @@ process BWA_MEM { """ stub: - def args = task.ext.args ?: '' def args2 = task.ext.args2 ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def samtools_command = sort_bam ? 'sort' : 'view' def extension = args2.contains("--output-fmt sam") ? "sam" : args2.contains("--output-fmt cram") ? "cram": sort_bam && args2.contains("-O cram")? "cram": diff --git a/modules/nf-core/bwa/mem/meta.yml b/modules/nf-core/bwa/mem/meta.yml index b126dd86..e1265ab7 100644 --- a/modules/nf-core/bwa/mem/meta.yml +++ b/modules/nf-core/bwa/mem/meta.yml @@ -17,55 +17,95 @@ tools: documentation: https://bio-bwa.sourceforge.net/bwa.shtml arxiv: arXiv:1303.3997 licence: ["GPL-3.0-or-later"] + identifier: "biotools:bwa" 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. - - meta2: - type: map - description: | - Groovy Map containing reference information. - e.g. [ id:'test', single_end:false ] - - index: - type: file - description: BWA genome index files - pattern: "Directory containing BWA index *.{amb,ann,bwt,pac,sa}" - - fasta: - type: file - description: Reference genome in FASTA format - pattern: "*.{fasta,fa}" + - - 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 reference information. + e.g. [ id:'test', single_end:false ] + - index: + type: file + description: BWA genome index files + pattern: "Directory containing BWA index *.{amb,ann,bwt,pac,sa}" + ontologies: + - edam: "http://edamontology.org/data_3210" # Genome index + - - meta3: + 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 - sort_bam: type: boolean description: use samtools sort (true) or samtools view (false) pattern: "true or false" output: - - bam: - type: file - description: Output BAM file containing read alignments - pattern: "*.{bam}" - - cram: - type: file - description: Output CRAM file containing read alignments - pattern: "*.{cram}" - - csi: - type: file - description: Optional index file for BAM file - pattern: "*.{csi}" - - crai: - type: file - description: Optional index file for CRAM file - pattern: "*.{crai}" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + 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: [] + 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 b/modules/nf-core/bwa/mem/tests/main.nf.test index 463b76f8..5de2c2f4 100644 --- a/modules/nf-core/bwa/mem/tests/main.nf.test +++ b/modules/nf-core/bwa/mem/tests/main.nf.test @@ -9,21 +9,21 @@ nextflow_process { script "../main.nf" process "BWA_MEM" - test("Single-End") { - - setup { - run("BWA_INDEX") { - script "../../index/main.nf" - process { - """ - input[0] = [ - [id: 'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - """ - } + setup { + run("BWA_INDEX") { + script "../../index/main.nf" + process { + """ + input[0] = [ + [id: 'test'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + """ } } + } + + test("Single-End") { when { process { @@ -49,7 +49,8 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - file(process.out.bam[0][1]).name + bam(process.out.bam[0][1]).getHeaderMD5(), + bam(process.out.bam[0][1]).getReadsMD5() ).match() } ) @@ -59,20 +60,6 @@ nextflow_process { test("Single-End Sort") { - setup { - run("BWA_INDEX") { - script "../../index/main.nf" - process { - """ - input[0] = [ - [id: 'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - """ - } - } - } - when { process { """ @@ -97,7 +84,8 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - file(process.out.bam[0][1]).name + bam(process.out.bam[0][1]).getHeaderMD5(), + bam(process.out.bam[0][1]).getReadsMD5() ).match() } ) @@ -107,20 +95,6 @@ nextflow_process { test("Paired-End") { - setup { - run("BWA_INDEX") { - script "../../index/main.nf" - process { - """ - input[0] = [ - [id: 'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - """ - } - } - } - when { process { """ @@ -146,7 +120,8 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - file(process.out.bam[0][1]).name + bam(process.out.bam[0][1]).getHeaderMD5(), + bam(process.out.bam[0][1]).getReadsMD5() ).match() } ) @@ -156,20 +131,6 @@ nextflow_process { test("Paired-End Sort") { - setup { - run("BWA_INDEX") { - script "../../index/main.nf" - process { - """ - input[0] = [ - [id: 'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - """ - } - } - } - when { process { """ @@ -195,7 +156,8 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - file(process.out.bam[0][1]).name + bam(process.out.bam[0][1]).getHeaderMD5(), + bam(process.out.bam[0][1]).getReadsMD5() ).match() } ) @@ -205,20 +167,6 @@ nextflow_process { test("Paired-End - no fasta") { - setup { - run("BWA_INDEX") { - script "../../index/main.nf" - process { - """ - input[0] = [ - [id: 'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - """ - } - } - } - when { process { """ @@ -244,7 +192,8 @@ nextflow_process { process.out.csi, process.out.crai, process.out.versions, - file(process.out.bam[0][1]).name + bam(process.out.bam[0][1]).getHeaderMD5(), + bam(process.out.bam[0][1]).getReadsMD5() ).match() } ) @@ -253,20 +202,9 @@ nextflow_process { } test("Single-end - stub") { + options "-stub" - setup { - run("BWA_INDEX") { - script "../../index/main.nf" - process { - """ - input[0] = [ - [id: 'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - """ - } - } - } + when { process { """ @@ -286,30 +224,15 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - file(process.out.csi[0][1]).name, - process.out.versions - ).match() } + { assert snapshot(process.out).match() } ) } } test("Paired-end - stub") { + options "-stub" - setup { - run("BWA_INDEX") { - script "../../index/main.nf" - process { - """ - input[0] = [ - [id: 'test'], - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ] - """ - } - } - } + when { process { """ @@ -330,11 +253,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.bam[0][1]).name, - file(process.out.csi[0][1]).name, - process.out.versions - ).match() } + { assert snapshot(process.out).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 038ee7b7..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,15 +11,16 @@ ], [ - "versions.yml:md5,478b816fbd37871f5e8c617833d51d80" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "test.bam" + "37b4ee1649480bd1ff98666447f64fa5", + "798439cbd7fd81cbcc5078022dc5479d" ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-20T08:44:32.953673185" + "timestamp": "2025-09-23T11:05:11.396076472" }, "Single-End Sort": { "content": [ @@ -33,15 +34,16 @@ ], [ - "versions.yml:md5,478b816fbd37871f5e8c617833d51d80" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "test.bam" + "57106634fcaf3bf503d5487a7717c5d3", + "94fcf617f5b994584c4e8d4044e16b4f" ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-20T08:44:45.27066093" + "timestamp": "2025-09-23T11:05:19.529514701" }, "Paired-End": { "content": [ @@ -55,15 +57,16 @@ ], [ - "versions.yml:md5,478b816fbd37871f5e8c617833d51d80" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "test.bam" + "57770ff7c7186ed40c42f3d71c16ce3c", + "57aeef88ed701a8ebc8e2f0a381b2a6" ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-20T08:44:57.706852274" + "timestamp": "2025-09-23T11:05:27.433790935" }, "Paired-End Sort": { "content": [ @@ -77,29 +80,93 @@ ], [ - "versions.yml:md5,478b816fbd37871f5e8c617833d51d80" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "test.bam" + "8f5d8f83b485dcfa1f47a73ae645e3a7", + "af8628d9df18b2d3d4f6fd47ef2bb872" ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-20T08:45:10.376505036" + "timestamp": "2025-09-23T11:05:35.775774487" }, "Single-end - stub": { "content": [ - "test.bam", - "test.csi", - [ - "versions.yml:md5,478b816fbd37871f5e8c617833d51d80" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": true + }, + "test.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "test", + "single_end": true + }, + "test.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + ], + "bam": [ + [ + { + "id": "test", + "single_end": true + }, + "test.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + [ + { + "id": "test", + "single_end": true + }, + "test.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "cram": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": true + }, + "test.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-20T08:46:07.182072398" + "timestamp": "2025-09-23T11:05:51.638917351" }, "Paired-End - no fasta": { "content": [ @@ -113,28 +180,92 @@ ], [ - "versions.yml:md5,478b816fbd37871f5e8c617833d51d80" + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" ], - "test.bam" + "57770ff7c7186ed40c42f3d71c16ce3c", + "57aeef88ed701a8ebc8e2f0a381b2a6" ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-20T08:45:53.813076501" + "timestamp": "2025-09-23T11:05:43.764589371" }, "Paired-end - stub": { "content": [ - "test.bam", - "test.csi", - [ - "versions.yml:md5,478b816fbd37871f5e8c617833d51d80" - ] + { + "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": [ + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + ], + "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" + ] + ], + "versions": [ + "versions.yml:md5,f882069f942ae2a95e2c91f82e4445c6" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.7" }, - "timestamp": "2024-05-20T08:46:18.412916364" + "timestamp": "2025-09-23T11:05:59.642014144" } } \ No newline at end of file diff --git a/modules/nf-core/bwa/mem/tests/tags.yml b/modules/nf-core/bwa/mem/tests/tags.yml deleted file mode 100644 index 82992d1f..00000000 --- a/modules/nf-core/bwa/mem/tests/tags.yml +++ /dev/null @@ -1,3 +0,0 @@ -bwa/mem: - - modules/nf-core/bwa/index/** - - modules/nf-core/bwa/mem/** diff --git a/modules/nf-core/calder2/environment.yml b/modules/nf-core/calder2/environment.yml index e694b729..17e4cd31 100644 --- a/modules/nf-core/calder2/environment.yml +++ b/modules/nf-core/calder2/environment.yml @@ -1,7 +1,7 @@ -name: calder2 +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::r-calder2=0.3 + - bioconda::r-calder2=0.7 diff --git a/modules/nf-core/calder2/main.nf b/modules/nf-core/calder2/main.nf index cb77dfe9..d2300f59 100644 --- a/modules/nf-core/calder2/main.nf +++ b/modules/nf-core/calder2/main.nf @@ -1,11 +1,12 @@ process CALDER2 { - tag '$meta.id' + tag "$meta.id" label 'process_high' + // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/r-calder2:0.3--r41hdfd78af_0' : - 'biocontainers/r-calder2:0.3--r41hdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/r-calder2:0.7--r43hdfd78af_1' : + 'biocontainers/r-calder2:0.7--r43hdfd78af_1' }" input: @@ -13,8 +14,8 @@ process CALDER2 { val resolution output: - tuple val(meta), path("${meta.id}/") , emit: output_folder - tuple val(meta), path("${meta.id}/intermediate_data/") , emit: intermediate_data_folder , optional: true + tuple val(meta), path("${prefix}/") , emit: output_folder + tuple val(meta), path("${prefix}/intermediate_data/") , emit: intermediate_data_folder , optional: true path "versions.yml" , emit: versions when: @@ -22,10 +23,10 @@ process CALDER2 { script: def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" + prefix = task.ext.prefix ?: "${meta.id}" def suffix = resolution ? "::/resolutions/$resolution" : "" def cpus = task.cpus ?: 1 - def VERSION = '0.3' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + def VERSION = '0.7' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. """ # getting binsize as mandatory input for calder binsize="\$(cooler info --field bin-size $cool$suffix)" @@ -42,4 +43,25 @@ process CALDER2 { calder: $VERSION END_VERSIONS """ + + stub: + prefix = task.ext.prefix ?: "${meta.id}" + def VERSION = '0.7' // WARN: Version information not provided by tool on CLI. Please update this string when bumping container versions. + """ + mkdir -p ${prefix}/sub_compartments + mkdir -p ${prefix}/sub_domains + + touch ${prefix}/sub_compartments/all_sub_compartments.bed + touch ${prefix}/sub_compartments/all_sub_compartments.tsv + touch ${prefix}/sub_compartments/cor_with_ref.ALL.txt + touch ${prefix}/sub_compartments/cor_with_ref.pdf + touch ${prefix}/sub_compartments/cor_with_ref.txt + + touch ${prefix}/sub_domains/all_nested_boundaries.bed + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + calder: $VERSION + END_VERSIONS + """ } diff --git a/modules/nf-core/calder2/meta.yml b/modules/nf-core/calder2/meta.yml index fef6a2cf..9e353380 100644 --- a/modules/nf-core/calder2/meta.yml +++ b/modules/nf-core/calder2/meta.yml @@ -15,31 +15,47 @@ tools: tool_dev_url: "https://github.com/CSOgroup/CALDER2" doi: "10.1038/s41467-021-22666-3" licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: Groovy Map containing sample information. E.g. [ id:'test', single_end:false ] - - input: - type: file - description: Path to COOL file - pattern: "*.{cool.mcool}" + - - meta: + type: map + description: Groovy Map containing sample information. E.g. [ id:'test', single_end:false + ] + - cool: + type: file + description: Path to COOL file + pattern: "*.{cool.mcool}" + ontologies: [] - resolution: - type: value - description: In case a .mcool file is provided, which resolution level to use for the analysis + type: integer + description: In case a .mcool file is provided, which resolution level to use + for the analysis output: - - meta: - type: map - description: Groovy Map containing sample information. E.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - output: - type: directory - description: Output folder containing sub-compartment (.tsv/.bed) and domain boundaries calls (.bed) - - intermediate_data: - type: directory - description: Output folder containing intermediate data produced during the computation + output_folder: + - - meta: + type: map + description: Groovy Map containing sample information. E.g. [ id:'test', single_end:false + ] + - ${prefix}/: + type: directory + description: Output folder containing sub-compartment (.tsv/.bed) and domain + boundaries calls (.bed) + intermediate_data_folder: + - - meta: + type: map + description: Groovy Map containing sample information. E.g. [ id:'test', single_end:false + ] + - ${prefix}/intermediate_data/: + type: directory + description: Output folder containing intermediate data produced during the + computation + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@lucananni93" maintainers: diff --git a/modules/nf-core/calder2/tests/main.nf.test b/modules/nf-core/calder2/tests/main.nf.test new file mode 100644 index 00000000..7833470e --- /dev/null +++ b/modules/nf-core/calder2/tests/main.nf.test @@ -0,0 +1,135 @@ +import groovy.io.FileType + +nextflow_process { + + name "Test Process CALDER2" + script "../main.nf" + process "CALDER2" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "calder2" + + test("test-calder2-cool") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], //meta map + file('https://raw.githubusercontent.com/CSOgroup/CALDER2/main/tests/testthat/data/test.cool', checkIfExists: true) + ] + + input[1] = [:] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { + def all_files = [] + + file(process.out.output_folder[0][1]).eachFileRecurse (FileType.FILES) { file -> + all_files << file + } + + def all_file_names = all_files.collect { it.name }.toSorted() + + def stable_file_names = [ + 'all_sub_compartments.bed', + 'all_sub_compartments.tsv', + 'cor_with_ref.ALL.txt', + 'cor_with_ref.txt', + 'all_nested_boundaries.bed' + ] + + def stable_files = all_files.findAll { it.name in stable_file_names }.toSorted() + + assert snapshot( + all_file_names, + stable_files, + process.out.versions[0] + ).match() + } + ) + } + } + + test("test-calder2-mcool") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], //meta map + file('https://raw.githubusercontent.com/CSOgroup/CALDER2/main/tests/testthat/data/test.mcool', checkIfExists: true) + ] + + input[1] = 100000 + + """ + } + } + + then { + assertAll( + { assert process.success }, + { + def all_files = [] + + file(process.out.output_folder[0][1]).eachFileRecurse (FileType.FILES) { file -> + all_files << file + } + + def all_file_names = all_files.collect { it.name }.toSorted() + + def stable_file_names = [ + 'all_sub_compartments.bed', + 'all_sub_compartments.tsv', + 'cor_with_ref.ALL.txt', + 'cor_with_ref.txt', + 'all_nested_boundaries.bed' + ] + + def stable_files = all_files.findAll { it.name in stable_file_names }.toSorted() + + assert snapshot( + all_file_names, + stable_files, + process.out.versions[0] + ).match() + } + ) + } + } + + test("test-calder2-mcool-stub") { + options '-stub' + + when { + process { + """ + input[0] = [ + [ id:'test' ], //meta map + file('https://raw.githubusercontent.com/CSOgroup/CALDER2/main/tests/testthat/data/test.mcool', checkIfExists: true) + ] + + input[1] = 100000 + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + +} diff --git a/modules/nf-core/calder2/tests/main.nf.test.snap b/modules/nf-core/calder2/tests/main.nf.test.snap new file mode 100644 index 00000000..22312cd2 --- /dev/null +++ b/modules/nf-core/calder2/tests/main.nf.test.snap @@ -0,0 +1,113 @@ +{ + "test-calder2-mcool-stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + [ + [ + "all_sub_compartments.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "all_sub_compartments.tsv:md5,d41d8cd98f00b204e9800998ecf8427e", + "cor_with_ref.ALL.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "cor_with_ref.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "cor_with_ref.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + [ + "all_nested_boundaries.bed:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ] + ], + "1": [ + + ], + "2": [ + "versions.yml:md5,b312ffd67c18a79a5db11b78777c00d0" + ], + "intermediate_data_folder": [ + + ], + "output_folder": [ + [ + { + "id": "test" + }, + [ + [ + "all_sub_compartments.bed:md5,d41d8cd98f00b204e9800998ecf8427e", + "all_sub_compartments.tsv:md5,d41d8cd98f00b204e9800998ecf8427e", + "cor_with_ref.ALL.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "cor_with_ref.pdf:md5,d41d8cd98f00b204e9800998ecf8427e", + "cor_with_ref.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + [ + "all_nested_boundaries.bed:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ] + ], + "versions": [ + "versions.yml:md5,b312ffd67c18a79a5db11b78777c00d0" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-09-02T15:17:11.435944" + }, + "test-calder2-cool": { + "content": [ + [ + "all_nested_boundaries.bed", + "all_sub_compartments.bed", + "all_sub_compartments.tsv", + "cor_with_ref.ALL.txt", + "cor_with_ref.pdf", + "cor_with_ref.txt" + ], + [ + "all_sub_compartments.bed:md5,1ba23032928f207bf4c7f77b3a0cdf15", + "all_sub_compartments.tsv:md5,059bf7738512ff5f8684d0e69f7897fe", + "cor_with_ref.ALL.txt:md5,05fd4e65c0ba139b87ca36712a5a5b6a", + "cor_with_ref.txt:md5,54f954d92df161db5cae7845d2786ad2", + "all_nested_boundaries.bed:md5,56172ee755f573ad57320273ca0f52cd" + ], + "versions.yml:md5,b312ffd67c18a79a5db11b78777c00d0" + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-09-02T15:16:37.504391" + }, + "test-calder2-mcool": { + "content": [ + [ + "all_nested_boundaries.bed", + "all_sub_compartments.bed", + "all_sub_compartments.tsv", + "cor_with_ref.ALL.txt", + "cor_with_ref.pdf", + "cor_with_ref.txt" + ], + [ + "all_sub_compartments.bed:md5,21b32c66d7ebe5acd2459a32a6592534", + "all_sub_compartments.tsv:md5,743c841b4d4aaa97c5a197c9921fba92", + "cor_with_ref.ALL.txt:md5,5cef6f44386930f637b8c4c4c3b5ee3b", + "cor_with_ref.txt:md5,f748876d367d0fdb751bd00e8e9bf60a", + "all_nested_boundaries.bed:md5,c066de5e2e789e3fe65b900a3b0a4876" + ], + "versions.yml:md5,b312ffd67c18a79a5db11b78777c00d0" + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + }, + "timestamp": "2024-09-02T15:17:06.081233" + } +} \ No newline at end of file diff --git a/modules/nf-core/calder2/tests/nextflow.config b/modules/nf-core/calder2/tests/nextflow.config new file mode 100644 index 00000000..9849869a --- /dev/null +++ b/modules/nf-core/calder2/tests/nextflow.config @@ -0,0 +1,3 @@ +process { + ext.args = '--genome hg38' +} \ No newline at end of file diff --git a/modules/nf-core/cooler/balance/environment.yml b/modules/nf-core/cooler/balance/environment.yml index b39304de..0a8647f5 100644 --- a/modules/nf-core/cooler/balance/environment.yml +++ b/modules/nf-core/cooler/balance/environment.yml @@ -1,7 +1,7 @@ -name: cooler_balance +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::cooler=0.9.2 + - bioconda::cooler=0.10.4 diff --git a/modules/nf-core/cooler/balance/main.nf b/modules/nf-core/cooler/balance/main.nf index 8e0f3935..4296bdb3 100644 --- a/modules/nf-core/cooler/balance/main.nf +++ b/modules/nf-core/cooler/balance/main.nf @@ -4,8 +4,8 @@ process COOLER_BALANCE { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/cooler:0.9.2--pyh7cba7a3_0' : - 'biocontainers/cooler:0.9.2--pyh7cba7a3_0' }" + 'https://depot.galaxyproject.org/singularity/cooler:0.10.4--pyhdfd78af_0' : + 'biocontainers/cooler:0.10.4--pyhdfd78af_0' }" input: tuple val(meta), path(cool), val(resolution) @@ -24,7 +24,7 @@ process COOLER_BALANCE { extension = cool.getExtension() if ("$cool" == "${prefix}.${extension}") error "Input and output names are the same, use \"task.ext.prefix\" to disambiguate!" """ - cp ${cool} ${prefix}.${extension} + ln -s ${cool} ${prefix}.${extension} cooler balance \\ $args \\ @@ -36,4 +36,17 @@ process COOLER_BALANCE { cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') END_VERSIONS """ + + stub: + prefix = task.ext.prefix ?: "${meta.id}" + suffix = resolution ? "::/resolutions/$resolution" : "" + extension = cool.getExtension() + def creation_cmd = suffix.endsWith(".gz") ? "echo '' | gzip -c >" : "touch" + """ + ${creation_cmd} ${prefix}.${extension}${suffix} + cat <<-END_VERSIONS > versions.yml + "${task.process}": + cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') + END_VERSIONS + """ } diff --git a/modules/nf-core/cooler/balance/meta.yml b/modules/nf-core/cooler/balance/meta.yml index 9b890638..cde8782b 100644 --- a/modules/nf-core/cooler/balance/meta.yml +++ b/modules/nf-core/cooler/balance/meta.yml @@ -13,33 +13,40 @@ tools: tool_dev_url: https://github.com/open2c/cooler doi: "10.1093/bioinformatics/btz540" licence: ["BSD-3-Clause"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - cool: - type: file - description: Path to COOL file - pattern: "*.{cool,mcool}" - - resolution: - type: integer - description: Resolution + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - cool: + type: file + description: Path to COOL file + pattern: "*.{cool,mcool}" + ontologies: [] + - resolution: + type: integer + description: Resolution output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - cool: - type: file - description: Output COOL file balancing weigths - pattern: "*.cool" + cool: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - ${prefix}.${extension}: + type: file + description: Output COOL file balancing weights + pattern: "*.cool" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@nservant" - "@muffato" diff --git a/modules/nf-core/cooler/balance/tests/main.nf.test b/modules/nf-core/cooler/balance/tests/main.nf.test new file mode 100644 index 00000000..fb5587ac --- /dev/null +++ b/modules/nf-core/cooler/balance/tests/main.nf.test @@ -0,0 +1,63 @@ +nextflow_process { + + name "Test Process COOLER_BALANCE" + + script "../main.nf" + process "COOLER_BALANCE" + + tag "modules" + tag "modules_nfcore" + tag "cooler" + tag "cooler/balance" + + test("test_cooler_balance") { + when { + + process { + """ + input[0] = [ + [id:'test'],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/merge/toy/toy.symm.upper.2.cool', checkIfExists:true), + '' + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.versions, + process.out.cool.collect{ file(it[1]).name } + ).match() } + ) + } + } + + test("test_cooler_balance - stub") { + + options "-stub" + + when { + + process { + """ + input[0] = input[0] = [ + [id:'test'],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/merge/toy/toy.symm.upper.2.cool', checkIfExists:true), + '' + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out, + process.out.versions.collect{ path(it).yaml } + ).match() } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/cooler/balance/tests/main.nf.test.snap b/modules/nf-core/cooler/balance/tests/main.nf.test.snap new file mode 100644 index 00000000..7d64d30c --- /dev/null +++ b/modules/nf-core/cooler/balance/tests/main.nf.test.snap @@ -0,0 +1,57 @@ +{ + "test_cooler_balance - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.cool:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,0dd67198104cb35ff26349deab04305e" + ], + "cool": [ + [ + { + "id": "test" + }, + "test.cool:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,0dd67198104cb35ff26349deab04305e" + ] + }, + [ + { + "COOLER_BALANCE": { + "cooler": "0.10.4" + } + } + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-17T16:14:41.886977" + }, + "test_cooler_balance": { + "content": [ + [ + "versions.yml:md5,0dd67198104cb35ff26349deab04305e" + ], + [ + "test.cool" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-17T16:14:08.908408" + } +} \ No newline at end of file diff --git a/modules/nf-core/cooler/cload/environment.yml b/modules/nf-core/cooler/cload/environment.yml index 03abee73..0a8647f5 100644 --- a/modules/nf-core/cooler/cload/environment.yml +++ b/modules/nf-core/cooler/cload/environment.yml @@ -1,7 +1,7 @@ -name: cooler_cload +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::cooler=0.9.2 + - bioconda::cooler=0.10.4 diff --git a/modules/nf-core/cooler/cload/main.nf b/modules/nf-core/cooler/cload/main.nf index b170a5d0..a440db7d 100644 --- a/modules/nf-core/cooler/cload/main.nf +++ b/modules/nf-core/cooler/cload/main.nf @@ -1,34 +1,35 @@ process COOLER_CLOAD { - tag "$meta.id" + tag "${meta.id}" label 'process_high' conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/cooler:0.9.2--pyh7cba7a3_0' : - 'biocontainers/cooler:0.9.2--pyh7cba7a3_0' }" + 'https://depot.galaxyproject.org/singularity/cooler:0.10.4--pyhdfd78af_0' : + 'biocontainers/cooler:0.10.4--pyhdfd78af_0' }" input: - tuple val(meta), path(pairs), path(index), val(cool_bin) - path chromsizes + tuple val(meta), path(contacts), path(index) + tuple val(meta2), path(chromsizes) + val(mode) + val(cool_bin) output: - tuple val(meta), path("*.cool"), val(cool_bin), emit: cool - path "versions.yml" , emit: versions + tuple val(meta), path("*.cool"), emit: cool + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: - def args = task.ext.args ?: '' + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def nproc = args.contains('pairix') || args.contains('tabix')? "--nproc $task.cpus" : '' - + def nproc = mode in ["pairix", "tabix"] ? "--nproc ${task.cpus}" : "" """ - cooler cload \\ - $args \\ - $nproc \\ + cooler cload ${mode} \\ + ${args} \\ + ${nproc} \\ ${chromsizes}:${cool_bin} \\ - $pairs \\ + ${contacts} \\ ${prefix}.cool cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/cooler/cload/meta.yml b/modules/nf-core/cooler/cload/meta.yml index fa5474ae..4f8593c2 100644 --- a/modules/nf-core/cooler/cload/meta.yml +++ b/modules/nf-core/cooler/cload/meta.yml @@ -13,41 +13,59 @@ tools: tool_dev_url: https://github.com/open2c/cooler doi: "10.1093/bioinformatics/btz540" licence: ["BSD-3-clause"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - pairs: - type: file - description: Path to contacts (i.e. read pairs) file. - - index: - type: file - description: Path to index file of the contacts. - - cool_bin: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - contacts: + type: file + description: Path to contacts (e.g. read pairs, pairix, tabix) file. + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + - index: + type: file + description: Path to index file of the contacts. + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + - - meta2: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - chromsizes: + type: file + description: Path to a chromsizes file. + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + - mode: type: integer - description: Bins size in bp - - chromsizes: - type: file - description: Path to a chromsizes file. -output: - - meta: - type: map description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - version: - type: file - description: File containing software version - pattern: "versions.yml" - - cool: - type: file - description: Output COOL file path - pattern: "*.cool" + Input mode for cooler cload - one of pairs, pairix, tabix - cool_bin: type: integer description: Bins size in bp +output: + cool: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.cool": + type: file + description: Output COOL file path + pattern: "*.cool" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" - "@muffato" diff --git a/modules/nf-core/cooler/cload/tests/main.nf.test b/modules/nf-core/cooler/cload/tests/main.nf.test new file mode 100644 index 00000000..2d7b05e8 --- /dev/null +++ b/modules/nf-core/cooler/cload/tests/main.nf.test @@ -0,0 +1,170 @@ +nextflow_process { + + name "Test Process COOLER_CLOAD" + config "./nextflow.config" + script "../main.nf" + process "COOLER_CLOAD" + + tag "modules" + tag "modules_nfcore" + tag "cooler" + tag "cooler/cload" + tag "cooler/dump" + + test("test_cooler_cload_pairix") { + when { + + params { + module_args = "" + } + + process { + """ + input[0] = [ + [id:'test_pairix', single_end:false],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.GM12878-MboI.pairs.subsample.blksrt.txt.gz', checkIfExists:true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.GM12878-MboI.pairs.subsample.blksrt.txt.gz.px2', checkIfExists:true) + ] + input[1] = [ + [id:'test_pairix', single_end:false], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.chrom.sizes', checkIfExists:true) + ] + input[2] = "pairix" + input[3] = 2000000 + """ + } + } + + then { + + assertAll( + { assert process.success }, + { assert snapshot( + process.out.versions, + process.out.cool.collect{file(it[1]).name} + ).match() } + ) + + } + } + + + test("test_cooler_cload_pairs") { + + when { + + params { + module_args = '--chrom1 1 --pos1 2 --chrom2 4 --pos2 5 -N' + } + + process { + """ + input[0] = [ + [id:'test_pairs', single_end:false],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.sample1.pairs', checkIfExists:true), + [] + ] + input[1] = [ + [id:'test_pairs', single_end:false], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.chrom.sizes', checkIfExists:true) + ] + input[2] = "pairs" + input[3] = 2000000 + """ + } + } + + then { + + assertAll( + { assert process.success }, + { assert snapshot( + process.out.versions, + process.out.cool.collect{file(it[1]).name} + ).match() } + ) + + } + } + + + test("test_cooler_cload_tabix") { + + when { + + params { + module_args = "" + } + + process { + """ + input[0] = [ + [id:'test_tabix', single_end:false],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.GM12878-MboI.pairs.subsample.sorted.possrt.txt.gz', checkIfExists:true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.GM12878-MboI.pairs.subsample.sorted.possrt.txt.gz.tbi', checkIfExists:true) + ] + input[1] = [ + [id:'test_tabix', single_end:false], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.chrom.sizes',checkIfExists:true) + ] + input[2] = "tabix" + input[3] = 2000000 + """ + } + } + + then { + + assertAll( + { assert process.success }, + { assert snapshot( + process.out.versions, + process.out.cool.collect{file(it[1]).name} + ).match() } + ) + + } + + } + + + test("test_cooler_cload_pairix - stub") { + + options '-stub' + + when { + + params { + module_args = "" + } + + process { + """ + input[0] = [ + [id:'test_pairix', single_end:false],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.GM12878-MboI.pairs.subsample.blksrt.txt.gz', checkIfExists:true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.GM12878-MboI.pairs.subsample.blksrt.txt.gz.px2', checkIfExists:true) + ] + input[1] = [ + [id:'test_pairix', single_end:false], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.chrom.sizes', checkIfExists:true) + ] + input[2] = "pairix" + input[3] = 2000000 + """ + } + } + + then { + + assertAll( + { assert process.success }, + { assert snapshot( + process.out, + process.out.versions.collect{path(it).yaml} + ).match() } + ) + + } + } +} \ No newline at end of file diff --git a/modules/nf-core/cooler/cload/tests/main.nf.test.snap b/modules/nf-core/cooler/cload/tests/main.nf.test.snap new file mode 100644 index 00000000..e42ea735 --- /dev/null +++ b/modules/nf-core/cooler/cload/tests/main.nf.test.snap @@ -0,0 +1,89 @@ +{ + "test_cooler_cload_pairs": { + "content": [ + [ + "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" + ], + [ + "test_pairs.cool" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-08-07T13:29:49.554886524" + }, + "test_cooler_cload_tabix": { + "content": [ + [ + "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" + ], + [ + "test_tabix.cool" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-08-07T13:30:07.963246077" + }, + "test_cooler_cload_pairix": { + "content": [ + [ + "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" + ], + [ + "test_pairix.cool" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-08-07T13:29:32.981383309" + }, + "test_cooler_cload_pairix - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test_pairix", + "single_end": false + }, + "test_pairix.cool:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" + ], + "cool": [ + [ + { + "id": "test_pairix", + "single_end": false + }, + "test_pairix.cool:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" + ] + }, + [ + { + "COOLER_CLOAD": { + "cooler": "0.10.4" + } + } + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-08-07T13:30:28.269060239" + } +} \ No newline at end of file diff --git a/modules/nf-core/cooler/cload/tests/nextflow.config b/modules/nf-core/cooler/cload/tests/nextflow.config new file mode 100644 index 00000000..095becee --- /dev/null +++ b/modules/nf-core/cooler/cload/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: "COOLER_CLOAD" { + ext.args = params.module_args + } +} diff --git a/modules/nf-core/cooler/dump/environment.yml b/modules/nf-core/cooler/dump/environment.yml index b4d88e92..4cb91d27 100644 --- a/modules/nf-core/cooler/dump/environment.yml +++ b/modules/nf-core/cooler/dump/environment.yml @@ -1,7 +1,7 @@ -name: cooler_dump +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::cooler=0.9.2 + - bioconda::cooler=0.10.3 diff --git a/modules/nf-core/cooler/dump/main.nf b/modules/nf-core/cooler/dump/main.nf index 3bb6162c..d2d2cfc6 100644 --- a/modules/nf-core/cooler/dump/main.nf +++ b/modules/nf-core/cooler/dump/main.nf @@ -4,8 +4,8 @@ process COOLER_DUMP { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/cooler:0.9.2--pyh7cba7a3_0' : - 'biocontainers/cooler:0.9.2--pyh7cba7a3_0' }" + 'https://depot.galaxyproject.org/singularity/cooler:0.10.3--pyhdfd78af_0' : + 'biocontainers/cooler:0.10.3--pyhdfd78af_0' }" input: tuple val(meta), path(cool), val(resolution) @@ -18,14 +18,25 @@ process COOLER_DUMP { task.ext.when == null || task.ext.when script: - def args = task.ext.args ?: '' + def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = resolution ? "::/resolutions/$resolution" : "" + def suffix = resolution ? "::/resolutions/$resolution" : "" """ cooler dump \\ - $args \\ + ${args} \\ -o ${prefix}.bedpe \\ - $cool$suffix + ${cool}${suffix} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.bedpe cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/cooler/dump/meta.yml b/modules/nf-core/cooler/dump/meta.yml index 2f882aeb..da621d36 100644 --- a/modules/nf-core/cooler/dump/meta.yml +++ b/modules/nf-core/cooler/dump/meta.yml @@ -12,33 +12,40 @@ tools: tool_dev_url: https://github.com/open2c/cooler doi: "10.1093/bioinformatics/btz540" licence: ["BSD-3-Clause"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - cool: - type: file - description: Path to COOL file - pattern: "*.{cool,mcool}" - - resolution: - type: integer - description: Resolution + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - cool: + type: file + description: Path to COOL file + pattern: "*.{cool,mcool}" + ontologies: [] + - resolution: + type: integer + description: Resolution output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - bedpe: - type: file - description: Output text file - pattern: "*.bedpe" + bedpe: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.bedpe": + type: file + description: Output text file + pattern: "*.bedpe" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" - "@muffato" diff --git a/modules/nf-core/cooler/dump/tests/main.nf.test b/modules/nf-core/cooler/dump/tests/main.nf.test new file mode 100644 index 00000000..ef4a10c1 --- /dev/null +++ b/modules/nf-core/cooler/dump/tests/main.nf.test @@ -0,0 +1,59 @@ + +nextflow_process { + + name "Test Process COOLER_DUMP" + script "../main.nf" + process "COOLER_DUMP" + + tag "modules" + tag "modules_nfcore" + tag "cooler" + tag "cooler/dump" + + test("test-cooler-dump") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file("https://raw.githubusercontent.com/open2c/cooler/master/tests/data/toy.asymm.16.cool", checkIfExists: true), + [:] // resolution if any + ] + """ + } + } + + then { + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() + } + } + + test("test-cooler-dump-stub") { + options '-stub' + + when { + process { + """ + input[0] = [ + [ id:'test' ], + file("https://raw.githubusercontent.com/open2c/cooler/master/tests/data/toy.asymm.16.cool", checkIfExists: true), + [:] // resolution if any + ] + """ + } + } + + then { + assert process.success + assert snapshot( + process.out, + path(process.out.versions[0]).yaml + ).match() + } + } +} diff --git a/modules/nf-core/cooler/dump/tests/main.nf.test.snap b/modules/nf-core/cooler/dump/tests/main.nf.test.snap new file mode 100644 index 00000000..d12afe32 --- /dev/null +++ b/modules/nf-core/cooler/dump/tests/main.nf.test.snap @@ -0,0 +1,78 @@ +{ + "test-cooler-dump-stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bedpe:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + ], + "bedpe": [ + [ + { + "id": "test" + }, + "test.bedpe:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + ] + }, + { + "COOLER_DUMP": { + "cooler": "0.10.3" + } + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.2" + }, + "timestamp": "2025-06-09T15:33:42.848808039" + }, + "test-cooler-dump": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bedpe:md5,38e9b0b8cc74f55a15e8ab01023048bd" + ] + ], + "1": [ + "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + ], + "bedpe": [ + [ + { + "id": "test" + }, + "test.bedpe:md5,38e9b0b8cc74f55a15e8ab01023048bd" + ] + ], + "versions": [ + "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + ] + }, + { + "COOLER_DUMP": { + "cooler": "0.10.3" + } + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.2" + }, + "timestamp": "2025-06-09T15:33:34.433029525" + } +} diff --git a/modules/nf-core/cooler/makebins/environment.yml b/modules/nf-core/cooler/makebins/environment.yml index e48b3a17..0a8647f5 100644 --- a/modules/nf-core/cooler/makebins/environment.yml +++ b/modules/nf-core/cooler/makebins/environment.yml @@ -1,7 +1,7 @@ -name: cooler_makebins +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::cooler=0.9.2 + - bioconda::cooler=0.10.4 diff --git a/modules/nf-core/cooler/makebins/main.nf b/modules/nf-core/cooler/makebins/main.nf index 8a415567..b0273acd 100644 --- a/modules/nf-core/cooler/makebins/main.nf +++ b/modules/nf-core/cooler/makebins/main.nf @@ -1,11 +1,11 @@ process COOLER_MAKEBINS { - tag "${meta.id}}" + 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/cooler:0.9.2--pyh7cba7a3_0' : - 'biocontainers/cooler:0.9.2--pyh7cba7a3_0' }" + 'https://depot.galaxyproject.org/singularity/cooler:0.10.4--pyhdfd78af_0' : + 'biocontainers/cooler:0.10.4--pyhdfd78af_0' }" input: tuple val(meta), path(chromsizes), val(cool_bin) @@ -26,6 +26,16 @@ process COOLER_MAKEBINS { ${chromsizes} \\ ${cool_bin} > ${prefix}.bed + cat <<-END_VERSIONS > versions.yml + "${task.process}": + cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') + END_VERSIONS + """ + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.bed + cat <<-END_VERSIONS > versions.yml "${task.process}": cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') diff --git a/modules/nf-core/cooler/makebins/meta.yml b/modules/nf-core/cooler/makebins/meta.yml index 16e2c598..38e6dbac 100644 --- a/modules/nf-core/cooler/makebins/meta.yml +++ b/modules/nf-core/cooler/makebins/meta.yml @@ -12,22 +12,37 @@ tools: tool_dev_url: https://github.com/open2c/cooler doi: "10.1093/bioinformatics/btz540" licence: ["BSD-3-Clause"] + identifier: "" input: - - chromsize: - type: file - description: Path to chromosome size file - - cool_bin: - type: integer - description: Resolution (bin size) in base pairs + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - chromsizes: + type: file + description: Path to a chromsizes file. + ontologies: [] + - cool_bin: + type: integer + description: Resolution (bin size) in base pairs output: - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - bed: - type: file - description: Genome segmentation at a fixed resolution as a BED file. - pattern: "*.bed" + bed: + - - meta: + type: map + description: Groovy Map containing sample information + - "*.bed": + type: file + description: Genome segmentation at a fixed resolution as a BED file. + pattern: "*.bed" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@nservant" - "@muffato" diff --git a/modules/nf-core/cooler/makebins/tests/main.nf.test b/modules/nf-core/cooler/makebins/tests/main.nf.test new file mode 100644 index 00000000..dc058bd1 --- /dev/null +++ b/modules/nf-core/cooler/makebins/tests/main.nf.test @@ -0,0 +1,59 @@ + +nextflow_process { + + name "Test Process COOLER_MAKEBINS" + script "../main.nf" + process "COOLER_MAKEBINS" + + tag "modules" + tag "modules_nfcore" + tag "cooler" + tag "cooler/makebins" + + test("test-cooler-makebins") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.chrom.sizes', checkIfExists: true), + "1000000" + ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test-cooler-makebins - stub") { + options "-stub" + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/cload/hg19/hg19.chrom.sizes', checkIfExists: true), + "1000000" + ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + +} diff --git a/modules/nf-core/cooler/makebins/tests/main.nf.test.snap b/modules/nf-core/cooler/makebins/tests/main.nf.test.snap new file mode 100644 index 00000000..32dc5172 --- /dev/null +++ b/modules/nf-core/cooler/makebins/tests/main.nf.test.snap @@ -0,0 +1,68 @@ +{ + "test-cooler-makebins - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bed:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + ], + "bed": [ + [ + { + "id": "test" + }, + "test.bed:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-17T16:22:17.078101" + }, + "test-cooler-makebins": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.bed:md5,99e887ba1237ebcdcf31954476ab0adf" + ] + ], + "1": [ + "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + ], + "bed": [ + [ + { + "id": "test" + }, + "test.bed:md5,99e887ba1237ebcdcf31954476ab0adf" + ] + ], + "versions": [ + "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.7" + }, + "timestamp": "2025-09-17T16:21:44.342196" + } +} \ No newline at end of file diff --git a/modules/nf-core/cooler/zoomify/environment.yml b/modules/nf-core/cooler/zoomify/environment.yml index 2288f376..be496d89 100644 --- a/modules/nf-core/cooler/zoomify/environment.yml +++ b/modules/nf-core/cooler/zoomify/environment.yml @@ -1,7 +1,8 @@ -name: cooler_zoomify +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::cooler=0.9.2 + - bioconda::cooler=0.10.4 + - conda-forge::numpy=1.26.4 diff --git a/modules/nf-core/cooler/zoomify/main.nf b/modules/nf-core/cooler/zoomify/main.nf index f9933dff..8bc51da7 100644 --- a/modules/nf-core/cooler/zoomify/main.nf +++ b/modules/nf-core/cooler/zoomify/main.nf @@ -4,8 +4,8 @@ process COOLER_ZOOMIFY { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/cooler:0.9.2--pyh7cba7a3_0' : - 'biocontainers/cooler:0.9.2--pyh7cba7a3_0' }" + 'https://depot.galaxyproject.org/singularity/cooler:0.10.4--pyhdfd78af_0' : + 'biocontainers/cooler:0.10.4--pyhdfd78af_0' }" input: tuple val(meta), path(cool) diff --git a/modules/nf-core/cooler/zoomify/meta.yml b/modules/nf-core/cooler/zoomify/meta.yml index d87aaf29..4e23ad53 100644 --- a/modules/nf-core/cooler/zoomify/meta.yml +++ b/modules/nf-core/cooler/zoomify/meta.yml @@ -12,30 +12,37 @@ tools: tool_dev_url: https://github.com/open2c/cooler doi: "10.1093/bioinformatics/btz540" licence: ["BSD-3-clause"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - cool: - type: file - description: Path to COOL file - pattern: "*.{cool,mcool}" + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - cool: + type: file + description: Path to COOL file + pattern: "*.{cool,mcool}" + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - mcool: - type: file - description: Output mcool file - pattern: "*.mcool" + mcool: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.mcool": + type: file + description: Output mcool file + pattern: "*.mcool" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" maintainers: diff --git a/modules/nf-core/cooler/zoomify/tests/main.nf.test b/modules/nf-core/cooler/zoomify/tests/main.nf.test new file mode 100644 index 00000000..63b3c74c --- /dev/null +++ b/modules/nf-core/cooler/zoomify/tests/main.nf.test @@ -0,0 +1,67 @@ +nextflow_process { + + name "Test Process COOLER_ZOOMIFY" + config "./nextflow.config" + script "../main.nf" + process "COOLER_ZOOMIFY" + + tag "modules" + tag "modules_nfcore" + tag "cooler" + tag "cooler/zoomify" + + test("test_cooler_zoomify") { + + when { + params { + module_args = '-r 2,4,8' + } + process { + """ + input[0] = [ + [id:'test'],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/merge/toy/toy.symm.upper.2.cool', checkIfExists:true) + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.versions, + process.out.mcool.collect{ file(it[1]).name } + ).match() } + ) + } + } + + + test("test_cooler_zoomify -- stub") { + + options '-stub' + + when { + params { + module_args = '-r 2,4,8' + } + process { + """ + input[0] = [ + [id:'test'],// meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/cooler/merge/toy/toy.symm.upper.2.cool', checkIfExists:true) + ] + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out, + process.out.versions.collect{ path(it).yaml } + ).match() } + ) + } + } +} \ No newline at end of file diff --git a/modules/nf-core/cooler/zoomify/tests/main.nf.test.snap b/modules/nf-core/cooler/zoomify/tests/main.nf.test.snap new file mode 100644 index 00000000..fde90a63 --- /dev/null +++ b/modules/nf-core/cooler/zoomify/tests/main.nf.test.snap @@ -0,0 +1,57 @@ +{ + "test_cooler_zoomify -- stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.mcool:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "versions.yml:md5,2f43da81c39434336500d1ec837316e2" + ], + "mcool": [ + [ + { + "id": "test" + }, + "test.mcool:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,2f43da81c39434336500d1ec837316e2" + ] + }, + [ + { + "COOLER_ZOOMIFY": { + "cooler": "0.10.4" + } + } + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-08-07T15:41:31.109709721" + }, + "test_cooler_zoomify": { + "content": [ + [ + "versions.yml:md5,2f43da81c39434336500d1ec837316e2" + ], + [ + "test.mcool" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-08-07T15:41:17.557195332" + } +} \ No newline at end of file diff --git a/modules/nf-core/cooler/zoomify/tests/nextflow.config b/modules/nf-core/cooler/zoomify/tests/nextflow.config new file mode 100644 index 00000000..606da9f6 --- /dev/null +++ b/modules/nf-core/cooler/zoomify/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: "COOLER_ZOOMIFY" { + ext.args = params.module_args + } +} diff --git a/modules/nf-core/custom/getchromsizes/environment.yml b/modules/nf-core/custom/getchromsizes/environment.yml index 2ecd0128..9b3b149b 100644 --- a/modules/nf-core/custom/getchromsizes/environment.yml +++ b/modules/nf-core/custom/getchromsizes/environment.yml @@ -1,8 +1,11 @@ -name: custom_getchromsizes +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults + dependencies: - - bioconda::samtools=1.20 - - bioconda::htslib=1.20 + # 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/custom/getchromsizes/main.nf b/modules/nf-core/custom/getchromsizes/main.nf index 3edf7c22..217f4b80 100644 --- a/modules/nf-core/custom/getchromsizes/main.nf +++ b/modules/nf-core/custom/getchromsizes/main.nf @@ -4,8 +4,8 @@ process CUSTOM_GETCHROMSIZES { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : - 'biocontainers/samtools:1.20--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(fasta) diff --git a/modules/nf-core/custom/getchromsizes/meta.yml b/modules/nf-core/custom/getchromsizes/meta.yml index 529be07e..6f0a0585 100644 --- a/modules/nf-core/custom/getchromsizes/meta.yml +++ b/modules/nf-core/custom/getchromsizes/meta.yml @@ -12,38 +12,59 @@ tools: tool_dev_url: https://github.com/samtools/samtools doi: 10.1093/bioinformatics/btp352 licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - fasta: - type: file - description: FASTA file - pattern: "*.{fa,fasta,fna,fas}" + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: FASTA file + pattern: "*.{fa,fasta,fna,fas}" + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - sizes: - type: file - description: File containing chromosome lengths - pattern: "*.{sizes}" - - fai: - type: file - description: FASTA index file - pattern: "*.{fai}" - - gzi: - type: file - description: Optional gzip index file for compressed inputs - pattern: "*.gzi" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + sizes: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.sizes": + type: file + description: File containing chromosome lengths + pattern: "*.{sizes}" + ontologies: [] + fai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.fai": + type: file + description: FASTA index file + pattern: "*.{fai}" + ontologies: [] + gzi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.gzi": + type: file + description: Optional gzip index file for compressed inputs + pattern: "*.gzi" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@tamara-hodgetts" - "@chris-cheshire" diff --git a/modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap b/modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap index c37b284d..90dc1f9e 100644 --- a/modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap +++ b/modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap @@ -27,7 +27,7 @@ ] ], "3": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ], "fai": [ [ @@ -54,15 +54,15 @@ ] ], "versions": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T12:38:36.927106" + "timestamp": "2025-09-10T15:33:15.306675" }, "test_custom_getchromsizes": { "content": [ @@ -87,7 +87,7 @@ ], "3": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ], "fai": [ [ @@ -109,15 +109,15 @@ ] ], "versions": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-06-20T13:22:34.14237" + "timestamp": "2025-09-10T15:33:03.74832" }, "test_custom_getchromsizes_bgzip": { "content": [ @@ -147,7 +147,7 @@ ] ], "3": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ], "fai": [ [ @@ -174,15 +174,15 @@ ] ], "versions": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-06-20T13:23:06.241379" + "timestamp": "2025-09-10T15:33:07.739978" }, "test_custom_getchromsizes - stub": { "content": [ @@ -207,7 +207,7 @@ ], "3": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ], "fai": [ [ @@ -229,14 +229,14 @@ ] ], "versions": [ - "versions.yml:md5,0d5a7c33bddcb1edad6bf0705b258e6f" + "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" ] } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-07-05T12:24:05.697845" + "timestamp": "2025-09-10T15:33:11.508353" } } \ No newline at end of file diff --git a/modules/nf-core/custom/getchromsizes/tests/tags.yml b/modules/nf-core/custom/getchromsizes/tests/tags.yml deleted file mode 100644 index d89a805f..00000000 --- a/modules/nf-core/custom/getchromsizes/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -custom/getchromsizes: - - modules/nf-core/custom/getchromsizes/** diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index 812fc4c5..dd513cbd 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.31 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 0ac3c369..5288f5cc 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,8 @@ 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/ef/eff0eafe78d5f3b65a6639265a16b89fdca88d06d18894f90fcdb50142004329/data' : + 'community.wave.seqera.io/library/multiqc:1.31--1efbafd542a23882' }" input: path multiqc_files, stageAs: "?/*" diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index 88e90571..17881d15 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -2,14 +2,14 @@ "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" + "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-05-22T11:50:41.182332996" + "timestamp": "2025-09-08T20:57:36.139055243" }, "multiqc_stub": { "content": [ @@ -17,25 +17,25 @@ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" + "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-05-22T11:51:22.448739369" + "timestamp": "2025-09-08T20:59:15.142230631" }, "multiqc_versions_config": { "content": [ [ - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" + "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" ] ], "meta": { "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-05-22T11:51:06.198928424" + "timestamp": "2025-09-08T20:58:29.629087066" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/tags.yml b/modules/nf-core/multiqc/tests/tags.yml deleted file mode 100644 index bea6c0d3..00000000 --- a/modules/nf-core/multiqc/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -multiqc: - - modules/nf-core/multiqc/** diff --git a/modules/nf-core/pairix/environment.yml b/modules/nf-core/pairix/environment.yml index 51ab4007..a41df61c 100644 --- a/modules/nf-core/pairix/environment.yml +++ b/modules/nf-core/pairix/environment.yml @@ -1,7 +1,7 @@ -name: pairix +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairix=0.3.7 diff --git a/modules/nf-core/pairix/meta.yml b/modules/nf-core/pairix/meta.yml index 2b837d12..1117e0a5 100644 --- a/modules/nf-core/pairix/meta.yml +++ b/modules/nf-core/pairix/meta.yml @@ -4,6 +4,8 @@ description: | containing pairs of genomic coordinates keywords: - index + - block-compressed + - pairs tools: - pairix: description: 2D indexing on bgzipped text files of paired genomic coordinates @@ -11,29 +13,41 @@ tools: documentation: "https://github.com/4dn-dcic/pairix" tool_dev_url: "https://github.com/4dn-dcic/pairix" licence: ["MIT"] + identifier: biotools:pairix input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - pair: - type: file - description: pair file + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - pair: + type: file + description: pair file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - index: - type: file - description: pair index file - pattern: "*.px2" + index: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - pair: + type: file + description: pair index file + pattern: "*.px2" + ontologies: [] + - "*.px2": + type: file + description: pair index file + pattern: "*.px2" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" maintainers: diff --git a/modules/nf-core/pairix/tests/main.nf.test b/modules/nf-core/pairix/tests/main.nf.test new file mode 100644 index 00000000..bcfffff8 --- /dev/null +++ b/modules/nf-core/pairix/tests/main.nf.test @@ -0,0 +1,32 @@ + +nextflow_process { + + name "Test Process PAIRIX" + script "../main.nf" + process "PAIRIX" + + tag "modules" + tag "modules_nfcore" + tag "pairix" + + test("test-pairix") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file("https://raw.githubusercontent.com/4dn-dcic/pairix/master/samples/4dn.bsorted.chr21_22_only.nontriangle.pairs.gz", checkIfExists: true) ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + +} diff --git a/modules/nf-core/pairix/tests/main.nf.test.snap b/modules/nf-core/pairix/tests/main.nf.test.snap new file mode 100644 index 00000000..d11b4bb4 --- /dev/null +++ b/modules/nf-core/pairix/tests/main.nf.test.snap @@ -0,0 +1,39 @@ +{ + "test-pairix": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "4dn.bsorted.chr21_22_only.nontriangle.pairs.gz:md5,ee90dc99987ece492d598ed939d54561", + "4dn.bsorted.chr21_22_only.nontriangle.pairs.gz.px2:md5,a6e41cc7cff16fd15b5ee505549ec99a" + ] + ], + "1": [ + "versions.yml:md5,848c8be602ec36645d30010ea30f0684" + ], + "index": [ + [ + { + "id": "test", + "single_end": false + }, + "4dn.bsorted.chr21_22_only.nontriangle.pairs.gz:md5,ee90dc99987ece492d598ed939d54561", + "4dn.bsorted.chr21_22_only.nontriangle.pairs.gz.px2:md5,a6e41cc7cff16fd15b5ee505549ec99a" + ] + ], + "versions": [ + "versions.yml:md5,848c8be602ec36645d30010ea30f0684" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:25:18.874503" + } +} \ No newline at end of file diff --git a/modules/nf-core/pairtools/dedup/environment.yml b/modules/nf-core/pairtools/dedup/environment.yml index 2f7ccc10..d2523556 100644 --- a/modules/nf-core/pairtools/dedup/environment.yml +++ b/modules/nf-core/pairtools/dedup/environment.yml @@ -1,8 +1,8 @@ -name: pairtools_dedup +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairtools=1.0.2 - conda-forge::numpy=1.23 diff --git a/modules/nf-core/pairtools/dedup/meta.yml b/modules/nf-core/pairtools/dedup/meta.yml index 3c67e3fb..03910206 100644 --- a/modules/nf-core/pairtools/dedup/meta.yml +++ b/modules/nf-core/pairtools/dedup/meta.yml @@ -12,33 +12,47 @@ tools: documentation: http://pairtools.readthedocs.io/ tool_dev_url: https://github.com/mirnylab/pairtools licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - input: - type: file - description: pair file + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: pair file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - pairs: - type: file - description: Duplicates removed pairs - pattern: "*.{pairs.gz}" - - stat: - type: file - description: stats of the pairs - pattern: "*.{pairs.stat}" + pairs: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.pairs.gz": + type: file + description: Duplicates removed pairs + pattern: "*.{pairs.gz}" + ontologies: [] + stat: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.pairs.stat": + type: file + description: stats of the pairs + pattern: "*.{pairs.stat}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" maintainers: diff --git a/modules/nf-core/pairtools/dedup/tests/main.nf.test b/modules/nf-core/pairtools/dedup/tests/main.nf.test new file mode 100644 index 00000000..41bbfabb --- /dev/null +++ b/modules/nf-core/pairtools/dedup/tests/main.nf.test @@ -0,0 +1,39 @@ + +nextflow_process { + + name "Test Process PAIRTOOLS_DEDUP" + script "../main.nf" + process "PAIRTOOLS_DEDUP" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "pairtools" + tag "pairtools/dedup" + + test("test-pairtools-dedup") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.4dedup.pairsam', checkIfExists: true) ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.pairs[0][1]).linesGzip[3..7], + process.out.stat, + process.out.versions + ).match() + } + ) + } + } + +} diff --git a/modules/nf-core/pairtools/dedup/tests/main.nf.test.snap b/modules/nf-core/pairtools/dedup/tests/main.nf.test.snap new file mode 100644 index 00000000..46dcf965 --- /dev/null +++ b/modules/nf-core/pairtools/dedup/tests/main.nf.test.snap @@ -0,0 +1,30 @@ +{ + "test-pairtools-dedup": { + "content": [ + [ + "#genome_assembly: unknown", + "#chromosomes: chr1 chr2", + "#columns: readID chrom1 pos1 chrom2 pos2 strand1 strand2 pair_type sam1 sam2", + "readid3\tchr1\t1\tchr1\t20\t+\t+\tUU\t.\t.", + "readid5\tchr1\t1\tchr1\t25\t+\t+\tUU\t.\t." + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.dedup.pairs.stat:md5,94682d1bc608ade150dd11993fbfd2a3" + ] + ], + [ + "versions.yml:md5,485fbdd68f35d563c8559e1afedc4c53" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:23:16.451408" + } +} \ No newline at end of file diff --git a/modules/nf-core/pairtools/dedup/tests/nextflow.config b/modules/nf-core/pairtools/dedup/tests/nextflow.config new file mode 100644 index 00000000..d0cfe51f --- /dev/null +++ b/modules/nf-core/pairtools/dedup/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: PAIRTOOLS_DEDUP { + ext.prefix = { "${meta.id}.dedup" } + } +} diff --git a/modules/nf-core/pairtools/merge/environment.yml b/modules/nf-core/pairtools/merge/environment.yml index f85858a7..d2523556 100644 --- a/modules/nf-core/pairtools/merge/environment.yml +++ b/modules/nf-core/pairtools/merge/environment.yml @@ -1,8 +1,8 @@ -name: pairtools_merge +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairtools=1.0.2 - conda-forge::numpy=1.23 diff --git a/modules/nf-core/pairtools/merge/meta.yml b/modules/nf-core/pairtools/merge/meta.yml index b7bccc3c..d76b0923 100644 --- a/modules/nf-core/pairtools/merge/meta.yml +++ b/modules/nf-core/pairtools/merge/meta.yml @@ -11,29 +11,36 @@ tools: documentation: http://pairtools.readthedocs.io/ tool_dev_url: https://github.com/mirnylab/pairtools licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - allpairs: - type: file - description: All pair files to merge + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - allpairs: + type: file + description: All pair files to merge + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - pairs: - type: file - description: Merged pairs file - pattern: "*.{pairs.gz}" + pairs: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*pairs.gz": + type: file + description: Merged pairs file + pattern: "*.{pairs.gz}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@nservant" maintainers: diff --git a/modules/nf-core/pairtools/merge/tests/main.nf.test b/modules/nf-core/pairtools/merge/tests/main.nf.test new file mode 100644 index 00000000..d9cfa7d0 --- /dev/null +++ b/modules/nf-core/pairtools/merge/tests/main.nf.test @@ -0,0 +1,37 @@ + +nextflow_process { + + name "Test Process PAIRTOOLS_MERGE" + script "../main.nf" + process "PAIRTOOLS_MERGE" + + tag "modules" + tag "modules_nfcore" + tag "pairtools" + tag "pairtools/merge" + + test("test-pairtools-merge") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.pairsam', checkIfExists: true) ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.pairs[0][1]).linesGzip[3..7], + process.out.versions + ).match() + } + ) + } + } + +} diff --git a/modules/nf-core/pairtools/merge/tests/main.nf.test.snap b/modules/nf-core/pairtools/merge/tests/main.nf.test.snap new file mode 100644 index 00000000..3aabbca3 --- /dev/null +++ b/modules/nf-core/pairtools/merge/tests/main.nf.test.snap @@ -0,0 +1,21 @@ +{ + "test-pairtools-merge": { + "content": [ + [ + "#samheader: @SQ\tSN:chr1\tLN:100", + "#samheader: @SQ\tSN:chr2\tLN:100", + "#samheader: @SQ\tSN:chr3\tLN:100", + "#samheader: @PG\tID:bwa\tPN:bwa\tVN:0.7.15-r1140\tCL:bwa mem -SP /path/ucsc.hg19.fasta.gz /path/1.fastq.gz /path/2.fastq.gz", + "#chromosomes: chr2 chr3 chr1" + ], + [ + "versions.yml:md5,e0acb3bd173f64f9984f597571e80eb0" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:19:28.360208" + } +} \ No newline at end of file diff --git a/modules/nf-core/pairtools/parse/environment.yml b/modules/nf-core/pairtools/parse/environment.yml index 0bd69ca2..d2523556 100644 --- a/modules/nf-core/pairtools/parse/environment.yml +++ b/modules/nf-core/pairtools/parse/environment.yml @@ -1,8 +1,8 @@ -name: pairtools_parse +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairtools=1.0.2 - conda-forge::numpy=1.23 diff --git a/modules/nf-core/pairtools/parse/meta.yml b/modules/nf-core/pairtools/parse/meta.yml index e7e448ef..2438df7a 100644 --- a/modules/nf-core/pairtools/parse/meta.yml +++ b/modules/nf-core/pairtools/parse/meta.yml @@ -11,37 +11,52 @@ tools: documentation: http://pairtools.readthedocs.io/ tool_dev_url: https://github.com/mirnylab/pairtools licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - bam: - type: file - description: BAM/CRAM/SAM file - pattern: "*.{bam,cram,sam}" + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + type: file + description: BAM/CRAM/SAM file + pattern: "*.{bam,cram,sam}" + ontologies: [] - chromsizes: type: file description: chromosome size file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - pairsam: - type: file - description: parsed pair file - pattern: "*.{pairsam.gz}" - - stat: - type: file - description: stats of the pairs - pattern: "*.{pairsam.stat}" + pairsam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.pairsam.gz": + type: file + description: parsed pair file + pattern: "*.{pairsam.gz}" + ontologies: [] + stat: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.pairsam.stat": + type: file + description: stats of the pairs + pattern: "*.{pairsam.stat}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" maintainers: diff --git a/modules/nf-core/pairtools/parse/tests/main.nf.test b/modules/nf-core/pairtools/parse/tests/main.nf.test new file mode 100644 index 00000000..27f9bc32 --- /dev/null +++ b/modules/nf-core/pairtools/parse/tests/main.nf.test @@ -0,0 +1,40 @@ + +nextflow_process { + + name "Test Process PAIRTOOLS_PARSE" + script "../main.nf" + process "PAIRTOOLS_PARSE" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "pairtools" + tag "pairtools/parse" + + test("test-pairtools-parse") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.sam', checkIfExists: true) ] + input[1] = file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.chrom.sizes', checkIfExists: true) + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.pairsam[0][1]).linesGzip[3..7], + process.out.stat, + process.out.versions + ).match() + } + ) + } + } + +} diff --git a/modules/nf-core/pairtools/parse/tests/main.nf.test.snap b/modules/nf-core/pairtools/parse/tests/main.nf.test.snap new file mode 100644 index 00000000..c06e572c --- /dev/null +++ b/modules/nf-core/pairtools/parse/tests/main.nf.test.snap @@ -0,0 +1,30 @@ +{ + "test-pairtools-parse": { + "content": [ + [ + "#chromsize: chr1 1000", + "#chromsize: chr2 1000", + "#samheader: @SQ\tSN:chr1\tLN:1000", + "#samheader: @SQ\tSN:chr2\tLN:1000", + "#samheader: @PG\tID:mock\tPN:mock\tVN:0.0.0\tCL:mock" + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.raw.pairsam.stat:md5,054bf78ee4f0a4c447ad3eeb81f1f4ae" + ] + ], + [ + "versions.yml:md5,2c8cb00722749f8e3831464a5057c519" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:17:35.185642" + } +} \ No newline at end of file diff --git a/modules/nf-core/pairtools/parse/tests/nextflow.config b/modules/nf-core/pairtools/parse/tests/nextflow.config new file mode 100644 index 00000000..d662e86b --- /dev/null +++ b/modules/nf-core/pairtools/parse/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: PAIRTOOLS_PARSE { + ext.prefix = { "${meta.id}.raw" } + } +} diff --git a/modules/nf-core/pairtools/restrict/environment.yml b/modules/nf-core/pairtools/restrict/environment.yml index 4ba65c72..d2523556 100644 --- a/modules/nf-core/pairtools/restrict/environment.yml +++ b/modules/nf-core/pairtools/restrict/environment.yml @@ -1,8 +1,8 @@ -name: pairtools_restrict +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairtools=1.0.2 - conda-forge::numpy=1.23 diff --git a/modules/nf-core/pairtools/restrict/meta.yml b/modules/nf-core/pairtools/restrict/meta.yml index 12f6b986..126aeee7 100644 --- a/modules/nf-core/pairtools/restrict/meta.yml +++ b/modules/nf-core/pairtools/restrict/meta.yml @@ -11,35 +11,43 @@ tools: documentation: http://pairtools.readthedocs.io/ tool_dev_url: https://github.com/mirnylab/pairtools licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - pairs: - type: file - description: pairs file + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - pairs: + type: file + description: pairs file + ontologies: [] - frag: type: file description: | a tab-separated BED file with the positions of restriction fragments (chrom, start, end). Can be generated using cooler digest. + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - restrict: - type: file - description: Filtered pairs file - pattern: "*.{pairs.gz}" + restrict: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.pairs.gz": + type: file + description: Filtered pairs file + pattern: "*.{pairs.gz}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" maintainers: diff --git a/modules/nf-core/pairtools/restrict/tests/main.nf.test b/modules/nf-core/pairtools/restrict/tests/main.nf.test new file mode 100644 index 00000000..b9fa5c87 --- /dev/null +++ b/modules/nf-core/pairtools/restrict/tests/main.nf.test @@ -0,0 +1,40 @@ + +nextflow_process { + + name "Test Process PAIRTOOLS_RESTRICT" + script "../main.nf" + process "PAIRTOOLS_RESTRICT" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "pairtools" + tag "pairtools/restrict" + + test("test-pairtools-restrict") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.4flip.pairs', checkIfExists: true) + ] + input[1] = file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/frag.bed', checkIfExists: true) + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.restrict[0][1]).linesGzip[3..7], + process.out.versions + ).match() + } + ) + } + } + +} diff --git a/modules/nf-core/pairtools/restrict/tests/main.nf.test.snap b/modules/nf-core/pairtools/restrict/tests/main.nf.test.snap new file mode 100644 index 00000000..b56cc90c --- /dev/null +++ b/modules/nf-core/pairtools/restrict/tests/main.nf.test.snap @@ -0,0 +1,21 @@ +{ + "test-pairtools-restrict": { + "content": [ + [ + "#chromosomes: chr1 chr2", + "#chromsize: chr1 10000", + "#chromsize: chr2 10000", + "#samheader: @SQ\tSN:chr1\tLN:10000", + "#samheader: @SQ\tSN:chr2\tLN:10000" + ], + [ + "versions.yml:md5,c67dacbd4b0c4f2f060bd65b776113da" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:15:44.880469" + } +} \ No newline at end of file diff --git a/modules/nf-core/pairtools/restrict/tests/nextflow.config b/modules/nf-core/pairtools/restrict/tests/nextflow.config new file mode 100644 index 00000000..49b0723b --- /dev/null +++ b/modules/nf-core/pairtools/restrict/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: PAIRTOOLS_RESTRICT { + ext.prefix = { "${meta.id}.restrict" } + } +} diff --git a/modules/nf-core/pairtools/select/environment.yml b/modules/nf-core/pairtools/select/environment.yml index ef1b0d40..d2523556 100644 --- a/modules/nf-core/pairtools/select/environment.yml +++ b/modules/nf-core/pairtools/select/environment.yml @@ -1,8 +1,8 @@ -name: pairtools_select +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairtools=1.0.2 - conda-forge::numpy=1.23 diff --git a/modules/nf-core/pairtools/select/meta.yml b/modules/nf-core/pairtools/select/meta.yml index e9aef9a2..cad52489 100644 --- a/modules/nf-core/pairtools/select/meta.yml +++ b/modules/nf-core/pairtools/select/meta.yml @@ -11,33 +11,47 @@ tools: documentation: http://pairtools.readthedocs.io/ tool_dev_url: https://github.com/mirnylab/pairtools licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - input: - type: file - description: pairs file + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: pairs file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - selected: - type: file - description: Selected pairs file - pattern: "*.{selected.pairs.gz}" - - unselected: - type: file - description: Rest pairs file. - pattern: "*.{unselected.pairs.gz}" + selected: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.selected.pairs.gz": + type: file + description: Selected pairs file + pattern: "*.{selected.pairs.gz}" + ontologies: [] + unselected: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.unselected.pairs.gz": + type: file + description: Rest pairs file. + pattern: "*.{unselected.pairs.gz}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" maintainers: diff --git a/modules/nf-core/pairtools/select/tests/main.nf.test b/modules/nf-core/pairtools/select/tests/main.nf.test new file mode 100644 index 00000000..ec4ece4f --- /dev/null +++ b/modules/nf-core/pairtools/select/tests/main.nf.test @@ -0,0 +1,39 @@ + +nextflow_process { + + name "Test Process PAIRTOOLS_SELECT" + script "../main.nf" + process "PAIRTOOLS_SELECT" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "pairtools" + tag "pairtools/select" + + test("test-pairtools-select") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.pairsam', checkIfExists: true) ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.selected[0][1]).linesGzip[3..7], + path(process.out.unselected[0][1]).linesGzip[3..7], + process.out.versions + ).match() + } + ) + } + } + +} diff --git a/modules/nf-core/pairtools/select/tests/main.nf.test.snap b/modules/nf-core/pairtools/select/tests/main.nf.test.snap new file mode 100644 index 00000000..d4361209 --- /dev/null +++ b/modules/nf-core/pairtools/select/tests/main.nf.test.snap @@ -0,0 +1,28 @@ +{ + "test-pairtools-select": { + "content": [ + [ + "#chromosomes: chr2 chr3 chr1", + "#chromsize: chr2 100", + "#chromsize: chr3 100", + "#chromsize: chr1 100", + "#samheader: @SQ\tSN:chr1\tLN:100" + ], + [ + "#chromosomes: chr2 chr3 chr1", + "#chromsize: chr2 100", + "#chromsize: chr3 100", + "#chromsize: chr1 100", + "#samheader: @SQ\tSN:chr1\tLN:100" + ], + [ + "versions.yml:md5,ca2f02d3bd0e277e9f578067ff87c19d" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:13:46.44029" + } +} \ No newline at end of file diff --git a/modules/nf-core/pairtools/select/tests/nextflow.config b/modules/nf-core/pairtools/select/tests/nextflow.config new file mode 100644 index 00000000..67ff4e1d --- /dev/null +++ b/modules/nf-core/pairtools/select/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: PAIRTOOLS_SELECT { + ext.args = "(pair_type == \'RU\') or (pair_type == \'UR\') or (pair_type == \'UU\')" + } +} diff --git a/modules/nf-core/pairtools/sort/environment.yml b/modules/nf-core/pairtools/sort/environment.yml index 21bd011a..d2523556 100644 --- a/modules/nf-core/pairtools/sort/environment.yml +++ b/modules/nf-core/pairtools/sort/environment.yml @@ -1,8 +1,8 @@ -name: pairtools_sort +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairtools=1.0.2 - conda-forge::numpy=1.23 diff --git a/modules/nf-core/pairtools/sort/meta.yml b/modules/nf-core/pairtools/sort/meta.yml index 987aebb0..a8239d45 100644 --- a/modules/nf-core/pairtools/sort/meta.yml +++ b/modules/nf-core/pairtools/sort/meta.yml @@ -11,29 +11,36 @@ tools: documentation: http://pairtools.readthedocs.io/ tool_dev_url: https://github.com/mirnylab/pairtools licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - input: - type: file - description: A pairs file + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: A pairs file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - sorted: - type: file - description: Sorted pairs file - pattern: "*.{pairs.gz}" + sorted: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.pairs.gz": + type: file + description: Sorted pairs file + pattern: "*.{pairs.gz}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@jianhong" - "@nservant" diff --git a/modules/nf-core/pairtools/sort/tests/main.nf.test b/modules/nf-core/pairtools/sort/tests/main.nf.test new file mode 100644 index 00000000..a4e789bc --- /dev/null +++ b/modules/nf-core/pairtools/sort/tests/main.nf.test @@ -0,0 +1,38 @@ + +nextflow_process { + + name "Test Process PAIRTOOLS_SORT" + script "../main.nf" + process "PAIRTOOLS_SORT" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "pairtools" + tag "pairtools/sort" + + test("test-pairtools-sort") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.pairsam', checkIfExists: true) ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.sorted[0][1]).linesGzip[3..7], + process.out.versions + ).match() + } + ) + } + } + +} diff --git a/modules/nf-core/pairtools/sort/tests/main.nf.test.snap b/modules/nf-core/pairtools/sort/tests/main.nf.test.snap new file mode 100644 index 00000000..1b22f328 --- /dev/null +++ b/modules/nf-core/pairtools/sort/tests/main.nf.test.snap @@ -0,0 +1,21 @@ +{ + "test-pairtools-sort": { + "content": [ + [ + "#genome_assembly: unknown", + "#chromosomes: : chr1 chr2 chr3", + "#chromsize: chr2 100", + "#chromsize: chr3 100", + "#chromsize: chr1 100" + ], + [ + "versions.yml:md5,6f5e6b4260ee11d35e306d2e085fb762" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:12:01.451816" + } +} \ No newline at end of file diff --git a/modules/nf-core/pairtools/sort/tests/nextflow.config b/modules/nf-core/pairtools/sort/tests/nextflow.config new file mode 100644 index 00000000..566f8da2 --- /dev/null +++ b/modules/nf-core/pairtools/sort/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: PAIRTOOLS_SORT { + ext.prefix = { "${meta.id}.sorted" } + } +} diff --git a/modules/nf-core/pairtools/stats/environment.yml b/modules/nf-core/pairtools/stats/environment.yml index c1f95fbc..d2523556 100644 --- a/modules/nf-core/pairtools/stats/environment.yml +++ b/modules/nf-core/pairtools/stats/environment.yml @@ -1,8 +1,8 @@ -name: pairtools_stats +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::pairtools=1.0.2 - conda-forge::numpy=1.23 diff --git a/modules/nf-core/pairtools/stats/meta.yml b/modules/nf-core/pairtools/stats/meta.yml index da2a1fa3..49171b95 100644 --- a/modules/nf-core/pairtools/stats/meta.yml +++ b/modules/nf-core/pairtools/stats/meta.yml @@ -11,29 +11,36 @@ tools: documentation: http://pairtools.readthedocs.io/ tool_dev_url: https://github.com/mirnylab/pairtools licence: ["MIT"] + identifier: "" input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - pairs: - type: file - description: pairs file + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - pairs: + type: file + description: pairs file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" - - stat: - type: file - description: stats of the pairs - pattern: "*.{pairs.stat}" + stats: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.pairs.stat": + type: file + description: Pairs statistics + pattern: "*{.pairs.stat}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@nservant" maintainers: diff --git a/modules/nf-core/pairtools/stats/tests/main.nf.test b/modules/nf-core/pairtools/stats/tests/main.nf.test new file mode 100644 index 00000000..3e665961 --- /dev/null +++ b/modules/nf-core/pairtools/stats/tests/main.nf.test @@ -0,0 +1,33 @@ + +nextflow_process { + + name "Test Process PAIRTOOLS_STATS" + script "../main.nf" + process "PAIRTOOLS_STATS" + + tag "modules" + tag "modules_nfcore" + tag "pairtools" + tag "pairtools/stats" + + test("test-pairtools-stats") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pairtools/mock.pairsam', checkIfExists: true) ] + + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + +} diff --git a/modules/nf-core/pairtools/stats/tests/main.nf.test.snap b/modules/nf-core/pairtools/stats/tests/main.nf.test.snap new file mode 100644 index 00000000..929db454 --- /dev/null +++ b/modules/nf-core/pairtools/stats/tests/main.nf.test.snap @@ -0,0 +1,37 @@ +{ + "test-pairtools-stats": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.pairs.stat:md5,77a1b2b0b146e00313435f4a707d2d0d" + ] + ], + "1": [ + "versions.yml:md5,97ccf9babab2e888f52934164b9ef0d8" + ], + "stats": [ + [ + { + "id": "test", + "single_end": false + }, + "test.pairs.stat:md5,77a1b2b0b146e00313435f4a707d2d0d" + ] + ], + "versions": [ + "versions.yml:md5,97ccf9babab2e888f52934164b9ef0d8" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.4" + }, + "timestamp": "2024-08-23T11:05:50.844045" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/flagstat/environment.yml b/modules/nf-core/samtools/flagstat/environment.yml index 68b81558..89e12a64 100644 --- a/modules/nf-core/samtools/flagstat/environment.yml +++ b/modules/nf-core/samtools/flagstat/environment.yml @@ -1,8 +1,10 @@ -name: samtools_flagstat +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::samtools=1.20 - - bioconda::htslib=1.20 + # 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 754d84b7..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.20--h50ea8bc_0' : - 'biocontainers/samtools:1.20--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) @@ -18,7 +18,6 @@ process SAMTOOLS_FLAGSTAT { task.ext.when == null || task.ext.when script: - def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" """ samtools \\ @@ -36,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 97991358..ebbc15f2 100644 --- a/modules/nf-core/samtools/flagstat/meta.yml +++ b/modules/nf-core/samtools/flagstat/meta.yml @@ -1,5 +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,34 +18,42 @@ tools: 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 ] - - bam: - type: file - description: BAM/CRAM/SAM file - pattern: "*.{bam,cram,sam}" - - bai: - type: file - description: Index for BAM/CRAM/SAM file - pattern: "*.{bai,crai,sai}" + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + 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: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - flagstat: - type: file - description: File containing samtools flagstat output - pattern: "*.{flagstat}" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + flagstat: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.flagstat": + type: file + description: File containing samtools flagstat output + pattern: "*.{flagstat}" + 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 b/modules/nf-core/samtools/flagstat/tests/main.nf.test index 24c3c04b..3b648a37 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test @@ -11,9 +11,30 @@ nextflow_process { test("BAM") { 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/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) + ]) + """ } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("BAM - stub") { + + options "-stub" + + when { process { """ input[0] = Channel.of([ @@ -28,8 +49,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.flagstat).match("flagstat") }, - { assert snapshot(process.out.versions).match("versions") } + { assert snapshot(process.out).match() } ) } } 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 e9f85efa..0a0a9b15 100644 --- a/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/flagstat/tests/main.nf.test.snap @@ -1,32 +1,72 @@ { - "flagstat": { + "BAM - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,67394650dbae96d1a4fcc70484822159" + ] + ], + "1": [ + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,67394650dbae96d1a4fcc70484822159" + ] + ], + "versions": [ + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-02-12T18:31:37.783927" + "timestamp": "2025-09-15T15:02:00.813612" }, - "versions": { + "BAM": { "content": [ - [ - "versions.yml:md5,f606681ef971cbb548a4d9e3fbabdbc2" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + ] + ], + "1": [ + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" + ], + "flagstat": [ + [ + { + "id": "test", + "single_end": false + }, + "test.flagstat:md5,4f7ffd1e6a5e85524d443209ac97d783" + ] + ], + "versions": [ + "versions.yml:md5,bdc0bfb2b0542580e7cd65e80d8570bc" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-28T15:41:52.516253882" + "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/index/environment.yml b/modules/nf-core/samtools/index/environment.yml index 260d516b..89e12a64 100644 --- a/modules/nf-core/samtools/index/environment.yml +++ b/modules/nf-core/samtools/index/environment.yml @@ -1,8 +1,10 @@ -name: samtools_index +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::samtools=1.20 - - bioconda::htslib=1.20 + # 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/index/main.nf b/modules/nf-core/samtools/index/main.nf index b523c21b..a77ad821 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -4,8 +4,8 @@ process SAMTOOLS_INDEX { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : - 'biocontainers/samtools:1.20--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) @@ -24,7 +24,7 @@ process SAMTOOLS_INDEX { """ samtools \\ index \\ - -@ ${task.cpus-1} \\ + -@ ${task.cpus} \\ $args \\ $input @@ -35,10 +35,11 @@ process SAMTOOLS_INDEX { """ stub: + def args = task.ext.args ?: '' + def extension = file(input).getExtension() == 'cram' ? + "crai" : args.contains("-c") ? "csi" : "bai" """ - touch ${input}.bai - touch ${input}.crai - touch ${input}.csi + touch ${input}.${extension} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/index/meta.yml b/modules/nf-core/samtools/index/meta.yml index 01a4ee03..1bed6bca 100644 --- a/modules/nf-core/samtools/index/meta.yml +++ b/modules/nf-core/samtools/index/meta.yml @@ -15,38 +15,58 @@ tools: 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 ] - - bam: - type: file - description: BAM/CRAM/SAM file - pattern: "*.{bam,cram,sam}" + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: input file + ontologies: [] output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - bai: - type: file - description: BAM/CRAM/SAM index file - pattern: "*.{bai,crai,sai}" - - crai: - type: file - description: BAM/CRAM/SAM index file - pattern: "*.{bai,crai,sai}" - - csi: - type: file - description: CSI index file - pattern: "*.{csi}" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + bai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.bai": + type: file + description: BAM/CRAM/SAM index file + pattern: "*.{bai,crai,sai}" + ontologies: [] + csi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.csi": + type: file + description: CSI index file + pattern: "*.{csi}" + ontologies: [] + crai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.crai": + type: file + description: BAM/CRAM/SAM index file + pattern: "*.{bai,crai,sai}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML authors: - "@drpatelh" - "@ewels" diff --git a/modules/nf-core/samtools/index/tests/main.nf.test b/modules/nf-core/samtools/index/tests/main.nf.test index bb7756d1..ca34fb5c 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test +++ b/modules/nf-core/samtools/index/tests/main.nf.test @@ -9,11 +9,7 @@ nextflow_process { tag "samtools/index" test("bai") { - when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -27,18 +23,13 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.bai).match("bai") }, - { assert snapshot(process.out.versions).match("bai_versions") } + { assert snapshot(process.out).match() } ) } } test("crai") { - when { - params { - outdir = "$outputDir" - } process { """ input[0] = Channel.of([ @@ -52,20 +43,83 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out.crai).match("crai") }, - { assert snapshot(process.out.versions).match("crai_versions") } + { assert snapshot(process.out).match() } ) } } test("csi") { - config "./csi.nextflow.config" 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/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + file(process.out.csi[0][1]).name, + process.out.versions + ).match() } + ) + } + } + + test("bai - 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("crai - stub") { + options "-stub" + 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.recalibrated.sorted.cram', checkIfExists: true) + ]) + """ } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("csi - stub") { + options "-stub" + config "./csi.nextflow.config" + + when { process { """ input[0] = Channel.of([ @@ -79,8 +133,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert path(process.out.csi.get(0).get(1)).exists() }, - { assert snapshot(process.out.versions).match("csi_versions") } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap index 52756e85..3836c6bf 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -1,74 +1,250 @@ { - "crai_versions": { + "csi - stub": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ], + "bai": [ + + ], + "crai": [ + + ], + "csi": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-28T15:42:04.203740976" + "timestamp": "2025-09-10T14:13:38.25787" }, - "csi_versions": { + "crai - stub": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ], + "bai": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-28T15:42:09.57475878" + "timestamp": "2025-09-10T14:13:34.496412" }, - "crai": { + "bai - stub": { "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" ] - ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-02-12T18:41:38.446424" + "timestamp": "2025-09-10T14:13:25.934431" }, - "bai": { + "csi": { "content": [ + "test.paired_end.sorted.bam.csi", [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" - ] + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.04.3" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-02-12T18:40:46.579747" + "timestamp": "2025-09-10T14:13:22.262088" }, - "bai_versions": { + "crai": { "content": [ - [ - "versions.yml:md5,802c9776d9c5e95314e888cf18e96d77" - ] + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ], + "3": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ], + "bai": [ + + ], + "crai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T14:13:18.191664" + }, + "bai": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ], + "bai": [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ], + "crai": [ + + ], + "csi": [ + + ], + "versions": [ + "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-28T15:41:57.929287369" + "timestamp": "2025-09-10T14:13:08.51539" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/index/tests/tags.yml b/modules/nf-core/samtools/index/tests/tags.yml deleted file mode 100644 index e0f58a7a..00000000 --- a/modules/nf-core/samtools/index/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -samtools/index: - - modules/nf-core/samtools/index/** diff --git a/modules/nf-core/samtools/sort/environment.yml b/modules/nf-core/samtools/sort/environment.yml index 36a12eab..89e12a64 100644 --- a/modules/nf-core/samtools/sort/environment.yml +++ b/modules/nf-core/samtools/sort/environment.yml @@ -1,8 +1,10 @@ -name: samtools_sort +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::samtools=1.20 - - bioconda::htslib=1.20 + # 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 596c6f7e..d4bd5a32 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -4,35 +4,45 @@ process SAMTOOLS_SORT { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/samtools:1.20--h50ea8bc_0' : - 'biocontainers/samtools:1.20--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) tuple val(meta2), path(fasta) + val index_format 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 + 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 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}" : "" + 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!" """ samtools cat \\ - --threads $task.cpus \\ ${bam} \\ | \\ samtools sort \\ @@ -40,7 +50,7 @@ process SAMTOOLS_SORT { -T ${prefix} \\ --threads $task.cpus \\ ${reference} \\ - -o ${prefix}.${extension} \\ + -o ${output_file} \\ - cat <<-END_VERSIONS > versions.yml @@ -50,10 +60,23 @@ process SAMTOOLS_SORT { """ stub: - def prefix = task.ext.prefix ?: "${meta.id}" + def args = task.ext.args ?: '' + 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}.bam - touch ${prefix}.bam.csi + touch ${prefix}.${extension} + ${index} cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-core/samtools/sort/meta.yml b/modules/nf-core/samtools/sort/meta.yml index 341a7d0e..4c4010bb 100644 --- a/modules/nf-core/samtools/sort/meta.yml +++ b/modules/nf-core/samtools/sort/meta.yml @@ -15,52 +15,108 @@ tools: 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 ] - - bam: - type: file - description: BAM/CRAM/SAM file(s) - pattern: "*.{bam,cram,sam}" - - meta2: - type: map - description: | - Groovy Map containing reference information - e.g. [ id:'genome' ] - - fasta: - type: file - description: Reference genome FASTA file - pattern: "*.{fa,fasta,fna}" - optional: true + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - bam: + type: file + description: BAM/CRAM/SAM file(s) + pattern: "*.{bam,cram,sam}" + ontologies: [] + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'genome' ] + - fasta: + type: file + 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: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - bam: - type: file - description: Sorted BAM file - pattern: "*.{bam}" - - cram: - type: file - description: Sorted CRAM file - pattern: "*.{cram}" - - crai: - type: file - description: CRAM index file (optional) - pattern: "*.crai" - - csi: - type: file - description: BAM index file (optional) - pattern: "*.csi" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + bam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "${prefix}.bam": + type: file + description: Sorted 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: Sorted CRAM file + pattern: "*.{cram}" + ontologies: [] + sam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "${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" + ontologies: [] + csi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "${prefix}.${extension}.csi": + type: file + description: BAM index file (optional) + pattern: "*.csi" + ontologies: [] + bai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "${prefix}.${extension}.bai": + type: file + description: BAM index file (optional) + pattern: "*.bai" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML 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 fb38ed9b..fa277872 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,14 +33,14 @@ nextflow_process { { assert process.success }, { assert snapshot( process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } - ).match("test_bam") - } + process.out.bai, + process.out.versions + ).match()} ) } } - test("cram") { + test("bam_bai_index") { config "./nextflow.config" @@ -48,12 +49,80 @@ nextflow_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/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.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.versions + ).match()} + ) + } + } + + test("multiple bam") { + + 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] = '' """ } } @@ -62,23 +131,122 @@ nextflow_process { assertAll ( { assert process.success }, { assert snapshot( - process.out.bam, - process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } } - ).match("test_cram") - } + process.out.bam, + process.out.csi.collect { it.collect { it instanceof Map ? it : file(it).name } }, + process.out.versions + ).match()} ) } } - test("bam_stub") { + test("multiple bam bai index") { config "./nextflow.config" - options "-stub" when { - params { - outdir = "$outputDir" + 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.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' + """ + } + } + + 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.versions + ).match()} + ) + } + } + + test("cram") { + + config "./nextflow_cram.config" + + 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) + ]) + input[1] = Channel.of([ + [ 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.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 + ).match()} + ) + } + } + + test("bam - stub") { + + options "-stub" + config "./nextflow.config" + + when { process { """ input[0] = Channel.of([ @@ -89,6 +257,67 @@ nextflow_process { [ id:'fasta' ], // meta map file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ]) + input[2] = '' + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("multiple bam - stub") { + + 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] = '' + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("cram - stub") { + + options "-stub" + config "./nextflow_cram.config" + + 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) + ]) + input[1] = Channel.of([ + [ id:'fasta' ], // meta map + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true) + ]) + input[2] = '' """ } } @@ -96,8 +325,7 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(file(process.out.bam[0][1]).name).match("bam_stub_bam") }, - { assert snapshot(process.out.versions).match("bam_stub_versions") } + { assert snapshot(process.out).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 5a27de1d..473e1745 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/sort/tests/main.nf.test.snap @@ -7,27 +7,94 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" + "test.sorted.cram" ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram.crai" + ] + ], + [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-31T08:13:54.512837189" + "timestamp": "2025-09-10T14:43:31.395604" }, - "bam_stub_bam": { + "bam - stub": { "content": [ - "test.sorted.bam" + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + + ], + "5": [ + + ], + "6": [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ], + "bai": [ + + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "crai": [ + + ], + "cram": [ + + ], + "csi": [ + + ], + "sam": [ + + ], + "versions": [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-31T07:29:00.761845507" + "timestamp": "2025-09-10T14:43:37.387063" }, - "test_cram": { + "bam_csi_index": { "content": [ [ [ @@ -35,7 +102,7 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,22b2093be34a7637f5fbc84272b89d06" + "test.sorted.bam:md5,72ca1dff5344a5e5e6b892fe5f6b134d" ] ], [ @@ -44,17 +111,20 @@ "id": "test", "single_end": false }, - "test.sorted.bam.csi" + "test.sorted.bam.csi:md5,01394e702c729cb478df914ffaf9f7f8" ] + ], + [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-31T09:16:51.924951855" + "timestamp": "2025-09-10T14:43:06.976036" }, - "test_bam": { + "multiple bam bai index": { "content": [ [ [ @@ -62,7 +132,7 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" + "test.sorted.bam:md5,3ffa2affc29f0aa6e7b36dded84625fe" ] ], [ @@ -71,27 +141,226 @@ "id": "test", "single_end": false }, - "test.sorted.bam.csi" + "test.sorted.bam.bai" + ] + ], + [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T14:43:18.72271" + }, + "cram - stub": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + + ], + "5": [ + + ], + "6": [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ], + "bai": [ + + ], + "bam": [ + + ], + "crai": [ + + ], + "cram": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "csi": [ + + ], + "sam": [ + + ], + "versions": [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T14:43:48.734367" + }, + "multiple bam": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,cd4eb0077f25e9cff395366b8883dd1f" + ] + ], + [ + + ], + [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ] + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T14:43:12.989244" + }, + "multiple bam - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,cd4eb0077f25e9cff395366b8883dd1f" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + + ], + "5": [ + + ], + "6": [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ], + "bai": [ + + ], + "bam": [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,cd4eb0077f25e9cff395366b8883dd1f" + ] + ], + "crai": [ + + ], + "cram": [ + + ], + "csi": [ + + ], + "sam": [ + + ], + "versions": [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T14:43:43.196638" + }, + "bam_no_index": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,26b27d1f9bcb61c25da21b562349784e" ] + ], + [ + + ], + [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-31T08:28:12.15952312" + "timestamp": "2025-09-10T14:42:54.926504" }, - "bam_stub_versions": { + "multiple bam csi index": { "content": [ [ - "versions.yml:md5,7a360de20e1d7a6f15a5e8fbe0a9c062" + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,295503ba5342531a3310c33ad0efbc22" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi" + ] + ], + [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-31T07:29:00.765038811" + "timestamp": "2025-09-10T14:43:25.059178" }, "bam": { "content": [ @@ -101,14 +370,56 @@ "id": "test", "single_end": false }, - "test.sorted.bam:md5,21c992d59615936b99f2ad008aa54400" + "test.sorted.bam:md5,34aa85e86abefe637f7a4a9887f016fc" ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.csi" + ] + ], + [ + "versions.yml:md5,2659b187d681241451539d4c53500b9f" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.09.0" + }, + "timestamp": "2024-10-08T11:59:46.372244" + }, + "bam_bai_index": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam:md5,cae7564cb83bb4a5911205bf94124b54" + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + "test.sorted.bam.bai:md5,50dd467c169545a4d5d1f709f7e986e0" + ] + ], + [ + "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "24.04.2" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2024-05-31T08:13:48.538030517" + "timestamp": "2025-09-10T14:43:00.82974" } } \ 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/nextflow_cram.config b/modules/nf-core/samtools/sort/tests/nextflow_cram.config new file mode 100644 index 00000000..3a8c0188 --- /dev/null +++ b/modules/nf-core/samtools/sort/tests/nextflow_cram.config @@ -0,0 +1,8 @@ +process { + + withName: SAMTOOLS_SORT { + ext.prefix = { "${meta.id}.sorted" } + ext.args = "--write-index --output-fmt cram" + } + +} 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/** From 7bed463d0d2d80c962ad0204b3ffc655c5398a49 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 29 Sep 2025 17:36:13 +0200 Subject: [PATCH 03/55] Update subworkflows --- modules.json | 6 +- subworkflows/local/hicpro/main.nf | 1 + .../local/utils_nfcore_hic_pipeline/main.nf | 8 --- .../utils_nextflow_pipeline/tests/tags.yml | 2 - .../utils_nfcore_pipeline/tests/tags.yml | 2 - .../nf-core/utils_nfschema_plugin/main.nf | 40 +++++++++++-- .../utils_nfschema_plugin/tests/main.nf.test | 56 +++++++++++++++++++ .../tests/nextflow.config | 4 +- 8 files changed, 96 insertions(+), 23 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/modules.json b/modules.json index 0a33033d..5660a674 100644 --- a/modules.json +++ b/modules.json @@ -131,17 +131,17 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "c2b22d85f30a706a3073387f30380704fcae013b", + "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "51ae5406a030d4da1e49e4dab49756844fdd6c7a", + "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "2fd2cd6d0e7b273747f32e465fdc6bcc3ae0814e", + "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", "installed_by": ["subworkflows"] } } diff --git a/subworkflows/local/hicpro/main.nf b/subworkflows/local/hicpro/main.nf index 7730e21f..1365f45b 100644 --- a/subworkflows/local/hicpro/main.nf +++ b/subworkflows/local/hicpro/main.nf @@ -128,6 +128,7 @@ workflow HICPRO { chrsize.collect() ) ch_hicpro_raw_maps = BUILD_CONTACT_MAPS.out.maps + ch_versions = ch_versions.mix(BUILD_CONTACT_MAPS.out.versions) // run_ice ICE_NORMALIZATION( diff --git a/subworkflows/local/utils_nfcore_hic_pipeline/main.nf b/subworkflows/local/utils_nfcore_hic_pipeline/main.nf index fc0dbe3c..fa69bdd2 100644 --- a/subworkflows/local/utils_nfcore_hic_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_hic_pipeline/main.nf @@ -8,14 +8,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { samplesheetToList } 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' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 4994303e..ee4738c8 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -4,6 +4,7 @@ include { paramsSummaryLog } from 'plugin/nf-schema' include { validateParameters } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' workflow UTILS_NFSCHEMA_PLUGIN { @@ -15,29 +16,56 @@ workflow UTILS_NFSCHEMA_PLUGIN { // 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) { - log.info paramsSummaryLog(input_workflow, parameters_schema:parameters_schema) - } else { - log.info paramsSummaryLog(input_workflow) + 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) { - validateParameters(parameters_schema:parameters_schema) - } else { - validateParameters() + validateOptions << [parametersSchema: parameters_schema] } + validateParameters(validateOptions) } emit: diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test index 8fb30164..c977917a 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test @@ -25,6 +25,12 @@ nextflow_workflow { input[0] = workflow input[1] = validate_params input[2] = "" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" """ } } @@ -51,6 +57,12 @@ nextflow_workflow { input[0] = workflow input[1] = validate_params input[2] = "" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" """ } } @@ -77,6 +89,12 @@ nextflow_workflow { 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] = "" """ } } @@ -103,6 +121,12 @@ nextflow_workflow { 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] = "" """ } } @@ -114,4 +138,36 @@ nextflow_workflow { ) } } + + 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 index 09ef842a..8d8c7371 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,8 +1,8 @@ plugins { - id "nf-schema@2.4.2" + id "nf-schema@2.5.1" } validation { parametersSchema = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" monochromeLogs = true -} \ No newline at end of file +} From a6240c7dd820c84c48ab294f2a31a40d429899b8 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Wed, 19 Nov 2025 10:51:14 +0100 Subject: [PATCH 04/55] Update modules --- modules.json | 34 +++++++++---------- modules/nf-core/bowtie2/align/meta.yml | 2 +- .../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/calder2/tests/nextflow.config | 2 +- modules/nf-core/cooler/balance/meta.yml | 1 - .../nf-core/cooler/balance/tests/main.nf.test | 12 +++---- .../nf-core/cooler/cload/tests/main.nf.test | 2 +- .../nf-core/cooler/zoomify/tests/main.nf.test | 12 +++---- modules/nf-core/custom/getchromsizes/main.nf | 22 ++++++------ .../custom/getchromsizes/tests/main.nf.test | 16 ++++----- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 5 +-- .../nf-core/multiqc/tests/main.nf.test.snap | 24 ++++++------- modules/nf-core/pairix/tests/main.nf.test | 4 +-- .../pairtools/dedup/tests/main.nf.test | 4 +-- .../pairtools/merge/tests/main.nf.test | 4 +-- .../pairtools/parse/tests/main.nf.test | 4 +-- .../pairtools/select/tests/main.nf.test | 4 +-- .../nf-core/pairtools/sort/tests/main.nf.test | 4 +-- .../pairtools/stats/tests/main.nf.test | 4 +-- .../nf-core/samtools/sort/tests/main.nf.test | 4 +-- 23 files changed, 87 insertions(+), 85 deletions(-) diff --git a/modules.json b/modules.json index 5660a674..0ce05585 100644 --- a/modules.json +++ b/modules.json @@ -7,7 +7,7 @@ "nf-core": { "bowtie2/align": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "bowtie2/build": { @@ -27,17 +27,17 @@ }, "calder2": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "cooler/balance": { "branch": "master", - "git_sha": "679deaa32d2862bec641ddaf463e8d8fd9119baf", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "cooler/cload": { "branch": "master", - "git_sha": "e36263e74125f9c7c400f4a0faafa006408f57ed", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "cooler/dump": { @@ -52,12 +52,12 @@ }, "cooler/zoomify": { "branch": "master", - "git_sha": "528e4142f86093d92c72f90d40bff9b5131747ca", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "custom/getchromsizes": { "branch": "master", - "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "fastqc": { @@ -67,27 +67,27 @@ }, "multiqc": { "branch": "master", - "git_sha": "e10b76ca0c66213581bec2833e30d31f239dec0b", + "git_sha": "82a79183037a403ad1b6714e5dbcff25500efaf6", "installed_by": ["modules"] }, "pairix": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "pairtools/dedup": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "pairtools/merge": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "pairtools/parse": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "pairtools/restrict": { @@ -97,17 +97,17 @@ }, "pairtools/select": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "pairtools/sort": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "pairtools/stats": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, "samtools/flagstat": { @@ -122,7 +122,7 @@ }, "samtools/sort": { "branch": "master", - "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] } } @@ -136,12 +136,12 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "05954dab2ff481bcb999f24455da29a5828af08d", + "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["subworkflows"] } } diff --git a/modules/nf-core/bowtie2/align/meta.yml b/modules/nf-core/bowtie2/align/meta.yml index f38da12e..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: 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/calder2/tests/nextflow.config b/modules/nf-core/calder2/tests/nextflow.config index 9849869a..7bc72018 100644 --- a/modules/nf-core/calder2/tests/nextflow.config +++ b/modules/nf-core/calder2/tests/nextflow.config @@ -1,3 +1,3 @@ process { ext.args = '--genome hg38' -} \ No newline at end of file +} diff --git a/modules/nf-core/cooler/balance/meta.yml b/modules/nf-core/cooler/balance/meta.yml index cde8782b..02dac67e 100644 --- a/modules/nf-core/cooler/balance/meta.yml +++ b/modules/nf-core/cooler/balance/meta.yml @@ -4,7 +4,6 @@ keywords: - cooler/balance - cooler - cool - - cooler tools: - "cooler": description: Sparse binary format for genomic interaction matrices diff --git a/modules/nf-core/cooler/balance/tests/main.nf.test b/modules/nf-core/cooler/balance/tests/main.nf.test index fb5587ac..35940575 100644 --- a/modules/nf-core/cooler/balance/tests/main.nf.test +++ b/modules/nf-core/cooler/balance/tests/main.nf.test @@ -1,18 +1,18 @@ nextflow_process { name "Test Process COOLER_BALANCE" - + script "../main.nf" process "COOLER_BALANCE" - + tag "modules" tag "modules_nfcore" tag "cooler" tag "cooler/balance" - + test("test_cooler_balance") { when { - + process { """ input[0] = [ @@ -39,7 +39,7 @@ nextflow_process { options "-stub" when { - + process { """ input[0] = input[0] = [ @@ -60,4 +60,4 @@ nextflow_process { ) } } -} \ No newline at end of file +} diff --git a/modules/nf-core/cooler/cload/tests/main.nf.test b/modules/nf-core/cooler/cload/tests/main.nf.test index 2d7b05e8..df6083e0 100644 --- a/modules/nf-core/cooler/cload/tests/main.nf.test +++ b/modules/nf-core/cooler/cload/tests/main.nf.test @@ -167,4 +167,4 @@ nextflow_process { } } -} \ No newline at end of file +} diff --git a/modules/nf-core/cooler/zoomify/tests/main.nf.test b/modules/nf-core/cooler/zoomify/tests/main.nf.test index 63b3c74c..05221b05 100644 --- a/modules/nf-core/cooler/zoomify/tests/main.nf.test +++ b/modules/nf-core/cooler/zoomify/tests/main.nf.test @@ -4,14 +4,14 @@ nextflow_process { config "./nextflow.config" script "../main.nf" process "COOLER_ZOOMIFY" - + tag "modules" tag "modules_nfcore" tag "cooler" tag "cooler/zoomify" - + test("test_cooler_zoomify") { - + when { params { module_args = '-r 2,4,8' @@ -35,8 +35,8 @@ nextflow_process { ) } } - - + + test("test_cooler_zoomify -- stub") { options '-stub' @@ -64,4 +64,4 @@ nextflow_process { ) } } -} \ No newline at end of file +} diff --git a/modules/nf-core/custom/getchromsizes/main.nf b/modules/nf-core/custom/getchromsizes/main.nf index 217f4b80..b57463e7 100644 --- a/modules/nf-core/custom/getchromsizes/main.nf +++ b/modules/nf-core/custom/getchromsizes/main.nf @@ -1,3 +1,11 @@ +def deprecation_message = """ +WARNING: The getchromsizes process has been deprecated. Please use nf-core/modules/samtools/faidx. + +Reason: +Getting chromosome sizes was added to samtools/faidx (https://github.com/nf-core/modules/pull/7041) +via a boolean switch, making 'getchromsizes' unnecessary. +""" + process CUSTOM_GETCHROMSIZES { tag "$fasta" label 'process_single' @@ -20,6 +28,8 @@ process CUSTOM_GETCHROMSIZES { task.ext.when == null || task.ext.when script: + assert false: deprecation_message + def args = task.ext.args ?: '' """ samtools faidx $fasta @@ -33,15 +43,7 @@ process CUSTOM_GETCHROMSIZES { stub: """ - touch ${fasta}.fai - touch ${fasta}.sizes - if [[ "${fasta.extension}" == "gz" ]]; then - touch ${fasta}.gzi - fi - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - getchromsizes: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS + >&2 echo "${deprecation_message}" + false """ } diff --git a/modules/nf-core/custom/getchromsizes/tests/main.nf.test b/modules/nf-core/custom/getchromsizes/tests/main.nf.test index 2f741a4b..3efe99ae 100644 --- a/modules/nf-core/custom/getchromsizes/tests/main.nf.test +++ b/modules/nf-core/custom/getchromsizes/tests/main.nf.test @@ -24,8 +24,8 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert process.failed }, + { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } ) } } @@ -45,8 +45,8 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert process.failed }, + { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } ) } } @@ -68,8 +68,8 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert process.failed }, + { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } ) } } @@ -91,8 +91,8 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert process.failed }, + { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } ) } } diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index dd513cbd..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.31 + - bioconda::multiqc=1.32 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 5288f5cc..5d0780af 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,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/ef/eff0eafe78d5f3b65a6639265a16b89fdca88d06d18894f90fcdb50142004329/data' : - 'community.wave.seqera.io/library/multiqc:1.31--1efbafd542a23882' }" + '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: "?/*" @@ -52,6 +52,7 @@ process MULTIQC { stub: """ mkdir multiqc_data + touch multiqc_data/.stub mkdir multiqc_plots touch multiqc_report.html diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index 17881d15..a88bafd6 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -2,14 +2,14 @@ "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" + "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "24.10.4" }, - "timestamp": "2025-09-08T20:57:36.139055243" + "timestamp": "2025-10-27T13:33:24.356715" }, "multiqc_stub": { "content": [ @@ -17,25 +17,25 @@ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" + "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "24.10.4" }, - "timestamp": "2025-09-08T20:59:15.142230631" + "timestamp": "2025-10-27T13:34:11.103619" }, "multiqc_versions_config": { "content": [ [ - "versions.yml:md5,8968b114a3e20756d8af2b80713bcc4f" + "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "24.10.4" }, - "timestamp": "2025-09-08T20:58:29.629087066" + "timestamp": "2025-10-27T13:34:04.615233" } } \ No newline at end of file diff --git a/modules/nf-core/pairix/tests/main.nf.test b/modules/nf-core/pairix/tests/main.nf.test index bcfffff8..69bf7759 100644 --- a/modules/nf-core/pairix/tests/main.nf.test +++ b/modules/nf-core/pairix/tests/main.nf.test @@ -10,7 +10,7 @@ nextflow_process { tag "pairix" test("test-pairix") { - + when { process { """ @@ -28,5 +28,5 @@ nextflow_process { ) } } - + } diff --git a/modules/nf-core/pairtools/dedup/tests/main.nf.test b/modules/nf-core/pairtools/dedup/tests/main.nf.test index 41bbfabb..c812a6ac 100644 --- a/modules/nf-core/pairtools/dedup/tests/main.nf.test +++ b/modules/nf-core/pairtools/dedup/tests/main.nf.test @@ -12,7 +12,7 @@ nextflow_process { tag "pairtools/dedup" test("test-pairtools-dedup") { - + when { process { """ @@ -35,5 +35,5 @@ nextflow_process { ) } } - + } diff --git a/modules/nf-core/pairtools/merge/tests/main.nf.test b/modules/nf-core/pairtools/merge/tests/main.nf.test index d9cfa7d0..8d2b9d8d 100644 --- a/modules/nf-core/pairtools/merge/tests/main.nf.test +++ b/modules/nf-core/pairtools/merge/tests/main.nf.test @@ -11,7 +11,7 @@ nextflow_process { tag "pairtools/merge" test("test-pairtools-merge") { - + when { process { """ @@ -33,5 +33,5 @@ nextflow_process { ) } } - + } diff --git a/modules/nf-core/pairtools/parse/tests/main.nf.test b/modules/nf-core/pairtools/parse/tests/main.nf.test index 27f9bc32..0535d4dd 100644 --- a/modules/nf-core/pairtools/parse/tests/main.nf.test +++ b/modules/nf-core/pairtools/parse/tests/main.nf.test @@ -12,7 +12,7 @@ nextflow_process { tag "pairtools/parse" test("test-pairtools-parse") { - + when { process { """ @@ -36,5 +36,5 @@ nextflow_process { ) } } - + } diff --git a/modules/nf-core/pairtools/select/tests/main.nf.test b/modules/nf-core/pairtools/select/tests/main.nf.test index ec4ece4f..de783340 100644 --- a/modules/nf-core/pairtools/select/tests/main.nf.test +++ b/modules/nf-core/pairtools/select/tests/main.nf.test @@ -12,7 +12,7 @@ nextflow_process { tag "pairtools/select" test("test-pairtools-select") { - + when { process { """ @@ -35,5 +35,5 @@ nextflow_process { ) } } - + } diff --git a/modules/nf-core/pairtools/sort/tests/main.nf.test b/modules/nf-core/pairtools/sort/tests/main.nf.test index a4e789bc..8413a2b1 100644 --- a/modules/nf-core/pairtools/sort/tests/main.nf.test +++ b/modules/nf-core/pairtools/sort/tests/main.nf.test @@ -12,7 +12,7 @@ nextflow_process { tag "pairtools/sort" test("test-pairtools-sort") { - + when { process { """ @@ -34,5 +34,5 @@ nextflow_process { ) } } - + } diff --git a/modules/nf-core/pairtools/stats/tests/main.nf.test b/modules/nf-core/pairtools/stats/tests/main.nf.test index 3e665961..4dd0e82d 100644 --- a/modules/nf-core/pairtools/stats/tests/main.nf.test +++ b/modules/nf-core/pairtools/stats/tests/main.nf.test @@ -11,7 +11,7 @@ nextflow_process { tag "pairtools/stats" test("test-pairtools-stats") { - + when { process { """ @@ -29,5 +29,5 @@ nextflow_process { ) } } - + } diff --git a/modules/nf-core/samtools/sort/tests/main.nf.test b/modules/nf-core/samtools/sort/tests/main.nf.test index fa277872..ff069190 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -71,7 +71,7 @@ nextflow_process { ) } } - + test("bam_csi_index") { config "./nextflow.config" @@ -173,7 +173,7 @@ nextflow_process { ) } } - + test("multiple bam csi index") { config "./nextflow.config" From d47a02f63400cc294084dbb9b2e6f320c5204058 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Wed, 19 Nov 2025 10:51:44 +0100 Subject: [PATCH 05/55] Update subworkflows --- subworkflows/local/compartments/meta.yml | 36 +++++++++++++++++++ .../nf-core/utils_nfcore_pipeline/main.nf | 2 +- .../nf-core/utils_nfschema_plugin/main.nf | 1 - 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 subworkflows/local/compartments/meta.yml diff --git a/subworkflows/local/compartments/meta.yml b/subworkflows/local/compartments/meta.yml new file mode 100644 index 00000000..d9f367a5 --- /dev/null +++ b/subworkflows/local/compartments/meta.yml @@ -0,0 +1,36 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "COMPARTMENTS" +description: +keywords: + - Eigcis + - Calder2 +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_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/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 818cdb8c46af534fd38bf581cd47e3f5ad09bc49 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Wed, 19 Nov 2025 12:05:56 +0100 Subject: [PATCH 06/55] Write subworkflows meta.yml --- subworkflows/local/compartments/meta.yml | 53 ++++++----- subworkflows/local/cooler/meta.yml | 57 ++++++++++++ subworkflows/local/hicpro/meta.yml | 87 +++++++++++++++++++ subworkflows/local/hicpro_mapping/meta.yml | 67 ++++++++++++++ subworkflows/local/pairtools/meta.yml | 86 ++++++++++++++++++ subworkflows/local/prepare_genome/meta.yml | 73 ++++++++++++++++ subworkflows/local/tads/meta.yml | 39 +++++++++ .../local/utils_nfcore_hic_pipeline/meta.yml | 58 +++++++++++++ 8 files changed, 500 insertions(+), 20 deletions(-) create mode 100644 subworkflows/local/cooler/meta.yml create mode 100644 subworkflows/local/hicpro/meta.yml create mode 100644 subworkflows/local/hicpro_mapping/meta.yml create mode 100644 subworkflows/local/pairtools/meta.yml create mode 100644 subworkflows/local/prepare_genome/meta.yml create mode 100644 subworkflows/local/tads/meta.yml create mode 100644 subworkflows/local/utils_nfcore_hic_pipeline/meta.yml diff --git a/subworkflows/local/compartments/meta.yml b/subworkflows/local/compartments/meta.yml index d9f367a5..fc8b5256 100644 --- a/subworkflows/local/compartments/meta.yml +++ b/subworkflows/local/compartments/meta.yml @@ -1,36 +1,49 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json name: "COMPARTMENTS" -description: +description: | + Subworkflow to call genomic compartments from Hi-C data using either + Cooltools Eigscis or Calder2. Takes a .cool file, reference FASTA, + and chromosome sizes, then runs the selected caller based on the + `params.compartments_caller` parameter. Outputs compartment calls + and tool version information. keywords: - - Eigcis + - Eigscis - Calder2 -components: [] + - Hi-C + - Compartments + - Genomics +components: + - cooltools_eigscis + - calder2 input: - - print_version: - type: boolean + - cool: + type: file description: | - Print the version of the pipeline and exit - - dump_parameters: - type: boolean + Input Hi-C contact map in .cool format + pattern: "*.cool" + - fasta: + type: file 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 + Reference genome FASTA file + pattern: "*.fa" + - chrsize: + type: file description: | - Check if the conda channel priority is correct. + Chromosome sizes file + pattern: "*.txt" output: - - dummy_emit: - type: boolean + - compartments: + type: directory + description: | + Directory containing compartment calls from the selected caller + - versions: + type: file description: | - Dummy emit to make nf-core subworkflows lint happy + Versions of tools used in the workflow authors: - "@adamrtalbot" - "@drpatelh" maintainers: - "@adamrtalbot" - "@drpatelh" - - "@maxulysse" + - "@maxulysse" \ No newline at end of file diff --git a/subworkflows/local/cooler/meta.yml b/subworkflows/local/cooler/meta.yml new file mode 100644 index 00000000..7043df82 --- /dev/null +++ b/subworkflows/local/cooler/meta.yml @@ -0,0 +1,57 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "COOLER" +description: | + Main workflow to generate and process cooler files from Hi-C interaction pairs. + Takes a .pairs file of valid interactions, chromosome sizes, and bin definitions. + Builds cooler files at multiple resolutions, balances them, zoomifies at selected + resolution(s), and produces dumps for downstream analysis. +keywords: + - Hi-C + - Cooler + - Genomics + - Chromosome interactions +components: + - cooler_makebins + - cooler_cload + - cooler_balance + - cooler_zoomify + - cooler_dump + - split_cooler_dump +input: + - pairs: + type: file + description: | + Input .pairs text file containing valid Hi-C interactions + pattern: "*.pairs" + - chromsize: + type: file + description: | + Chromosome sizes file + pattern: "*.txt" + - cool_bins: + type: file + description: | + Bin size definitions for cooler construction + pattern: "*.txt" +output: + - cool: + type: file + description: | + Balanced cooler files at specified resolutions + pattern: "*.cool" + - mcool: + type: file + description: | + Multi-resolution cooler file (zoomified) + pattern: "*.mcool" + - versions: + type: file + description: | + Versions of tools used in the workflow +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" \ No newline at end of file diff --git a/subworkflows/local/hicpro/meta.yml b/subworkflows/local/hicpro/meta.yml new file mode 100644 index 00000000..a994f059 --- /dev/null +++ b/subworkflows/local/hicpro/meta.yml @@ -0,0 +1,87 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "HICPRO" +description: | + Main workflow to process raw Hi-C sequencing reads into valid interaction pairs + and contact maps. Performs mapping, digestion or DNase-like protocols, merges + interactions and statistics, converts to pairs format, and optionally builds + and normalizes contact maps. +keywords: + - Hi-C + - Hic-Pro + - Genomics + - Chromosome interactions + - Contact maps +components: + - hicpro_mapping + - get_valid_interaction + - get_valid_interaction_dnase + - merge_valid_interaction + - merge_stats + - hicpro2pairs + - build_contact_maps + - ice_normalization +input: + - reads: + type: file + description: | + Raw sequencing reads (paired-end FASTQ files) + pattern: "*.fastq.gz" + - fasta: + type: file + description: | + Reference genome FASTA file + pattern: "*.fa" + - index: + type: directory + description: | + Path to the genome index for read mapping + - fragments: + type: file + description: | + Restriction fragments file for digestion protocols + pattern: "*.txt" + - chrsize: + type: file + description: | + Chromosome sizes file + pattern: "*.txt" + - ligation_site: + type: string + description: | + Ligation site sequence used in digestion protocols + - map_res: + type: integer + description: | + Resolution(s) for building contact maps +output: + - pairs: + type: file + description: | + Valid interaction pairs in .pairs format + pattern: "*.pairs" + - mqc: + type: file + description: | + MultiQC-compatible statistics from mapping, interactions, and merging + pattern: "*.mqc" + - raw_maps: + type: file + description: | + Raw contact maps generated from valid pairs + pattern: "*.txt" + - iced_maps: + type: file + description: | + ICE-normalized contact maps + pattern: "*.txt" + - versions: + type: file + description: | + Versions of tools used in the workflow +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/local/hicpro_mapping/meta.yml b/subworkflows/local/hicpro_mapping/meta.yml new file mode 100644 index 00000000..ff065859 --- /dev/null +++ b/subworkflows/local/hicpro_mapping/meta.yml @@ -0,0 +1,67 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "HICPRO_MAPPING" +description: | + Workflow to map raw Hi-C sequencing reads to a reference genome using Bowtie2. + Handles digestion protocols by trimming reads at ligation sites, merging mapping + steps, and computing mapping statistics. For DNase-like protocols, generates + mapping statistics directly from aligned reads. Produces paired-end BAM files + and mapping/interaction statistics. +keywords: + - Hi-C + - Hic-Pro + - Mapping + - Bowtie2 + - Genomics +components: + - bowtie2_align + - trim_reads + - merge_bowtie2 + - hicpro_combine_mates + - mapping_stats_dnase + - combine_mates +input: + - reads: + type: file + description: | + Raw sequencing reads (paired-end FASTQ files) + pattern: "*.fastq.gz" + - fasta: + type: file + description: | + Reference genome FASTA file + pattern: "*.fa" + - index: + type: directory + description: | + Path to the genome index for Bowtie2 mapping + - ligation_site: + type: string + description: | + Ligation site sequence used for trimming in digestion protocols +output: + - bam: + type: file + description: | + Paired-end BAM files after mapping and mate combination + pattern: "*.bam" + - mapstats: + type: file + description: | + Mapping statistics from Bowtie2 or DNase mapping + pattern: "*.txt" + - pairstats: + type: file + description: | + Pairing statistics from mate combination + pattern: "*.txt" + - versions: + type: file + description: | + Versions of tools used in the workflow +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/local/pairtools/meta.yml b/subworkflows/local/pairtools/meta.yml new file mode 100644 index 00000000..f37d6322 --- /dev/null +++ b/subworkflows/local/pairtools/meta.yml @@ -0,0 +1,86 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "PAIRTOOLS" +description: | + Main workflow to process raw Hi-C sequencing reads into valid interaction pairs + using the Pairtools suite. Aligns reads with BWA, parses and restricts pairs, + sorts and merges them, deduplicates or retains duplicates depending on parameters, + selects valid pairs, computes statistics, and indexes with Pairix. Also manages + BAM files with Samtools for sorting, indexing, and flagstat reporting. +keywords: + - Hi-C + - Pairtools + - Genomics + - Chromosome interactions + - Contact maps +components: + - bwa_mem + - bwamem2_mem + - pairtools_parse + - pairtools_restrict + - pairtools_sort + - pairtools_merge + - pairtools_split + - pairtools_dedup + - pairtools_select + - pairtools_stats + - pairix + - samtools_sort + - samtools_index + - samtools_flagstat +input: + - reads: + type: file + description: | + Raw sequencing reads (paired-end FASTQ files) + pattern: "*.fastq.gz" + - fasta: + type: file + description: | + Reference genome FASTA file + pattern: "*.fa" + - index: + type: directory + description: | + Path to the genome index for BWA mapping + - frag: + type: file + description: | + Restriction fragments file for digestion protocols + pattern: "*.txt" + - chrsize: + type: file + description: | + Chromosome sizes file + pattern: "*.txt" +output: + - pairs: + type: file + description: | + Indexed valid interaction pairs in .pairs format + pattern: "*.pairs" + - bam: + type: file + description: | + BAM files with corresponding index (.bai) after alignment and processing + pattern: "*.bam" + - stats: + type: file + description: | + Pairtools statistics on selected valid pairs + pattern: "*.txt" + - flagstat: + type: file + description: | + Samtools flagstat output for BAM files + pattern: "*.txt" + - versions: + type: file + description: | + Versions of tools used in the workflow +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/local/prepare_genome/meta.yml b/subworkflows/local/prepare_genome/meta.yml new file mode 100644 index 00000000..ce06b7ff --- /dev/null +++ b/subworkflows/local/prepare_genome/meta.yml @@ -0,0 +1,73 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "PREPARE_GENOME" +description: | + Workflow to prepare a reference genome for Hi-C data analysis. Builds Bowtie2 or + BWA indexes depending on the processing mode, generates chromosome sizes, sets + digestion parameters (restriction and ligation sites), and computes restriction + fragments if required. Outputs ready-to-use genome resources for downstream Hi-C + workflows. +keywords: + - Hi-C + - Genome preparation + - Bowtie2 + - BWA + - Restriction fragments + - Chromosome sizes +components: + - bowtie2_build + - bwa_index + - custom_getchromsizes + - get_restriction_fragments +input: + - fasta: + type: file + description: | + Reference genome FASTA file + pattern: "*.fa" + - bwt2_index: + type: directory + description: | + Optional pre-built Bowtie2 index directory (used if processing mode is hicpro) + - bwa_index: + type: directory + description: | + Optional pre-built BWA index directory (used if processing mode is pairtools) +output: + - fasta: + type: file + description: | + Reference genome FASTA file with metadata + pattern: "*.fa" + - index: + type: directory + description: | + Genome index directory (Bowtie2 or BWA depending on processing mode) + - chromosome_size: + type: file + description: | + Chromosome sizes file generated from the reference genome + pattern: "*.txt" + - res_frag: + type: file + description: | + Restriction fragments file generated from the reference genome + pattern: "*.txt" + - restriction_site: + type: string + description: | + Restriction site motif used for digestion protocols + - ligation_site: + type: string + description: | + Ligation site motif used for digestion protocols + - versions: + type: file + description: | + Versions of tools used in the workflow +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/local/tads/meta.yml b/subworkflows/local/tads/meta.yml new file mode 100644 index 00000000..d92f128e --- /dev/null +++ b/subworkflows/local/tads/meta.yml @@ -0,0 +1,39 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "TADS" +description: | + Workflow to identify Topologically Associating Domains (TADs) from Hi-C data. + Supports two callers: Cooltools Insulation and HiCExplorer hicFindTADs. + Takes a .cool file as input and outputs TAD calls along with tool version + information. +keywords: + - Hi-C + - TADs + - Cooltools + - HiCExplorer + - Genomics +components: + - cooltools_insulation + - hic_find_tads +input: + - cool: + type: file + description: | + Input Hi-C contact map in .cool format + pattern: "*.cool" +output: + - tads: + type: file + description: | + TAD calls generated by the selected caller (TSV or results file) + pattern: "*.tsv" + - versions: + type: file + description: | + Versions of tools used in the workflow +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" diff --git a/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml b/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml new file mode 100644 index 00000000..27e977c7 --- /dev/null +++ b/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml @@ -0,0 +1,58 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "PIPELINE_INITIALISATION" +description: | + Subworkflow to initialise the nf-core/hic pipeline. Handles version printing, + parameter validation, configuration checks, and creation of the input samplesheet + channel from the provided samplesheet file. +keywords: + - Hi-C + - Pipeline initialisation + - nf-core + - Parameters + - Samplesheet +components: + - utils/nextflow_pipeline + - utils/nfschema_plugin + - utils/nfcore_pipeline +input: + - version: + type: boolean + description: | + Print pipeline version and exit + - validate_params: + type: boolean + description: | + Validate parameters against the schema at runtime + - monochrome_logs: + type: boolean + description: | + Disable coloured log outputs + - nextflow_cli_args: + type: array + description: | + List of positional Nextflow CLI arguments + - outdir: + type: string + description: | + Output directory where results will be saved + - input: + type: string + description: | + Path to input samplesheet +output: + - samplesheet: + type: file + description: | + Channel containing validated input samplesheet entries + - versions: + type: file + description: | + Versions of tools used in the workflow +authors: + - "@adamrtalbot" + - "@drpatelh" +maintainers: + - "@adamrtalbot" + - "@drpatelh" + - "@maxulysse" + \ No newline at end of file From 649e5482ac19894cad44331aa8e0bb2babcb20ba Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Wed, 26 Nov 2025 16:20:24 +0100 Subject: [PATCH 07/55] Add module faidx --- .../nf-core/samtools/faidx/environment.yml | 10 + modules/nf-core/samtools/faidx/main.nf | 61 ++ modules/nf-core/samtools/faidx/meta.yml | 102 ++++ .../nf-core/samtools/faidx/tests/main.nf.test | 219 +++++++ .../samtools/faidx/tests/main.nf.test.snap | 543 ++++++++++++++++++ .../samtools/faidx/tests/nextflow.config | 7 + .../samtools/faidx/tests/nextflow2.config | 6 + 7 files changed, 948 insertions(+) create mode 100644 modules/nf-core/samtools/faidx/environment.yml create mode 100644 modules/nf-core/samtools/faidx/main.nf create mode 100644 modules/nf-core/samtools/faidx/meta.yml create mode 100644 modules/nf-core/samtools/faidx/tests/main.nf.test create mode 100644 modules/nf-core/samtools/faidx/tests/main.nf.test.snap create mode 100644 modules/nf-core/samtools/faidx/tests/nextflow.config create mode 100644 modules/nf-core/samtools/faidx/tests/nextflow2.config diff --git a/modules/nf-core/samtools/faidx/environment.yml b/modules/nf-core/samtools/faidx/environment.yml new file mode 100644 index 00000000..89e12a64 --- /dev/null +++ b/modules/nf-core/samtools/faidx/environment.yml @@ -0,0 +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/htslib + - bioconda::htslib=1.22.1 + # renovate: datasource=conda depName=bioconda/samtools + - bioconda::samtools=1.22.1 diff --git a/modules/nf-core/samtools/faidx/main.nf b/modules/nf-core/samtools/faidx/main.nf new file mode 100644 index 00000000..ed2d70a6 --- /dev/null +++ b/modules/nf-core/samtools/faidx/main.nf @@ -0,0 +1,61 @@ +process SAMTOOLS_FAIDX { + tag "$fasta" + 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(fasta) + tuple val(meta2), path(fai) + val get_sizes + + output: + tuple val(meta), path ("*.{fa,fasta}") , emit: fa, optional: true + tuple val(meta), path ("*.sizes") , emit: sizes, optional: true + tuple val(meta), path ("*.fai") , emit: fai, optional: true + tuple val(meta), path ("*.gzi") , emit: gzi, optional: true + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def get_sizes_command = get_sizes ? "cut -f 1,2 ${fasta}.fai > ${fasta}.sizes" : '' + """ + samtools \\ + faidx \\ + $fasta \\ + $args + + ${get_sizes_command} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') + END_VERSIONS + """ + + stub: + def match = (task.ext.args =~ /-o(?:utput)?\s(.*)\s?/).findAll() + def fastacmd = match[0] ? "touch ${match[0][1]}" : '' + def get_sizes_command = get_sizes ? "touch ${fasta}.sizes" : '' + """ + ${fastacmd} + touch ${fasta}.fai + if [[ "${fasta.extension}" == "gz" ]]; then + touch ${fasta}.gzi + fi + + ${get_sizes_command} + + 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/faidx/meta.yml b/modules/nf-core/samtools/faidx/meta.yml new file mode 100644 index 00000000..b7a2e0c1 --- /dev/null +++ b/modules/nf-core/samtools/faidx/meta.yml @@ -0,0 +1,102 @@ +name: samtools_faidx +description: Index FASTA file, and optionally generate a file of chromosome sizes +keywords: + - index + - fasta + - faidx + - chromosome +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 reference information + e.g. [ id:'test' ] + - fasta: + type: file + description: FASTA file + pattern: "*.{fa,fasta}" + ontologies: [] + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test' ] + - fai: + type: file + description: FASTA index file + pattern: "*.{fai}" + ontologies: [] + - get_sizes: + type: boolean + description: use cut to get the sizes of the index (true) or not (false) + +output: + fa: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.{fa,fasta}": + type: file + description: FASTA file + pattern: "*.{fa}" + ontologies: [] + sizes: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.sizes": + type: file + description: File containing chromosome lengths + pattern: "*.{sizes}" + ontologies: [] + fai: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.fai": + type: file + description: FASTA index file + pattern: "*.{fai}" + ontologies: [] + gzi: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.gzi": + type: file + description: Optional gzip index file for compressed inputs + pattern: "*.gzi" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@drpatelh" + - "@ewels" + - "@phue" +maintainers: + - "@maxulysse" + - "@phue" diff --git a/modules/nf-core/samtools/faidx/tests/main.nf.test b/modules/nf-core/samtools/faidx/tests/main.nf.test new file mode 100644 index 00000000..a505abc1 --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/main.nf.test @@ -0,0 +1,219 @@ +nextflow_process { + + name "Test Process SAMTOOLS_FAIDX" + script "../main.nf" + process "SAMTOOLS_FAIDX" + + tag "modules" + tag "modules_nfcore" + tag "samtools" + tag "samtools/faidx" + + test("test_samtools_faidx") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + input[1] = [[],[]] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_bgzip") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true)] + input[1] = [[],[]] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_fasta") { + + config "./nextflow.config" + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + input[1] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_stub_fasta") { + + config "./nextflow2.config" + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + input[1] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_stub_fai") { + + when { + process { + """ + input[0] = [ [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] + input[1] = [[],[]] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_get_sizes") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = [[],[]] + input[2] = true + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_get_sizes_bgzip") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = [[],[]] + input[2] = true + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_get_sizes - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ]) + input[1] = [[],[]] + input[2] = true + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_samtools_faidx_get_sizes_bgzip - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) + ]) + input[1] = [[],[]] + input[2] = true + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + +} diff --git a/modules/nf-core/samtools/faidx/tests/main.nf.test.snap b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap new file mode 100644 index 00000000..3be7b824 --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap @@ -0,0 +1,543 @@ +{ + "test_samtools_faidx": { + "content": [ + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + + ], + "sizes": [ + + ], + "versions": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:09:38.874686" + }, + "test_samtools_faidx_get_sizes_bgzip - stub": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.fai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.gzi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "4": [ + "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.fai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "gzi": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.gzi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "sizes": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:10:10.958397" + }, + "test_samtools_faidx_get_sizes": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test" + }, + "genome.fasta.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test" + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + + ], + "sizes": [ + [ + { + "id": "test" + }, + "genome.fasta.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" + ] + ], + "versions": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:09:59.237249" + }, + "test_samtools_faidx_bgzip": { + "content": [ + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "3": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" + ] + ], + "4": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" + ] + ], + "sizes": [ + + ], + "versions": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:09:42.949204" + }, + "test_samtools_faidx_fasta": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,6a0774a0ad937ba0bfd2ac7457d90f36" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ], + "fa": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,6a0774a0ad937ba0bfd2ac7457d90f36" + ] + ], + "fai": [ + + ], + "gzi": [ + + ], + "sizes": [ + + ], + "versions": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:09:46.914038" + }, + "test_samtools_faidx_get_sizes - stub": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test" + }, + "genome.fasta.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "genome.fasta.fai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test" + }, + "genome.fasta.fai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "gzi": [ + + ], + "sizes": [ + [ + { + "id": "test" + }, + "genome.fasta.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:10:06.961912" + }, + "test_samtools_faidx_stub_fasta": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "1": [ + + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ], + "fa": [ + [ + { + "id": "test", + "single_end": false + }, + "extract.fa:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "fai": [ + + ], + "gzi": [ + + ], + "sizes": [ + + ], + "versions": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:09:51.226016" + }, + "test_samtools_faidx_stub_fai": { + "content": [ + { + "0": [ + + ], + "1": [ + + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test", + "single_end": false + }, + "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + + ], + "sizes": [ + + ], + "versions": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:09:55.423005" + }, + "test_samtools_faidx_get_sizes_bgzip": { + "content": [ + { + "0": [ + + ], + "1": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" + ] + ], + "2": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "3": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" + ] + ], + "4": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ], + "fa": [ + + ], + "fai": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + ] + ], + "gzi": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" + ] + ], + "sizes": [ + [ + { + "id": "test" + }, + "genome.fasta.gz.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" + ] + ], + "versions": [ + "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-10T13:10:03.04872" + } +} \ No newline at end of file diff --git a/modules/nf-core/samtools/faidx/tests/nextflow.config b/modules/nf-core/samtools/faidx/tests/nextflow.config new file mode 100644 index 00000000..f76a3ba0 --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/nextflow.config @@ -0,0 +1,7 @@ +process { + + withName: SAMTOOLS_FAIDX { + ext.args = 'MT192765.1 -o extract.fa' + } + +} diff --git a/modules/nf-core/samtools/faidx/tests/nextflow2.config b/modules/nf-core/samtools/faidx/tests/nextflow2.config new file mode 100644 index 00000000..33ebbd5d --- /dev/null +++ b/modules/nf-core/samtools/faidx/tests/nextflow2.config @@ -0,0 +1,6 @@ +process { + + withName: SAMTOOLS_FAIDX { + ext.args = '-o extract.fa' + } +} From 2482e60f8413f2f9514094657fe97ff15971ca09 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:00:14 +0100 Subject: [PATCH 08/55] Delete getchromsizes module --- conf/modules.config | 8 - .../custom/getchromsizes/environment.yml | 11 - modules/nf-core/custom/getchromsizes/main.nf | 49 ---- modules/nf-core/custom/getchromsizes/meta.yml | 75 ------ .../custom/getchromsizes/tests/main.nf.test | 99 ------- .../getchromsizes/tests/main.nf.test.snap | 242 ------------------ 6 files changed, 484 deletions(-) delete mode 100644 modules/nf-core/custom/getchromsizes/environment.yml delete mode 100644 modules/nf-core/custom/getchromsizes/main.nf delete mode 100644 modules/nf-core/custom/getchromsizes/meta.yml delete mode 100644 modules/nf-core/custom/getchromsizes/tests/main.nf.test delete mode 100644 modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap diff --git a/conf/modules.config b/conf/modules.config index f9e5c6ec..1d6ade55 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -37,14 +37,6 @@ process { ] } - withName: 'CUSTOM_GETCHROMSIZES' { - publishDir = [ - path: { "${params.outdir}/genome" }, - mode: 'copy', - enabled: params.save_reference - ] - } - withName: 'GET_RESTRICTION_FRAGMENTS' { publishDir = [ path: { "${params.outdir}/genome" }, diff --git a/modules/nf-core/custom/getchromsizes/environment.yml b/modules/nf-core/custom/getchromsizes/environment.yml deleted file mode 100644 index 9b3b149b..00000000 --- a/modules/nf-core/custom/getchromsizes/environment.yml +++ /dev/null @@ -1,11 +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/custom/getchromsizes/main.nf b/modules/nf-core/custom/getchromsizes/main.nf deleted file mode 100644 index b57463e7..00000000 --- a/modules/nf-core/custom/getchromsizes/main.nf +++ /dev/null @@ -1,49 +0,0 @@ -def deprecation_message = """ -WARNING: The getchromsizes process has been deprecated. Please use nf-core/modules/samtools/faidx. - -Reason: -Getting chromosome sizes was added to samtools/faidx (https://github.com/nf-core/modules/pull/7041) -via a boolean switch, making 'getchromsizes' unnecessary. -""" - -process CUSTOM_GETCHROMSIZES { - tag "$fasta" - 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(fasta) - - output: - tuple val(meta), path ("*.sizes"), emit: sizes - tuple val(meta), path ("*.fai") , emit: fai - tuple val(meta), path ("*.gzi") , emit: gzi, optional: true - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - assert false: deprecation_message - - def args = task.ext.args ?: '' - """ - samtools faidx $fasta - cut -f 1,2 ${fasta}.fai > ${fasta}.sizes - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - getchromsizes: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS - """ - - stub: - """ - >&2 echo "${deprecation_message}" - false - """ -} diff --git a/modules/nf-core/custom/getchromsizes/meta.yml b/modules/nf-core/custom/getchromsizes/meta.yml deleted file mode 100644 index 6f0a0585..00000000 --- a/modules/nf-core/custom/getchromsizes/meta.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: custom_getchromsizes -description: Generates a FASTA file of chromosome sizes and a fasta index file -keywords: - - fasta - - chromosome - - indexing -tools: - - samtools: - description: Tools for dealing with SAM, BAM and CRAM files - homepage: http://www.htslib.org/ - documentation: http://www.htslib.org/doc/samtools.html - tool_dev_url: https://github.com/samtools/samtools - doi: 10.1093/bioinformatics/btp352 - licence: ["MIT"] - identifier: "" -input: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - fasta: - type: file - description: FASTA file - pattern: "*.{fa,fasta,fna,fas}" - ontologies: [] -output: - sizes: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.sizes": - type: file - description: File containing chromosome lengths - pattern: "*.{sizes}" - ontologies: [] - fai: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.fai": - type: file - description: FASTA index file - pattern: "*.{fai}" - ontologies: [] - gzi: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.gzi": - type: file - description: Optional gzip index file for compressed inputs - pattern: "*.gzi" - ontologies: [] - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -authors: - - "@tamara-hodgetts" - - "@chris-cheshire" - - "@muffato" -maintainers: - - "@tamara-hodgetts" - - "@chris-cheshire" - - "@muffato" diff --git a/modules/nf-core/custom/getchromsizes/tests/main.nf.test b/modules/nf-core/custom/getchromsizes/tests/main.nf.test deleted file mode 100644 index 3efe99ae..00000000 --- a/modules/nf-core/custom/getchromsizes/tests/main.nf.test +++ /dev/null @@ -1,99 +0,0 @@ -nextflow_process { - - name "Test Process CUSTOM_GETCHROMSIZES" - script "../main.nf" - process "CUSTOM_GETCHROMSIZES" - - tag "modules" - tag "modules_nfcore" - tag "custom" - tag "custom/getchromsizes" - - test("test_custom_getchromsizes") { - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.failed }, - { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } - ) - } - } - - test("test_custom_getchromsizes_bgzip") { - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.failed }, - { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } - ) - } - } - - test("test_custom_getchromsizes - stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.failed }, - { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } - ) - } - } - - test("test_custom_getchromsizes_bgzip - stub") { - - options "-stub" - - when { - process { - """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.failed }, - { assert process.errorReport.contains("WARNING: The getchromsizes process has been deprecated.") } - ) - } - } -} diff --git a/modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap b/modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap deleted file mode 100644 index 90dc1f9e..00000000 --- a/modules/nf-core/custom/getchromsizes/tests/main.nf.test.snap +++ /dev/null @@ -1,242 +0,0 @@ -{ - "test_custom_getchromsizes_bgzip - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.fai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.gzi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ], - "fai": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.fai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "gzi": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.gzi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "sizes": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ] - } - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T15:33:15.306675" - }, - "test_custom_getchromsizes": { - "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "genome.fasta.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ], - "fai": [ - [ - { - "id": "test" - }, - "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "gzi": [ - - ], - "sizes": [ - [ - { - "id": "test" - }, - "genome.fasta.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" - ] - ], - "versions": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ] - } - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T15:33:03.74832" - }, - "test_custom_getchromsizes_bgzip": { - "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" - ] - ], - "3": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ], - "fai": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "gzi": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" - ] - ], - "sizes": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" - ] - ], - "versions": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ] - } - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T15:33:07.739978" - }, - "test_custom_getchromsizes - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "genome.fasta.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.fai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ], - "fai": [ - [ - { - "id": "test" - }, - "genome.fasta.fai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "gzi": [ - - ], - "sizes": [ - [ - { - "id": "test" - }, - "genome.fasta.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,1c65f4e4ebfe3ddf41fc30a8fcfa9f40" - ] - } - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T15:33:11.508353" - } -} \ No newline at end of file From bee7db7db234d8d8f253af786925cd8b87d6b48a Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:03:08 +0100 Subject: [PATCH 09/55] fix matplotlib config dir error in pairtools --- nextflow.config | 1 + 1 file changed, 1 insertion(+) diff --git a/nextflow.config b/nextflow.config index 23233aff..441b2749 100644 --- a/nextflow.config +++ b/nextflow.config @@ -288,6 +288,7 @@ env { R_PROFILE_USER = "/.Rprofile" R_ENVIRON_USER = "/.Renviron" JULIA_DEPOT_PATH = "/usr/local/share/julia" + MPLCONFIGDIR = "${baseDir}/mplconfig" } // Set bash options From bb25849a84c62d5a5b89f957debede7d097a5e9c Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:11:35 +0100 Subject: [PATCH 10/55] Fix channel syntax and inputs for cooler cload and samtool sort modules --- main.nf | 2 +- subworkflows/local/compartments/main.nf | 8 ++--- subworkflows/local/cooler/main.nf | 23 ++++++------ subworkflows/local/hicpro/main.nf | 22 ++++++------ subworkflows/local/hicpro_mapping/main.nf | 12 +++---- subworkflows/local/pairtools/main.nf | 43 ++++++++++++----------- subworkflows/local/tads/main.nf | 8 ++--- workflows/hic.nf | 34 +++++++++--------- 8 files changed, 77 insertions(+), 75 deletions(-) diff --git a/main.nf b/main.nf index 3bdaee29..af9dc112 100644 --- a/main.nf +++ b/main.nf @@ -47,7 +47,7 @@ workflow NFCORE_HIC { main: - ch_versions = Channel.empty() + ch_versions = channel.empty() // // SUBWORKFLOW: prepare genome annotation diff --git a/subworkflows/local/compartments/main.nf b/subworkflows/local/compartments/main.nf index 4f965d3b..e4993ead 100644 --- a/subworkflows/local/compartments/main.nf +++ b/subworkflows/local/compartments/main.nf @@ -1,5 +1,5 @@ -include { COOLTOOLS_EIGSCIS } from '../../modules/local/cooltools/eigscis' -include { CALDER2 } from '../../modules/nf-core/calder2/main' +include { COOLTOOLS_EIGSCIS } from '../../../modules/local/cooltools/eigscis.nf' +include { CALDER2 } from '../../../modules/nf-core/calder2/main' workflow COMPARTMENTS { @@ -9,7 +9,7 @@ workflow COMPARTMENTS { chrsize main: - ch_versions = Channel.empty() + ch_versions = channel.empty() if (params.compartments_caller =~ 'cooltools'){ COOLTOOLS_EIGSCIS( @@ -24,7 +24,7 @@ workflow COMPARTMENTS { if (params.compartments_caller =~ 'calder2'){ CALDER2( cool.map{meta, cool, res -> [meta, cool] }, - Channel.value([]) + channel.value([]) ) ch_versions = ch_versions.mix(CALDER2.out.versions) ch_comp = CALDER2.out.output_folder diff --git a/subworkflows/local/cooler/main.nf b/subworkflows/local/cooler/main.nf index 38570337..f737e20f 100644 --- a/subworkflows/local/cooler/main.nf +++ b/subworkflows/local/cooler/main.nf @@ -4,13 +4,13 @@ * OUTPUT : cooler files */ -include { COOLER_ZOOMIFY } from '../../modules/nf-core/cooler/zoomify/main' -include { COOLER_DUMP } from '../../modules/nf-core/cooler/dump/main' -include { COOLER_CLOAD } from '../../modules/nf-core/cooler/cload/main' -include { COOLER_BALANCE } from '../../modules/nf-core/cooler/balance/main' -include { COOLER_MAKEBINS } from '../../modules/nf-core/cooler/makebins/main' +include { COOLER_ZOOMIFY } from '../../../modules/nf-core/cooler/zoomify/main' +include { COOLER_DUMP } from '../../../modules/nf-core/cooler/dump/main' +include { COOLER_CLOAD } from '../../../modules/nf-core/cooler/cload/main' +include { COOLER_BALANCE } from '../../../modules/nf-core/cooler/balance/main' +include { COOLER_MAKEBINS } from '../../../modules/nf-core/cooler/makebins/main' -include { SPLIT_COOLER_DUMP } from '../../modules/local/split_cooler_dump' +include { SPLIT_COOLER_DUMP } from '../../../modules/local/split_cooler_dump' // add resolution in meta def addResolution(row) { @@ -28,7 +28,7 @@ workflow COOLER { cool_bins main: - ch_versions = Channel.empty() + ch_versions = channel.empty() //***************************************** // EXPORT BINS @@ -40,11 +40,12 @@ workflow COOLER { //***************************************** // BUILD COOL FILE PER RESOLUTION - // [meta, pairs, resolution] COOLER_CLOAD( - pairs.combine(cool_bins), - chromsize.map{it -> it[1]}.collect() + pairs, + chromsize, + "pairs", + cool_bins ) ch_versions = ch_versions.mix(COOLER_CLOAD.out.versions) @@ -62,7 +63,7 @@ workflow COOLER { if (!params.res_zoomify){ ch_res_zoomify = cool_bins.min() }else{ - ch_res_zoomify = Channel.from(params.res_zoomify).splitCsv().flatten().unique().toInteger() + ch_res_zoomify = channel.from(params.res_zoomify).splitCsv().flatten().unique().toInteger() } ch_cool diff --git a/subworkflows/local/hicpro/main.nf b/subworkflows/local/hicpro/main.nf index 1365f45b..aeecdef4 100644 --- a/subworkflows/local/hicpro/main.nf +++ b/subworkflows/local/hicpro/main.nf @@ -4,14 +4,14 @@ * From the raw sequencing reads to the list of valid interactions */ -include { HICPRO_MAPPING } from './hicpro_mapping' -include { GET_VALID_INTERACTION } from '../../modules/local/hicpro/get_valid_interaction' -include { GET_VALID_INTERACTION_DNASE } from '../../modules/local/hicpro/get_valid_interaction_dnase' -include { MERGE_VALID_INTERACTION } from '../../modules/local/hicpro/merge_valid_interaction' -include { MERGE_STATS } from '../../modules/local/hicpro/merge_stats' -include { HICPRO2PAIRS } from '../../modules/local/hicpro/hicpro2pairs' -include { BUILD_CONTACT_MAPS } from '../../modules/local/hicpro/build_contact_maps' -include { ICE_NORMALIZATION } from '../../modules/local/hicpro/run_ice' +include { HICPRO_MAPPING } from '../hicpro_mapping' +include { GET_VALID_INTERACTION } from '../../../modules/local/hicpro/get_valid_interaction' +include { GET_VALID_INTERACTION_DNASE } from '../../../modules/local/hicpro/get_valid_interaction_dnase' +include { MERGE_VALID_INTERACTION } from '../../../modules/local/hicpro/merge_valid_interaction' +include { MERGE_STATS } from '../../../modules/local/hicpro/merge_stats' +include { HICPRO2PAIRS } from '../../../modules/local/hicpro/hicpro2pairs' +include { BUILD_CONTACT_MAPS } from '../../../modules/local/hicpro/build_contact_maps' +include { ICE_NORMALIZATION } from '../../../modules/local/hicpro/run_ice' // Remove meta.chunks def removeChunks(row){ @@ -32,7 +32,7 @@ workflow HICPRO { map_res // values main: - ch_versions = Channel.empty() + ch_versions = channel.empty() // Fastq to paired-end bam HICPRO_MAPPING( @@ -138,8 +138,8 @@ workflow HICPRO { ch_versions = ch_versions.mix(ICE_NORMALIZATION.out.versions) }else{ - ch_hicpro_raw_maps = Channel.empty() - ch_hicpro_iced_maps = Channel.empty() + ch_hicpro_raw_maps = channel.empty() + ch_hicpro_iced_maps = channel.empty() } emit: diff --git a/subworkflows/local/hicpro_mapping/main.nf b/subworkflows/local/hicpro_mapping/main.nf index 05ccd982..9c6c2c85 100644 --- a/subworkflows/local/hicpro_mapping/main.nf +++ b/subworkflows/local/hicpro_mapping/main.nf @@ -3,12 +3,12 @@ * From the raw sequencing reads to a paired-end bam file */ -include { BOWTIE2_ALIGN } from '../../modules/nf-core/bowtie2/align/main' -include { TRIM_READS } from '../../modules/local/hicpro/trim_reads' -include { BOWTIE2_ALIGN as BOWTIE2_ALIGN_TRIMMED } from '../../modules/nf-core/bowtie2/align/main' -include { MERGE_BOWTIE2 } from '../../modules/local/hicpro/bowtie2_merge' -include { COMBINE_MATES} from '../../modules/local/hicpro/combine_mates' -include { MAPPING_STATS_DNASE } from '../../modules/local/hicpro/dnase_mapping_stats' +include { BOWTIE2_ALIGN } from '../../../modules/nf-core/bowtie2/align/main' +include { TRIM_READS } from '../../../modules/local/hicpro/trim_reads' +include { BOWTIE2_ALIGN as BOWTIE2_ALIGN_TRIMMED } from '../../../modules/nf-core/bowtie2/align/main' +include { MERGE_BOWTIE2 } from '../../../modules/local/hicpro/bowtie2_merge' +include { COMBINE_MATES} from '../../../modules/local/hicpro/combine_mates' +include { MAPPING_STATS_DNASE } from '../../../modules/local/hicpro/dnase_mapping_stats' workflow HICPRO_MAPPING { diff --git a/subworkflows/local/pairtools/main.nf b/subworkflows/local/pairtools/main.nf index 7f889936..30cb97f9 100644 --- a/subworkflows/local/pairtools/main.nf +++ b/subworkflows/local/pairtools/main.nf @@ -4,24 +4,24 @@ * From the raw sequencing reads to the list of valid interactions */ -//include { BWAMEM2_MEM } from '../../modules/nf-core/bwamem2/mem/main' -include { BWA_MEM } from '../../modules/nf-core/bwa/mem/main' -include { PAIRTOOLS_DEDUP } from '../../modules/nf-core/pairtools/dedup/main' -//include { PAIRTOOLS_PARSE } from '../../modules/nf-core/pairtools/parse/main' -include { PAIRTOOLS_RESTRICT } from '../../modules/nf-core/pairtools/restrict/main' -include { PAIRTOOLS_SELECT } from '../../modules/nf-core/pairtools/select/main' -include { PAIRTOOLS_SORT } from '../../modules/nf-core/pairtools/sort/main' -include { PAIRTOOLS_MERGE } from '../../modules/nf-core/pairtools/merge/main' -include { PAIRTOOLS_STATS } from '../../modules/nf-core/pairtools/stats/main' -include { SAMTOOLS_FLAGSTAT } from '../../modules/nf-core/samtools/flagstat/main' -include { SAMTOOLS_SORT } from '../../modules/nf-core/samtools/sort/main' -include { SAMTOOLS_INDEX } from '../../modules/nf-core/samtools/index/main' -include { PAIRIX } from '../../modules/nf-core/pairix/main' - -//include { PAIRTOOLS_MERGE } from '../../modules/local/pairtools/pairtools_merge' -include { PAIRTOOLS_SPLIT } from '../../modules/local/pairtools/pairtools_split' -//include { PAIRTOOLS_STATS } from '../../modules/local/pairtools/pairtools_stats' -include { PAIRTOOLS_PARSE } from '../../modules/local/pairtools/pairtools_parse' +//include { BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' +include { BWA_MEM } from '../../../modules/nf-core/bwa/mem/main' +include { PAIRTOOLS_DEDUP } from '../../../modules/nf-core/pairtools/dedup/main' +//include { PAIRTOOLS_PARSE } from '../../../modules/nf-core/pairtools/parse/main' +include { PAIRTOOLS_RESTRICT } from '../../../modules/nf-core/pairtools/restrict/main' +include { PAIRTOOLS_SELECT } from '../../../modules/nf-core/pairtools/select/main' +include { PAIRTOOLS_SORT } from '../../../modules/nf-core/pairtools/sort/main' +include { PAIRTOOLS_MERGE } from '../../../modules/nf-core/pairtools/merge/main' +include { PAIRTOOLS_STATS } from '../../../modules/nf-core/pairtools/stats/main' +include { SAMTOOLS_FLAGSTAT } from '../../../modules/nf-core/samtools/flagstat/main' +include { SAMTOOLS_SORT } from '../../../modules/nf-core/samtools/sort/main' +include { SAMTOOLS_INDEX } from '../../../modules/nf-core/samtools/index/main' +include { PAIRIX } from '../../../modules/nf-core/pairix/main' + +//include { PAIRTOOLS_MERGE } from '../../../modules/local/pairtools/pairtools_merge' +include { PAIRTOOLS_SPLIT } from '../../../modules/local/pairtools/pairtools_split' +//include { PAIRTOOLS_STATS } from '../../../modules/local/pairtools/pairtools_stats' +include { PAIRTOOLS_PARSE } from '../../../modules/local/pairtools/pairtools_parse' workflow PAIRTOOLS { @@ -33,13 +33,13 @@ workflow PAIRTOOLS { chrsize // path main: - ch_versions = Channel.empty() + ch_versions = channel.empty() BWA_MEM( reads, index.collect(), fasta.collect(), - Channel.value([]) + channel.value([]) ) ch_versions = ch_versions.mix(BWA_MEM.out.versions) @@ -86,7 +86,8 @@ workflow PAIRTOOLS { // Manage BAM files SAMTOOLS_SORT( PAIRTOOLS_SPLIT.out.bam, - fasta + fasta, + "bai" ) ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions) diff --git a/subworkflows/local/tads/main.nf b/subworkflows/local/tads/main.nf index f70a01ff..b62e6cfc 100644 --- a/subworkflows/local/tads/main.nf +++ b/subworkflows/local/tads/main.nf @@ -1,5 +1,5 @@ -include { COOLTOOLS_INSULATION } from '../../modules/local/cooltools/insulation' -include { HIC_FIND_TADS } from '../../modules/local/hicexplorer/hicFindTADs' +include { COOLTOOLS_INSULATION } from '../../../modules/local/cooltools/insulation.nf' +include { HIC_FIND_TADS } from '../../../modules/local/hicexplorer/hicFindTADs' workflow TADS { @@ -7,8 +7,8 @@ workflow TADS { cool main: - ch_versions = Channel.empty() - ch_tads = Channel.empty() + ch_versions = channel.empty() + ch_tads = channel.empty() if (params.tads_caller =~ 'insulation'){ COOLTOOLS_INSULATION(cool) diff --git a/workflows/hic.nf b/workflows/hic.nf index 5a59285e..9909aa48 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -23,38 +23,38 @@ include { TADS } from '../subworkflows/local/tads' //**************************************** // Combine all maps resolution for downstream analysis -ch_map_res = Channel.from( params.bin_size ).splitCsv().flatten().toInteger() +ch_map_res = channel.from( params.bin_size ).splitCsv().flatten().toInteger() if (params.res_zoomify){ - ch_zoom_res = Channel.from( params.res_zoomify ).splitCsv().flatten().toInteger() + ch_zoom_res = channel.from( params.res_zoomify ).splitCsv().flatten().toInteger() ch_map_res = ch_map_res.concat(ch_zoom_res) } if (params.res_tads && !params.skip_tads){ - ch_tads_res = Channel.from( "${params.res_tads}" ).splitCsv().flatten().toInteger() + ch_tads_res = channel.from( "${params.res_tads}" ).splitCsv().flatten().toInteger() ch_map_res = ch_map_res.concat(ch_tads_res) }else{ - ch_tads_res=Channel.empty() + ch_tads_res=channel.empty() if (!params.skip_tads){ log.warn "[nf-core/hic] Hi-C resolution for TADs calling not specified. See --res_tads" } } if (params.res_dist_decay && !params.skip_dist_decay){ - ch_ddecay_res = Channel.from( "${params.res_dist_decay}" ).splitCsv().flatten().toInteger() + ch_ddecay_res = channel.from( "${params.res_dist_decay}" ).splitCsv().flatten().toInteger() ch_map_res = ch_map_res.concat(ch_ddecay_res) }else{ - ch_ddecay_res = Channel.empty() + ch_ddecay_res = channel.empty() if (!params.skip_dist_decay){ log.warn "[nf-core/hic] Hi-C resolution for distance decay not specified. See --res_dist_decay" } } if (params.res_compartments && !params.skip_compartments){ - ch_comp_res = Channel.from( "${params.res_compartments}" ).splitCsv().flatten().toInteger() + ch_comp_res = channel.from( "${params.res_compartments}" ).splitCsv().flatten().toInteger() ch_map_res = ch_map_res.concat(ch_comp_res) }else{ - ch_comp_res = Channel.empty() + ch_comp_res = channel.empty() if (!params.skip_compartments){ log.warn "[nf-core/hic] Hi-C resolution for compartment calling not specified. See --res_compartments" } @@ -81,8 +81,8 @@ workflow HIC { main: - ch_versions = Channel.empty() - ch_multiqc_files = Channel.empty() + ch_versions = channel.empty() + ch_multiqc_files = channel.empty() // // MODULE: Run FastQC // @@ -196,24 +196,24 @@ workflow HIC { // // MODULE: MultiQC // - ch_multiqc_config = Channel.fromPath( + 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() + channel.fromPath(params.multiqc_config, checkIfExists: true) : + channel.empty() ch_multiqc_logo = params.multiqc_logo ? - Channel.fromPath(params.multiqc_logo, checkIfExists: true) : - Channel.empty() + 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_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( + ch_methods_description = channel.value( methodsDescriptionText(ch_multiqc_custom_methods_description)) ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) From af17a3d71b4c59eab72227907ea75a47c1077ffe Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:15:49 +0100 Subject: [PATCH 11/55] Replace getchromsizes module by faidx module --- modules.json | 12 +++--- subworkflows/local/hicpro_mapping/main.nf | 2 +- subworkflows/local/prepare_genome/main.nf | 46 ++++++++++++----------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/modules.json b/modules.json index 0ce05585..492dab10 100644 --- a/modules.json +++ b/modules.json @@ -55,11 +55,6 @@ "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, - "custom/getchromsizes": { - "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", - "installed_by": ["modules"] - }, "fastqc": { "branch": "master", "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", @@ -110,6 +105,11 @@ "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", "installed_by": ["modules"] }, + "samtools/faidx": { + "branch": "master", + "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "installed_by": ["modules"] + }, "samtools/flagstat": { "branch": "master", "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", @@ -136,7 +136,7 @@ }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "271e7fc14eb1320364416d996fb077421f3faed2", + "git_sha": "df4d1c8cdee98a1bbbed8fc51e82296568e0f9c1", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { diff --git a/subworkflows/local/hicpro_mapping/main.nf b/subworkflows/local/hicpro_mapping/main.nf index 9c6c2c85..665861bd 100644 --- a/subworkflows/local/hicpro_mapping/main.nf +++ b/subworkflows/local/hicpro_mapping/main.nf @@ -20,7 +20,7 @@ workflow HICPRO_MAPPING { ligation_site // value main: - ch_versions = Channel.empty() + ch_versions = channel.empty() // Align each mates separetly and add mates information in [meta] ch_reads_r1 = reads diff --git a/subworkflows/local/prepare_genome/main.nf b/subworkflows/local/prepare_genome/main.nf index af2b9d01..05ab24bd 100644 --- a/subworkflows/local/prepare_genome/main.nf +++ b/subworkflows/local/prepare_genome/main.nf @@ -2,10 +2,10 @@ * Prepare Annotation Genome for Hi-C data analysis */ -include { BOWTIE2_BUILD } from '../../modules/nf-core/bowtie2/build/main' -include { BWA_INDEX } from '../../modules/nf-core/bwa/index/main' -include { CUSTOM_GETCHROMSIZES } from '../../modules/nf-core/custom/getchromsizes/main' -include { GET_RESTRICTION_FRAGMENTS } from '../../modules/local/hicpro/get_restriction_fragments' +include { BOWTIE2_BUILD } from '../../../modules/nf-core/bowtie2/build/main.nf' +include { BWA_INDEX } from '../../../modules/nf-core/bwa/index/main' +include { SAMTOOLS_FAIDX } from '../../../modules/nf-core/samtools/faidx/main' +include { GET_RESTRICTION_FRAGMENTS } from '../../../modules/local/hicpro/get_restriction_fragments' workflow PREPARE_GENOME { @@ -15,13 +15,13 @@ workflow PREPARE_GENOME { bwa_index main: - ch_versions = Channel.empty() + ch_versions = channel.empty() // // Fasta reference genome // def genomeName = params.genome ?: fasta.substring(fasta.lastIndexOf(File.separator)+1) - ch_fasta = Channel.fromPath( fasta ) + ch_fasta = channel.fromPath( fasta ) .ifEmpty { exit 1, "Genome index: Fasta file not found: ${fasta}" } .map{it->[[id:genomeName],it]} @@ -36,7 +36,7 @@ workflow PREPARE_GENOME { ch_index = BOWTIE2_BUILD.out.index ch_versions = ch_versions.mix(BOWTIE2_BUILD.out.versions) }else{ - ch_index = Channel.fromPath( bwt2_index , checkIfExists: true) + ch_index = channel.fromPath( bwt2_index , checkIfExists: true) .map { it -> [[:], it]} .ifEmpty { exit 1, "Genome index: Provided index not found: ${params.bwt2_index}" } } @@ -53,7 +53,7 @@ workflow PREPARE_GENOME { ch_index = BWA_INDEX.out.index ch_versions = ch_versions.mix(BWA_INDEX.out.versions) }else{ - ch_index = Channel.fromPath( bwa_index , checkIfExists: true) + ch_index = channel.fromPath( bwa_index , checkIfExists: true) .map { it -> [[:], it]} .ifEmpty { exit 1, "Genome index: Provided index not found: ${params.bwa_index}" } } @@ -63,13 +63,15 @@ workflow PREPARE_GENOME { // Chromosome size // if(!params.chromosome_size){ - CUSTOM_GETCHROMSIZES( - ch_fasta - ) - ch_chromsize = CUSTOM_GETCHROMSIZES.out.sizes - ch_versions = ch_versions.mix(CUSTOM_GETCHROMSIZES.out.versions) + SAMTOOLS_FAIDX( + ch_fasta, + ch_index, + true + ) + ch_chromsize = SAMTOOLS_FAIDX.out.sizes + ch_versions = ch_versions.mix(SAMTOOLS_FAIDX.out.versions) }else{ - ch_chromsize = Channel.fromPath( params.chromosome_size , checkIfExists: true) + ch_chromsize = channel.fromPath( params.chromosome_size , checkIfExists: true) .map { it -> [[:], it]} } @@ -79,15 +81,15 @@ workflow PREPARE_GENOME { // if (params.digestion){ restriction_site = params.digestion ? params.digest[ params.digestion ].restriction_site ?: false : false - ch_restriction_site = Channel.value(restriction_site) + ch_restriction_site = channel.value(restriction_site) ligation_site = params.digestion ? params.digest[ params.digestion ].ligation_site ?: false : false - ch_ligation_site = Channel.value(ligation_site) + ch_ligation_site = channel.value(ligation_site) }else if (params.restriction_site && params.ligation_site){ - ch_restriction_site = Channel.value(params.restriction_site) - ch_ligation_site = Channel.value(params.ligation_site) + ch_restriction_site = channel.value(params.restriction_site) + ch_ligation_site = channel.value(params.ligation_site) }else if (params.no_digestion){ - ch_restriction_site = Channel.empty() - ch_ligation_site = Channel.empty() + ch_restriction_site = channel.empty() + ch_ligation_site = channel.empty() }else{ exit 1, "Ligation motif not found. Please either use the `--digestion` parameters or specify the `--restriction_site` and `--ligation_site`. For DNase/Micro-C Hi-C, please use '--no_digestion' option" } @@ -104,11 +106,11 @@ workflow PREPARE_GENOME { ch_resfrag = GET_RESTRICTION_FRAGMENTS.out.results ch_versions = ch_versions.mix(GET_RESTRICTION_FRAGMENTS.out.versions) }else if (!params.no_digestion){ - Channel.fromPath( params.restriction_fragments, checkIfExists: true ) + channel.fromPath( params.restriction_fragments, checkIfExists: true ) .map { it -> [[:], it] } .set {ch_resfrag} }else{ - ch_resfrag = Channel.empty() + ch_resfrag = channel.empty() } emit: From 37016ecf439a2e886b8435c8da8be2f1300c99d0 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:17:40 +0100 Subject: [PATCH 12/55] Update utils_nfschema_plugin import and input --- .../local/utils_nfcore_hic_pipeline/main.nf | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/utils_nfcore_hic_pipeline/main.nf b/subworkflows/local/utils_nfcore_hic_pipeline/main.nf index fa69bdd2..64134d79 100644 --- a/subworkflows/local/utils_nfcore_hic_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_hic_pipeline/main.nf @@ -7,6 +7,12 @@ IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +include { UTILS_NEXTFLOW_PIPELINE } from '../../../subworkflows/nf-core/utils_nextflow_pipeline/main.nf' +include { UTILS_NFCORE_PIPELINE } from '../../../subworkflows/nf-core/utils_nfcore_pipeline/main.nf' +include { UTILS_NFSCHEMA_PLUGIN } from '../../../subworkflows/nf-core/utils_nfschema_plugin/main.nf' +include { completionSummary } from '../../../subworkflows/nf-core/utils_nfcore_pipeline' +include { samplesheetToList } from 'plugin/nf-schema' +include { paramsSummaryMap } from 'plugin/nf-schema' /* @@ -27,7 +33,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 @@ -42,10 +48,16 @@ workflow PIPELINE_INITIALISATION { // // Validate parameters and generate parameter summary to stdout // - UTILS_NFSCHEMA_PLUGIN ( - workflow, - validate_params, - null + UTILS_NFSCHEMA_PLUGIN( + workflow, // input_workflow + validate_params, // validate_params + null, // parameters_schema (null: will use default schema) + false, // help (true: help message) + false, // help_full (true: full help message) + false, // show_hidden (true: show hidden params) + "", // before_text (string before help message) + "", // after_text (string after help message) + "" // command (example command string) ) // @@ -63,7 +75,7 @@ workflow PIPELINE_INITIALISATION { // // Create channel from input file provided through params.input // - ch_input = Channel.fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json")) + ch_input = channel.fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json")) if (params.split_fastq) { ch_input = ch_input.splitFastq( by: params.fastq_chunks_size, pe:true, file: true, compress:true) From 30b5b3a7dbb0a1296280f810bb9b227b0e4cd462 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:21:53 +0100 Subject: [PATCH 13/55] Update markdown settings --- .vscode/settings.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a33b527c..b9adac7c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "markdown.styles": ["public/vscode_markdown.css"] + "markdown.styles": [ + "public/vscode_markdown.css" + ], + "nextflow.telemetry.enabled": false } From ad51f7b16955e8c7c93b4203a3d61bb7a088b7d2 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:33:44 +0100 Subject: [PATCH 14/55] Lint template files --- .github/workflows/linting.yml | 16 ++++++++-------- .github/workflows/linting_comment.yml | 2 +- .prettierignore | 3 +++ assets/nf-core-hic_logo_light.png | Bin 61022 -> 59371 bytes 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 8b0f88c3..7a527a34 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -11,12 +11,12 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - - name: Set up Python 3.13 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + - name: Set up Python 3.14 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 with: - python-version: "3.13" + python-version: "3.14" - name: Install pre-commit run: pip install pre-commit @@ -28,14 +28,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Install Nextflow uses: nf-core/setup-nextflow@v2 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 with: - python-version: "3.13" + python-version: "3.14" architecture: "x64" - name: read .nf-core.yml @@ -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/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index d43797d9..e6e9bc26 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -21,7 +21,7 @@ jobs: run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - name: Post PR comment - uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2 + uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.pr_number.outputs.pr_number }} diff --git a/.prettierignore b/.prettierignore index edd29f01..dd749d43 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,4 +10,7 @@ testing/ testing* *.pyc bin/ +.nf-test/ ro-crate-metadata.json +modules/nf-core/ +subworkflows/nf-core/ diff --git a/assets/nf-core-hic_logo_light.png b/assets/nf-core-hic_logo_light.png index 7d3fedf5f154d1b6b1bb1f7248c6bf1e7071d33a..dc3d54a0054f5b0a44ac6bad70f62010f156e2b0 100644 GIT binary patch literal 59371 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

1|E+OC2%U3$AG)++csOgxYtvgnHkMm=yrNR; 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

<*O1}GUBj<*uHZV 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 Date: Fri, 5 Dec 2025 11:39:40 +0100 Subject: [PATCH 15/55] Update nf-core version --- .nf-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nf-core.yml b/.nf-core.yml index ac261bbd..696dcb6e 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,6 +1,6 @@ lint: schema_params: false -nf_core_version: 3.3.2 +nf_core_version: 3.5.0 repository_type: pipeline template: author: Nicolas Servant From 821dccddf3537d3fc210dd109c845d12c32e5266 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:50:24 +0100 Subject: [PATCH 16/55] Fix error in cooler cload ext.args --- conf/modules.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/modules.config b/conf/modules.config index 1d6ade55..6794534d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -336,7 +336,7 @@ process { enabled : params.save_raw_maps ] ext.prefix = { "${meta.id}.${cool_bin}" } - ext.args = "pairs -c1 2 -p1 3 -c2 4 -p2 5" + ext.args = "-c1 2 -p1 3 -c2 4 -p2 5" } withName: 'COOLER_BALANCE' { From cc2a8cfa5f2d0f6ad7f6a75f29bd4c2bb2c5d1c0 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 11:56:06 +0100 Subject: [PATCH 17/55] Update fastqc for topic channel --- modules.json | 2 +- modules/nf-core/fastqc/main.nf | 16 +- modules/nf-core/fastqc/meta.yml | 26 +- modules/nf-core/fastqc/tests/main.nf.test | 12 +- .../nf-core/fastqc/tests/main.nf.test.snap | 228 ++++++++++++------ workflows/hic.nf | 1 - 6 files changed, 186 insertions(+), 99 deletions(-) diff --git a/modules.json b/modules.json index 492dab10..654dba15 100644 --- a/modules.json +++ b/modules.json @@ -57,7 +57,7 @@ }, "fastqc": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", "installed_by": ["modules"] }, "multiqc": { diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 23e16634..4b3041dc 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -11,9 +11,9 @@ process FASTQC { 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 + tuple val(meta) , path("*.html") , emit: html + tuple val(meta) , path("*.zip") , emit: zip + tuple val("${task.process}"), val('fastqc'), eval('fastqc --version | sed "/FastQC v/!d; s/.*v//"'), emit: versions_fastqc, topic: versions when: task.ext.when == null || task.ext.when @@ -43,11 +43,6 @@ process FASTQC { --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: @@ -55,10 +50,5 @@ process FASTQC { """ 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 index c8d9d025..f988697a 100644 --- a/modules/nf-core/fastqc/meta.yml +++ b/modules/nf-core/fastqc/meta.yml @@ -53,13 +53,27 @@ output: description: FastQC report archive pattern: "*_{fastqc.zip}" ontologies: [] + versions_fastqc: + - - ${task.process}: + type: string + description: The process the versions were collected from + - fastqc: + type: string + description: The tool name + - fastqc --version | sed "/FastQC v/!d; s/.*v//: + 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 + - fastqc: + type: string + description: The tool name + - fastqc --version | sed "/FastQC v/!d; s/.*v//: + type: string + description: The command used to generate the version of the tool authors: - "@drpatelh" - "@grst" diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index e9d79a07..66c44da9 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -30,7 +30,7 @@ nextflow_process { { 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() } + { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() } ) } } @@ -58,7 +58,7 @@ nextflow_process { { 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() } + { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() } ) } } @@ -82,7 +82,7 @@ nextflow_process { { 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() } + { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() } ) } } @@ -106,7 +106,7 @@ nextflow_process { { 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() } + { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() } ) } } @@ -142,7 +142,7 @@ nextflow_process { { 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() } + { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() } ) } } @@ -166,7 +166,7 @@ nextflow_process { { 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() } + { assert snapshot(sanitizeOutput(process.out).findAll { key, val -> key != 'html' && key != 'zip' }).match() } ) } } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index d5db3092..c8ee120f 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,15 +1,21 @@ { "sarscov2 custom_prefix": { "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:02:16.374038" + "timestamp": "2025-10-28T16:39:14.518503" }, "sarscov2 single-end [fastq] - stub": { "content": [ @@ -33,7 +39,11 @@ ] ], "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "html": [ [ @@ -44,8 +54,12 @@ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "zip": [ [ @@ -59,10 +73,10 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:02:24.993809" + "timestamp": "2025-10-28T16:39:19.309008" }, "sarscov2 custom_prefix - stub": { "content": [ @@ -86,7 +100,11 @@ ] ], "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "html": [ [ @@ -97,8 +115,12 @@ "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "zip": [ [ @@ -112,58 +134,82 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:03:10.93942" + "timestamp": "2025-10-28T16:39:44.94888" }, "sarscov2 interleaved [fastq]": { "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:01:42.355718" + "timestamp": "2025-10-28T16:38:45.168496" }, "sarscov2 paired-end [bam]": { "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:01:53.276274" + "timestamp": "2025-10-28T16:38:53.268919" }, "sarscov2 multiple [fastq]": { "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:02:05.527626" + "timestamp": "2025-10-28T16:39:05.050305" }, "sarscov2 paired-end [fastq]": { "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:01:31.188871" + "timestamp": "2025-10-28T16:38:37.2373" }, "sarscov2 paired-end [fastq] - stub": { "content": [ @@ -187,7 +233,11 @@ ] ], "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "html": [ [ @@ -198,8 +248,12 @@ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "zip": [ [ @@ -213,10 +267,10 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:02:34.273566" + "timestamp": "2025-10-28T16:39:24.450398" }, "sarscov2 multiple [fastq] - stub": { "content": [ @@ -240,7 +294,11 @@ ] ], "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "html": [ [ @@ -251,8 +309,12 @@ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "zip": [ [ @@ -266,22 +328,28 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:03:02.304411" + "timestamp": "2025-10-28T16:39:39.758762" }, "sarscov2 single-end [fastq]": { "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:01:19.095607" + "timestamp": "2025-10-28T16:38:29.555068" }, "sarscov2 interleaved [fastq] - stub": { "content": [ @@ -305,7 +373,11 @@ ] ], "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "html": [ [ @@ -316,8 +388,12 @@ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "zip": [ [ @@ -331,10 +407,10 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:02:44.640184" + "timestamp": "2025-10-28T16:39:29.193136" }, "sarscov2 paired-end [bam] - stub": { "content": [ @@ -358,7 +434,11 @@ ] ], "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "html": [ [ @@ -369,8 +449,12 @@ "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + "versions_fastqc": [ + [ + "FASTQC", + "fastqc", + "0.12.1" + ] ], "zip": [ [ @@ -384,9 +468,9 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" + "nf-test": "0.9.2", + "nextflow": "25.10.0" }, - "timestamp": "2024-07-22T11:02:53.550742" + "timestamp": "2025-10-28T16:39:34.144919" } } \ No newline at end of file diff --git a/workflows/hic.nf b/workflows/hic.nf index 9909aa48..c996c0e7 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -90,7 +90,6 @@ workflow HIC { ch_samplesheet ) ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) - ch_versions = ch_versions.mix(FASTQC.out.versions.first()) // // SUB-WORFLOW: HiC-Pro From 3c6806b7b4713ecdc34eee0c1108641c76cf7fc6 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 12:07:56 +0100 Subject: [PATCH 18/55] Update module multiqc with topic channel --- modules.json | 4 +- modules/nf-core/multiqc/main.nf | 37 +++++------- modules/nf-core/multiqc/meta.yml | 38 ++++++++---- .../multiqc/tests/custom_prefix.config | 5 ++ modules/nf-core/multiqc/tests/main.nf.test | 32 +++++++++- .../nf-core/multiqc/tests/main.nf.test.snap | 58 +++++++++++++------ workflows/hic.nf | 1 - 7 files changed, 115 insertions(+), 60 deletions(-) create mode 100644 modules/nf-core/multiqc/tests/custom_prefix.config diff --git a/modules.json b/modules.json index 654dba15..390d8610 100644 --- a/modules.json +++ b/modules.json @@ -62,7 +62,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "82a79183037a403ad1b6714e5dbcff25500efaf6", + "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", "installed_by": ["modules"] }, "pairix": { @@ -122,7 +122,7 @@ }, "samtools/sort": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", "installed_by": ["modules"] } } diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 5d0780af..335afccc 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -7,7 +7,7 @@ process MULTIQC { '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,27 +26,22 @@ 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: @@ -56,9 +51,5 @@ process MULTIQC { 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 ce30eb73..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 @@ -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 @@ -57,10 +57,10 @@ input: - edam: http://edamontology.org/format_3475 # TSV output: report: - - "*multiqc_report.html": + - "*.html": type: file description: MultiQC report file - pattern: "multiqc_report.html" + pattern: ".html" ontologies: [] data: - "*_data": @@ -73,13 +73,27 @@ 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: - - 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 + - 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 a88bafd6..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,737bb2c7cad54ffc2ec020791dc48b8f" - ] + { + "versions_multiqc": [ + [ + "MULTIQC", + "multiqc", + "1.32" + ] + ] + } ], "meta": { - "nf-test": "0.9.3", - "nextflow": "24.10.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2025-10-27T13:33:24.356715" + "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,737bb2c7cad54ffc2ec020791dc48b8f" + { + "versions_multiqc": [ + [ + "MULTIQC", + "multiqc", + "1.32" + ] + ] + } ] ], "meta": { - "nf-test": "0.9.3", - "nextflow": "24.10.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2025-10-27T13:34:11.103619" + "timestamp": "2025-10-28T15:30:48.963962021" }, - "multiqc_versions_config": { + "sarscov2 single-end [fastqc] [config]": { "content": [ - [ - "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" - ] + { + "versions_multiqc": [ + [ + "MULTIQC", + "multiqc", + "1.32" + ] + ] + } ], "meta": { - "nf-test": "0.9.3", - "nextflow": "24.10.4" + "nf-test": "0.9.2", + "nextflow": "25.04.6" }, - "timestamp": "2025-10-27T13:34:04.615233" + "timestamp": "2025-10-28T15:29:30.664969334" } } \ No newline at end of file diff --git a/workflows/hic.nf b/workflows/hic.nf index c996c0e7..0480c7c6 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -237,7 +237,6 @@ workflow HIC { ) emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html - versions = ch_versions // channel: [ path(versions.yml) ] } From 86523328281a8b6b32199720a6f713922e9c5b7e Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 12:08:29 +0100 Subject: [PATCH 19/55] Update module samtools_sort with topic channel --- modules/nf-core/samtools/sort/main.nf | 10 +- modules/nf-core/samtools/sort/meta.yml | 28 +- .../nf-core/samtools/sort/tests/main.nf.test | 20 +- .../samtools/sort/tests/main.nf.test.snap | 349 ++++++------------ subworkflows/local/pairtools/main.nf | 1 - 5 files changed, 142 insertions(+), 266 deletions(-) diff --git a/modules/nf-core/samtools/sort/main.nf b/modules/nf-core/samtools/sort/main.nf index d4bd5a32..6b5aa31d 100644 --- a/modules/nf-core/samtools/sort/main.nf +++ b/modules/nf-core/samtools/sort/main.nf @@ -19,7 +19,7 @@ process SAMTOOLS_SORT { 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 - 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 @@ -53,10 +53,6 @@ process SAMTOOLS_SORT { -o ${output_file} \\ - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -78,9 +74,5 @@ process SAMTOOLS_SORT { touch ${prefix}.${extension} ${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 4c4010bb..809a57fc 100644 --- a/modules/nf-core/samtools/sort/meta.yml +++ b/modules/nf-core/samtools/sort/meta.yml @@ -76,7 +76,6 @@ output: description: Sorted SAM file pattern: "*.{sam}" ontologies: [] - crai: - - meta: type: map @@ -110,13 +109,28 @@ output: 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: - - 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: 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 ff069190..df47bb25 100644 --- a/modules/nf-core/samtools/sort/tests/main.nf.test +++ b/modules/nf-core/samtools/sort/tests/main.nf.test @@ -34,7 +34,7 @@ nextflow_process { { assert snapshot( process.out.bam, process.out.bai, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -66,7 +66,7 @@ nextflow_process { { assert snapshot( process.out.bam, process.out.bai, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -98,7 +98,7 @@ nextflow_process { { assert snapshot( process.out.bam, process.out.csi, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -133,7 +133,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()} ) } @@ -168,7 +168,7 @@ nextflow_process { { assert snapshot( process.out.bam, process.out.bai.collect { it.collect { it instanceof Map ? it : file(it).name } }, - process.out.versions + process.out.findAll { key, val -> key.startsWith("versions") } ).match()} ) } @@ -203,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()} ) } @@ -235,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()} ) } @@ -265,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() } ) } } @@ -296,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() } ) } } @@ -325,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 473e1745..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,80 +19,21 @@ "test.sorted.cram.crai" ] ], - [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ] - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T14:43:31.395604" - }, - "bam - stub": { - "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - - ], - "6": [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ], - "bai": [ - - ], - "bam": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "crai": [ - - ], - "cram": [ - - ], - "csi": [ - - ], - "sam": [ - - ], - "versions": [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:43:37.387063" + "timestamp": "2025-10-29T12:47:01.171084" }, "bam_csi_index": { "content": [ @@ -114,15 +55,39 @@ "test.sorted.bam.csi:md5,01394e702c729cb478df914ffaf9f7f8" ] ], - [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:43:06.976036" + "timestamp": "2025-10-29T12:46:00.961675" + }, + "bam - stub": { + "content": [ + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-29T12:47:12.154354" }, "multiple bam bai index": { "content": [ @@ -144,80 +109,39 @@ "test.sorted.bam.bai" ] ], - [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:43:18.72271" + "timestamp": "2025-10-29T12:46:25.488622" }, "cram - stub": { "content": [ { - "0": [ - - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - - ], - "6": [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ], - "bai": [ - - ], - "bam": [ - - ], - "crai": [ - - ], - "cram": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.cram:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "csi": [ - - ], - "sam": [ - - ], - "versions": [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:43:48.734367" + "timestamp": "2025-10-29T12:47:28.485045" }, "multiple bam": { "content": [ @@ -233,80 +157,39 @@ [ ], - [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:43:12.989244" + "timestamp": "2025-10-29T12:46:13.168476" }, "multiple bam - stub": { "content": [ { - "0": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,cd4eb0077f25e9cff395366b8883dd1f" + "SAMTOOLS_SORT", + "samtools", + "1.22.1" ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - - ], - "5": [ - - ], - "6": [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ], - "bai": [ - - ], - "bam": [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,cd4eb0077f25e9cff395366b8883dd1f" - ] - ], - "crai": [ - - ], - "cram": [ - - ], - "csi": [ - - ], - "sam": [ - - ], - "versions": [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:43:43.196638" + "timestamp": "2025-10-29T12:47:21.628088" }, "bam_no_index": { "content": [ @@ -322,15 +205,21 @@ [ ], - [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:42:54.926504" + "timestamp": "2025-10-29T12:45:47.139418" }, "multiple bam csi index": { "content": [ @@ -352,45 +241,21 @@ "test.sorted.bam.csi" ] ], - [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ] - ], - "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" - }, - "timestamp": "2025-09-10T14:43:25.059178" - }, - "bam": { - "content": [ - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam:md5,34aa85e86abefe637f7a4a9887f016fc" - ] - ], - [ - [ - { - "id": "test", - "single_end": false - }, - "test.sorted.bam.csi" + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] ] - ], - [ - "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:59:46.372244" + "timestamp": "2025-10-29T12:46:51.5531" }, "bam_bai_index": { "content": [ @@ -412,14 +277,20 @@ "test.sorted.bam.bai:md5,50dd467c169545a4d5d1f709f7e986e0" ] ], - [ - "versions.yml:md5,18e8b3709b62aa2ba61966672eee91b2" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_SORT", + "samtools", + "1.22.1" + ] + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-09-10T14:43:00.82974" + "timestamp": "2025-10-29T12:45:52.796936" } } \ No newline at end of file diff --git a/subworkflows/local/pairtools/main.nf b/subworkflows/local/pairtools/main.nf index 30cb97f9..4508983f 100644 --- a/subworkflows/local/pairtools/main.nf +++ b/subworkflows/local/pairtools/main.nf @@ -89,7 +89,6 @@ workflow PAIRTOOLS { fasta, "bai" ) - ch_versions = ch_versions.mix(SAMTOOLS_SORT.out.versions) SAMTOOLS_INDEX( SAMTOOLS_SORT.out.bam From a2e5b48866c99981c0500a5f26635d0e29696ee6 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 12:30:43 +0100 Subject: [PATCH 20/55] Fix typo --- subworkflows/nf-core/utils_nfcore_pipeline/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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())) } // From a783902cc95ba2386f18b97d299233d7f3bb5a3b Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 5 Dec 2025 14:37:03 +0100 Subject: [PATCH 21/55] Update components names in subworkflows meta.yml --- subworkflows/local/compartments/meta.yml | 2 +- subworkflows/local/cooler/meta.yml | 12 ++++----- subworkflows/local/hicpro/meta.yml | 12 ++++----- subworkflows/local/hicpro_mapping/meta.yml | 12 ++++----- subworkflows/local/pairtools/meta.yml | 26 +++++++++---------- subworkflows/local/prepare_genome/meta.yml | 8 +++--- subworkflows/local/tads/meta.yml | 4 +-- .../local/utils_nfcore_hic_pipeline/meta.yml | 7 ++--- 8 files changed, 42 insertions(+), 41 deletions(-) diff --git a/subworkflows/local/compartments/meta.yml b/subworkflows/local/compartments/meta.yml index fc8b5256..06fbb445 100644 --- a/subworkflows/local/compartments/meta.yml +++ b/subworkflows/local/compartments/meta.yml @@ -13,7 +13,7 @@ keywords: - Compartments - Genomics components: - - cooltools_eigscis + - cooltools/eigscis - calder2 input: - cool: diff --git a/subworkflows/local/cooler/meta.yml b/subworkflows/local/cooler/meta.yml index 7043df82..3f0b3783 100644 --- a/subworkflows/local/cooler/meta.yml +++ b/subworkflows/local/cooler/meta.yml @@ -11,12 +11,12 @@ keywords: - Genomics - Chromosome interactions components: - - cooler_makebins - - cooler_cload - - cooler_balance - - cooler_zoomify - - cooler_dump - - split_cooler_dump + - cooler/makebins + - cooler/cload + - cooler/balance + - cooler/zoomify + - cooler/dump + - split/cooler/dump input: - pairs: type: file diff --git a/subworkflows/local/hicpro/meta.yml b/subworkflows/local/hicpro/meta.yml index a994f059..de43855b 100644 --- a/subworkflows/local/hicpro/meta.yml +++ b/subworkflows/local/hicpro/meta.yml @@ -13,13 +13,13 @@ keywords: - Contact maps components: - hicpro_mapping - - get_valid_interaction - - get_valid_interaction_dnase - - merge_valid_interaction - - merge_stats + - get/valid/interaction + - get/valid/interaction/dnase + - merge/valid/interaction + - merge/stats - hicpro2pairs - - build_contact_maps - - ice_normalization + - build/contact/maps + - ice/normalization input: - reads: type: file diff --git a/subworkflows/local/hicpro_mapping/meta.yml b/subworkflows/local/hicpro_mapping/meta.yml index ff065859..48aa14c2 100644 --- a/subworkflows/local/hicpro_mapping/meta.yml +++ b/subworkflows/local/hicpro_mapping/meta.yml @@ -13,12 +13,12 @@ keywords: - Bowtie2 - Genomics components: - - bowtie2_align - - trim_reads - - merge_bowtie2 - - hicpro_combine_mates - - mapping_stats_dnase - - combine_mates + - bowtie2/align + - trim/reads + - merge/bowtie2 + - hicpro/combine/mates + - mapping/stats/dnase + - combine/mates input: - reads: type: file diff --git a/subworkflows/local/pairtools/meta.yml b/subworkflows/local/pairtools/meta.yml index f37d6322..e31721b8 100644 --- a/subworkflows/local/pairtools/meta.yml +++ b/subworkflows/local/pairtools/meta.yml @@ -13,20 +13,20 @@ keywords: - Chromosome interactions - Contact maps components: - - bwa_mem - - bwamem2_mem - - pairtools_parse - - pairtools_restrict - - pairtools_sort - - pairtools_merge - - pairtools_split - - pairtools_dedup - - pairtools_select - - pairtools_stats + - bwa/mem + - bwamem2/mem + - pairtools/parse + - pairtools/restrict + - pairtools/sort + - pairtools/merge + - pairtools/split + - pairtools/dedup + - pairtools/select + - pairtools/stats - pairix - - samtools_sort - - samtools_index - - samtools_flagstat + - samtools/sort + - samtools/index + - samtools/flagstat input: - reads: type: file diff --git a/subworkflows/local/prepare_genome/meta.yml b/subworkflows/local/prepare_genome/meta.yml index ce06b7ff..a5b9211a 100644 --- a/subworkflows/local/prepare_genome/meta.yml +++ b/subworkflows/local/prepare_genome/meta.yml @@ -14,10 +14,10 @@ keywords: - Restriction fragments - Chromosome sizes components: - - bowtie2_build - - bwa_index - - custom_getchromsizes - - get_restriction_fragments + - bowtie2/build + - bwa/index + - samtools/faidx + - get/restriction/fragments input: - fasta: type: file diff --git a/subworkflows/local/tads/meta.yml b/subworkflows/local/tads/meta.yml index d92f128e..e60c48d4 100644 --- a/subworkflows/local/tads/meta.yml +++ b/subworkflows/local/tads/meta.yml @@ -12,8 +12,8 @@ keywords: - HiCExplorer - Genomics components: - - cooltools_insulation - - hic_find_tads + - cooltools/insulation + - hic/find/tads input: - cool: type: file diff --git a/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml b/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml index 27e977c7..dd61abeb 100644 --- a/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml +++ b/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml @@ -11,9 +11,10 @@ keywords: - Parameters - Samplesheet components: - - utils/nextflow_pipeline - - utils/nfschema_plugin - - utils/nfcore_pipeline + - utils/nextflow/pipeline + - utils/nfschema/plugin + - utils/nfcore/pipeline + - completionsummary input: - version: type: boolean From 77b1f06d92e417df85b420653a23a407234aeb10 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 15 Dec 2025 11:00:40 +0100 Subject: [PATCH 22/55] Fix --bin_sizes error #62 --- nextflow_schema.json | 2 +- workflows/hic.nf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 47df423f..66ce54e1 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -262,7 +262,7 @@ "fa_icon": "fas fa-chess-board", "properties": { "bin_size": { - "type": "string", + "type": ["string", "integer"], "pattern": "^(\\d+)(,\\d+)*$", "default": "1000000", "description": "Resolution to build the maps (comma separated)" diff --git a/workflows/hic.nf b/workflows/hic.nf index 0480c7c6..b821a36e 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -23,7 +23,7 @@ include { TADS } from '../subworkflows/local/tads' //**************************************** // Combine all maps resolution for downstream analysis -ch_map_res = channel.from( params.bin_size ).splitCsv().flatten().toInteger() +ch_map_res = channel.from( params.bin_size.toString()).splitCsv().flatten().toInteger() if (params.res_zoomify){ ch_zoom_res = channel.from( params.res_zoomify ).splitCsv().flatten().toInteger() From 88b5eb97549f96f10499533eb711e52d59a9da4c Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Feb 2026 13:47:27 +0100 Subject: [PATCH 23/55] Add trimgalore module --- modules/nf-core/trimgalore/environment.yml | 7 + modules/nf-core/trimgalore/main.nf | 86 ++++ modules/nf-core/trimgalore/meta.yml | 129 +++++ modules/nf-core/trimgalore/tests/main.nf.test | 162 ++++++ .../trimgalore/tests/main.nf.test.snap | 468 ++++++++++++++++++ .../nf-core/trimgalore/tests/nextflow.config | 5 + 6 files changed, 857 insertions(+) create mode 100644 modules/nf-core/trimgalore/environment.yml create mode 100644 modules/nf-core/trimgalore/main.nf create mode 100644 modules/nf-core/trimgalore/meta.yml create mode 100644 modules/nf-core/trimgalore/tests/main.nf.test create mode 100644 modules/nf-core/trimgalore/tests/main.nf.test.snap create mode 100644 modules/nf-core/trimgalore/tests/nextflow.config diff --git a/modules/nf-core/trimgalore/environment.yml b/modules/nf-core/trimgalore/environment.yml new file mode 100644 index 00000000..60b33ef2 --- /dev/null +++ b/modules/nf-core/trimgalore/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::trim-galore=0.6.10 diff --git a/modules/nf-core/trimgalore/main.nf b/modules/nf-core/trimgalore/main.nf new file mode 100644 index 00000000..7372e720 --- /dev/null +++ b/modules/nf-core/trimgalore/main.nf @@ -0,0 +1,86 @@ +process TRIMGALORE { + tag "${meta.id}" + label 'process_high' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/trim-galore:0.6.10--hdfd78af_2' : + 'biocontainers/trim-galore:0.6.10--hdfd78af_2'}" + + input: + tuple val(meta), path(reads) + + output: + tuple val(meta), path("*{3prime,5prime,trimmed,val}{,_1,_2}.fq.gz"), emit: reads + tuple val(meta), path("*report.txt") , emit: log , optional: true + tuple val(meta), path("*unpaired{,_1,_2}.fq.gz") , emit: unpaired, optional: true + tuple val(meta), path("*.html") , emit: html , optional: true + tuple val(meta), path("*.zip") , emit: zip , optional: true + tuple val("${task.process}"), val("trimgalore"), eval('trim_galore --version | grep -Eo "[0-9]+(\\.[0-9]+)+"'), topic: versions, emit: versions_trimgalore + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + // Calculate number of --cores for TrimGalore based on value of task.cpus + // See: https://github.com/FelixKrueger/TrimGalore/blob/master/CHANGELOG.md#version-060-release-on-1-mar-2019 + // See: https://github.com/nf-core/atacseq/pull/65 + def cores = 1 + if (task.cpus) { + cores = (task.cpus as int) - 4 + if (meta.single_end) { + cores = (task.cpus as int) - 3 + } + if (cores < 1) { + cores = 1 + } + if (cores > 8) { + cores = 8 + } + } + + // Added soft-links to original fastqs for consistent naming in MultiQC + def prefix = task.ext.prefix ?: "${meta.id}" + if (meta.single_end) { + def args_list = args.split("\\s(?=--)").toList() + args_list.removeAll { it.toLowerCase().contains('_r2 ') } + """ + [ ! -f ${prefix}.fastq.gz ] && ln -s ${reads} ${prefix}.fastq.gz + trim_galore \\ + ${args_list.join(' ')} \\ + --cores ${cores} \\ + --gzip \\ + ${prefix}.fastq.gz + """ + } + else { + """ + [ ! -f ${prefix}_1.fastq.gz ] && ln -s ${reads[0]} ${prefix}_1.fastq.gz + [ ! -f ${prefix}_2.fastq.gz ] && ln -s ${reads[1]} ${prefix}_2.fastq.gz + trim_galore \\ + ${args} \\ + --cores ${cores} \\ + --paired \\ + --gzip \\ + ${prefix}_1.fastq.gz \\ + ${prefix}_2.fastq.gz + """ + } + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + if (meta.single_end) { + output_command = "echo '' | gzip > ${prefix}_trimmed.fq.gz ;" + output_command += "touch ${prefix}.fastq.gz_trimming_report.txt" + } + else { + output_command = "echo '' | gzip > ${prefix}_1_trimmed.fq.gz ;" + output_command += "touch ${prefix}_1.fastq.gz_trimming_report.txt ;" + output_command += "echo '' | gzip > ${prefix}_2_trimmed.fq.gz ;" + output_command += "touch ${prefix}_2.fastq.gz_trimming_report.txt" + } + """ + ${output_command} + """ +} diff --git a/modules/nf-core/trimgalore/meta.yml b/modules/nf-core/trimgalore/meta.yml new file mode 100644 index 00000000..dcd9b170 --- /dev/null +++ b/modules/nf-core/trimgalore/meta.yml @@ -0,0 +1,129 @@ +name: trimgalore +description: | + A wrapper around Cutadapt and FastQC to consistently apply adapter and quality trimming to FastQ files, + with extra functionality for RRBS data +keywords: + - trimming + - adapters + - sequencing + - fastq +tools: + - trimgalore: + description: | + A wrapper tool around Cutadapt and FastQC to consistently apply quality + and adapter trimming to FastQ files, with some extra functionality for + MspI-digested RRBS-type (Reduced Representation Bisufite-Seq) libraries. + homepage: https://www.bioinformatics.babraham.ac.uk/projects/trim_galore/ + documentation: https://github.com/FelixKrueger/TrimGalore/blob/master/Docs/Trim_Galore_User_Guide.md + licence: ["GPL-3.0-or-later"] + identifier: biotools:trim_galore + +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/format_1930" # FASTQ +output: + reads: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*{3prime,5prime,trimmed,val}{,_1,_2}.fq.gz": + type: file + description: The trimmed/modified fastq reads + pattern: "*{3prime,5prime,trimmed,val}{,_1,_2}.fq.gz" + ontologies: + - edam: "http://edamontology.org/format_1930" # FASTQ + - edam: http://edamontology.org/format_3989 # GZIP format + log: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*report.txt": + type: file + description: trimgalore log file + pattern: "*report.txt" + ontologies: + - edam: "http://edamontology.org/format_2330" # Textual format + unpaired: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*unpaired{,_1,_2}.fq.gz": + type: file + description: unpaired reads when --retain_unpaired flag is used + pattern: "*unpaired*.fq.gz" + ontologies: + - edam: "http://edamontology.org/format_1930" # FASTQ + - edam: http://edamontology.org/format_3989 # GZIP format + html: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.html": + type: file + description: FastQC HTML report after trimming when the --fastqc flag is used + pattern: "*_fastqc.html" + ontologies: + - edam: "http://edamontology.org/format_2331" # HTML + zip: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.zip": + type: file + description: FastQC report output zip after trimming when the --fastqc flag + is used + pattern: "*_fastqc.zip" + ontologies: + - edam: http://edamontology.org/format_3987 # ZIP format + versions_trimgalore: + - - ${task.process}: + type: string + description: The name of the process + - trimgalore: + type: string + description: The name of the tool + - trim_galore --version | grep -Eo "[0-9]+(\.[0-9]+)+": + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - trimgalore: + type: string + description: The name of the tool + - trim_galore --version | grep -Eo "[0-9]+(\.[0-9]+)+": + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@drpatelh" + - "@ewels" + - "@FelixKrueger" +maintainers: + - "@drpatelh" + - "@ewels" + - "@FelixKrueger" + - "@vagkaratzas" diff --git a/modules/nf-core/trimgalore/tests/main.nf.test b/modules/nf-core/trimgalore/tests/main.nf.test new file mode 100644 index 00000000..ac97b087 --- /dev/null +++ b/modules/nf-core/trimgalore/tests/main.nf.test @@ -0,0 +1,162 @@ +nextflow_process { + + name "Test Process TRIMGALORE" + script "../main.nf" + process "TRIMGALORE" + + tag "modules" + tag "modules_nfcore" + tag "trimgalore" + + test("sarscov2 - fastq - single-end") { + + 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.reads, + file(process.out.log[0][1]).readLines()[0..9], // line 11 changes + file(process.out.log[0][1]).readLines()[11..59], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + } + + test("sarscov2 - fastq - paired-end") { + + when { + process { + """ + input[0] = [ [ 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) + ] + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.reads[0][1][0], + process.out.reads[0][1][1], + file(process.out.log[0][1][0]).readLines()[0..9], // line 11 changes + file(process.out.log[0][1][0]).readLines()[11..58], + file(process.out.log[0][1][1]).readLines()[0..9], // line 11 changes + file(process.out.log[0][1][1]).readLines()[11..60], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + } + + test("sarscov2 - fastq - paired-end - keep-unpaired") { + + config "./nextflow.config" + + when { + params { + module_args = '--retain_unpaired --length 150' + } + + process { + """ + input[0] = [ [ 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) + ] + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.reads[0][1][0], + process.out.reads[0][1][1], + process.out.unpaired[0][1][0], + process.out.unpaired[0][1][1], + file(process.out.log[0][1][0]).readLines()[0..9], // line 11 changes + file(process.out.log[0][1][0]).readLines()[11..59], + file(process.out.log[0][1][1]).readLines()[0..9], // line 11 changes + file(process.out.log[0][1][1]).readLines()[11..63], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + } + + 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.reads, + process.out.log, + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + } + + test("sarscov2 - fastq - paired-end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [ 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) + ] + ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.reads, + process.out.log, + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + } +} diff --git a/modules/nf-core/trimgalore/tests/main.nf.test.snap b/modules/nf-core/trimgalore/tests/main.nf.test.snap new file mode 100644 index 00000000..2fb55f2d --- /dev/null +++ b/modules/nf-core/trimgalore/tests/main.nf.test.snap @@ -0,0 +1,468 @@ +{ + "sarscov2 - fastq - paired-end - stub": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e", + "test_2.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + { + "versions_trimgalore": [ + [ + "TRIMGALORE", + "trimgalore", + "0.6.10" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-15T14:40:14.896140126" + }, + "sarscov2 - fastq - paired-end - keep-unpaired": { + "content": [ + "test_1_val_1.fq.gz:md5,75413e85910bbc2e1556e12f6479f935", + "test_2_val_2.fq.gz:md5,d3c588c12646ebd36a0812fe02d0bda6", + "test_1_unpaired_1.fq.gz:md5,17e0e878f6d0e93b9008a05f128660b6", + "test_2_unpaired_2.fq.gz:md5,b09a064368a867e099e66df5ef69b044", + [ + "", + "SUMMARISING RUN PARAMETERS", + "==========================", + "Input filename: test_1.fastq.gz", + "Trimming mode: paired-end", + "Trim Galore version: 0.6.10", + "Cutadapt version: 5.2", + "Number of cores used for trimming: 1", + "Quality Phred score cutoff: 20", + "Quality encoding type selected: ASCII+33" + ], + [ + "Defaulting to Illumina universal adapter ( AGATCGGAAGAGC ). Specify -a SEQUENCE to avoid this behavior).", + "Adapter sequence: 'AGATCGGAAGAGC' (Illumina TruSeq, Sanger iPCR; default (inconclusive auto-detection))", + "Maximum trimming error rate: 0.1 (default)", + "Minimum required adapter overlap (stringency): 1 bp", + "Minimum required sequence length for both reads before a sequence pair gets removed: 150 bp", + "Length cut-off for read 1: 35 bp (default)", + "Length cut-off for read 2: 35 bp (default)", + "Output file will be GZIP compressed", + "", + "", + "This is cutadapt 5.2 with Python 3.12.12", + "Command line parameters: -j 1 -e 0.1 -q 20 -O 1 -a AGATCGGAAGAGC test_1.fastq.gz", + "Processing single-end reads on 1 core ...", + "", + "=== Summary ===", + "", + "Total reads processed: 100", + "Reads with adapters: 31 (31.0%)", + "Reads written (passing filters): 100 (100.0%)", + "", + "Total basepairs processed: 13,897 bp", + "Quality-trimmed: 0 bp (0.0%)", + "Total written (filtered): 13,851 bp (99.7%)", + "", + "=== Adapter 1 ===", + "", + "Sequence: AGATCGGAAGAGC; Type: regular 3'; Length: 13; Trimmed: 31 times", + "", + "Minimum overlap: 1", + "No. of allowed errors:", + "1-9 bp: 0; 10-13 bp: 1", + "", + "Bases preceding removed adapters:", + " A: 35.5%", + " C: 25.8%", + " G: 9.7%", + " T: 29.0%", + " none/other: 0.0%", + "", + "Overview of removed sequences", + "length\tcount\texpect\tmax.err\terror counts", + "1\t19\t25.0\t0\t19", + "2\t10\t6.2\t0\t10", + "3\t1\t1.6\t0\t1", + "4\t1\t0.4\t0\t1", + "", + "RUN STATISTICS FOR INPUT FILE: test_1.fastq.gz", + "=============================================", + "100 sequences processed in total" + ], + [ + "", + "SUMMARISING RUN PARAMETERS", + "==========================", + "Input filename: test_2.fastq.gz", + "Trimming mode: paired-end", + "Trim Galore version: 0.6.10", + "Cutadapt version: 5.2", + "Number of cores used for trimming: 1", + "Quality Phred score cutoff: 20", + "Quality encoding type selected: ASCII+33" + ], + [ + "Defaulting to Illumina universal adapter ( AGATCGGAAGAGC ). Specify -a SEQUENCE to avoid this behavior).", + "Adapter sequence: 'AGATCGGAAGAGC' (Illumina TruSeq, Sanger iPCR; default (inconclusive auto-detection))", + "Maximum trimming error rate: 0.1 (default)", + "Minimum required adapter overlap (stringency): 1 bp", + "Minimum required sequence length for both reads before a sequence pair gets removed: 150 bp", + "Length cut-off for read 1: 35 bp (default)", + "Length cut-off for read 2: 35 bp (default)", + "Output file will be GZIP compressed", + "", + "", + "This is cutadapt 5.2 with Python 3.12.12", + "Command line parameters: -j 1 -e 0.1 -q 20 -O 1 -a AGATCGGAAGAGC test_2.fastq.gz", + "Processing single-end reads on 1 core ...", + "", + "=== Summary ===", + "", + "Total reads processed: 100", + "Reads with adapters: 40 (40.0%)", + "Reads written (passing filters): 100 (100.0%)", + "", + "Total basepairs processed: 13,748 bp", + "Quality-trimmed: 0 bp (0.0%)", + "Total written (filtered): 13,693 bp (99.6%)", + "", + "=== Adapter 1 ===", + "", + "Sequence: AGATCGGAAGAGC; Type: regular 3'; Length: 13; Trimmed: 40 times", + "", + "Minimum overlap: 1", + "No. of allowed errors:", + "1-9 bp: 0; 10-13 bp: 1", + "", + "Bases preceding removed adapters:", + " A: 35.0%", + " C: 25.0%", + " G: 5.0%", + " T: 35.0%", + " none/other: 0.0%", + "", + "Overview of removed sequences", + "length\tcount\texpect\tmax.err\terror counts", + "1\t28\t25.0\t0\t28", + "2\t10\t6.2\t0\t10", + "3\t1\t1.6\t0\t1", + "4\t1\t0.4\t0\t1", + "", + "RUN STATISTICS FOR INPUT FILE: test_2.fastq.gz", + "=============================================", + "100 sequences processed in total", + "", + "Total number of sequences analysed for the sequence pair length validation: 100", + "", + "Number of sequence pairs removed because at least one read was shorter than the length cutoff (150 bp): 81 (81.00%)" + ], + { + "versions_trimgalore": [ + [ + "TRIMGALORE", + "trimgalore", + "0.6.10" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-15T14:39:53.811844594" + }, + "sarscov2 - fastq - single-end - stub": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test_trimmed.fq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + [ + [ + { + "id": "test", + "single_end": true + }, + "test.fastq.gz_trimming_report.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + { + "versions_trimgalore": [ + [ + "TRIMGALORE", + "trimgalore", + "0.6.10" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-15T14:40:03.991561892" + }, + "sarscov2 - fastq - paired-end": { + "content": [ + "test_1_val_1.fq.gz:md5,566d44cca0d22c522d6cf0e50c7165dc", + "test_2_val_2.fq.gz:md5,3c023e8e890b897821df3dc98f48c2b3", + [ + "", + "SUMMARISING RUN PARAMETERS", + "==========================", + "Input filename: test_1.fastq.gz", + "Trimming mode: paired-end", + "Trim Galore version: 0.6.10", + "Cutadapt version: 5.2", + "Number of cores used for trimming: 1", + "Quality Phred score cutoff: 20", + "Quality encoding type selected: ASCII+33" + ], + [ + "Defaulting to Illumina universal adapter ( AGATCGGAAGAGC ). Specify -a SEQUENCE to avoid this behavior).", + "Adapter sequence: 'AGATCGGAAGAGC' (Illumina TruSeq, Sanger iPCR; default (inconclusive auto-detection))", + "Maximum trimming error rate: 0.1 (default)", + "Minimum required adapter overlap (stringency): 1 bp", + "Minimum required sequence length for both reads before a sequence pair gets removed: 20 bp", + "Output file will be GZIP compressed", + "", + "", + "This is cutadapt 5.2 with Python 3.12.12", + "Command line parameters: -j 1 -e 0.1 -q 20 -O 1 -a AGATCGGAAGAGC test_1.fastq.gz", + "Processing single-end reads on 1 core ...", + "", + "=== Summary ===", + "", + "Total reads processed: 100", + "Reads with adapters: 31 (31.0%)", + "Reads written (passing filters): 100 (100.0%)", + "", + "Total basepairs processed: 13,897 bp", + "Quality-trimmed: 0 bp (0.0%)", + "Total written (filtered): 13,851 bp (99.7%)", + "", + "=== Adapter 1 ===", + "", + "Sequence: AGATCGGAAGAGC; Type: regular 3'; Length: 13; Trimmed: 31 times", + "", + "Minimum overlap: 1", + "No. of allowed errors:", + "1-9 bp: 0; 10-13 bp: 1", + "", + "Bases preceding removed adapters:", + " A: 35.5%", + " C: 25.8%", + " G: 9.7%", + " T: 29.0%", + " none/other: 0.0%", + "", + "Overview of removed sequences", + "length\tcount\texpect\tmax.err\terror counts", + "1\t19\t25.0\t0\t19", + "2\t10\t6.2\t0\t10", + "3\t1\t1.6\t0\t1", + "4\t1\t0.4\t0\t1", + "", + "RUN STATISTICS FOR INPUT FILE: test_1.fastq.gz", + "=============================================", + "100 sequences processed in total", + "" + ], + [ + "", + "SUMMARISING RUN PARAMETERS", + "==========================", + "Input filename: test_2.fastq.gz", + "Trimming mode: paired-end", + "Trim Galore version: 0.6.10", + "Cutadapt version: 5.2", + "Number of cores used for trimming: 1", + "Quality Phred score cutoff: 20", + "Quality encoding type selected: ASCII+33" + ], + [ + "Defaulting to Illumina universal adapter ( AGATCGGAAGAGC ). Specify -a SEQUENCE to avoid this behavior).", + "Adapter sequence: 'AGATCGGAAGAGC' (Illumina TruSeq, Sanger iPCR; default (inconclusive auto-detection))", + "Maximum trimming error rate: 0.1 (default)", + "Minimum required adapter overlap (stringency): 1 bp", + "Minimum required sequence length for both reads before a sequence pair gets removed: 20 bp", + "Output file will be GZIP compressed", + "", + "", + "This is cutadapt 5.2 with Python 3.12.12", + "Command line parameters: -j 1 -e 0.1 -q 20 -O 1 -a AGATCGGAAGAGC test_2.fastq.gz", + "Processing single-end reads on 1 core ...", + "", + "=== Summary ===", + "", + "Total reads processed: 100", + "Reads with adapters: 40 (40.0%)", + "Reads written (passing filters): 100 (100.0%)", + "", + "Total basepairs processed: 13,748 bp", + "Quality-trimmed: 0 bp (0.0%)", + "Total written (filtered): 13,693 bp (99.6%)", + "", + "=== Adapter 1 ===", + "", + "Sequence: AGATCGGAAGAGC; Type: regular 3'; Length: 13; Trimmed: 40 times", + "", + "Minimum overlap: 1", + "No. of allowed errors:", + "1-9 bp: 0; 10-13 bp: 1", + "", + "Bases preceding removed adapters:", + " A: 35.0%", + " C: 25.0%", + " G: 5.0%", + " T: 35.0%", + " none/other: 0.0%", + "", + "Overview of removed sequences", + "length\tcount\texpect\tmax.err\terror counts", + "1\t28\t25.0\t0\t28", + "2\t10\t6.2\t0\t10", + "3\t1\t1.6\t0\t1", + "4\t1\t0.4\t0\t1", + "", + "RUN STATISTICS FOR INPUT FILE: test_2.fastq.gz", + "=============================================", + "100 sequences processed in total", + "", + "Total number of sequences analysed for the sequence pair length validation: 100", + "" + ], + { + "versions_trimgalore": [ + [ + "TRIMGALORE", + "trimgalore", + "0.6.10" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-15T14:39:43.937555685" + }, + "sarscov2 - fastq - single-end": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test_trimmed.fq.gz:md5,566d44cca0d22c522d6cf0e50c7165dc" + ] + ], + [ + "", + "SUMMARISING RUN PARAMETERS", + "==========================", + "Input filename: test.fastq.gz", + "Trimming mode: single-end", + "Trim Galore version: 0.6.10", + "Cutadapt version: 5.2", + "Number of cores used for trimming: 1", + "Quality Phred score cutoff: 20", + "Quality encoding type selected: ASCII+33" + ], + [ + "Defaulting to Illumina universal adapter ( AGATCGGAAGAGC ). Specify -a SEQUENCE to avoid this behavior).", + "Adapter sequence: 'AGATCGGAAGAGC' (Illumina TruSeq, Sanger iPCR; default (inconclusive auto-detection))", + "Maximum trimming error rate: 0.1 (default)", + "Minimum required adapter overlap (stringency): 1 bp", + "Minimum required sequence length before a sequence gets removed: 20 bp", + "Output file will be GZIP compressed", + "", + "", + "This is cutadapt 5.2 with Python 3.12.12", + "Command line parameters: -j 1 -e 0.1 -q 20 -O 1 -a AGATCGGAAGAGC test.fastq.gz", + "Processing single-end reads on 1 core ...", + "", + "=== Summary ===", + "", + "Total reads processed: 100", + "Reads with adapters: 31 (31.0%)", + "Reads written (passing filters): 100 (100.0%)", + "", + "Total basepairs processed: 13,897 bp", + "Quality-trimmed: 0 bp (0.0%)", + "Total written (filtered): 13,851 bp (99.7%)", + "", + "=== Adapter 1 ===", + "", + "Sequence: AGATCGGAAGAGC; Type: regular 3'; Length: 13; Trimmed: 31 times", + "", + "Minimum overlap: 1", + "No. of allowed errors:", + "1-9 bp: 0; 10-13 bp: 1", + "", + "Bases preceding removed adapters:", + " A: 35.5%", + " C: 25.8%", + " G: 9.7%", + " T: 29.0%", + " none/other: 0.0%", + "", + "Overview of removed sequences", + "length\tcount\texpect\tmax.err\terror counts", + "1\t19\t25.0\t0\t19", + "2\t10\t6.2\t0\t10", + "3\t1\t1.6\t0\t1", + "4\t1\t0.4\t0\t1", + "", + "RUN STATISTICS FOR INPUT FILE: test.fastq.gz", + "=============================================", + "100 sequences processed in total", + "Sequences removed because they became shorter than the length cutoff of 20 bp:\t0 (0.0%)", + "" + ], + { + "versions_trimgalore": [ + [ + "TRIMGALORE", + "trimgalore", + "0.6.10" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-15T14:39:33.985021562" + } +} \ No newline at end of file diff --git a/modules/nf-core/trimgalore/tests/nextflow.config b/modules/nf-core/trimgalore/tests/nextflow.config new file mode 100644 index 00000000..d8e3ac13 --- /dev/null +++ b/modules/nf-core/trimgalore/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: TRIMGALORE { + ext.args = params.module_args + } +} From bdee18067d9b066da073ca61584aefd4c367ee03 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Feb 2026 13:56:36 +0100 Subject: [PATCH 24/55] Add clip trimming --- conf/modules.config | 8 ++++++-- modules.json | 5 +++++ workflows/hic.nf | 11 +++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 6794534d..223fda92 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -10,6 +10,10 @@ process { ext.args = '--quiet' } + withName: TRIMGALORE { + ext.args = '--clip_R1 5 --clip_R2 5' + } + withName: 'MULTIQC' { ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } publishDir = [ @@ -281,8 +285,8 @@ process { params.min_cis_dist > 0 ? " and ((chrom1==chrom2 and abs(pos1-pos2) > ${params.min_cis_dist}) or chrom1!=chrom2)" : '', params.keep_multi ? " and ((pair_type.upper()=='UU') or (pair_type.upper()=='UR') or (pair_type.upper()=='RU') or (pair_type.upper()=='MM') or (pair_type.upper()=='MU'))" : " and ((pair_type.upper()=='UU') or (pair_type.upper()=='UR') or (pair_type.upper()=='RU'))", params.no_digestion ? '' : " and ((chrom1==chrom2 and abs(int(rfrag1) - int(rfrag2)) > 1) or chrom1!=chrom2)", - //params.min_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) > ${params.min_insert_size}" : '', - //params.max_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) < ${params.max_insert_size}" : '', + params.min_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) > ${params.min_insert_size}" : '', + params.max_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) < ${params.max_insert_size}" : '', //params.min_restriction_fragment_size > 0 ? " -t ${params.min_restriction_fragment_size}" : '', //params.max_restriction_fragment_size > 0 ? " -m ${params.max_restriction_fragment_size}" : '', ].join(' ').trim() } diff --git a/modules.json b/modules.json index 390d8610..7f3baa5f 100644 --- a/modules.json +++ b/modules.json @@ -124,6 +124,11 @@ "branch": "master", "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", "installed_by": ["modules"] + }, + "trimgalore": { + "branch": "master", + "git_sha": "1b32b48b7d2803ae78a1beb20b7e9657dbcda776", + "installed_by": ["modules"] } } }, diff --git a/workflows/hic.nf b/workflows/hic.nf index b821a36e..d6a94f9a 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -19,6 +19,7 @@ include { PAIRTOOLS } from '../subworkflows/local/pairtools' include { COOLER } from '../subworkflows/local/cooler' include { COMPARTMENTS } from '../subworkflows/local/compartments' include { TADS } from '../subworkflows/local/tads' +include { TRIMGALORE } from '../modules/nf-core/trimgalore/main.nf' //**************************************** // Combine all maps resolution for downstream analysis @@ -90,6 +91,16 @@ workflow HIC { ch_samplesheet ) ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) + + // + // MODULE: Run trimgalore + // + if (params.digestion == 'arimaV2'){ + TRIMGALORE ( + ch_samplesheet + ) + ch_samplesheet = TRIMGALORE.out.reads + } // // SUB-WORFLOW: HiC-Pro From 59eec1ec08819a6592f453e716ffe0ea182c363c Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Wed, 11 Feb 2026 16:04:22 +0100 Subject: [PATCH 25/55] Fix cooler add resolution step --- subworkflows/local/cooler/main.nf | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/subworkflows/local/cooler/main.nf b/subworkflows/local/cooler/main.nf index f737e20f..4c62d27d 100644 --- a/subworkflows/local/cooler/main.nf +++ b/subworkflows/local/cooler/main.nf @@ -12,14 +12,6 @@ include { COOLER_MAKEBINS } from '../../../modules/nf-core/cooler/makebins/main' include { SPLIT_COOLER_DUMP } from '../../../modules/local/split_cooler_dump' -// add resolution in meta -def addResolution(row) { - def meta = [:] - meta.id = row[0].id - meta.resolution = row[2] - return [meta, row[1], row[2]] -} - workflow COOLER { take: @@ -51,8 +43,11 @@ workflow COOLER { // Add resolution in meta COOLER_CLOAD.out.cool - .map{ it -> addResolution(it) } - .set{ ch_cool } + .combine(cool_bins) + .map { meta, file, res -> + [meta + [resolution: res], file] + } + .set { ch_cool } COOLER_BALANCE( ch_cool.map{[it[0], it[1], ""]} From f1d09933a4f574a56703e24053630403b45c2d3b Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Wed, 11 Feb 2026 16:07:38 +0100 Subject: [PATCH 26/55] Add chromosomes size filtering module --- modules/local/filter_chromsize/main.nf | 20 ++++++++++++++++++++ subworkflows/local/cooler/main.nf | 8 ++++++++ 2 files changed, 28 insertions(+) create mode 100644 modules/local/filter_chromsize/main.nf diff --git a/modules/local/filter_chromsize/main.nf b/modules/local/filter_chromsize/main.nf new file mode 100644 index 00000000..947d49aa --- /dev/null +++ b/modules/local/filter_chromsize/main.nf @@ -0,0 +1,20 @@ +/* + * Filter chromsize + * Filter out chromosomes smaller than a given threshold + */ + +process FILTER_CHROMSIZE { + tag "${meta.id}" + label 'process_low' + + input: + tuple val(meta), path(sizes_file) + + output: + tuple val(meta), path("filtered.sizes") + + script: + """ + awk -v MIN=${params.min_size} '\$2 >= MIN' ${sizes_file} > filtered.sizes + """ +} diff --git a/subworkflows/local/cooler/main.nf b/subworkflows/local/cooler/main.nf index 4c62d27d..949fe8c2 100644 --- a/subworkflows/local/cooler/main.nf +++ b/subworkflows/local/cooler/main.nf @@ -10,6 +10,7 @@ include { COOLER_CLOAD } from '../../../modules/nf-core/cooler/cload/main' include { COOLER_BALANCE } from '../../../modules/nf-core/cooler/balance/main' include { COOLER_MAKEBINS } from '../../../modules/nf-core/cooler/makebins/main' +include { FILTER_CHROMSIZE } from '../../../modules/local/filter_chromsize' include { SPLIT_COOLER_DUMP } from '../../../modules/local/split_cooler_dump' workflow COOLER { @@ -22,6 +23,13 @@ workflow COOLER { main: ch_versions = channel.empty() + //***************************************** + // FILTER CHROMOSOMES ON SIZE + + if( params.min_size ) { + chromsize = chromsize | FILTER_CHROMSIZE + } + //***************************************** // EXPORT BINS From 1db353aea4d4cd3bc2f71012d58c3c0fce47c091 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Thu, 12 Feb 2026 09:41:24 +0100 Subject: [PATCH 27/55] Fix modules order --- workflows/hic.nf | 102 ++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/workflows/hic.nf b/workflows/hic.nf index d6a94f9a..bc6d6e4e 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -21,48 +21,6 @@ include { COMPARTMENTS } from '../subworkflows/local/compartments' include { TADS } from '../subworkflows/local/tads' include { TRIMGALORE } from '../modules/nf-core/trimgalore/main.nf' -//**************************************** -// Combine all maps resolution for downstream analysis - -ch_map_res = channel.from( params.bin_size.toString()).splitCsv().flatten().toInteger() - -if (params.res_zoomify){ - ch_zoom_res = channel.from( params.res_zoomify ).splitCsv().flatten().toInteger() - ch_map_res = ch_map_res.concat(ch_zoom_res) -} - -if (params.res_tads && !params.skip_tads){ - ch_tads_res = channel.from( "${params.res_tads}" ).splitCsv().flatten().toInteger() - ch_map_res = ch_map_res.concat(ch_tads_res) -}else{ - ch_tads_res=channel.empty() - if (!params.skip_tads){ - log.warn "[nf-core/hic] Hi-C resolution for TADs calling not specified. See --res_tads" - } -} - -if (params.res_dist_decay && !params.skip_dist_decay){ - ch_ddecay_res = channel.from( "${params.res_dist_decay}" ).splitCsv().flatten().toInteger() - ch_map_res = ch_map_res.concat(ch_ddecay_res) -}else{ - ch_ddecay_res = channel.empty() - if (!params.skip_dist_decay){ - log.warn "[nf-core/hic] Hi-C resolution for distance decay not specified. See --res_dist_decay" - } -} - -if (params.res_compartments && !params.skip_compartments){ - ch_comp_res = channel.from( "${params.res_compartments}" ).splitCsv().flatten().toInteger() - ch_map_res = ch_map_res.concat(ch_comp_res) -}else{ - ch_comp_res = channel.empty() - if (!params.skip_compartments){ - log.warn "[nf-core/hic] Hi-C resolution for compartment calling not specified. See --res_compartments" - } -} - -ch_map_res = ch_map_res.unique() - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RUN MAIN WORKFLOW @@ -82,16 +40,51 @@ workflow HIC { main: + //**************************************** + // Combine all maps resolution for downstream analysis + + ch_map_res = channel.from( params.bin_size.toString()).splitCsv().flatten().toInteger() + + if (params.res_zoomify){ + ch_zoom_res = channel.from( params.res_zoomify ).splitCsv().flatten().toInteger() + ch_map_res = ch_map_res.concat(ch_zoom_res) + } + + if (params.res_tads && !params.skip_tads){ + ch_tads_res = channel.from( "${params.res_tads}" ).splitCsv().flatten().toInteger() + ch_map_res = ch_map_res.concat(ch_tads_res) + }else{ + ch_tads_res=channel.empty() + if (!params.skip_tads){ + log.warn "[nf-core/hic] Hi-C resolution for TADs calling not specified. See --res_tads" + } + } + + if (params.res_dist_decay && !params.skip_dist_decay){ + ch_ddecay_res = channel.from( "${params.res_dist_decay}" ).splitCsv().flatten().toInteger() + ch_map_res = ch_map_res.concat(ch_ddecay_res) + }else{ + ch_ddecay_res = channel.empty() + if (!params.skip_dist_decay){ + log.warn "[nf-core/hic] Hi-C resolution for distance decay not specified. See --res_dist_decay" + } + } + + if (params.res_compartments && !params.skip_compartments){ + ch_comp_res = channel.from( "${params.res_compartments}" ).splitCsv().flatten().toInteger() + ch_map_res = ch_map_res.concat(ch_comp_res) + }else{ + ch_comp_res = channel.empty() + if (!params.skip_compartments){ + log.warn "[nf-core/hic] Hi-C resolution for compartment calling not specified. See --res_compartments" + } + } + + ch_map_res = ch_map_res.unique() + 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]}) - + // // MODULE: Run trimgalore // @@ -101,6 +94,15 @@ workflow HIC { ) ch_samplesheet = TRIMGALORE.out.reads } + + // + // MODULE: Run FastQC + // + FASTQC ( + ch_samplesheet + ) + ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) + // // SUB-WORFLOW: HiC-Pro From 01c33ce8d65bc288965160c2ff333d596607f1fa Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Thu, 12 Feb 2026 09:50:15 +0100 Subject: [PATCH 28/55] Update nfcore modules with topic channels --- modules.json | 36 +- 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/bowtie2/build/main.nf | 11 +- modules/nf-core/bowtie2/build/meta.yml | 30 +- .../nf-core/bowtie2/build/tests/main.nf.test | 9 +- .../bowtie2/build/tests/main.nf.test.snap | 56 +-- modules/nf-core/bwa/index/main.nf | 15 +- modules/nf-core/bwa/index/meta.yml | 27 +- modules/nf-core/bwa/index/tests/main.nf.test | 26 +- .../nf-core/bwa/index/tests/main.nf.test.snap | 73 +++- modules/nf-core/bwa/mem/tests/main.nf.test | 5 - .../nf-core/bwa/mem/tests/main.nf.test.snap | 35 +- modules/nf-core/cooler/balance/main.nf | 11 +- modules/nf-core/cooler/balance/meta.yml | 29 +- .../nf-core/cooler/balance/tests/main.nf.test | 7 +- .../cooler/balance/tests/main.nf.test.snap | 47 ++- modules/nf-core/cooler/cload/main.nf | 12 +- modules/nf-core/cooler/cload/meta.yml | 26 +- .../nf-core/cooler/cload/tests/main.nf.test | 11 +- .../cooler/cload/tests/main.nf.test.snap | 83 ++-- modules/nf-core/cooler/dump/main.nf | 12 +- modules/nf-core/cooler/dump/meta.yml | 26 +- .../nf-core/cooler/dump/tests/main.nf.test | 10 +- .../cooler/dump/tests/main.nf.test.snap | 52 +-- modules/nf-core/cooler/makebins/main.nf | 13 +- modules/nf-core/cooler/makebins/meta.yml | 26 +- .../cooler/makebins/tests/main.nf.test.snap | 40 +- modules/nf-core/cooler/zoomify/main.nf | 12 +- modules/nf-core/cooler/zoomify/meta.yml | 26 +- .../nf-core/cooler/zoomify/tests/main.nf.test | 7 +- .../cooler/zoomify/tests/main.nf.test.snap | 47 ++- modules/nf-core/fastqc/main.nf | 2 +- modules/nf-core/fastqc/meta.yml | 37 +- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 8 +- modules/nf-core/multiqc/meta.yml | 51 ++- .../nf-core/multiqc/tests/main.nf.test.snap | 30 +- modules/nf-core/samtools/faidx/main.nf | 16 +- modules/nf-core/samtools/faidx/meta.yml | 38 +- .../nf-core/samtools/faidx/tests/main.nf.test | 178 ++++---- .../samtools/faidx/tests/main.nf.test.snap | 369 ++++------------- .../samtools/faidx/tests/nextflow.config | 2 +- .../samtools/faidx/tests/nextflow2.config | 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/index/main.nf | 12 +- modules/nf-core/samtools/index/meta.yml | 29 +- .../nf-core/samtools/index/tests/main.nf.test | 27 +- .../samtools/index/tests/main.nf.test.snap | 278 +++++-------- modules/nf-core/samtools/sort/meta.yml | 1 + modules/nf-core/trimgalore/main.nf | 2 +- .../nf-core/utils_nfcore_pipeline/main.nf | 2 +- .../nf-core/utils_nfschema_plugin/main.nf | 2 +- .../tests/nextflow.config | 2 +- 58 files changed, 1366 insertions(+), 1125 deletions(-) delete mode 100644 modules/nf-core/samtools/faidx/tests/nextflow2.config diff --git a/modules.json b/modules.json index 7f3baa5f..a30b71c4 100644 --- a/modules.json +++ b/modules.json @@ -7,22 +7,22 @@ "nf-core": { "bowtie2/align": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "ab146e7909edbf6dcc6459de57eef29dceb61d42", "installed_by": ["modules"] }, "bowtie2/build": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "447f7bc0fa41dfc2400c8cad4c0291880dc060cf", "installed_by": ["modules"] }, "bwa/index": { "branch": "master", - "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", + "git_sha": "966ba9887e2b04d89d64db06c01508873bde13b1", "installed_by": ["modules"] }, "bwa/mem": { "branch": "master", - "git_sha": "1c46359c837ef768b004519f535c30378e8289fc", + "git_sha": "966ba9887e2b04d89d64db06c01508873bde13b1", "installed_by": ["modules"] }, "calder2": { @@ -32,37 +32,37 @@ }, "cooler/balance": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "5d491ae33d61ab37e13850951b92ae7d6e3f4e31", "installed_by": ["modules"] }, "cooler/cload": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "5d491ae33d61ab37e13850951b92ae7d6e3f4e31", "installed_by": ["modules"] }, "cooler/dump": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "5d491ae33d61ab37e13850951b92ae7d6e3f4e31", "installed_by": ["modules"] }, "cooler/makebins": { "branch": "master", - "git_sha": "679deaa32d2862bec641ddaf463e8d8fd9119baf", + "git_sha": "5d491ae33d61ab37e13850951b92ae7d6e3f4e31", "installed_by": ["modules"] }, "cooler/zoomify": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "5d491ae33d61ab37e13850951b92ae7d6e3f4e31", "installed_by": ["modules"] }, "fastqc": { "branch": "master", - "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", + "git_sha": "3009f27c4e4b6e99da4eeebe82799e13924a4a1f", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", + "git_sha": "575e1a4b51a9bad7a8cd1316a88fb85684ef7c7b", "installed_by": ["modules"] }, "pairix": { @@ -107,27 +107,27 @@ }, "samtools/faidx": { "branch": "master", - "git_sha": "e753770db613ce014b3c4bc94f6cba443427b726", + "git_sha": "b2e78932ef01165fd85829513eaca29eff8e640a", "installed_by": ["modules"] }, "samtools/flagstat": { "branch": "master", - "git_sha": "e334e12a1e985adc5ffc3fc78a68be1de711de45", + "git_sha": "1d2fbdcbca677bbe8da0f9d0d2bb7c02f2cab1c9", "installed_by": ["modules"] }, "samtools/index": { "branch": "master", - "git_sha": "c8be52dba1166c678e74cda9c3a3c221635c8bb1", + "git_sha": "1d2fbdcbca677bbe8da0f9d0d2bb7c02f2cab1c9", "installed_by": ["modules"] }, "samtools/sort": { "branch": "master", - "git_sha": "0b2435805036a16dcdcf21533632d956b8273ac4", + "git_sha": "5cb9a8694da0a0e550921636bb60bc8c56445fd7", "installed_by": ["modules"] }, "trimgalore": { "branch": "master", - "git_sha": "1b32b48b7d2803ae78a1beb20b7e9657dbcda776", + "git_sha": "eed5d14302a6c9070dcc25feeab707a27a4b3254", "installed_by": ["modules"] } } @@ -141,12 +141,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/bowtie2/align/main.nf b/modules/nf-core/bowtie2/align/main.nf index 631d0bf7..4264bb2c 100644 --- a/modules/nf-core/bowtie2/align/main.nf +++ b/modules/nf-core/bowtie2/align/main.nf @@ -22,7 +22,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 @@ -70,13 +72,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: @@ -104,13 +99,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/bowtie2/build/main.nf b/modules/nf-core/bowtie2/build/main.nf index fb7effec..1be06ac8 100644 --- a/modules/nf-core/bowtie2/build/main.nf +++ b/modules/nf-core/bowtie2/build/main.nf @@ -12,7 +12,7 @@ process BOWTIE2_BUILD { output: tuple val(meta), path('bowtie2') , emit: index - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('bowtie2'), eval('bowtie2 --version 2>&1 | head -1 | sed "s/^.*bowtie2-align-s version //; s/ .*//"'), emit: versions_bowtie2, topic: versions when: task.ext.when == null || task.ext.when @@ -22,10 +22,6 @@ process BOWTIE2_BUILD { """ mkdir bowtie2 bowtie2-build $args --threads $task.cpus $fasta bowtie2/${fasta.baseName} - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bowtie2: \$(echo \$(bowtie2 --version 2>&1) | sed 's/^.*bowtie2-align-s version //; s/ .*\$//') - END_VERSIONS """ stub: @@ -33,10 +29,5 @@ process BOWTIE2_BUILD { mkdir bowtie2 touch bowtie2/${fasta.baseName}.{1..4}.bt2 touch bowtie2/${fasta.baseName}.rev.{1,2}.bt2 - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bowtie2: \$(echo \$(bowtie2 --version 2>&1) | sed 's/^.*bowtie2-align-s version //; s/ .*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/bowtie2/build/meta.yml b/modules/nf-core/bowtie2/build/meta.yml index 3e83ecb4..3a9d31cf 100644 --- a/modules/nf-core/bowtie2/build/meta.yml +++ b/modules/nf-core/bowtie2/build/meta.yml @@ -34,17 +34,33 @@ output: Groovy Map containing reference information e.g. [ id:'test', single_end:false ] - bowtie2: - type: file + type: directory description: Bowtie2 genome index files pattern: "*.bt2" ontologies: [] + 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 | head -1 | sed "s/^.*bowtie2-align-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 + - bowtie2: + type: string + description: The name of the tool + - 'bowtie2 --version 2>&1 | head -1 | sed "s/^.*bowtie2-align-s version //; s/ .*//"': + type: eval + description: The expression to obtain the version of the tool + authors: - "@joseespinosa" - "@drpatelh" diff --git a/modules/nf-core/bowtie2/build/tests/main.nf.test b/modules/nf-core/bowtie2/build/tests/main.nf.test index ee94c19c..a4bad2a1 100644 --- a/modules/nf-core/bowtie2/build/tests/main.nf.test +++ b/modules/nf-core/bowtie2/build/tests/main.nf.test @@ -22,8 +22,13 @@ nextflow_process { } then { - assert process.success - assert snapshot(process.out).match() + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.index, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } + ) } } diff --git a/modules/nf-core/bowtie2/build/tests/main.nf.test.snap b/modules/nf-core/bowtie2/build/tests/main.nf.test.snap index ea5711e4..9f1bf080 100644 --- a/modules/nf-core/bowtie2/build/tests/main.nf.test.snap +++ b/modules/nf-core/bowtie2/build/tests/main.nf.test.snap @@ -1,49 +1,35 @@ { "Should run without failures": { "content": [ - { - "0": [ + [ + [ + { + "id": "test" + }, [ - { - "id": "test" - }, - [ - "genome.1.bt2:md5,cbe3d0bbea55bc57c99b4bfa25b5fbdf", - "genome.2.bt2:md5,47b153cd1319abc88dda532462651fcf", - "genome.3.bt2:md5,4ed93abba181d8dfab2e303e33114777", - "genome.4.bt2:md5,c25be5f8b0378abf7a58c8a880b87626", - "genome.rev.1.bt2:md5,52be6950579598a990570fbcf5372184", - "genome.rev.2.bt2:md5,e3b4ef343dea4dd571642010a7d09597" - ] + "genome.1.bt2:md5,cbe3d0bbea55bc57c99b4bfa25b5fbdf", + "genome.2.bt2:md5,47b153cd1319abc88dda532462651fcf", + "genome.3.bt2:md5,4ed93abba181d8dfab2e303e33114777", + "genome.4.bt2:md5,c25be5f8b0378abf7a58c8a880b87626", + "genome.rev.1.bt2:md5,52be6950579598a990570fbcf5372184", + "genome.rev.2.bt2:md5,e3b4ef343dea4dd571642010a7d09597" ] - ], - "1": [ - "versions.yml:md5,d136fb9c16f0a9fb2ae804b2a5fbc09c" - ], - "index": [ + ] + ], + { + "versions_bowtie2": [ [ - { - "id": "test" - }, - [ - "genome.1.bt2:md5,cbe3d0bbea55bc57c99b4bfa25b5fbdf", - "genome.2.bt2:md5,47b153cd1319abc88dda532462651fcf", - "genome.3.bt2:md5,4ed93abba181d8dfab2e303e33114777", - "genome.4.bt2:md5,c25be5f8b0378abf7a58c8a880b87626", - "genome.rev.1.bt2:md5,52be6950579598a990570fbcf5372184", - "genome.rev.2.bt2:md5,e3b4ef343dea4dd571642010a7d09597" - ] + "BOWTIE2_BUILD", + "bowtie2", + "2.5.4" ] - ], - "versions": [ - "versions.yml:md5,d136fb9c16f0a9fb2ae804b2a5fbc09c" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.02.1" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2023-11-23T11:51:01.107681997" + "timestamp": "2026-01-28T17:52:30.165111" } } \ No newline at end of file diff --git a/modules/nf-core/bwa/index/main.nf b/modules/nf-core/bwa/index/main.nf index 1860ecfa..6be2c43b 100644 --- a/modules/nf-core/bwa/index/main.nf +++ b/modules/nf-core/bwa/index/main.nf @@ -13,8 +13,8 @@ process BWA_INDEX { tuple val(meta), path(fasta) output: - tuple val(meta), path("bwa") , emit: index - path "versions.yml" , emit: versions + tuple val(meta), path("bwa"), emit: index + tuple val("${task.process}"), val('bwa'), eval('bwa 2>&1 | sed -n "s/^Version: //p"'), topic: versions, emit: versions_bwa when: task.ext.when == null || task.ext.when @@ -29,27 +29,16 @@ process BWA_INDEX { $args \\ -p bwa/${prefix} \\ $fasta - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bwa: \$(echo \$(bwa 2>&1) | sed 's/^.*Version: //; s/Contact:.*\$//') - END_VERSIONS """ stub: def prefix = task.ext.prefix ?: "${fasta.baseName}" """ mkdir bwa - touch bwa/${prefix}.amb touch bwa/${prefix}.ann touch bwa/${prefix}.bwt touch bwa/${prefix}.pac touch bwa/${prefix}.sa - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - bwa: \$(echo \$(bwa 2>&1) | sed 's/^.*Version: //; s/Contact:.*\$//') - END_VERSIONS """ } diff --git a/modules/nf-core/bwa/index/meta.yml b/modules/nf-core/bwa/index/meta.yml index 1781586f..f5bf7f52 100644 --- a/modules/nf-core/bwa/index/meta.yml +++ b/modules/nf-core/bwa/index/meta.yml @@ -42,17 +42,30 @@ output: pattern: "*.{amb,ann,bwt,pac,sa}" ontologies: - edam: "http://edamontology.org/data_3210" # Genome index + versions_bwa: + - - ${task.process}: + type: string + description: The process the versions were collected from + - bwa: + type: string + description: The tool name + - 'bwa 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 + - bwa: + type: string + description: The tool name + - 'bwa 2>&1 | sed -n "s/^Version: //p"': + type: string + description: The command used to generate the version of the tool authors: - "@drpatelh" - "@maxulysse" maintainers: - - "@drpatelh" - "@maxulysse" - "@gallvp" diff --git a/modules/nf-core/bwa/index/tests/main.nf.test b/modules/nf-core/bwa/index/tests/main.nf.test index af33e73c..f0fba82a 100644 --- a/modules/nf-core/bwa/index/tests/main.nf.test +++ b/modules/nf-core/bwa/index/tests/main.nf.test @@ -22,8 +22,32 @@ nextflow_process { } then { + assert process.success + assertAll( + { assert snapshot(process.out).match() } + ) + } + + } + + test("BWA index - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [id: 'test'], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success assertAll( - { assert process.success }, { assert snapshot(process.out).match() } ) } diff --git a/modules/nf-core/bwa/index/tests/main.nf.test.snap b/modules/nf-core/bwa/index/tests/main.nf.test.snap index 8fdb482a..21a6f73c 100644 --- a/modules/nf-core/bwa/index/tests/main.nf.test.snap +++ b/modules/nf-core/bwa/index/tests/main.nf.test.snap @@ -1,4 +1,57 @@ { + "BWA index - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + [ + "genome.amb:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.ann:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.bwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.pac:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.sa:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "1": [ + [ + "BWA_INDEX", + "bwa", + "0.7.19-r1273" + ] + ], + "index": [ + [ + { + "id": "test" + }, + [ + "genome.amb:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.ann:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.bwt:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.pac:md5,d41d8cd98f00b204e9800998ecf8427e", + "genome.sa:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions_bwa": [ + [ + "BWA_INDEX", + "bwa", + "0.7.19-r1273" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-23T16:58:59.966558606" + }, "BWA index": { "content": [ { @@ -17,7 +70,11 @@ ] ], "1": [ - "versions.yml:md5,9a94c646009e4e01912bde135de16400" + [ + "BWA_INDEX", + "bwa", + "0.7.19-r1273" + ] ], "index": [ [ @@ -33,15 +90,19 @@ ] ] ], - "versions": [ - "versions.yml:md5,9a94c646009e4e01912bde135de16400" + "versions_bwa": [ + [ + "BWA_INDEX", + "bwa", + "0.7.19-r1273" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-23T11:05:03.657185748" + "timestamp": "2026-01-23T16:58:53.330725134" } } \ 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/cooler/balance/main.nf b/modules/nf-core/cooler/balance/main.nf index 4296bdb3..547da95a 100644 --- a/modules/nf-core/cooler/balance/main.nf +++ b/modules/nf-core/cooler/balance/main.nf @@ -12,7 +12,7 @@ process COOLER_BALANCE { output: tuple val(meta), path("${prefix}.${extension}"), emit: cool - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('cooler'), eval('cooler --version 2>&1 | sed "s/cooler, version //"'), emit: versions_cooler, topic: versions when: task.ext.when == null || task.ext.when @@ -30,11 +30,6 @@ process COOLER_BALANCE { $args \\ -p ${task.cpus} \\ ${prefix}.${extension}${suffix} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ stub: @@ -44,9 +39,5 @@ process COOLER_BALANCE { def creation_cmd = suffix.endsWith(".gz") ? "echo '' | gzip -c >" : "touch" """ ${creation_cmd} ${prefix}.${extension}${suffix} - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ } diff --git a/modules/nf-core/cooler/balance/meta.yml b/modules/nf-core/cooler/balance/meta.yml index 02dac67e..06acdd2a 100644 --- a/modules/nf-core/cooler/balance/meta.yml +++ b/modules/nf-core/cooler/balance/meta.yml @@ -11,7 +11,8 @@ tools: documentation: https://cooler.readthedocs.io/en/latest/index.html tool_dev_url: https://github.com/open2c/cooler doi: "10.1093/bioinformatics/btz540" - licence: ["BSD-3-Clause"] + licence: + - "BSD-3-Clause" identifier: "" input: - - meta: @@ -39,13 +40,27 @@ output: description: Output COOL file balancing weights pattern: "*.cool" ontologies: [] + versions_cooler: + - - ${task.process}: + type: string + description: The name of the process + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, 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 + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, version //": + type: eval + description: The expression to obtain the version of the tool authors: - "@nservant" - "@muffato" diff --git a/modules/nf-core/cooler/balance/tests/main.nf.test b/modules/nf-core/cooler/balance/tests/main.nf.test index 35940575..a9e591b3 100644 --- a/modules/nf-core/cooler/balance/tests/main.nf.test +++ b/modules/nf-core/cooler/balance/tests/main.nf.test @@ -27,7 +27,7 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions")}, process.out.cool.collect{ file(it[1]).name } ).match() } ) @@ -53,10 +53,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - process.out, - process.out.versions.collect{ path(it).yaml } - ).match() } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/cooler/balance/tests/main.nf.test.snap b/modules/nf-core/cooler/balance/tests/main.nf.test.snap index 7d64d30c..a8e3f6e9 100644 --- a/modules/nf-core/cooler/balance/tests/main.nf.test.snap +++ b/modules/nf-core/cooler/balance/tests/main.nf.test.snap @@ -11,7 +11,11 @@ ] ], "1": [ - "versions.yml:md5,0dd67198104cb35ff26349deab04305e" + [ + "COOLER_BALANCE", + "cooler", + "0.10.4" + ] ], "cool": [ [ @@ -21,37 +25,40 @@ "test.cool:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,0dd67198104cb35ff26349deab04305e" + "versions_cooler": [ + [ + "COOLER_BALANCE", + "cooler", + "0.10.4" + ] ] - }, - [ - { - "COOLER_BALANCE": { - "cooler": "0.10.4" - } - } - ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-17T16:14:41.886977" + "timestamp": "2026-02-10T12:56:53.088011" }, "test_cooler_balance": { "content": [ - [ - "versions.yml:md5,0dd67198104cb35ff26349deab04305e" - ], + { + "versions_cooler": [ + [ + "COOLER_BALANCE", + "cooler", + "0.10.4" + ] + ] + }, [ "test.cool" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-17T16:14:08.908408" + "timestamp": "2026-02-10T12:56:47.719373" } } \ No newline at end of file diff --git a/modules/nf-core/cooler/cload/main.nf b/modules/nf-core/cooler/cload/main.nf index a440db7d..109beac6 100644 --- a/modules/nf-core/cooler/cload/main.nf +++ b/modules/nf-core/cooler/cload/main.nf @@ -15,7 +15,7 @@ process COOLER_CLOAD { output: tuple val(meta), path("*.cool"), emit: cool - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('cooler'), eval('cooler --version 2>&1 | sed "s/cooler, version //"'), emit: versions_cooler, topic: versions when: task.ext.when == null || task.ext.when @@ -31,21 +31,11 @@ process COOLER_CLOAD { ${chromsizes}:${cool_bin} \\ ${contacts} \\ ${prefix}.cool - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ stub: def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.cool - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ } diff --git a/modules/nf-core/cooler/cload/meta.yml b/modules/nf-core/cooler/cload/meta.yml index 4f8593c2..e7a79b15 100644 --- a/modules/nf-core/cooler/cload/meta.yml +++ b/modules/nf-core/cooler/cload/meta.yml @@ -59,13 +59,27 @@ output: description: Output COOL file path pattern: "*.cool" ontologies: [] + versions_cooler: + - - ${task.process}: + type: string + description: The name of the process + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, 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 + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, version //": + type: eval + description: The expression to obtain the version of the tool authors: - "@jianhong" - "@muffato" diff --git a/modules/nf-core/cooler/cload/tests/main.nf.test b/modules/nf-core/cooler/cload/tests/main.nf.test index df6083e0..7ee4ec86 100644 --- a/modules/nf-core/cooler/cload/tests/main.nf.test +++ b/modules/nf-core/cooler/cload/tests/main.nf.test @@ -40,7 +40,7 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions")}, process.out.cool.collect{file(it[1]).name} ).match() } ) @@ -79,7 +79,7 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions")}, process.out.cool.collect{file(it[1]).name} ).match() } ) @@ -118,7 +118,7 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions")}, process.out.cool.collect{file(it[1]).name} ).match() } ) @@ -159,10 +159,7 @@ nextflow_process { assertAll( { assert process.success }, - { assert snapshot( - process.out, - process.out.versions.collect{path(it).yaml} - ).match() } + { assert snapshot(process.out).match() } ) } diff --git a/modules/nf-core/cooler/cload/tests/main.nf.test.snap b/modules/nf-core/cooler/cload/tests/main.nf.test.snap index e42ea735..80476396 100644 --- a/modules/nf-core/cooler/cload/tests/main.nf.test.snap +++ b/modules/nf-core/cooler/cload/tests/main.nf.test.snap @@ -1,48 +1,66 @@ { "test_cooler_cload_pairs": { "content": [ - [ - "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" - ], + { + "versions_cooler": [ + [ + "COOLER_CLOAD", + "cooler", + "0.10.4" + ] + ] + }, [ "test_pairs.cool" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-08-07T13:29:49.554886524" + "timestamp": "2026-02-10T12:57:13.675799" }, "test_cooler_cload_tabix": { "content": [ - [ - "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" - ], + { + "versions_cooler": [ + [ + "COOLER_CLOAD", + "cooler", + "0.10.4" + ] + ] + }, [ "test_tabix.cool" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-08-07T13:30:07.963246077" + "timestamp": "2026-02-10T12:57:23.827346" }, "test_cooler_cload_pairix": { "content": [ - [ - "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" - ], + { + "versions_cooler": [ + [ + "COOLER_CLOAD", + "cooler", + "0.10.4" + ] + ] + }, [ "test_pairix.cool" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-08-07T13:29:32.981383309" + "timestamp": "2026-02-10T12:57:05.111461" }, "test_cooler_cload_pairix - stub": { "content": [ @@ -57,7 +75,11 @@ ] ], "1": [ - "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" + [ + "COOLER_CLOAD", + "cooler", + "0.10.4" + ] ], "cool": [ [ @@ -68,22 +90,19 @@ "test_pairix.cool:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,57207f2d703f224af29472bbcc6d1c35" + "versions_cooler": [ + [ + "COOLER_CLOAD", + "cooler", + "0.10.4" + ] ] - }, - [ - { - "COOLER_CLOAD": { - "cooler": "0.10.4" - } - } - ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-08-07T13:30:28.269060239" + "timestamp": "2026-02-10T12:57:29.005184" } } \ No newline at end of file diff --git a/modules/nf-core/cooler/dump/main.nf b/modules/nf-core/cooler/dump/main.nf index d2d2cfc6..ea179835 100644 --- a/modules/nf-core/cooler/dump/main.nf +++ b/modules/nf-core/cooler/dump/main.nf @@ -12,7 +12,7 @@ process COOLER_DUMP { output: tuple val(meta), path("*.bedpe"), emit: bedpe - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('cooler'), eval('cooler --version 2>&1 | sed "s/cooler, version //"'), emit: versions_cooler, topic: versions when: task.ext.when == null || task.ext.when @@ -26,21 +26,11 @@ process COOLER_DUMP { ${args} \\ -o ${prefix}.bedpe \\ ${cool}${suffix} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ stub: def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.bedpe - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ } diff --git a/modules/nf-core/cooler/dump/meta.yml b/modules/nf-core/cooler/dump/meta.yml index da621d36..c77992c3 100644 --- a/modules/nf-core/cooler/dump/meta.yml +++ b/modules/nf-core/cooler/dump/meta.yml @@ -39,13 +39,27 @@ output: description: Output text file pattern: "*.bedpe" ontologies: [] + versions_cooler: + - - ${task.process}: + type: string + description: The name of the process + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, 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 + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, version //": + type: eval + description: The expression to obtain the version of the tool authors: - "@jianhong" - "@muffato" diff --git a/modules/nf-core/cooler/dump/tests/main.nf.test b/modules/nf-core/cooler/dump/tests/main.nf.test index ef4a10c1..2fdf1a72 100644 --- a/modules/nf-core/cooler/dump/tests/main.nf.test +++ b/modules/nf-core/cooler/dump/tests/main.nf.test @@ -26,10 +26,7 @@ nextflow_process { then { assert process.success - assert snapshot( - process.out, - path(process.out.versions[0]).yaml - ).match() + assert snapshot(process.out).match() } } @@ -50,10 +47,7 @@ nextflow_process { then { assert process.success - assert snapshot( - process.out, - path(process.out.versions[0]).yaml - ).match() + assert snapshot(process.out).match() } } } diff --git a/modules/nf-core/cooler/dump/tests/main.nf.test.snap b/modules/nf-core/cooler/dump/tests/main.nf.test.snap index d12afe32..644ea24d 100644 --- a/modules/nf-core/cooler/dump/tests/main.nf.test.snap +++ b/modules/nf-core/cooler/dump/tests/main.nf.test.snap @@ -11,7 +11,11 @@ ] ], "1": [ - "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + [ + "COOLER_DUMP", + "cooler", + "0.10.3" + ] ], "bedpe": [ [ @@ -21,21 +25,20 @@ "test.bedpe:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + "versions_cooler": [ + [ + "COOLER_DUMP", + "cooler", + "0.10.3" + ] ] - }, - { - "COOLER_DUMP": { - "cooler": "0.10.3" - } } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-06-09T15:33:42.848808039" + "timestamp": "2026-02-10T12:58:21.563411" }, "test-cooler-dump": { "content": [ @@ -49,7 +52,11 @@ ] ], "1": [ - "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + [ + "COOLER_DUMP", + "cooler", + "0.10.3" + ] ], "bedpe": [ [ @@ -59,20 +66,19 @@ "test.bedpe:md5,38e9b0b8cc74f55a15e8ab01023048bd" ] ], - "versions": [ - "versions.yml:md5,ceb1c767e340f442ef70b93867809fc0" + "versions_cooler": [ + [ + "COOLER_DUMP", + "cooler", + "0.10.3" + ] ] - }, - { - "COOLER_DUMP": { - "cooler": "0.10.3" - } } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.2" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-06-09T15:33:34.433029525" + "timestamp": "2026-02-10T12:58:14.616531" } -} +} \ No newline at end of file diff --git a/modules/nf-core/cooler/makebins/main.nf b/modules/nf-core/cooler/makebins/main.nf index b0273acd..764eec5e 100644 --- a/modules/nf-core/cooler/makebins/main.nf +++ b/modules/nf-core/cooler/makebins/main.nf @@ -12,7 +12,7 @@ process COOLER_MAKEBINS { output: tuple val(meta), path("*.bed"), emit: bed - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('cooler'), eval('cooler --version 2>&1 | sed "s/cooler, version //"'), emit: versions_cooler, topic: versions when: task.ext.when == null || task.ext.when @@ -25,20 +25,11 @@ process COOLER_MAKEBINS { $args \\ ${chromsizes} \\ ${cool_bin} > ${prefix}.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ + stub: def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.bed - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ } diff --git a/modules/nf-core/cooler/makebins/meta.yml b/modules/nf-core/cooler/makebins/meta.yml index 38e6dbac..6acde891 100644 --- a/modules/nf-core/cooler/makebins/meta.yml +++ b/modules/nf-core/cooler/makebins/meta.yml @@ -36,13 +36,27 @@ output: description: Genome segmentation at a fixed resolution as a BED file. pattern: "*.bed" ontologies: [] + versions_cooler: + - - ${task.process}: + type: string + description: The name of the process + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, 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 + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, version //": + type: eval + description: The expression to obtain the version of the tool authors: - "@nservant" - "@muffato" diff --git a/modules/nf-core/cooler/makebins/tests/main.nf.test.snap b/modules/nf-core/cooler/makebins/tests/main.nf.test.snap index 32dc5172..91c795f0 100644 --- a/modules/nf-core/cooler/makebins/tests/main.nf.test.snap +++ b/modules/nf-core/cooler/makebins/tests/main.nf.test.snap @@ -11,7 +11,11 @@ ] ], "1": [ - "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + [ + "COOLER_MAKEBINS", + "cooler", + "0.10.4" + ] ], "bed": [ [ @@ -21,16 +25,20 @@ "test.bed:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + "versions_cooler": [ + [ + "COOLER_MAKEBINS", + "cooler", + "0.10.4" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-17T16:22:17.078101" + "timestamp": "2026-02-10T12:58:34.746836" }, "test-cooler-makebins": { "content": [ @@ -44,7 +52,11 @@ ] ], "1": [ - "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + [ + "COOLER_MAKEBINS", + "cooler", + "0.10.4" + ] ], "bed": [ [ @@ -54,15 +66,19 @@ "test.bed:md5,99e887ba1237ebcdcf31954476ab0adf" ] ], - "versions": [ - "versions.yml:md5,635a3a60e7a6e56098c5cd565d639b76" + "versions_cooler": [ + [ + "COOLER_MAKEBINS", + "cooler", + "0.10.4" + ] ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-09-17T16:21:44.342196" + "timestamp": "2026-02-10T12:58:29.59093" } } \ No newline at end of file diff --git a/modules/nf-core/cooler/zoomify/main.nf b/modules/nf-core/cooler/zoomify/main.nf index 8bc51da7..b2a5b2b7 100644 --- a/modules/nf-core/cooler/zoomify/main.nf +++ b/modules/nf-core/cooler/zoomify/main.nf @@ -12,7 +12,7 @@ process COOLER_ZOOMIFY { output: tuple val(meta), path("*.mcool"), emit: mcool - path "versions.yml" , emit: versions + tuple val("${task.process}"), val('cooler'), eval('cooler --version 2>&1 | sed "s/cooler, version //"'), emit: versions_cooler, topic: versions when: task.ext.when == null || task.ext.when @@ -26,21 +26,11 @@ process COOLER_ZOOMIFY { -n $task.cpus \\ -o ${prefix}.mcool \\ $cool - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ stub: def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.mcool - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cooler: \$(cooler --version 2>&1 | sed 's/cooler, version //') - END_VERSIONS """ } diff --git a/modules/nf-core/cooler/zoomify/meta.yml b/modules/nf-core/cooler/zoomify/meta.yml index 4e23ad53..4bfc50ce 100644 --- a/modules/nf-core/cooler/zoomify/meta.yml +++ b/modules/nf-core/cooler/zoomify/meta.yml @@ -36,13 +36,27 @@ output: description: Output mcool file pattern: "*.mcool" ontologies: [] + versions_cooler: + - - ${task.process}: + type: string + description: The name of the process + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, 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 + - cooler: + type: string + description: The name of the tool + - cooler --version 2>&1 | sed "s/cooler, version //": + type: eval + description: The expression to obtain the version of the tool authors: - "@jianhong" maintainers: diff --git a/modules/nf-core/cooler/zoomify/tests/main.nf.test b/modules/nf-core/cooler/zoomify/tests/main.nf.test index 05221b05..bc8ae4c1 100644 --- a/modules/nf-core/cooler/zoomify/tests/main.nf.test +++ b/modules/nf-core/cooler/zoomify/tests/main.nf.test @@ -29,7 +29,7 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - process.out.versions, + process.out.findAll { key, val -> key.startsWith("versions")}, process.out.mcool.collect{ file(it[1]).name } ).match() } ) @@ -57,10 +57,7 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - process.out, - process.out.versions.collect{ path(it).yaml } - ).match() } + { assert snapshot(process.out).match() } ) } } diff --git a/modules/nf-core/cooler/zoomify/tests/main.nf.test.snap b/modules/nf-core/cooler/zoomify/tests/main.nf.test.snap index fde90a63..5d5a207b 100644 --- a/modules/nf-core/cooler/zoomify/tests/main.nf.test.snap +++ b/modules/nf-core/cooler/zoomify/tests/main.nf.test.snap @@ -11,7 +11,11 @@ ] ], "1": [ - "versions.yml:md5,2f43da81c39434336500d1ec837316e2" + [ + "COOLER_ZOOMIFY", + "cooler", + "0.10.4" + ] ], "mcool": [ [ @@ -21,37 +25,40 @@ "test.mcool:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,2f43da81c39434336500d1ec837316e2" + "versions_cooler": [ + [ + "COOLER_ZOOMIFY", + "cooler", + "0.10.4" + ] ] - }, - [ - { - "COOLER_ZOOMIFY": { - "cooler": "0.10.4" - } - } - ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-08-07T15:41:31.109709721" + "timestamp": "2026-02-10T12:59:02.183744" }, "test_cooler_zoomify": { "content": [ - [ - "versions.yml:md5,2f43da81c39434336500d1ec837316e2" - ], + { + "versions_cooler": [ + [ + "COOLER_ZOOMIFY", + "cooler", + "0.10.4" + ] + ] + }, [ "test.mcool" ] ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.3" }, - "timestamp": "2025-08-07T15:41:17.557195332" + "timestamp": "2026-02-10T12:58:56.885229" } } \ No newline at end of file diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 4b3041dc..f5629527 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -1,6 +1,6 @@ process FASTQC { tag "${meta.id}" - label 'process_medium' + label 'process_low' conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml index f988697a..49164c88 100644 --- a/modules/nf-core/fastqc/meta.yml +++ b/modules/nf-core/fastqc/meta.yml @@ -60,9 +60,10 @@ output: - fastqc: type: string description: The tool name - - fastqc --version | sed "/FastQC v/!d; s/.*v//: - type: string - description: The command used to generate the version of the tool + - fastqc --version | sed "/FastQC v/!d; s/.*v//": + type: eval + description: The expression to obtain the version of the tool + topics: versions: - - ${task.process}: @@ -71,9 +72,9 @@ topics: - fastqc: type: string description: The tool name - - fastqc --version | sed "/FastQC v/!d; s/.*v//: - type: string - description: The command used to generate the version of the tool + - fastqc --version | sed "/FastQC v/!d; s/.*v//": + type: eval + description: The expression to obtain the version of the tool authors: - "@drpatelh" - "@grst" @@ -84,3 +85,27 @@ maintainers: - "@grst" - "@ewels" - "@FelixKrueger" +containers: + conda: + linux_amd64: + lock_file: https://wave.seqera.io/v1alpha1/builds/bd-af7a5314d5015c29_1/condalock + linux_arm64: + lock_file: https://wave.seqera.io/v1alpha1/builds/bd-df99cb252670875a_2/condalock + docker: + linux_amd64: + build_id: bd-af7a5314d5015c29_1 + name: community.wave.seqera.io/library/fastqc:0.12.1--af7a5314d5015c29 + scanId: sc-a618548acbee5a8a_30 + linux_arm64: + build_id: bd-df99cb252670875a_2 + name: community.wave.seqera.io/library/fastqc:0.12.1--df99cb252670875a + scanId: sc-b5913ed5d42b22d2_18 + singularity: + linux_amd64: + build_id: bd-104d26ddd9519960_1 + name: oras://community.wave.seqera.io/library/fastqc:0.12.1--104d26ddd9519960 + https: https://community.wave.seqera.io/v2/library/fastqc/blobs/sha256:e0c976cb2eca5fee72618a581537a4f8ea42fcae24c9b201e2e0f764fd28648a + linux_arm64: + build_id: bd-d56b505a93aef38a_1 + name: oras://community.wave.seqera.io/library/fastqc:0.12.1--d56b505a93aef38a + https: https://community.wave.seqera.io/v2/library/fastqc/blobs/sha256:fd39534bf298698cbe3ee4d4a6f1e73330ec4bca44c38dd9a4d06cb5ea838017 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 335afccc..3b0e975b 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,8 +3,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: path multiqc_files, stageAs: "?/*" @@ -18,7 +18,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"'), topic: versions, 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 @@ -50,6 +51,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..9fd34f37 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 @@ -71,19 +71,8 @@ output: - "*_plots": type: file description: Plots created by MultiQC - pattern: "*_data" + pattern: "*_plots" 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,9 @@ 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" @@ -104,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/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 diff --git a/modules/nf-core/samtools/faidx/main.nf b/modules/nf-core/samtools/faidx/main.nf index ed2d70a6..97bfb578 100644 --- a/modules/nf-core/samtools/faidx/main.nf +++ b/modules/nf-core/samtools/faidx/main.nf @@ -8,8 +8,7 @@ process SAMTOOLS_FAIDX { 'biocontainers/samtools:1.22.1--h96c455f_0' }" input: - tuple val(meta), path(fasta) - tuple val(meta2), path(fai) + tuple val(meta), path(fasta), path(fai) val get_sizes output: @@ -17,7 +16,7 @@ process SAMTOOLS_FAIDX { tuple val(meta), path ("*.sizes") , emit: sizes, optional: true tuple val(meta), path ("*.fai") , emit: fai, optional: true tuple val(meta), path ("*.gzi") , emit: gzi, 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 @@ -32,11 +31,6 @@ process SAMTOOLS_FAIDX { $args ${get_sizes_command} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -51,11 +45,5 @@ process SAMTOOLS_FAIDX { fi ${get_sizes_command} - - 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/faidx/meta.yml b/modules/nf-core/samtools/faidx/meta.yml index b7a2e0c1..80aae1da 100644 --- a/modules/nf-core/samtools/faidx/meta.yml +++ b/modules/nf-core/samtools/faidx/meta.yml @@ -1,5 +1,6 @@ name: samtools_faidx -description: Index FASTA file, and optionally generate a file of chromosome sizes +description: Index FASTA file, and optionally generate a file of chromosome + sizes keywords: - index - fasta @@ -14,7 +15,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: @@ -27,11 +29,6 @@ input: description: FASTA file pattern: "*.{fa,fasta}" ontologies: [] - - - meta2: - type: map - description: | - Groovy Map containing reference information - e.g. [ id:'test' ] - fai: type: file description: FASTA index file @@ -40,7 +37,6 @@ input: - get_sizes: type: boolean description: use cut to get the sizes of the index (true) or not (false) - output: fa: - - meta: @@ -86,13 +82,27 @@ output: description: Optional gzip index file for compressed inputs pattern: "*.gzi" 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: - "@drpatelh" - "@ewels" diff --git a/modules/nf-core/samtools/faidx/tests/main.nf.test b/modules/nf-core/samtools/faidx/tests/main.nf.test index a505abc1..9a86db86 100644 --- a/modules/nf-core/samtools/faidx/tests/main.nf.test +++ b/modules/nf-core/samtools/faidx/tests/main.nf.test @@ -8,24 +8,30 @@ nextflow_process { tag "modules_nfcore" tag "samtools" tag "samtools/faidx" + config "./nextflow.config" test("test_samtools_faidx") { when { + params { + module_args = '' + } process { """ - input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] - input[1] = [[],[]] - input[2] = false + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + [] + ] + input[1] = false """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } @@ -33,89 +39,105 @@ nextflow_process { test("test_samtools_faidx_bgzip") { when { + params { + module_args = '' + } process { """ - input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true)] - input[1] = [[],[]] - input[2] = false + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true), + [] + ] + input[1] = false """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } test("test_samtools_faidx_fasta") { - config "./nextflow.config" - when { + params { + module_args = 'MT192765.1 -o extract.fa' + } process { """ - input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] - input[1] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] - input[2] = false + input[0] = [ + [ id:'test' ], + 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) + ] + input[1] = false """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } test("test_samtools_faidx_stub_fasta") { - config "./nextflow2.config" - + options "-stub" when { + params { + module_args = '-o extract.fa' + } process { """ - input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] - input[1] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.fai', checkIfExists: true) ] - input[2] = false + input[0] = [ + [ id:'test' ], + 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) + ] + input[1] = false """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } test("test_samtools_faidx_stub_fai") { + options "-stub" when { + params { + module_args = '' + } process { """ - input[0] = [ [ id:'test', single_end:false ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) ] - input[1] = [[],[]] - input[2] = false + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + [] + ] + input[1] = false """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } @@ -123,22 +145,25 @@ nextflow_process { test("test_samtools_faidx_get_sizes") { when { + params { + module_args = '' + } process { """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[1] = [[],[]] - input[2] = true + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + [] + ] + input[1] = true """ } } then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } @@ -146,22 +171,25 @@ nextflow_process { test("test_samtools_faidx_get_sizes_bgzip") { when { + params { + module_args = '' + } process { """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) - ]) - input[1] = [[],[]] - input[2] = true + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true), + [] + ] + input[1] = true """ } } then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } @@ -171,22 +199,25 @@ nextflow_process { options "-stub" when { + params { + module_args = '' + } process { """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) - ]) - input[1] = [[],[]] - input[2] = true + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true), + [] + ] + input[1] = true """ } } then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } @@ -196,22 +227,25 @@ nextflow_process { options "-stub" when { + params { + module_args = '' + } process { """ - input[0] = Channel.of([ - [ id:'test' ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true) - ]) - input[1] = [[],[]] - input[2] = true + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta.gz', checkIfExists: true), + [] + ] + input[1] = true """ } } then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match()} ) } } diff --git a/modules/nf-core/samtools/faidx/tests/main.nf.test.snap b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap index 3be7b824..41697444 100644 --- a/modules/nf-core/samtools/faidx/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/faidx/tests/main.nf.test.snap @@ -2,35 +2,13 @@ "test_samtools_faidx": { "content": [ { - "0": [ - - ], - "1": [ - - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" - ], "fa": [ ], "fai": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" ] @@ -41,50 +19,24 @@ "sizes": [ ], - "versions": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:09:38.874686" + "timestamp": "2026-02-10T15:39:12.541649151" }, "test_samtools_faidx_get_sizes_bgzip - stub": { "content": [ { - "0": [ - - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.fai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.gzi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "4": [ - "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" - ], "fa": [ ], @@ -112,45 +64,24 @@ "genome.fasta.gz.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:10:10.958397" + "timestamp": "2026-02-10T15:41:44.040426987" }, "test_samtools_faidx_get_sizes": { "content": [ { - "0": [ - - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" - ], "fa": [ ], @@ -173,55 +104,31 @@ "genome.fasta.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" ] ], - "versions": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:09:59.237249" + "timestamp": "2026-02-10T15:47:03.653912015" }, "test_samtools_faidx_bgzip": { "content": [ { - "0": [ - - ], - "1": [ - - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "3": [ - [ - { - "id": "test", - "single_end": false - }, - "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" - ] - ], - "4": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" - ], "fa": [ ], "fai": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" ] @@ -229,8 +136,7 @@ "gzi": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" ] @@ -238,46 +144,28 @@ "sizes": [ ], - "versions": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:09:42.949204" + "timestamp": "2026-02-10T15:50:04.023566795" }, "test_samtools_faidx_fasta": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "extract.fa:md5,6a0774a0ad937ba0bfd2ac7457d90f36" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" - ], "fa": [ [ { - "id": "test", - "single_end": false + "id": "test" }, "extract.fa:md5,6a0774a0ad937ba0bfd2ac7457d90f36" ] @@ -291,45 +179,24 @@ "sizes": [ ], - "versions": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:09:46.914038" + "timestamp": "2026-02-10T15:39:23.529404162" }, "test_samtools_faidx_get_sizes - stub": { "content": [ { - "0": [ - - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "genome.fasta.fai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" - ], "fa": [ ], @@ -352,48 +219,30 @@ "genome.fasta.sizes:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "versions": [ - "versions.yml:md5,8e7d141eb8c2944042dfb5e942bffe08" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:10:06.961912" + "timestamp": "2026-02-10T15:41:39.039834304" }, "test_samtools_faidx_stub_fasta": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "extract.fa:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" - ], "fa": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "extract.fa:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + "extract.fa:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "fai": [ @@ -405,51 +254,33 @@ "sizes": [ ], - "versions": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:09:51.226016" + "timestamp": "2026-02-10T15:39:28.961701609" }, "test_samtools_faidx_stub_fai": { "content": [ { - "0": [ - - ], - "1": [ - - ], - "2": [ - [ - { - "id": "test", - "single_end": false - }, - "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "3": [ - - ], - "4": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" - ], "fa": [ ], "fai": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "genome.fasta.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" + "genome.fasta.fai:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], "gzi": [ @@ -458,50 +289,24 @@ "sizes": [ ], - "versions": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:09:55.423005" + "timestamp": "2026-02-10T15:39:34.471028474" }, "test_samtools_faidx_get_sizes_bgzip": { "content": [ { - "0": [ - - ], - "1": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" - ] - ], - "2": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.fai:md5,9da2a56e2853dc8c0b86a9e7229c9fe5" - ] - ], - "3": [ - [ - { - "id": "test" - }, - "genome.fasta.gz.gzi:md5,7dea362b3fac8e00956a4952a3d4f474" - ] - ], - "4": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" - ], "fa": [ ], @@ -529,15 +334,19 @@ "genome.fasta.gz.sizes:md5,a57c401f27ae5133823fb09fb21c8a3c" ] ], - "versions": [ - "versions.yml:md5,001211003daf11e8dd2f1aca7a378a68" + "versions_samtools": [ + [ + "SAMTOOLS_FAIDX", + "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:10:03.04872" + "timestamp": "2026-02-10T15:39:45.439016495" } } \ No newline at end of file diff --git a/modules/nf-core/samtools/faidx/tests/nextflow.config b/modules/nf-core/samtools/faidx/tests/nextflow.config index f76a3ba0..202c036e 100644 --- a/modules/nf-core/samtools/faidx/tests/nextflow.config +++ b/modules/nf-core/samtools/faidx/tests/nextflow.config @@ -1,7 +1,7 @@ process { withName: SAMTOOLS_FAIDX { - ext.args = 'MT192765.1 -o extract.fa' + ext.args = params.module_args } } diff --git a/modules/nf-core/samtools/faidx/tests/nextflow2.config b/modules/nf-core/samtools/faidx/tests/nextflow2.config deleted file mode 100644 index 33ebbd5d..00000000 --- a/modules/nf-core/samtools/faidx/tests/nextflow2.config +++ /dev/null @@ -1,6 +0,0 @@ -process { - - withName: SAMTOOLS_FAIDX { - ext.args = '-o extract.fa' - } -} 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/index/main.nf b/modules/nf-core/samtools/index/main.nf index a77ad821..e2a0e56d 100644 --- a/modules/nf-core/samtools/index/main.nf +++ b/modules/nf-core/samtools/index/main.nf @@ -14,7 +14,7 @@ process SAMTOOLS_INDEX { tuple val(meta), path("*.bai") , optional:true, emit: bai tuple val(meta), path("*.csi") , optional:true, emit: csi tuple val(meta), path("*.crai"), optional:true, emit: crai - 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_INDEX { -@ ${task.cpus} \\ $args \\ $input - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - samtools: \$(echo \$(samtools --version 2>&1) | sed 's/^.*samtools //; s/Using.*\$//') - END_VERSIONS """ stub: @@ -40,10 +35,5 @@ process SAMTOOLS_INDEX { "crai" : args.contains("-c") ? "csi" : "bai" """ touch ${input}.${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/index/meta.yml b/modules/nf-core/samtools/index/meta.yml index 1bed6bca..c6d4ce25 100644 --- a/modules/nf-core/samtools/index/meta.yml +++ b/modules/nf-core/samtools/index/meta.yml @@ -14,7 +14,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: @@ -60,13 +61,27 @@ output: description: BAM/CRAM/SAM index file pattern: "*.{bai,crai,sai}" 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" - "@ewels" diff --git a/modules/nf-core/samtools/index/tests/main.nf.test b/modules/nf-core/samtools/index/tests/main.nf.test index ca34fb5c..c96cec86 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test +++ b/modules/nf-core/samtools/index/tests/main.nf.test @@ -23,7 +23,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.bai, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -43,7 +46,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.crai, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -67,7 +73,7 @@ nextflow_process { { assert process.success }, { assert snapshot( file(process.out.csi[0][1]).name, - process.out.versions + process.out.findAll { key, val -> key.startsWith('versions') } ).match() } ) } @@ -89,7 +95,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.bai, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -110,7 +119,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.crai, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } @@ -133,7 +145,10 @@ nextflow_process { then { assertAll ( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + process.out.csi, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } ) } } diff --git a/modules/nf-core/samtools/index/tests/main.nf.test.snap b/modules/nf-core/samtools/index/tests/main.nf.test.snap index 3836c6bf..afc8a1ff 100644 --- a/modules/nf-core/samtools/index/tests/main.nf.test.snap +++ b/modules/nf-core/samtools/index/tests/main.nf.test.snap @@ -1,250 +1,156 @@ { "csi - stub": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], { - "0": [ - - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" - ], - "bai": [ - - ], - "crai": [ - - ], - "csi": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.csi:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_INDEX", + "samtools", + "1.22.1" ] - ], - "versions": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T14:13:38.25787" + "timestamp": "2026-01-28T17:52:10.030187" }, "crai - stub": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], { - "0": [ - - ], - "1": [ - - ], - "2": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_INDEX", + "samtools", + "1.22.1" ] - ], - "3": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" - ], - "bai": [ - - ], - "crai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T14:13:34.496412" + "timestamp": "2026-01-28T17:51:59.125484" }, "bai - stub": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], { - "0": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" + "SAMTOOLS_INDEX", + "samtools", + "1.22.1" ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" - ], - "bai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "crai": [ - - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T14:13:25.934431" + "timestamp": "2026-01-28T17:51:47.277042" }, "csi": { "content": [ "test.paired_end.sorted.bam.csi", - [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" - ] + { + "versions_samtools": [ + [ + "SAMTOOLS_INDEX", + "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:13:22.262088" + "timestamp": "2026-01-28T17:51:35.758735" }, "crai": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + ] + ], { - "0": [ - - ], - "1": [ - - ], - "2": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" + "SAMTOOLS_INDEX", + "samtools", + "1.22.1" ] - ], - "3": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" - ], - "bai": [ - - ], - "crai": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.recalibrated.sorted.cram.crai:md5,14bc3bd5c89cacc8f4541f9062429029" - ] - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T14:13:18.191664" + "timestamp": "2026-01-28T17:51:26.561965" }, "bai": { "content": [ + [ + [ + { + "id": "test", + "single_end": false + }, + "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + ] + ], { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" - ] - ], - "1": [ - - ], - "2": [ - - ], - "3": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" - ], - "bai": [ + "versions_samtools": [ [ - { - "id": "test", - "single_end": false - }, - "test.paired_end.sorted.bam.bai:md5,704c10dd1326482448ca3073fdebc2f4" + "SAMTOOLS_INDEX", + "samtools", + "1.22.1" ] - ], - "crai": [ - - ], - "csi": [ - - ], - "versions": [ - "versions.yml:md5,b8717818c91b07de87c2a5590bad02e6" ] } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.6" + "nf-test": "0.9.3", + "nextflow": "25.10.2" }, - "timestamp": "2025-09-10T14:13:08.51539" + "timestamp": "2026-01-28T17:51:15.299035" } } \ 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" diff --git a/modules/nf-core/trimgalore/main.nf b/modules/nf-core/trimgalore/main.nf index 7372e720..5790b520 100644 --- a/modules/nf-core/trimgalore/main.nf +++ b/modules/nf-core/trimgalore/main.nf @@ -44,7 +44,7 @@ process TRIMGALORE { def prefix = task.ext.prefix ?: "${meta.id}" if (meta.single_end) { def args_list = args.split("\\s(?=--)").toList() - args_list.removeAll { it.toLowerCase().contains('_r2 ') } + args_list.removeAll { arg -> arg.toLowerCase().contains('_r2 ') } """ [ ! -f ${prefix}.fastq.gz ] && ln -s ${reads} ${prefix}.fastq.gz trim_galore \\ 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/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 a5c5f642acfb6c5515958e395c7ef7902ce147f5 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 24 Feb 2026 15:22:47 +0100 Subject: [PATCH 29/55] Remove version channels from subworkflows --- main.nf | 3 --- subworkflows/local/cooler/main.nf | 8 -------- subworkflows/local/pairtools/main.nf | 14 -------------- subworkflows/local/prepare_genome/main.nf | 9 +-------- workflows/hic.nf | 2 -- 5 files changed, 1 insertion(+), 35 deletions(-) diff --git a/main.nf b/main.nf index af9dc112..1994512b 100644 --- a/main.nf +++ b/main.nf @@ -47,8 +47,6 @@ workflow NFCORE_HIC { main: - ch_versions = channel.empty() - // // SUBWORKFLOW: prepare genome annotation // @@ -57,7 +55,6 @@ workflow NFCORE_HIC { params.bwt2_index, params.bwa_index ) - ch_versions = ch_versions.mix(PREPARE_GENOME.out.versions) // // WORKFLOW: Run pipeline diff --git a/subworkflows/local/cooler/main.nf b/subworkflows/local/cooler/main.nf index 949fe8c2..c55fe969 100644 --- a/subworkflows/local/cooler/main.nf +++ b/subworkflows/local/cooler/main.nf @@ -21,7 +21,6 @@ workflow COOLER { cool_bins main: - ch_versions = channel.empty() //***************************************** // FILTER CHROMOSOMES ON SIZE @@ -36,7 +35,6 @@ workflow COOLER { COOLER_MAKEBINS( chromsize.combine(cool_bins) ) - ch_versions = ch_versions.mix(COOLER_MAKEBINS.out.versions) //***************************************** // BUILD COOL FILE PER RESOLUTION @@ -47,7 +45,6 @@ workflow COOLER { "pairs", cool_bins ) - ch_versions = ch_versions.mix(COOLER_CLOAD.out.versions) // Add resolution in meta COOLER_CLOAD.out.cool @@ -60,7 +57,6 @@ workflow COOLER { COOLER_BALANCE( ch_cool.map{[it[0], it[1], ""]} ) - ch_versions = ch_versions.mix(COOLER_BALANCE.out.versions) // Zoomify at minimum bin resolution if (!params.res_zoomify){ @@ -78,7 +74,6 @@ workflow COOLER { COOLER_ZOOMIFY( ch_cool_zoomify ) - ch_versions = ch_versions.mix(COOLER_ZOOMIFY.out.versions) //***************************************** // DUMP DATA @@ -87,15 +82,12 @@ workflow COOLER { COOLER_DUMP( COOLER_BALANCE.out.cool.map{[it[0], it[1], ""]} ) - ch_versions = ch_versions.mix(COOLER_DUMP.out.versions) SPLIT_COOLER_DUMP( COOLER_DUMP.out.bedpe ) - ch_versions = ch_versions.mix(SPLIT_COOLER_DUMP.out.versions) emit: - versions = ch_versions cool = COOLER_BALANCE.out.cool mcool = COOLER_ZOOMIFY.out.mcool } diff --git a/subworkflows/local/pairtools/main.nf b/subworkflows/local/pairtools/main.nf index 4508983f..471fba19 100644 --- a/subworkflows/local/pairtools/main.nf +++ b/subworkflows/local/pairtools/main.nf @@ -33,7 +33,6 @@ workflow PAIRTOOLS { chrsize // path main: - ch_versions = channel.empty() BWA_MEM( reads, @@ -41,25 +40,21 @@ workflow PAIRTOOLS { fasta.collect(), channel.value([]) ) - ch_versions = ch_versions.mix(BWA_MEM.out.versions) PAIRTOOLS_PARSE( BWA_MEM.out.bam, chrsize.collect() ) - ch_versions = ch_versions.mix(PAIRTOOLS_PARSE.out.versions) PAIRTOOLS_RESTRICT( PAIRTOOLS_PARSE.out.pairsam, frag.map{it->it[1]}.collect() ) - ch_versions = ch_versions.mix(PAIRTOOLS_RESTRICT.out.versions) ch_pairsam = params.no_digestion ? PAIRTOOLS_PARSE.out.pairsam : PAIRTOOLS_RESTRICT.out.restrict PAIRTOOLS_SORT( ch_pairsam ) - ch_versions = ch_versions.mix(PAIRTOOLS_SORT.out.versions) ch_valid_pairs = PAIRTOOLS_SORT.out.sorted .map{ meta, pairs -> @@ -75,13 +70,11 @@ workflow PAIRTOOLS { PAIRTOOLS_MERGE( ch_valid_pairs.multiple ) - ch_versions = ch_versions.mix(PAIRTOOLS_MERGE.out.versions) // Separate pairs/bam files PAIRTOOLS_SPLIT( PAIRTOOLS_MERGE.out.pairs.mix(ch_valid_pairs.single) ) - ch_versions = ch_versions.mix(PAIRTOOLS_SPLIT.out.versions) // Manage BAM files SAMTOOLS_SORT( @@ -93,36 +86,29 @@ workflow PAIRTOOLS { SAMTOOLS_INDEX( SAMTOOLS_SORT.out.bam ) - ch_versions = ch_versions.mix(SAMTOOLS_INDEX.out.versions) SAMTOOLS_FLAGSTAT( SAMTOOLS_SORT.out.bam.join(SAMTOOLS_INDEX.out.bai) ) - ch_versions = ch_versions.mix(SAMTOOLS_FLAGSTAT.out.versions) PAIRTOOLS_DEDUP( PAIRTOOLS_SPLIT.out.pairs ) - ch_versions = ch_versions.mix(PAIRTOOLS_DEDUP.out.versions) ch_pairselect = params.keep_dups ? PAIRTOOLS_SPLIT.out.pairs : PAIRTOOLS_DEDUP.out.pairs PAIRTOOLS_SELECT( ch_pairselect ) - ch_versions = ch_versions.mix(PAIRTOOLS_SELECT.out.versions) PAIRTOOLS_STATS( PAIRTOOLS_SELECT.out.selected ) - ch_versions = ch_versions.mix(PAIRTOOLS_STATS.out.versions) PAIRIX( PAIRTOOLS_SELECT.out.selected ) - ch_versions = ch_versions.mix(PAIRIX.out.versions) emit: - versions = ch_versions pairs = PAIRIX.out.index bam = PAIRTOOLS_SPLIT.out.bam.join(SAMTOOLS_INDEX.out.bai) stats = PAIRTOOLS_STATS.out.stats.map{it->it[1]} diff --git a/subworkflows/local/prepare_genome/main.nf b/subworkflows/local/prepare_genome/main.nf index 05ab24bd..0726567b 100644 --- a/subworkflows/local/prepare_genome/main.nf +++ b/subworkflows/local/prepare_genome/main.nf @@ -15,7 +15,6 @@ workflow PREPARE_GENOME { bwa_index main: - ch_versions = channel.empty() // // Fasta reference genome @@ -34,7 +33,6 @@ workflow PREPARE_GENOME { ch_fasta ) ch_index = BOWTIE2_BUILD.out.index - ch_versions = ch_versions.mix(BOWTIE2_BUILD.out.versions) }else{ ch_index = channel.fromPath( bwt2_index , checkIfExists: true) .map { it -> [[:], it]} @@ -51,7 +49,6 @@ workflow PREPARE_GENOME { ch_fasta ) ch_index = BWA_INDEX.out.index - ch_versions = ch_versions.mix(BWA_INDEX.out.versions) }else{ ch_index = channel.fromPath( bwa_index , checkIfExists: true) .map { it -> [[:], it]} @@ -64,12 +61,10 @@ workflow PREPARE_GENOME { // if(!params.chromosome_size){ SAMTOOLS_FAIDX( - ch_fasta, - ch_index, + ch_fasta.combine(ch_index), true ) ch_chromsize = SAMTOOLS_FAIDX.out.sizes - ch_versions = ch_versions.mix(SAMTOOLS_FAIDX.out.versions) }else{ ch_chromsize = channel.fromPath( params.chromosome_size , checkIfExists: true) .map { it -> [[:], it]} @@ -104,7 +99,6 @@ workflow PREPARE_GENOME { restriction_site ) ch_resfrag = GET_RESTRICTION_FRAGMENTS.out.results - ch_versions = ch_versions.mix(GET_RESTRICTION_FRAGMENTS.out.versions) }else if (!params.no_digestion){ channel.fromPath( params.restriction_fragments, checkIfExists: true ) .map { it -> [[:], it] } @@ -120,5 +114,4 @@ workflow PREPARE_GENOME { res_frag = ch_resfrag restriction_site = ch_restriction_site ligation_site = ch_ligation_site - versions = ch_versions } diff --git a/workflows/hic.nf b/workflows/hic.nf index bc6d6e4e..7f2df92e 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -128,7 +128,6 @@ workflow HIC { ch_res_frag, ch_chromosome_size ) - ch_versions = ch_versions.mix(PAIRTOOLS.out.versions) ch_pairs = PAIRTOOLS.out.pairs ch_process_mqc = PAIRTOOLS.out.stats } @@ -141,7 +140,6 @@ workflow HIC { ch_chromosome_size, ch_map_res ) - ch_versions = ch_versions.mix(COOLER.out.versions) // // MODULE: HICEXPLORER/HIC_PLOT_DIST_VS_COUNTS From 0e89b77b24fa406079f32756d1a7e1de4f2b9926 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 24 Feb 2026 15:23:36 +0100 Subject: [PATCH 30/55] Update mem module topic channel --- modules.json | 2 +- 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 +++++++++++++----- 5 files changed, 216 insertions(+), 85 deletions(-) diff --git a/modules.json b/modules.json index a30b71c4..fd3ba8c6 100644 --- a/modules.json +++ b/modules.json @@ -22,7 +22,7 @@ }, "bwa/mem": { "branch": "master", - "git_sha": "966ba9887e2b04d89d64db06c01508873bde13b1", + "git_sha": "707241c72951f24fd89982c4c80c5983a4c437ef", "installed_by": ["modules"] }, "calder2": { diff --git a/modules/nf-core/bwa/mem/main.nf b/modules/nf-core/bwa/mem/main.nf index 6893b047..e3732673 100644 --- a/modules/nf-core/bwa/mem/main.nf +++ b/modules/nf-core/bwa/mem/main.nf @@ -18,7 +18,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 @@ -44,12 +45,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: @@ -64,11 +59,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 From 006d5b2edd20d5fd56a4f56757cd09cd33e28b7e Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 24 Feb 2026 15:24:06 +0100 Subject: [PATCH 31/55] Add min_size params --- nextflow.config | 1 + nextflow_schema.json | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/nextflow.config b/nextflow.config index 441b2749..fe6c050b 100644 --- a/nextflow.config +++ b/nextflow.config @@ -90,6 +90,7 @@ params { ice_eps = 0.1 // Downstream Analysis + min_size = 0 res_dist_decay = '250000' tads_caller = 'insulation' res_tads = '40000' diff --git a/nextflow_schema.json b/nextflow_schema.json index 66ce54e1..9ad4c930 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -311,6 +311,11 @@ "description": "Set up downstream analysis from contact maps", "default": "", "properties": { + "min_size": { + "type": "integer", + "description": "Minimum chromosome size to be retained. Useful for Calder2, which cannot be applied to chromosomes that do not have a sufficient number of bins.", + "default": 0 + }, "res_dist_decay": { "type": "string", "pattern": "^(\\d+)(,\\d+)*$", From 1c9b5006c44831dca13a4b16698d1d37f68f1c41 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 24 Feb 2026 15:58:42 +0100 Subject: [PATCH 32/55] Fix cload input and output --- subworkflows/local/cooler/main.nf | 11 +++++------ subworkflows/local/cooler/meta.yml | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/cooler/main.nf b/subworkflows/local/cooler/main.nf index c55fe969..6feaab1d 100644 --- a/subworkflows/local/cooler/main.nf +++ b/subworkflows/local/cooler/main.nf @@ -38,19 +38,18 @@ workflow COOLER { //***************************************** // BUILD COOL FILE PER RESOLUTION - COOLER_CLOAD( - pairs, - chromsize, + pairs.collect(), + chromsize.collect(), "pairs", cool_bins ) // Add resolution in meta COOLER_CLOAD.out.cool - .combine(cool_bins) - .map { meta, file, res -> - [meta + [resolution: res], file] + .map { meta, file -> + def id = (file.baseName =~ /(\d+)(?!.*\d)/)[0][1] + [meta + [resolution: id], file] } .set { ch_cool } diff --git a/subworkflows/local/cooler/meta.yml b/subworkflows/local/cooler/meta.yml index 3f0b3783..cb9f146f 100644 --- a/subworkflows/local/cooler/meta.yml +++ b/subworkflows/local/cooler/meta.yml @@ -16,6 +16,7 @@ components: - cooler/balance - cooler/zoomify - cooler/dump + - filter/chromsize - split/cooler/dump input: - pairs: From 586fef22b1b678644d1ea830506ac9d1f2558a9c Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 24 Feb 2026 15:59:28 +0100 Subject: [PATCH 33/55] Fix faidx input --- subworkflows/local/prepare_genome/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/prepare_genome/main.nf b/subworkflows/local/prepare_genome/main.nf index 0726567b..9cddc7ef 100644 --- a/subworkflows/local/prepare_genome/main.nf +++ b/subworkflows/local/prepare_genome/main.nf @@ -61,7 +61,7 @@ workflow PREPARE_GENOME { // if(!params.chromosome_size){ SAMTOOLS_FAIDX( - ch_fasta.combine(ch_index), + ch_fasta.join(ch_index), true ) ch_chromsize = SAMTOOLS_FAIDX.out.sizes From 6d900d27aedaa701e055770758abb75c98985ed8 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 27 Feb 2026 16:03:06 +0100 Subject: [PATCH 34/55] Fix resolution not an integer --- subworkflows/local/cooler/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/local/cooler/main.nf b/subworkflows/local/cooler/main.nf index 6feaab1d..0089d2b1 100644 --- a/subworkflows/local/cooler/main.nf +++ b/subworkflows/local/cooler/main.nf @@ -49,7 +49,7 @@ workflow COOLER { COOLER_CLOAD.out.cool .map { meta, file -> def id = (file.baseName =~ /(\d+)(?!.*\d)/)[0][1] - [meta + [resolution: id], file] + [meta + [resolution: id.toInteger()], file] } .set { ch_cool } From 483ae291f1583b9b1f94848558e3bb564100ab57 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 27 Feb 2026 16:04:14 +0100 Subject: [PATCH 35/55] Set default params for arima/arimaV2 --- conf/modules.config | 4 ++-- nextflow.config | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 223fda92..5f20e329 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -285,8 +285,8 @@ process { params.min_cis_dist > 0 ? " and ((chrom1==chrom2 and abs(pos1-pos2) > ${params.min_cis_dist}) or chrom1!=chrom2)" : '', params.keep_multi ? " and ((pair_type.upper()=='UU') or (pair_type.upper()=='UR') or (pair_type.upper()=='RU') or (pair_type.upper()=='MM') or (pair_type.upper()=='MU'))" : " and ((pair_type.upper()=='UU') or (pair_type.upper()=='UR') or (pair_type.upper()=='RU'))", params.no_digestion ? '' : " and ((chrom1==chrom2 and abs(int(rfrag1) - int(rfrag2)) > 1) or chrom1!=chrom2)", - params.min_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) > ${params.min_insert_size}" : '', - params.max_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) < ${params.max_insert_size}" : '', + //params.min_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) > ${params.min_insert_size}" : '', + //params.max_insert_size > 0 ? " and ( (rfrag_end1 - r1pos) + (rfrag_end2 - r2pos)) < ${params.max_insert_size}" : '', //params.min_restriction_fragment_size > 0 ? " -t ${params.min_restriction_fragment_size}" : '', //params.max_restriction_fragment_size > 0 ? " -m ${params.max_restriction_fragment_size}" : '', ].join(' ').trim() } diff --git a/nextflow.config b/nextflow.config index fe6c050b..a6529f05 100644 --- a/nextflow.config +++ b/nextflow.config @@ -65,10 +65,10 @@ params { } } - min_restriction_fragment_size = 0 - max_restriction_fragment_size = 0 - min_insert_size = 0 - max_insert_size = 0 + min_restriction_fragment_size = (params.digest.arima || params.digest.arimaV2)? 10:0 + max_restriction_fragment_size = (params.digest.arima || params.digest.arimaV2)? 100000:0 + min_insert_size = (params.digest.arima || params.digest.arimaV2)? 100:0 + max_insert_size = (params.digest.arima || params.digest.arimaV2)? 1000:0 save_pairs_intermediates = false // Dnase/Micro-C Hi-C From 88057d865177c90c71d4ecdf4bbec731205e16ea Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 2 Mar 2026 15:23:42 +0100 Subject: [PATCH 36/55] Update changelog.md --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 031a952f..1649b3c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,14 +3,52 @@ 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). +## Version 2.2.0 2026-03-02 + +### `Added` + +- Subworkflows meta.yml +- Module FAIDX for chromosomes sizes calculation +- TRIMGALORE module for 5' clipping (see #225) +- CALDER2 compartments calling (see '--compartments_caller' option) +- Local FILTER_CHROMSIZE module (in order to apply CALDER2 without error) +- Optional '--min_size' parameter for chromosome selection +- Default MIN_FRAG_SIZE, MAX_FRAG_SIZE, MIN_INSERT_SIZE and MAX_INSERT_SIZE values for Arima and ArimV2 protocols + +### `Removed` + +- Module GETCHROMSIZES (replaced by FAIDX) +- Version channels from subworkflows (tools versions gathering still a WIP) + +### `Fixed` + +- #227: MPLCONFIGDIR is set to "${baseDir}/mplconfig" +- #62: a single number can be given as BIN_SIZES without error +- #225:TRIMGALORE remove the first 5 bases of the 5' end and + fragments and inserts size min/max settings are set to recommended values if Arima/ArimaV2 is used +- Bug from COOLER_CLOAD deprecated "pairs" ext.args calling +- Bug on the cooler "add resolution" step caused by module COOLER_CLOAD update + +### `Updated` + +- All nf-core modules (including topics channel) +- Modules path +- "channel" syntax with lowercase c +- Components names in subworkflows meta.yml +- COOLER_CLOAD inputs and outputs +- BWA_MEM inputs +- SAMTOOL_SORT inputs +- UTILS_NFSCHEMA_PLUGIN inputs and outputs +- Markdown settings +- Template files +- nf-core version to 3.5.0 + ## v2.2.0dev ### `Added` - Parameter `--dnase`is now replaced by `--no_digestion` -- Add CALDER2 compartments calling (see '--compartments_caller' option) - - Add new '--balancing_opts' to update `cooler balance` arguments (#193) - New subworkflow based on `pairtools` to detect valid pairs. The user From 005190e144757ed5f1cad8cafef7207144f6fc99 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 2 Mar 2026 15:52:54 +0100 Subject: [PATCH 37/55] Update .nf-core.yml --- .nf-core.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.nf-core.yml b/.nf-core.yml index 696dcb6e..6f14b577 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,6 +1,6 @@ lint: schema_params: false -nf_core_version: 3.5.0 +nf_core_version: 3.5.2 repository_type: pipeline template: author: Nicolas Servant @@ -10,4 +10,4 @@ template: name: hic org: nf-core outdir: . - version: 2.2.0dev + version: 2.2.0 From 275c466feea4692246fcf6ab109defaad1c3935f Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 2 Mar 2026 16:00:03 +0100 Subject: [PATCH 38/55] Run pre-commit --- .vscode/settings.json | 4 +--- CHANGELOG.md | 4 ++-- modules/local/filter_chromsize/main.nf | 6 +++--- subworkflows/local/compartments/meta.yml | 2 +- subworkflows/local/cooler/meta.yml | 2 +- subworkflows/local/prepare_genome/main.nf | 2 +- subworkflows/local/utils_nfcore_hic_pipeline/meta.yml | 1 - workflows/hic.nf | 2 +- 8 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b9adac7c..af2d783f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,4 @@ { - "markdown.styles": [ - "public/vscode_markdown.css" - ], + "markdown.styles": ["public/vscode_markdown.css"], "nextflow.telemetry.enabled": false } diff --git a/CHANGELOG.md b/CHANGELOG.md index 1649b3c4..d519d952 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). -## Version 2.2.0 2026-03-02 +## Version 2.2.0 2026-03-02 ### `Added` @@ -26,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #62: a single number can be given as BIN_SIZES without error - #225:TRIMGALORE remove the first 5 bases of the 5' end and fragments and inserts size min/max settings are set to recommended values if Arima/ArimaV2 is used -- Bug from COOLER_CLOAD deprecated "pairs" ext.args calling +- Bug from COOLER_CLOAD deprecated "pairs" ext.args calling - Bug on the cooler "add resolution" step caused by module COOLER_CLOAD update ### `Updated` diff --git a/modules/local/filter_chromsize/main.nf b/modules/local/filter_chromsize/main.nf index 947d49aa..b1a498e9 100644 --- a/modules/local/filter_chromsize/main.nf +++ b/modules/local/filter_chromsize/main.nf @@ -1,11 +1,11 @@ /* - * Filter chromsize - * Filter out chromosomes smaller than a given threshold + * Filter chromsize + * Filter out chromosomes smaller than a given threshold */ process FILTER_CHROMSIZE { tag "${meta.id}" - label 'process_low' + label 'process_low' input: tuple val(meta), path(sizes_file) diff --git a/subworkflows/local/compartments/meta.yml b/subworkflows/local/compartments/meta.yml index 06fbb445..53a1ac98 100644 --- a/subworkflows/local/compartments/meta.yml +++ b/subworkflows/local/compartments/meta.yml @@ -46,4 +46,4 @@ authors: maintainers: - "@adamrtalbot" - "@drpatelh" - - "@maxulysse" \ No newline at end of file + - "@maxulysse" diff --git a/subworkflows/local/cooler/meta.yml b/subworkflows/local/cooler/meta.yml index cb9f146f..e2570264 100644 --- a/subworkflows/local/cooler/meta.yml +++ b/subworkflows/local/cooler/meta.yml @@ -55,4 +55,4 @@ authors: maintainers: - "@adamrtalbot" - "@drpatelh" - - "@maxulysse" \ No newline at end of file + - "@maxulysse" diff --git a/subworkflows/local/prepare_genome/main.nf b/subworkflows/local/prepare_genome/main.nf index 9cddc7ef..1840223a 100644 --- a/subworkflows/local/prepare_genome/main.nf +++ b/subworkflows/local/prepare_genome/main.nf @@ -61,7 +61,7 @@ workflow PREPARE_GENOME { // if(!params.chromosome_size){ SAMTOOLS_FAIDX( - ch_fasta.join(ch_index), + ch_fasta.join(ch_index), true ) ch_chromsize = SAMTOOLS_FAIDX.out.sizes diff --git a/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml b/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml index dd61abeb..44de09b6 100644 --- a/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml +++ b/subworkflows/local/utils_nfcore_hic_pipeline/meta.yml @@ -56,4 +56,3 @@ maintainers: - "@adamrtalbot" - "@drpatelh" - "@maxulysse" - \ No newline at end of file diff --git a/workflows/hic.nf b/workflows/hic.nf index 7f2df92e..4c9ac0c9 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -94,7 +94,7 @@ workflow HIC { ) ch_samplesheet = TRIMGALORE.out.reads } - + // // MODULE: Run FastQC // From 6397ae39b8f1d927f4ec754497d82b2d597e848c Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Mon, 2 Mar 2026 16:57:23 +0100 Subject: [PATCH 39/55] Fix light logo asset --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d519d952..c365f53b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 fragments and inserts size min/max settings are set to recommended values if Arima/ArimaV2 is used - Bug from COOLER_CLOAD deprecated "pairs" ext.args calling - Bug on the cooler "add resolution" step caused by module COOLER_CLOAD update +- Logo matching template ### `Updated` From f9ecac2be62a00c790275948b84c1bc036841497 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 3 Mar 2026 13:52:45 +0100 Subject: [PATCH 40/55] Fix copy paste error in local subworkflows meta.yml --- assets/nf-core-hic_logo_light.png | Bin 59371 -> 61022 bytes subworkflows/local/compartments/meta.yml | 8 +++----- subworkflows/local/cooler/meta.yml | 8 +++----- subworkflows/local/hicpro/meta.yml | 8 +++----- subworkflows/local/hicpro_mapping/meta.yml | 8 +++----- subworkflows/local/pairtools/meta.yml | 8 +++----- subworkflows/local/prepare_genome/meta.yml | 8 +++----- subworkflows/local/tads/meta.yml | 8 +++----- .../local/utils_nfcore_hic_pipeline/meta.yml | 8 +++----- 9 files changed, 24 insertions(+), 40 deletions(-) diff --git a/assets/nf-core-hic_logo_light.png b/assets/nf-core-hic_logo_light.png index dc3d54a0054f5b0a44ac6bad70f62010f156e2b0..7d3fedf5f154d1b6b1bb1f7248c6bf1e7071d33a 100644 GIT binary patch literal 61022 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

1|E+OC2%U3$AG)++csOgxYtvgnHkMm=yrNR; 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

<*O1}GUBj<*uHZV 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 Date: Tue, 3 Mar 2026 14:33:57 +0100 Subject: [PATCH 41/55] Change nf-test profile --- .github/workflows/nf-test.yml | 2 +- subworkflows/local/compartments/meta.yml | 2 +- subworkflows/local/hicpro_mapping/meta.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index e7b58449..585d0fed 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -68,7 +68,7 @@ jobs: fail-fast: false matrix: shard: ${{ fromJson(needs.nf-test-changes.outputs.shard) }} - profile: [conda, docker, singularity] + profile: [singularity] isMain: - ${{ github.base_ref == 'master' || github.base_ref == 'main' }} # Exclude conda and singularity on dev diff --git a/subworkflows/local/compartments/meta.yml b/subworkflows/local/compartments/meta.yml index 93994baa..49295ef7 100644 --- a/subworkflows/local/compartments/meta.yml +++ b/subworkflows/local/compartments/meta.yml @@ -44,4 +44,4 @@ authors: - "@nservant" maintainers: - "@nservant" - - "@Thibault-Poinsignon" \ No newline at end of file + - "@Thibault-Poinsignon" diff --git a/subworkflows/local/hicpro_mapping/meta.yml b/subworkflows/local/hicpro_mapping/meta.yml index 22806f4e..4849c3c2 100644 --- a/subworkflows/local/hicpro_mapping/meta.yml +++ b/subworkflows/local/hicpro_mapping/meta.yml @@ -62,4 +62,4 @@ authors: - "@nservant" maintainers: - "@nservant" - - "@Thibault-Poinsignon" \ No newline at end of file + - "@Thibault-Poinsignon" From cc7815b9cf6a2d3d13af28aca8fcd536900aabac Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 6 Mar 2026 15:47:23 +0100 Subject: [PATCH 42/55] Update ro-crate-metadata.json --- 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 8ff2de74..ae06e9e7 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -23,7 +23,7 @@ "@type": "Dataset", "creativeWorkStatus": "InProgress", "datePublished": "2025-11-20T09:31:58+00:00", - "description": "

\n \n \n \"nf-core/hic\"\n \n

\n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/hic)\n[![GitHub Actions CI Status](https://github.com/nf-core/hic/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/hic/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/hic/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/hic/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/hic/results)[![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.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-core/hic)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23hic-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/hic)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/hic** 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-core/hic \\\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\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/hic/usage) and the [parameter documentation](https://nf-co.re/hic/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/hic/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/hic/output).\n\n## Credits\n\nnf-core/hic was originally written by Nicolas Servant.\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\nFor further information or help, don't hesitate to get in touch on the [Slack `#hic` channel](https://nfcore.slack.com/channels/hic) (you can join with [this invite](https://nf-co.re/join/slack)).\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\nYou can cite the `nf-core` publication as follows:\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": "

\n \n \n \"nf-core/hic\"\n \n

\n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/hic)\n[![GitHub Actions CI Status](https://github.com/nf-core/hic/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/hic/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/hic/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/hic/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/hic/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.2669512-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.2669512)\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.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-core/hic)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23hic-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/hic)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/hic** is a bioinformatics best-practice analysis pipeline for Analysis of Chromosome Conformation Capture data (Hi-C).\n\nThe pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community!\n\nOn release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources.The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/hic/results).\n\n## Pipeline summary\n\n1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))\n2. Hi-C data processing\n 1. [`HiC-Pro`](https://github.com/nservant/HiC-Pro)\n 1. Mapping using a two steps strategy to rescue reads spanning the ligation\n sites ([`bowtie2`](http://bowtie-bio.sourceforge.net/bowtie2/index.shtml))\n 2. Detection of valid interaction products\n 3. Duplicates removal\n 4. Generate raw and normalized contact maps ([`iced`](https://github.com/hiclib/iced))\n 5. Generate `pairs` files for downstream analysis\n 2. [`Pairtools`](https://github.com/open2c/pairtools)\n 1. Mapping using [`BWA-mem`](https://github.com/lh3/bwa)\n 2. Detection of valid interaction products with [`pairtools`](https://github.com/open2c/pairtools)\n 3. Duplicates removal\n 4. Generate `pairs` files for downstream analysis\n3. Create genome-wide contact maps at various resolutions ([`cooler`](https://github.com/open2c/cooler))\n4. Contact maps normalization using balancing algorithm ([`cooler`](https://github.com/open2c/cooler))\n5. Export to various contact maps formats ([`HiC-Pro`](https://github.com/nservant/HiC-Pro), [`cooler`](https://github.com/open2c/cooler))\n6. Quality controls ([`HiC-Pro`](https://github.com/nservant/HiC-Pro), [`HiCExplorer`](https://github.com/deeptools/HiCExplorer))\n7. Compartments calling ([`cooltools`](https://cooltools.readthedocs.io/en/latest/), [`Calder2`](https://github.com/CSOgroup/CALDER2))\n8. TADs calling ([`HiCExplorer`](https://github.com/deeptools/HiCExplorer), [`cooltools`](https://cooltools.readthedocs.io/en/latest/))\n9. Quality control report ([`MultiQC`](https://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\nFirst, prepare a samplesheet with your input data that looks as follows:\n\n`samplesheet.csv`:\n\n```csv\nsample,fastq_1,fastq_2\nHIC_ES_4,SRR5339783_1.fastq.gz,SRR5339783_2.fastq.gz\n```\n\nEach row represents a pair of fastq files (paired end).\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-core/hic \\\n -profile \\\n --input samplesheet.csv \\\n --genome GRCh37 \\\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\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/hic/usage) and the [parameter documentation](https://nf-co.re/hic/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/hic/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/hic/output).\n\n## Credits\n\nnf-core/hic was originally written by Nicolas Servant.\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#hic` channel](https://nfcore.slack.com/channels/hic) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\nIf you use nf-core/hic for your analysis, please cite it using the following doi: [10.5281/zenodo.2669512](https://doi.org/10.5281/zenodo.2669512)\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\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 6f55ebdebe166ff25492f76c15791706161d4522 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 6 Mar 2026 15:51:42 +0100 Subject: [PATCH 43/55] Fix logo --- assets/nf-core-hic_logo_light.png | Bin 61022 -> 59369 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/nf-core-hic_logo_light.png b/assets/nf-core-hic_logo_light.png index 4bd4656d9a30dd0f0aac271993efe7eac7c2a37d..fe97c0d3d57b3a8478a9d79f9ad5abb48014e6b9 100644 GIT binary patch literal 59369 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 literal 61022 zcmeEui93|*|NktQ%2p{POG2_GTh>fbF$vKkWvL`7S+eglWvLVyq^!vx5wgoR)sd*| zWoJr4wy}@>_kPs*ocb4j*Y~ijuVhOY*KysvQ|q$y*J-S zk72oMpYe0q?VAbaq#*9EMu$IdcoXp^so>_-$xz2=@*S~&`he~jv*V1qmOg7gB~|ku z4iN>q9{kdyZ|YpwtFN7@xuSZ(Q#H%X?NoYKwa=aXj}v2~+N64J89ds7jyopzTE&lL zTX=gIP6(U()S#j$694J$cS-q-%;cBHV%V6wo@O1Lq5Km$NZ4lj<2c zwqe?icigw3j2(aYEkjNIUZPcw=4bC$%q+7b?p1P^!$01``3%CuY^87 z;+7(ucG8n%c1WY$)*4{X-}BJ>bo;<}^v>;*r&@E0IG1l!Tp!}0zq857k7xHop+*u2 zhYp_fh#Tp4e`MwESuwGArBL97*%!gNov}{m$`q~G9=%d*-XykhUDcMx*9Z8vuM@7^ zqN{sbAGgU%AKj>j(OX~s_D#&UopxQN1x;TX$HSZzlLZ`_Gb!1jb;~7L&Ywo^QKs%) zxUATeJa=C$o`Wn(`0u~mq>XCCKR=-O+I-dd@AsmF+KsIEKYun3I>QM6^9}ib-h}=6 zbEGi0-=9BI*j~~_{@7B~`gWkupFc}zOE2mExy81N|91pY!vAprQIh}T!vAsMUo`nY zUHJc37fd(*<%jyNj>ddGOjDuh(wcH?O+~F) zy*V!xT4>~5XIq9C3WxslB9ww_rwy_0rjBu#Ls-qvr``6Tm$xt^>3K8T_l@z=OGNc| z{OQ*yW@k$;&ulm^LtjVxO1*P|%Sj|BfwDApil!xwCUk85>)Ea|@NA6dqzQN_MBjBAeIY*4-a5LZ}rt29e0)6v>K%{0$j*iFkO+3f9+DxIx< z+v?E92y74*4SXr;g8IY3vRqi>r6H-3=`>5Ig55ZdgHu4unAhM>KW^R8p_IW&Jwftk z3SG}{6PfzOp-pAGS^%Zd`OjS?^1fu5`YO`|sN0hAnD#OQr8nOH^?-9zx~4zN5_aBa zY|)!Ki<~FCTFC1U$*`RR_JvayNx=bin;UvxfC#x@qrHDc0rFOG=mC@vii0y=?1>OI z5jnETUy+5C13a>cewL<0N)B+_Pd}Nqs5^i8&(J~f3!K&*Rfn_Kta9{9EHOB{H^<3p za0mHK?w=tE-??k8nHHE9qBB-!{q^niHqa42yvs(ySJOXPbUy_IDT~!))3`uXE)^)| zWhgmbSSa+iW9DE^7&2&?m-=gP< zBGf8JnJYZW!@i^S?D@#5*j2H|BhEAH>LnzwWjg$(OCH~?*l!LR$Wl}3D+p_XPU#M`Ro-xbcbVrz=!@9$UE7?7&7TC8JvF)yp z0}is!dNs5-e)*qo)0VAEe)bX zy59jGOi=7JI=XkdfGS0r11)fJqZY~7zWK{|n2Uho&(t|0mfLB@5^Z<}j`;3%YDWQx z0?*C(hiGrFPQOfBh1Vxi(cP((^?!x0TUuZrPL>MJxU$MG4);{)%fjiGmr)XvuJ*H4x zkOlo!=_koIUa$WnOs1Sim}5qZ4=MhMN9_0Wt-9tg1d`CFXfxD<-X)AE>N%1-a_o)^ zHW7;Le<}Y>1Yo{Wvq`rW%YH7BY*=DOoDmsnZf0z!Sx~S3C>mYjU~HnR()xg*U3|Ne zCc|1Ib)cuNT7lTx3t zysmf^-ip<}ElPNN;m@TNjS*wvSmIYn3Crll#8rSUeF%;?O3qFGE0vINU%9zbtBLZr zZ`UDj{>yMh@_?;f|&!?*ExwwMEphmk)e80zpq&Z`$@2kwr$3Ogj)W;>>wQB z&nBw#LRm)!JmS%~cT(5*^xw49dQ$Id?pf8N-4wPCr+mDtCXkl!pGlB|u7O(Ouu9O?v8l;KGq8sj+Jv11t~Y<}yc_gS0PWv2@HuWwgy8+R1f|`X zPR}{bOOdkKfGmBszj%AW^G0IyDjkIH&L(z8RR6E^k3s?!awV;>;)VE*a1&w_|E9=s zpQDdZbR{2S{y{Dr_^-T=FUT)#(Z>on6`v#;PFeq#zA7FcQp?8woVwb}k1TuWuVrt! zsX3lWY(-XE{L9zaHjFh7^gFQl$=%yQR=o2U|5#r1zNs$)Csu5=n;>e7`Aa$2KZ2r* z&?0?TdS2)lpzM+skx zQRTPqcM>8#{wG>v&HXGY5-ztjKVrt&1hkqgy02|&oqtO`q1zPToD%&nb{T8N^Qaw2 z)aLE>X z{<=RNp6s8e<~9f~ILgppLVz$DAwt3~l!bzMon`t%7OF;)?>>-t0_qym+!fD_ep)-i zvcVi0p2^?+=X!m2sGE|sr!Q=$BLT-~-U%Kj0py`SH@)%XP*G$;rX}%QJI@~jsN-aU1!pHvzeYJIZqGCd^+vz4d-9D(Y7;t!1)Uh zx0`i+nNOfT_Z!wc8=p?UR{@HD13x=IQ|6%RH|A9f4m)%V zHI>=HVb?ai&xvH?;d`?g57w44?uokV#8jpTBK3XJezkWaLM_+>WfKxT)u!Aif5oQ4 zUW|3*C%jDa=Ew3gOAF8>93)yZ*lEU37H5rVCR7K$sE$x{g5Iz2@2A&B$3>9)bSf}b z<}UDnPZ-2RxpO+pM1;J#UVw)`O|GN&7LFVlGL{okU+`h(XFVw~wc3zqsVG_S<$cpH z1h+L_Q}2ovy8`7P4q;m((CVgjh^gww-6;1`tdWWqjH}o$Z}+tPE~zw4r`4{+Vi`^E zpJrGj8+UT=jQho^-1L+83|Ry>sp%x{StoFy>FIyOmBBJ7M@#a}`dc+Ux4)T7?6t%! zT%&yfngu-O5VmM%zJDG96z-%6iaPeNZL@vLmMijWt#; zPTos<-=mi8u6%CvGNSr=W$%Xt)Ehwcxe(p9$}r0oWGmzKP<7O8Q~X7m@nwz8DspRJ zzkkz>;YVUqP77DOx=`f&Dca&q*;=Ns7}9`ChcuI zi1J;Kqx%CG@ZGNB_Tw-GkK_byGFh@nY_}VUT zHiVi3(rzg{R5_}{obrJMOkWgLc9H&D#hAsQ5Hx99eZyI_$S9F=m$vl66v@oEgzTSK5fgY7Mcp>kc&*SZ z+v4N(kOO#!lUF}A9*IW>?Opya)4xx4uZ360c{xVnnCsSIu!DgM<7qg!cu|4WvbRE^t%Q*j&YLND}MaW)d z>m4io5yb? zr`NLFvpuDizo}jB+)jykY1~7e%M#M({D=FvV{M-2e{a%v4>LT&n7H!X@xo%H)xKWG z@51gDBiC)(F4HnZ`xEPxB@6U01L2C75uOG;H_O)KWf;<)G??xR_!rqn!6V`^8ma)F zKFI)|vM%dvn<9rlOVIYx-utR>FF*2CR4?sskjh@2&&7A;C|$j-THZXw&t_*j5p|Ad zf4}(Mr|q-YqnkF4PELJzxb*!;r%+{X$xq@5Ztu|bIpN={K0APDO@cT?Bs37aPXgrS zL~DLp37tGC3m>eROw0+%ch#t9j2=d3sJag%AP&sPrI=;EqmGgy9?6dKSJjCnyd}QT zz2&N=&QY@PE-|}!>D9TA#ERLL_V&6>AtjIB5Zl}x9mX4&%_BC7(4Mbu(#Vw%Q2dOr?M{ZtqM7V<-!`2|3cXdDgIXGWO2}k3+ z&pn&eZYze?&ivd=yL4XPt4r9|dvobyKZSj20tTfX&4GHA%fT6)JiU%BBZUHs8ux8# zE`0FoDC?V4AOB#Tto8NV_A#G}X}-s8FE^TsS1S|!v6{`#T9!&A`|kn&o2XI4pK+)} zvG(zd*Z)iPQAev(So}DT1=lqN_|}*xs^b#*mPOg7e36T*SVqJuE#; zWkp8m-J8|!Q5x6a@fo-ff7;ZU*=^ka3IhWnNFsZgI;eylCiHq?hjJjt&OqZVldxS9 zb1q@cZ+7wBzjanUMtq6ZVQIHK5oK5E>a2S9P3RTV3nvB`DJDf}X$Fr+vqu!N^S`ZT z6?djT^!w4xwxmR#J(5zm--Va()*2DPUJ$`C+VBB6mxt^BR}hH=XTEgrQn%shvV!)j zl`5c)kwE;G8m2@%M(|i}j8yB>x{)tKAF`Hfnm%O9=2&-{w|)Aa=<9ZTV!KJ4)1)sh z!v5mY7LN%a28V=QOE>Z61NgI^#{5&%Zq+13p7 zP`OCeSe*cU#fsEIyV45_O&R;7OBPZ^)YLBtJUU#C8uUW6!6_bo7#mD)~?Ac~`Og7hQz z<1GBAvX54lPVPE;uI}Qd6aIxl%FF((aW40U%k76*&I{1Tj->3{4w8E<5x}v75VLOJ zA|$PA_QMCHR0z-qL33RW4x*a&f(37dAZo+XX2vf1Md?N9TA5%$mqn>Dzm9g3Ugw$n z@k7`O!NZM8%Vz#H)~)fr4X(<|H_pt5#xP1wv&Ct?e-;fVz0R;Hg;d)dg;z)Ya32= z`mo6h)d@e5yAMw}Fs#KwC;auxAtP()IUFU9F>_fbJ81bYE1b+F+nBD zv}WLfIdbo&xDr@4IobQYsBFi~oGmQy+SedIx0c;=iJ0nBg# zLEU`b)!UWYzfT-4v9+%g%gGU+Y{&!pJd&$S2)O^ON_h=%hy}qSWc4uO{DrMT0 zIQV1MJXs(wR(qiKfdmZ?2X03Wtd6Yh*Cn<8*HK09*Ezrc@=v%FX%$lC4jy1ZIF*y6 zl$3YHF{`Zk<8oo52g6-0zK%SEH(ShW@RYyIOm7F&_5!ZXB1w0;Q2ly=1HXWvHUcmW zQ-&nCV$v4`Oy>E_ZsXw0C-hOe(0-t-&)94&cZy)q#ntK>JXiu zt#a1F{UPcwreAdeC_3az8O(;yc5b1+b`eXU$RSBjKIEvb%=E}VG)^-|5y_7+KKsA` zlWvsrp~sm8`PD)qozhUNND}Ueq%hvjLNx0C%(iUz*1mo!E0Tc6LJSC@EybLnM7JVsko|_##z}Byjj~x$xceKR9mx&&hFs8LWJG3ppI6L5gD?(E2B4ZT=kjX_|qj&D}qG zeQIov8F&}KreLfB)rz>mk)Ctw=-QIDOOW?(^RNSbP{X^R(h*3)d7K{PH|EetH_NU_ zGD=_G4GU)@3%kK5+(cY(om|i!5zmc%R^YMk`en5}YjH!Fq*cojy?}{=bQEnpwU2lT zt1tBnRHZ#Pwa08MM>DPtZZtM|RXf}bTvnY_>*5w>Uc)nW8&q%*hujfAjxsdE1G4sg z&$eGbdG#Dg7Go*hn&H1;2}{@7!PoK|mK0Z@k|uVX9f3S36&b*)Valj#C=T?$zXghq zg&fO73l~1QTTjM`&~&9+-GwOExNF<0*8l{sNe3VLa$h}pRT;v19_*Z`1n)2XmcS<* zDLh?i$>{^pQaWVFnzu)yeozSXg&XBRLms7|);KT_nuNVax=-zfT8B66^WGx8O_4T(?Ye30VXQ5n0 z(Li+V)qSWvFsbZ!2_;rAX(St^U*8}=F-m`d8)IJ5bm9I*9Q&saNLJ<#wFi6vhcFtT zXEVK{L6s8ceW=7j22{EKK7tfkaTsY%ft?RRNNG@m5lFh_l5!$w480`!zlBai9dUz( zG!pHBNwS32`Tq^AHAP^{uf~Z?4=y#4tA%QOg zHMRgXwiw*F`2gq~KO+P%08NLI&MRq`brOaTk>HF^&wYcyjt7-?C$Hi;1unYtMV;kp z+xRb@vLu5iVX0&1PqrKg2G@562bGcsOrjBmg4iXS!5zjHDhR|#dB)M5vGjz0(IQf+ z9&4pF87=|%eC-9UrmgEkWj&L8- zF7=V%Il%xamLVC$*}=93G=`CVB*o1WkY^2XYNOUt>0m%KS2#s_Fj@ir>PXQ6V*3LT zacOzRj$y|HewBio)wMWkE8!$Ms{o;X?Hk83kq#S1w6kQNcz}kQPO+6=^ zV2x+S_8Mpvq`=yRDN_bJuI2(x;|cZj-_4=wHpC}$3eb>R^?pGNqI~)F z_LdMOfspm(5%abP4zKKGhs^KyduH!DToMhTEEfV)cr6(XqR0zwbD#u-hehJ9Vgzru z1JE)3f{yu@b+)-6)R&jCGadZ~QO1DI<{TPo;8uLq)xmp{kuvCvWDv*Ri$!3sNLlfh ztD3M_cMPctCt@uDYJN^^oSeIP%62os&f-HPsoxD`tqS zp+n!&7Y>!|vyr7BAL*?YDaR1Y{ux!Y9-lS!OFNr#me)I80smRd!O%sV(HtjIR*fVo z!Pz5f*LLaI@ZaMNNKOjehQd}OlyU)bTp>e9CY^xDF#n1Tut;BWjb)za{_SV8H=oT_ zYCpeL=%+A`fnrdWZ=6L0g8<*!X?~w&ul4m;_5R=tq(BJVU{KbvfkL*rh`_xN9<6bO z1u}9QqE6s%`*8cZf)wjzGe8-3eg5TqtD-DmMXP7fJvd)=Q>3S=TJ6C0wzA-&PJnTn ze=Ki`+8zTsNZ;Lck4?Tw46HVO!ff}`vvYq3RO$B}u#?F6mDGLhgfIyQj3|dFDx8{* z=(?;p*nP24dVw}Bd>5dtEgR6^gPTetzMyiSKbLGgb#NL`v%& znQE}!I;jq&)vrI|8(J4py>G0FILm
mPZD+!f{MVmIY#*X}v+mxZr=t77&d(;=YE$NFL&m;e)x#KW7WM5k9n9i&GSQev1Ohn_E{eDE0)FuN=5x<}MAs!Jq z#l14xyS(Us#*I>mJttb(ya(-vT`C-SQQ5caBqYY`yKa4-t6l#w+ACDVv$1Wri%?~Z z!D>052lWjr7~p;B-Dor(weL*VX@fXc{*B;`_h2MtXX%}>+zOtyeP|-$a>i(%QOs`J ziA6Ca@qY2}uu|$6KUgA3MFtRPGgucl(0oEPJ5(*|dvtyJ{_2Z~$N0pVe^{btY0Qb8 zklV?k{n(c_GC1hV;NJRnV~>(4cDgz(y-}Cs-*@XKd{h;_l&UFXy;9Q|Xb}d9hwf(>%k9Aqpg5W8c0B&B@bTMfv6}FH$^Am5FHhd{KRT&g6-{#3cWzWBnPV5i zBu?y@f$_6q^_uabQwOz26H`V~pW(X9B;Q#wX)^n~CYblZLt*H#w>~8Ud#Jfjl7g(Z z(w|ME+D=No>%ClonqIz~QLcJY#rA-p!Q{@{nOCp{5Y_}jlEl;{2e69`Pw5RYzI=vZ zWDmxx-B$9kdB4F$d7)$NJSRjgR|!;+S3(f6@?d&LRsA4(@F{@YPnDe2_fuxB>;CtO zW(qey$EDV6-L#YUvPC6Um-rcc^!w1E?AC3z{f^Wu$8?|pw7Ww7y5VW`wdTHhLc;rH zN%~=!IS~_nO91P*cWHx35zU#C++<f4ZJl%vD;%e#>B=rU4 zlD{9e?dD0n4jh$**(yy3+mqW|*Ybx0d7mqUA-m!+*fGCoroDITYg@h4EOpQJrfVH} z@zy5Sd!1O0m+ACi_=DuJAbuSeYPD#E~p!N}tYPz%X+wjYXKjt?<+ru(pXd$MG0W~#i=&B@g zXzWJvc?r;3<*_YlR8dv$_NEVsE^W_4OrlR`syGg{Jhu*fBNuOA!}rL-vGL2p_B!jz zR|T%0dF+e(8|oddCiaXS8)2$`DEOvrM&xl)Q$gmL(lgGRWf zT=dy672z|sS;gS=^219%>ydylg_NgT3Tzo?O4zQZBUI64R{-S=t&S+D%_vi^X%D>5 zEtNUv)gO_@xiZ>q62)O@bemf#ec#=u+hwm^pZ`1`ZRtF{@adc(zsr&ScSzSt0&(kr z`SLH!va@zd%uRFq7_56tFgt3zG=Bi9#6~pf$50{4W`Q9-ZL6Vwn=~=}LoK(|u~77$ zXE3!mozBh8`Caw33m;IX!`D1UAd#B4vgi`I=;SBU$|I2N^66+^F_s+@S~vf=*b@e z#Wp#rlZ_VUuw(2Wnb=dx=g~E{WQDGsy!xWyLN45Vn1%3`LIS_RK5XD&U~U*9lyXgN&O^ z1M9);c!Q=AVUMLNQ^m{iDNf+FvzaU)Koau9W)`ZXIRQ6icY0drE)J&SGMCz?!qk0g zh#{J+pH?nReHmYA7cTbn0Q6c0bI99+TiHvNp9vvC_jdA! zIQ1H_-gL=mH%NL*F|W!#n0P5GhCT#RQ#AnyIr?Oqn$BsB%l&un%i>qw&!Y7<*xVb- zY%FkCUj7_iKJeqmy885cvGymgwnCh!znK-!2kqnnR9C|Mje1{_$jzXpy*}&=ahe`t zX$MN7l;jQRjd5?2>t;@I&&i=Ukbt*3Q5IaICb*KKfcpxjkiMzX&1k0>?nh4h3VNJ^ z?9+B|2VZ>tcV`o_twdNA59WTzC+ZZ?iqpbv!y$G>zdw!gl8vOc z_K9PJI3e;^##Zk;cb#=BpB_{jUC0Fcj$0xdj2899`Ip~DoZeGu_>8U6-hSns=Y6Sh zzfn6I&u474_fBk&ijgWyK~J7KzG0UPqw5aH$rt6WY*4Y7R^1A@niPo2{q4JO(KUcb z5*@y4fr{I>@BZxTE%e*d#gG%>wTxHhUmBi~v498)ov@*ddv~yY^76DJ?Q6=#B_o;= z#GdX+SX&Q}%5L)Khyl!7Go2?@rU!EkWLg6gAu8I;up##<7|~RYb_p=#>7R_{{9J(@ zM+Oi4&N)kE7O#AqpX;b>>HmUNxcQOe3)hpBcRwfsf{}Y zpu)P}4|+P|SWUpEY>pU7?W0x2C=CvVIxU~-qB3T>-3SvP=EE=+pDF+udBQjcFjGGKGIk-t~Sb$T3ssgFaCZlwkVEQtzJbvbK~`r zsY&bT#KMd7GYVB(V>vAg15yH?ctm^XWyJUSM-8GxHe_f+gmu=)^1m!2u0>K9=QOIL}}qePL}6w+Ya$5gfR<3irI@> z(uaD9hNB>XEH7o=J)=k)cj~VZEy2>Wsd#V|1BBF-miUFdYeNf(&P0Dy-8z1qw|Pt+ znsfwsP>cbf+KP7UY{0blti7mIX#!j3hFF-(f?q1rPt!u75}v5R>Tv)(VW(X|rJ&lq zU1z_fF17&nrU0~ie+@`9S8;A9OUbIt7ssC7@^mqXTx`#2xV?Oc0(C(^w z3fGxUhx0gP_EgdjW^k0vPGi4ekLsm{N>Yue$Gk=klC<5X9`C-pub^nW`1@U%PWvTS zX9dewLtpwTORTSPSJ*(1jD@N;76w{wIzB?anJ5)==)L{1-LOE3y*V7Gg6Go3r z(S**vs;HEh&!p`Q8MI)$U?A1>oiWs}IXske_PKE1KXy$1)5tvNyc(?+thSK)IG+=A z{t8)1cL0+Cb1Jitzrdi{9ZFoPohtea1j`Og7SMfB#?>XSkH|{$G5)s>E)=&>jauyK zBeBwtX#1vyZJmqt5D9$Fuy=2{%V^5*pZ$7Hxm&^|!6^1FZN&P+9^ba-SbzT?2dny< zKSXDZxu_KhO?yIvp?2$uK&2w7Jp*o4{Td_mTWvio*b!-n?nfxImKF(Wj zgA4($@d4svlkj`peoXY^{5F|Yrt8aCpMlK`Kt2y;3TUTyf$-xAcQrXV_z!Q`6~ED# zxkvX#qVc@*-Wsk6e+XO+p})<;QkQJ5YvQ&)h_cs-;~`HJdT1eQAmZ3@jops?G8Rlr z67-zuxqrg6aZQIjHQQsZu5!_0LF|h=SeuU?`Ee@v#ln}qP%~HML1{gFKDL;5H(F<} z#oUWN{QimeTzghOSx5UJUQ;W0TVSc|xrN{Xe$T=2F`wfT-?fZStD~PZZ!;ghOxW@% z&gr<*k9)W7F5!!P`d*BN;9a}*gZ*xtSe%wSy9y0!KDYvLHXo{dY#zLH08Pygvp(#$ ziTnB6pblr*@T_G;1X|nVcSdU4zPgG^l|7|8QO-Aw2f9ZrUEdkMehIoqs~C@Kd7l&5 z1$4n>R+BXv{q_)4^=bnE*fud#YC2T)gF3OjfYX)C7SQM{3g)2L>3zto2h29)DHc4l z%}Hwz)p!2zmQNKk#cx;V>Toaa5iIsDH%~MAr$4^>glaXPekDP3B%df-jwf_nO{>lT~-DY1u}VOHy#%N^5K8 zydAcGnfS={P^($K?Nnf5`B*9z?=zgLj@z>eg%}pVg9YdiiI8!s2^>puE9bw^`7u6a zX4$8SJW!k74kIU`wsv3xTqJi?222QP!4R1^+M#-!dDM=XzKhlfnx6?)Z#sCu6GA<4 zv_C<Q!Sh2s^fso0b)beL(_lNf`dsgcG5Q z^CGf#k@k;Ak9~A*nlr7)oajpCD4(9iZ5clc4v<~RT0w4l>` z?T4)Lp90F=3%az4fX5a?Q?*UR!^!+&sUu+c*0gld!-*#_)kZ5z+$w2C>E@f&-XoTf zQS;>%Ghe*TKFNYPD6B~U+-dT9u+qgz$-B$65-g+6Nxln4If!}QJlqixOX5Kb)lAKO zd@MeF;@MUsBq>>iQA$KL^q6Tvr3*%bc(?_^Uv|xu_f%DX(2o`a3sYNSV z9VvOb&jAqe8bp(`snD>;EUCGKQnPS^kjzz-Rw_ptpuAA@W3({di37KLi;Db)*YlYB zWeaRu4H+4+)|2(Np1<8Ily|Xx|F+6X=Y42P7EPSbrs9iUm%Hs(L!g+}FM2q~M4>~z zZ2@`_#7zl?F&#GCtO8W;(DNuct2Q# zlnwmBL1&)Ov>T*%7ithZG^u;7w>C7rho2(|f|UG`WWVK2bfmH)?>5_P=qoQwZEW<5xRy0FNG1eU@9V1-kCX*0t4R ze@>^;gevw{OBAZE}Y{LQHWCjgQ!M|+c?k_kc31v9L&u;c~5Bl z(iVoIV_1$Yr3!$1orehB;JhhKWrM>u`b$^=W*=$;c*0){m{hdGj1fN+sDrh&aO-Hd zsL9Y?dXcR56_9)ULFO)>)!PQ9ORCW1+NgGSb)@VJCp#=WNzvsLFH zKoz zPLg4`UFEudSE>RK`o$>G!|Sp+tH-_?|A?e>e22xCn;V1K3-WV$6;1@ku6qA?w7U3# zE6glU^zLP?0m3pz@i;I>oRZOY1cq9dG2nE!&^n9~&KdhdhwaIeifz!B7urcn22->E z9Ue$}t4mf~H-xPgLJJD0g={$sc{Zknw8#|twB{tL=QMa+Og405LZy0d<@?MHP%Y&& zvu{Lk!^|-&+;SQSu6z1&<~hJnD&%_-E*tNsq$!lizuCK#K>4`Cy5=?ZRs1#G+Mm5g z!+HVGyL;wjTQf3r?~Yz0NjgpwZ;Tk=JZzJVy+1st&(lGC5duUB8~Be-7I1zx%{Xd< zr@xBbvr_xxMbY-zlG)3WH%<6&(2G_XgW86Hb>-Rv1XtbE;}yGPE-{DuW&7kqL0}t$ zht_r6RCE-XD>FTf(S&Hb9z<>u%ppQ(S^>)uAqWPjDY$S;h9Rb&iPiTMgO17B22X z0MwPIJWFeGrq}a*+PQ_IBK6ee(fiRZ9Rg2<6R#D8K9;oenj=&%Ezzy@>J8NPS$)-_ zJqBh~Y**7Yfh0oE<1&=v_SP&9(hkcIrr>^{#BeC?C(M^~2pl3)svwT|Om%-bA_BRW z7%lJ2Y~!GY03*y;&h3*c{67@bwqG(AU#~m^ePD zfS(n`&rvc}JvOxtJvf&43h#IX3D|Mf-1^pEx%mAjSC*@GpWXc4^Teeen)j*ddn-ArZcRZ5J~Pr;V0 zbNPkWf_kJCv%oAz&~cG(vcc4s0^5;2-%}Int>B^qdlHGQ#d_&A<-tu z#2|ZN79a2OQSQVh@z8~?(wEyj-oWD~2KAYp{AwQ)K**=Tsh^-35i2bza!|8qqIk&D ztKksj7GS*}A6<;4DAuAjGylrOF50G~yxm1Gh$QWDTW(?}4JNmBZ;`o=!eu`h7jEk& zBP!qygW7O#3*swSG?3dHYxT`=j-KidbL zRBT1v<$)hiQID}f;o0I3*CKORyK3eEJ{}<5#||C{O8Lp+2@j#$fB%jNN){T+C3D&E zDU3devUkl>PiO@nPwj?5kF$a&{K`dLh?>4H+po$NM($unTCL<`XF4Nh5&QJgZX^8xufXLUyjed1jM%Cl$ z08@Im86|XHIeB#ySbc+LI?{PJI}FPS6<=je<#yV!`pi;hkD1+dGsVdqrp^mZ>DPi? z7iG`7Qs;VabWGs($R0}L80HV5E73;4^YR39tPw%s8%6Dy@8~Ua}0$7aMD4C$ML- zK^vY2W62?)b(V6=ed47lZImhjh8hoZLe*D9M$du~%hE;9cM9&Ab)cR=wr`~HJ)1+} zg=Ptm-X3%)>z2dHR%G6LDj=lt^;tH4xb1D-PZzbm{Ftc>sw(J+J)6L#Pi#gKxo{uD%ysdH&z|RFXaS4) zV4k%KV%=ntA?kycP2)eFdhjU>tsViA(}+B4V-7Jd+{B@#7|vlq9~XLXY}ym%l}j}b zBDYp$4kw&2Ny#wYgU9D31aQ&pcK z^Y=U8Q+cra2hog8!wH`JXR9U9afBvK=5ZZuk}bU6tNH4Xu_gjUcMO;<;4q?uaxlS5 zv=Ay90-U}b=D`#8v>X@*>xLM<-dJw-C6|O1z?3SzmudvT0aEnp{%lb)c?H65xD>}l ze+`M)a*m|0Hy0g4O8_aHKm6bVsE{S94sEZG&%b}^d3|M&o)Rwt@JHptFApZTj$BB2 zgYqlY>?eM!?{z<0ay(A5>%ywT^(Xt#VG!skyHyn&v^{w>mY9aE$L`8%5xp-WluuSn zUjcsz^Br*Ny>lC;WUXEv{0Xz;!T>AYFS$L8V8CP6{OlVKDaWt|Q^iKf;tnZ83vOgS z0xrP85QFe&@HW~qH67GNpf9)L8gk)FnYb8H);1jHQq@R#cK@5`hYgMCvgWQd_ql<6 z7GCd3y^GCUp=RvyLkIi$o}}pm4sKNYCkNc10Z4_%(U3+4ttP-to+gSK@ly6HQNlrp z5+!MRmxi|{H64e4%Tc#$4?LJ{9M-Gy*abSjIKoWL(+)nq2abmW=GReuVQ}Fs2e~OZ z(pm^OHvoafH7(o_xWYvz*yT*J@i`&255&);?K)0R)A;xMGVbm^+p;0wM4<5Jxq6k$ z3-;6|bTwZ%&0~zk)wl$+f z@bo|lT`eR(>@L;YY*g%iC4@eljt2+%YuQb_``@n3Oh!OKb`F@l2-8^wS~d-JNI=e_ zsd(2}|8UpX)@Gc4TJLcA*Jp1lCW=K&xl8w$y}=xtv_PHjTvGZ`$rQR%KhtR` zNt|%&1`|CWf!dPUv$P&q)#`^KQ3r;)W`-)L$XH3fcgjUGrXHO1dj7-n#;-qHaAiOu zh)dWEUHm#^M&qA_IivW&mpWOJLT7Flj()IC+vzdjq~o)UZpPgkRxC87)x!a0u3l{v z1#YT?kQ1>3m~)uw@LkBY&4{sjh=NaovQU_5ogM1d(3+opIn4MY!&DXN$Dm^`coH}Yjdr<G`-!E<%+U+c6PLwow;U<_ zlF>Yr>Gip>8UJ&|`|@+gDgT7C72ktJe}Pdf~k zODD#)gr!h3fYuvhhQwfaK!%P?cvc(}K0PGH6RV{Mmd~zp768=rz1<^wyX2}zjx!CDd*sd;xU#KP# zww48ECpjN`AV5{3x>D_E(h*b%eEY1{+J#}C^7gB%iU^rgfkp{-hlS6w$Dc~p81Q3= z(MbRY{nf|>lWjl(aWNAv%uT43ImnFGTEPUowyw7PVfp@n$1t>`I*p;x8-(RAapedy z1PLz(I+&~Vp^47@qxKaJ9gGT2trn&#I_jL4ar}0B%H~rCgrqPnuyS>9$4}_z^N$KbKlHQz_{?p<~#q$HH*ZedR)_%H0bW4a(9W+`>bR4pew&|KWvzvWTs7V`c^Ju zeysbFyYSp~20w_L=@QsEm z$mk)d5^`Q;lq}8y6L}=wime>QiZ`7^kvF@XRwRsnAQVgWW zhC2gRPF{oH?UZO(dsqK4j`RXzrqi6D(7zQ>dRrIWKpy*+Hb}Ej-;9%Db^*}1ra zT+T0=D{s1k3LfiMAyX(f-tVn=5a$U)idOat^gXmhIIWOY@KBVW(6SKSA99HeKgaBl% z_qc>O1ei1@9|9oQlcas`P7%ykOC&-Q%6rb6wm4!oHV-%5J98_Q;~pB=>xX^t)|`=e zB*i44H~CNVs)vzt^}9=%A$4ds200rY_>8=*tF z`wrgvytAZt#+;^3bqDef_>IBX`M#Rv7a!(aN}#+zJfZt#dpB1xE+@!m*{@3$DamWV z{Xx0Um>!lTXzf%;x;!d}y309|zwFk&IjkYZf;p2T_Nv_rrUX=(tRu&0;;5*+NMYE9^W?it)19xOwOG`F2b5<4^?YdRi$KBX<2E`kIUU2v7JdyASM`X;4??A6?YJUH&JM}jO3L=Y&4?bv z1t0Sgt2x9wn%FCEIX2IcBRn1PY=|$#GOc!FpAUKI#Y3YBhr!qvf@W+b{R$4RYdCYkGy3OduoJIG>3}E$2fd;Bca*8l>RWt(84e9z}KH?#zlS82B}7UC&Xk^ucxBA zqbc{Uqp$QdYvXtoics08o(S$*c`2EdGGw}exomr}Ax*dMM+GPb3~$J85IE%935}X; zHi3)$6nvV!Zdf8(XxML0ykl|D{N{$;{$cq0moP>NzFZz~HKt+@lqgbGD_=odz@ObG z?oyRmf(H2DzLCeG!<+KHMKe~#306o)W_EawSNAF=4EfeEDboLA>dWJy-oO6`MIkCn zTI9+wB-xX(l@`V_Dn)i>PqqxQD_47}89QSlOC?6xvXfGS&`gnKED?=8`|fw%?&te> z{Qj7GZ+`9hu(|we z9J?LqR>n0HX0vC4FC9ADR|hv&V)zrRE7>w9ko4f@PFlkYZuKxHE6aPq)_)E-4C)#b)-rUCI&d@a7!|hoI;m^r*9dBgHo*1a;FBI=?38rp3W} zc2x!05^)olJHpnq5t@q5TcS@rZW z-An9?yQf_3k=n1RS>t9s4Jjv_C(=}@;)#|SObzIVL*zxWvE7N)yJKy9L0`KHO1Bvh zZrJY@OMy~v7toBjw$hqiXn}BTc9lp@o`Jt74q!hfEFSXSz{#!;?4x17RxEGv_H1j^hPllZt{OX}nZ8lqR^|EM8E<Lf_{5f{Z|0XzL6Gq4W*-~8U0`T0%t_2z^;rm9PS6%xwEnYG!pzuC^ZDN!NC#z* zIk2LO2?(=-u5w$0qvf#M1Zfx-fDf+bN)2ql+amQ#Xc=0MefD175B~e+o~beC9CGrr z9{3eZjTWvU?6xn`w|=I~bJ#7-cMF~KASLfYvb5VRR$@(TTEU~%aoR%0>$ea%yGL+A z&~{g}#tLHEj3`L$iuBD=hreMEdU$l`|AGhnuU>VsMlNmU(dL#GB)96X5sPY8tk>r6 z28G!0Mfwo2P45Ahkr}(sz~KRXsSQn@#jw81k@GOgQeP8)YmZ4E`c5UpWASXmPv0bc zDgO+C-ARO_ziz?J_^B<^-5`jEt>Ske{;}g(-TpMYH_-$ZvS|D_YDxu=Mh0LC_v>sI z{U^er4;gtOLUZ*8kUJIiM506T_2vNJTF^0MP*9N|gxfXp47fsv_BIH7dg%~eK!eL9 zU$@XpHj+Zp#z~Omylmh7z@)K)b8v`lnzvWq>0KXlZCId9>qlwJ zWfj5RFyzseNqTn>nl@27Y*2jpxNS|K6@c$F9`41uK<7}e(Oa2s7PY6C;HupCr;qo4 zhP_txx1+>lFyMcKnI zctZU$Gm?G<^oR^^`wAbyzRUKa-fllHt_N449ppM70GAPYsC8M8Nhb*j_t@fLL{V2K6{H(WrfsBhm5P%+!)Xbf`L5|OO3+;*xiLk_B2Qu_leB?wO|fI}KU%rLz9MT7t@>sa*TSzJ!=o#tI%ssV6$PTdtT2gTQ@vC;))0yWp) z8~6F$90JuPh)^luUY`loz?ASb+*D4UEuJXxl(LhZL_2kvz>g3+udhe4#>cQJX~h%S zy|Q#r;s7}O-zS$~QlHCvqg7ql;k8d)e=@c5_sg|PvaX=y9^J4`w1&I7mjJLvhNX}_#Kj-4S7SVGVW=z%O=?#d+=O9i2ej4HcF81 z@}0m7o=0J$(E1DSOnrwVI$q{G;M`aR`=2Z=$gQmOUgyxrTP>C!8cMGn{i(m9~!*fmimxkX2N*?s^!+3zs4w#gR z+jaB!RB5aDjl;0VYqQG`#=MC0-w*~o>t(Bkxn*J*=*QCBKKSRpsv@+>tdqg;h}HYQ z<$Jz$6gyOVVh*EolcW#Ht)4!8{&eBno-_qjCU8KS&z3--PlA+ktH< zTL%NL-u+&J46AEGX=~StBOnQsaUJ^XzTo?>4QRzMXmY`%3Fx_&o zMTL?YLY{qhehV2`G@nS`U}q>@P?CIEz-T{qeuC}5ZtQ7$>h)h`*jXT z$WPy?V0#Zk((yHj^t7vaA3QjHBDejhTm zKiw++E*%^dYSrq`fm?8wupD19nM?ubp+JKYAISR1)DldPqFYQ$^q_&!90fk*g$aJ) zS&VA?Q=|K-1Rd~~n{#b9;8uApCB$S2sf#w(G-&f+em~8tNV3X_#kbwc7!&wvvd(HH z7jhJ^9_031vJ(wz3wtJb&;RJsET_d39(&N$v&_VD%LsnU)uTL3!s(^K_nEO*Pwy%) zjdHBKyx=Y^IK-_dpxKXUiK0BbPUo1i%khMn8`!f_8-#~?g;}$@z;?<44$ce;= zKN3k3O&1hXn{+bjjh1_tHkS(yK~Q#AW-n2yMNF4VbW<{<K4oVpJqtK9|6ONT*QkTOK+1*~B&WoCA8=R_g7v}M6) zJ*}jVgRFaH`1W~|tck;KOE1~7+8N{v-|useNjI5DC5;F_l`;X$WAavD3EP~`9>lCd z*)D>2<%qWjz(2$_odJPX!vOO(jg5z2D4*i`a{rC-LZFFd2r1(TG8ZZVA^7gWfCiIP zTUCgMMcaECvS8+){=x7;_e(PT8lQV+Eq;J+$9ny!Ak~TsF&-iYAAzc}UDeW&L6#mouFCexE z1nGMJP$6p%4AHd>1$$>-N}ejk~-d{x?EQ4@($~wY9oM*-R`ziMC9|A|>6JV!N&bmpix;DA5Ana=$ehkFw%IgX-rp zNP%S=DR#eA4KXsUgdy`VA-d`n(IE``_|dxV!_-taT~jSF*{4SH;-OtKf<%o-p0=B3 zSk*5GyU%e2JzQ`D!wyk1?5b6<<%fZP!?*CZ62K4I{N&}q`y$yy7! z`_koV^Xl@Om*<|hina;(d1=obTV%lp|X=_XIP@O zDlQ8SqC}jo2DjGUayvV<#%=!~2GL>o5tu+=C`4f}w67%bWVAwC6kD@pQ8*uV ztM1a+1`AoY$#6^;uQ#)_gX8Y*$tEY_jlS=MG2iVs@&D@&$90;JH2({FYju~+4X#|-?`*G7;pW|bCJdQLCC(DWp2|Fh71|S*7 zXvC8!zBHJ?eo>X_UO7F5p3sF^`}qkxtfEMeuj(uSx2M3)g=_~f%6ECXs@D9#t`FGX zvB`cB@b}}$`c0e1h&Ck@+q63}Y5*jAClh-FPGZP^l6e)k#5YiS71b?Ah``0*@j-3~-=WfN@&{#uQ@>&S2X$(86d~UnqO_4RZAdZp#d)-= zx`oc^ip)AvUS|Jfn7+Orl+DTz8!es2OQyUm`PVdoGNznt>+&FD*7T1Im!EkM8)3f= zlYQrDUnjAkti{u&tg?Jix&>cfbvjG8Kr2uq$~A9{WOOu1eyQnblh(;l7?!ccuS>;` zp?VI2@?gArF%)i5``d$Wrv~6waB}+M;?n;Tql8Ao{^6!pHmUFGNX9bTAJiuSi3=T7 z2%aI`5OR(T8*tOFM$3?Mh!pd`ALAI)?8q)zd}qqawt9JgNNTNBuIp)>clteiT5zoE zghw{X=ucvjETbttIB2p$h+9L|-_w*gsoXN)-MIkv^J+uZZZA&=o*7GM184!nLjTm?USUgWZ z2)2EpZ$8cU(NkIRc_cp3*A6p3-tTgJb7$2g0KqttaH6FAZp;cx1qVIL;D!5&SBIV^m@~goJ7JmoQbXpYRV%L7 z-|$$}#A6})eQknHZ^6MMmA2v!?nU4&I}@!Yx1KhQD!u*fdQ3=|p17Qh5I4(-(e+^H ziLOcQtDTZ1%tTo!R9cs8Q87=zEw~ABcROD_SCYWNoU@4{ zXKno|6iyeiVFnYTbg$%%)pdJ(?RCx$-mhgr{M8&1flsqq22=5C|MzRC@%b3Xk-P)4 zC{qDdCRZQe)YD*i#@@QmIGAR_|FXcBp}|2;L%{ zx|^UNze5x@iov}K73ogkblu$^WCPQ>=yBw#-Ub$Az#h4Fuk@uKJX}`u_x){if7o>W zV9AYUOwP91r4x3vUHneocDm*CbF$8{F4HEKV33)!pN1Aw^-ASv0bS;#>G_sIif3YW z_7{d6?-{M(@gaQ!gD7%asNbQ4af{zS$U_Vpj<);h8Dpl>t>Q_Av9^J-tH?%?UdVZs zhQGj>#!9}Lb(zoXXsZVxK8}U?+eb`A2+=#)SCt?{`EshC3mOGDjG*D$cI#$i)n<~i z<0m>#`Z}@(rn~_8k_(4{P0QJN$9$eu#Vt$v;81 zg^)drZXZ|oDU-@+mD_)Y^--*BGMi#zs4;eNDp7t&kUouX>3hBuYs*?8laD6n?J@KU zIDA`_6{v4`!q)g4=JX5LLT=m9Z=y8(J2XINQr) zY5S5OS92EFJh3gSF{w-MTDtd9r8|G*QznFu zV%@}D`yJCfJ6!axgc+R2*qm&;RSIr=@E;I`F=tb3=so(v{Xa&{-Cw#m5R-V@0v!QH z4OacbYQSIQOHhJ-znYqfY-Lk&l%TouXTh8!>?z@Z_AA59jw%dnv`IQmI^I7F2_o7p z072WNk8MR62ReM}q>cgFVw1Tbha<&>5^35qIr$N#bbO3$bm?|&T%b$XVZ0^Zh_L6O zdw#J)4ii8)p^9d34)uX%==V^v?8O7HZ;`X*NlN%71TM*0iVRc#6F z!OyB%tgpN}r;p)~ORz3v6sEb}NYZ|V+!4Ixff5KrC(@*8Gi&b;EfK(X=muJ}L^`d` zeu=fE9|hYMhx(%LqgD&J1?xesxMg=jI^`%F#yOyPLLHKjRkp>`P+3&jq5&Ae4to*z zSt0vlE)028r=4-%<^)dU9|lX9^nX zDz?=evOQ^n!yCzvhGd(HF5?%!{j#nbOBm(#IjuHnKN!k~Gd3m!=|xvq9!;_L z%bZeFX08Xsnu}j8&i?27{eKP%M%?R|UGwz0KU7{W<7aUo2-FXbzLIZ>GHonWT(-Zzsmw9NB*J%zH0DJnhVRb~>j_*)T%n(n6 zLF)ZV=*PLV;0I@k=->7E4cfl`1r6>K4pBWy=iV*9*648Y{Dr?#^;SS=$oz(1yNmI& z?xAi$N~)Xo>9LB2oTnk)uU*#61B@@HVf4hc90X5ZIlT1oq9tlXZocX4%xE2?fPzF- z2bMZ_lxL!hdcfVKU-T_;q5p(OQN+L?ni@>|hm)X|V)|#Nz=$~#ML~hN9d3Rm&4^T? z_`0V>ENw9;NFevdxKm2^qbRvZ&^lo>#DHztZofRLeQuIM(_O2Y7-VmT+)75gfz)V* zWCG!3a|+%v?taiib+^A+r%tQHT3>nK>RD;t-c2qb+%SQhL|l$?GT;F^i})ni|EtfZTY!mz9d@A!5a3k@}#FpVO_wqFz{kD2~)<2Fvw6bf^` z1x41hF-SUo*T9P1vwzybvh%x*7kzF=78-&=!xHa^HxQspL|~8>Nod>q2X{*4ew3KG zg2Df3Ja5hzM^kR=gEEO5`j~~LxohdAw=~ETzrpX`*JS>%WBCO&D4Ir1IFY(ilE;)w zs$`Q^G+C#gv(MyIVKsz8el87Yk!}U`Hk(KpJkV*CQHNEi z*BV;ckDiGHorDUIBYv?O_-{&PTra0Oh!8*l|- z0+2wI?|u)kvdcF&o`3)ekIqBl`i_O$$nw}QxGqp}Yy{}a=gXHs>e9$J6rg34i+7Ym z5>U4D+kI|dX50jtjBhziExnIreNQPJWsrLqzUo9a^#bNAZRXV$Yd4oLx=C8ADa3{t zHe)|Sb)IH1q4Xv8-7{KgFByr+e+0l5Gxu_{M)FFJ?PkW>R(_&L+w=;3&1I8FT4ZVK z6)>8z?gs?^kLo;LQTq!3oqSVwL2)3p|3A9tPQUZ(oh_-^vuU8oh1+$y;Fib_`4jWM z@9Lsg{q%QuIKQnyoB6>g+ojTMvLQF)G$V0Eq2}Ugr5~8eTznZ@4#Stcl>9)rdm@A* zI4`_z^`dC{y?d?`#X&14qF$Dpz3EaJN!3Y8Hv3MVWu%pind)b;W!hbbB0&^82+=H7 zh?}+}n{+#?jPzKle2insa(Jt7SmDjUq<^>ejgsz`+f|>3!MT8&)vp6%3qyX$=Sn~Ii{Rl{!Uh|mJqB;{&4#?e&HSSzFGz; zT)**Hl;`=oOBRZ(abbERhc5#>bJw^{><`oVM4dgpjF5Xn*{i4B3}2G)+eb149;B-T zXP--G?3P<01U)!ImX=u|q%XZQnRKL}uZzq3iqDuWmL4IXoXn6Yr(jCiI&ft&*dC$= zWOh$-kg9)pyx~5meQO6)1!1?pT+Iq{H7B0@amCLHNffk@ZCk|p&f;Xt!s;91=?sDJ zAq?Nw+}@E?*-C@#67+YQ?QJ-NlToubm^5vg2j)|%XI95VJ8?)Z!@Zg~Bej+CN?K0y zw;mMnz$aamL)_4`nf~6Q3gbl!WPO@5A4dMi4Yw9P$VnsrOA4TtR069^aHrxjRUfW2 zKq^q56n+jyx8D}cWgW}C0`*|6oC@xlPbq_>86e2aaSlI*>m6^3jT~xJJilB_n&^9w zK>2A31tTFp?kLx)LDN5_R&mZO{9l<2QUvz==`;l$o0nam5;c0e1BcB6cS+_{V9%R$ zVAi^?FBi=TKh5IC<-TksA3hy(_mZs*#GX(gdKg>s;dT_I9|9kYSCqP&m-Vouqycmj zxXGTolLaH;90!p#8_u_&2}T?zfh@*5dql^iSD%<+)DdKwJa2yN!&C4|WuFexwN0P| zd`;kMXjO2BC)>-NX9)Y%qNHtJ34Jx0hq;$l8G?Mdy@&agyj%uoi&f)R({CTxcWc;H zmxsN{9%E=NM5q3+qkT+weB6HBa-LNgwg8#`)oX{7s(t7!!=pXF6v6-eR7Je#wAp1> z$jkbt&0aQGUBP$4`doU&CD4;E4=8DU05;EZJAd%YnoutsFFbnC=&<_lA1ZE z-*|$Izc7D4D33vAS1I9p6Tp35MeWK8eTjl}qu7dv2whV|wGn$5;z z;@OYL*Q;DL+*}YlQnWU7EO|XZ#fdT~ra|pD=$S`~w|@x_kC9VvoKs@MB<3+-xh?bl zNmJJ6h*F4zGg5UY2PsRjb_6PyuX_}OG-6c0&a^b}-O}QH*Rs0H82^6Ek7p*qi z&Gg%!WR_Gj{IDl(eITY%b;5r^xZ(=8*b`%GSLsKA*e9SO$R(~->O?p!l-2)(+WYt7 zyGzl_d#4^FsqSfre(8{I!TLA{hn24$mJ*f&KSI0irGM6{ihi@UXZr(a7gh)fA6ex!?^$0N8eh@t++U4B zw%^XfoQlMMd$2?7u8Yg)AzuK8R6U94$5EcJ7ir%_@40Um>5lh<3{{v!qqL`j0qL%u zm)flVVr+i@kRd!&-X)rzs$@JFLr%S~#VoSW2)%yvD_*udYsk}On5L~jdBJhov~p|u zAXAj})&HTEZ?^tJ&B~k)L6`%^LJ_Y9-4hQ#9e&3TIr99aRH@bLuz;W{$?H9I*!@oK z6`;d66a+7v=$l0b9RB;(AGd#z@7ns0#;qmeL&wI&<3rPX(v4eQ=e{hN?%5Y7=YZqWz4*KY?iMMjE_x+z zzJI+WtpHivD1KaKRxmuhXI0BI40~S9+7m=KZ=9N%^0jL=aVMnFG*hsuJ%P*QL*vGA zZ5N}aA(CF6okv!FfsfvohC8wv1G@P?_`Tif@0;9ae)L~)uyp(=t4b_$D}~(VIrpYw zBrc%Lt6bn#8N+wT;JDjEX@iH@sEIGYO&#Aof5O5htZ7~MmJXRr&XPTGFu})aRW9X9 zFqV&x38nK3mt`l*tA2HI4m)%%dne%89~p&l!Q=6uZ7WhHCe6jVTwiWg#J--MU6UB+ zK}3#U?1+RmzP&dg2nqekS)qkc8w<@#HXj}HX0b?9dM7EQ`i>QGcB7+w=6LzYhxLs~ z+=pAirAN5$u`5X*eQ%cI*IxEL^x+T7fLy)%8 ztNQZpxyR(o?6#0!_^_R}y8d1b&q;cUbDkJZ4W_hw9?<0EXsX!ey!%G)%+iVT<~Bi} zyvKZhzYa?g#q>8>dz>qnDVY@6BIkH>hq-W=VuVEjgLYiGZdY@Xsz%;I($Xg!);$0# z=lV5T{997Lkd3=Ab(Mzj5*8d&?trqjhaZ!dC5gQxmfGr0{NZh%pGdw8F>d4HAk4!m?Py`+n{Z zGpachNzn?nWkomz1(&pMxUsfH?82&$mfXuFim!L}Eqsf3>omoI67>0zX+AjpB+TW< zXKh@V;sc8>P4f6bT9c8m|G`SMA$)&C8?VXy-gUofg##;t*UbIbu0|9LUBhsWYyPq* z7~GfN)Z{2t_oSNfkL$4MZGRP;wZqi$I)OWR+WRaIu-SMR6%MS}e@*JAY1ciYCplgj zHxgcbt&o@}5XL7fdg6ugFR#Aw=-QSM<;7d9W5(6%x81K!73?SbkLIJRP0Jh-@iL+) zg{!2SWOJoO(Jl!?J=9oqygw@9+5VKVf@KGaC}x^>{dl!V|JZTS;XPI#I~8K&5)d$qg9=c+GY+3i0{{l!v6tw*;$ zlGA(2hRR{-kV5)Ldf(6M?diTb{*22Gqj#|4n%K>+-Z2GFYxA8xyGqshG|S_AmOi~w zw^*G|>{qqc*x|t$u6cmgbY$I+hc*>MUcGumg_LN=`>2?IW8njl6d|mqv6nAcSWi9j zNl~b?ak0~12M@8Z)!IvTk$L0F?(agSB6B`EbG8TNCgYr)+juuhIm27Z$asEBkz-WR zDoP@6y|HZHYjk{WQ~BYmNu0d68{XMW%l7d(>S0k`31ddM-m>Dm<*f0Qn@M4-H9ZQ8 zx6XixM&Zkgj(sg}9*v>1p|%>0Y}cVVK1qzYGqc|qRr9)Ib!y|dEX|^N7IQFlV}Iz5 zv2QBmiGsQ`+|eVVCnapoW9|R#%;d;AL8`J0mz*`^s!33U=W^j*Ydofp1{-X3dr9s7oWdaP<3xiymVL(L;n46|BufwAbW@KZGV zubpu=v+NQvIDX>t9b001Of*V*P%4wd?3rxke@26%wb9wOimc{Sv)rb9y;%`53LYh{jbq#N11OQ@P_@5 z3S0@{1RH+wik&gTK5eAX>JsbTcH}JPLA4j)Szr2GUS(%nw6BN0>>3TvCTuw&uGZ|h zp*dtAZ-0I7Dhj1AS5~=RY}EVbbKl)i;05Jlk!_AgC#Mc$et;{Frjq(@Te&h#KIW)l zHWT{~t-vtg2ty{51I3**2>pYYRg^|pZ@#%9#g(IS*U&P@MxtNVDd2&tM>aEQnZbb_ZxbbUzao5AvQ8O%46o)+o~f9TipR2Tm})ZU@0$v>W~5RuXMI{f92vn6E`^1SAvm zze?mV(0ddi03vk+G)8flsx7h#tr%1LmEKe|8gf1QSx7#ie2sBzF|nB9-j^f-YHF&r zh?{<+GP=^oWZH)N0c>*irJgKQgpJ}N8!Fb_93_WE6%MH#6-DLCa_WGBc;i?R?4IYb z5oed-zjkR<5o$6((b}75Lt_U^K~S8JN9Ksd{_bkGR z?Fg>YXqg&utnZ%G>T@9V47ucEO&|NXo=gA7==wb=S${wI&-X6jgq5`9^+9B*ZtBaS zcPRnEYqExVH3^CJ0%0R)waNKqKh{nWiR#qBwoHk*{#CRW0Eq&p=Tm2LbFmKo=R3Dk zqhAEKKGyz;W8m5(Yp=%w0Am$~eAQdJ+t%im>IeigA08=+nWE z^j!iCeOy`Apwe+H&ELa4z)EXEXYPJ<;7wMv(@RptYr>YAgoLdBbd>i$9aSM;epe72 z%lG^lzz*qsoBJof&fG+!-dJ1EboX9)(Q^@CFhQP4ewW6q$}88GK+o$xih>p;)bcC% zZyHPABQ#H@1h)d92H;n9H15Vt7Tg0<38+V}lnuB9z2ouaKMsqsWx}IR5jAtcV#tLGK6u#QB%;6&fK%hY=6t1i?OrFMX5FqGH?Z@rUKfpL*X`Am_}3lIrN0$HlKFe;Fx&g8QHCW?^E0NuFhAu1xPEd$a^ z_X2bsJekSin&P&9HDwU}Mo8^3X4R;Rb~(Q!>#qSAN&pKbJ;sLfvc%X0i4V_IPtJ#PyFM7U)3e?mY=$$x; z0esJj2hH<9SpG#N6%h}Qh%#bC`L32+Issrcn7HWY=c~-I&r#rfpW@3eNtOnJYH5^o zjc!yBwmf(X`;PUOBg=X-8bM#tXs; zasJ6dD?kdi7vJ4V^2mcY#8~YNxloT1K|`g#^l^!7LP-Ai!p9>1@7;)9@yO{ffrFmt zhQDEsO=kfp-@>)UPe}KTB2Z#Hx?M*ZmuiP)KRf1z>qLx|0|0IxwP5Q{QZQ)J|Nl_F zFybJ;As5gG(1@F!0*mSk!$C-SzDCUeXiRRaH6gCz!S2$5wYm_&!~VzoM5&^j#|T z3qy{ih6f&>YKdW}3}h{(%mVWxnOzBN+(CicoZ%Qf8Vbu{qQuJ~^yI z#cs3+23tUCidlaxsl7);TkRPTg%d+w5Kt-~-N0H_BJt&_rtq}$4E#c%UrGC9EN}p0 zbggMcG-#b~NDK=z#p&>karoI~AzB;Ez%FP5U^XpFa&(ZwHC zx*b?8Bz9L5PIG7}&}sqYex?r2(s#9P0X}`kRoRri$TtUz9gT^OxHQ#-hH%O0rb|gX zWyn31%^&*6In+8q8`!|kb|a$u8OtDAU&f~AcS#0%vbNRt6sF$!ZAtwde3liVt38R` zc{$Ea=l3ucXFGaLUJ4upR)JOk^fF#Sj8y*>EY^=zuP4YM7mj~;4yR&MHnPdG7*TkMN;*Z7C4QrGZlWEM~Wm?INcQ5 ztN}=3vgKu%=UeXree>{+6M1v{-WwA)s6c#n7I|XEi)mX8K&0Rad2PNF zez6n_YWE*YCIV~SzRBLf_?;_n`$17ONcDTPjqJ3h-- zkJuY*I_ZhZOb~+lKeTet%5j6cMlbqXhkJ>upcH$#27sQkc zpq2ap&r&1v%kk(XM^?0=B56cAaiRD zf_EU(GeDX?@pIgSG=x(5;nq22-`Q|Ioo*$mm#~hV@EBF(`0%MFrH}?EiQVtL+l~k6 z65V5?FW)gC1h09;fd%LxK%+?`gR^^;4B_j4)T~UR&10fPl({4m!9$rG7FBYCw<50e z2QKXC;NHC(X(q%BP`uc|4FDd(0D8lYbwQYIrAbc!pU1WW^In@2?F~D6(~IaH z?KkB;B{t(euw@4*sXH-5hsL0fQ3b=z ziQ|Bp!H_eR*|6^IhF|DJd*N@)(B&NZ9)lNhXKhPBQKKp5{=P{`GsG1j5=y{L*8nTwD-%!nte@J7LgjVnDJ|{@_aFZkO@XK= zd^{@K9S*}cR%rF)Kv>b@0%_GVNoy8I1Ub+AilKakD> z2&U`ddMrTiwZv(ALA?EWi=E-{?}&bCi*`coefjWbgFio5JZ89+coHEV)QC$<9`r+O z_ov*i;W{n#D-Z;5fg)ukBT2b+B!o_vh~Y9!#i2IzQUO{Agyl>2&-u#{7Yi|tGjIcm z_sr4i^0aUlh3Lyx#n(SorXi4fl=c~Zs+f7|?3J6DO|nGIYVU^kixA!GydZ2bdJ5^j zh%d&`dv0t6`2DysOT`4@kuDGeh{85*aEv!B)PDobd2wYT5DCnR>SR;ceyX+yj&~#> zIh^9Pf*Ie1WHLn~jliX_3CqF5MYyAfMZcjwJ9}^aTmp}Man~W@6_Q~Bl!m7acH!`b z(_`rNqgF+)he+0dH@w}NG#5nXhIij&_2*B{;ZiRhcS@~~hlIhOD>Z5AIPJt*{ojAyIel#haT!j>Ac^eLK|4rfAE`%D-2E@G zBF-n0Dar5&K1t-4Dz#%Bw6}j9J|l`k&6`1ZAQkAuismfE5lb*j27m$AvY8_>eEVV{ z)}^u{GD zyVO(Duz7s!po#MPq0wh~OO`4Jmb!C*d@G_aDdZ5%muU1uC`DrGJKA_zbz=oQ2tPt? z4kQc&Vs|A$kE0v1W9g>m7SV*-xgQ$|wQlzUj#zCO`;WgZMs{@!5+7g*YuN;kox(-)~_hM$G= zQOjK4^lwa3D1$tEQ+|EAkT-MtQY+XrW+|I4x`ROB&Fj>pf>Kn#5wGmlYu5lRnE-uW z*NS}BqDRt{p!qe#8Asi9^e($%nvz<(jW>enOK$H;{If}VE-^%g#>|_~_SDwUQ5&z` z*y@n>th$sBh1y!FLIWSaBj6!AoLuWAvib(z;&F4l-6yKtAC7XVj&a`>pc*v#>EI(Y z6+fMUE|6TQhp@`-o@to>Z=X$gJNWbC9&4}(IZ}u;t@@*R;6#HODWnu^F<%X%4gumR z(Py=Dm+XwDnf-r)4uvt54y5;FFg&#i;B^v_rouWYgDhP1VJkI1NJs1w@uKTVLJ>@G zdm0#zj>0sbjmOn$&cnk8lLmb|<|YHbqD$9YA4b?%m}5~WR1$cX@Dkv=9w(+We_UtD*6uO=CYgP=|&d5{CA z4c2V?eSA*G9Q!AU_wG%3-1OjLdYV??<2`&=<^UaKL0Hw!3L?(EOmyUAUG+qv6{VqX zc+>>F^lb{A`Bv?KEK`G4dB^LCoYiU20YA?6DwR(yq*WIP^L&aSaM>@Z{uY$wKwPcc zZ2@IG1&kLroz5G^e4nkz5FPlaDcy_&YH^cPrQ^8+eROewKmYd6Op&W{Aw6u?zhOqC zIC`I{YxW8!f<>B7us*#;>cEk=zWFIFzMf=iwSVo~syJ{b6pqmX058_k7j-G}|OY?OY^EWAe^Y{RuNEI1V9=^ z2Zj>$CO+APeg2WlHh%|!{3E7tF#>V>@@F(elZ`R1lBLY4ju&tORhp1_u&|QIvb9F= zdIQ?5t@l&kaFQlrF$CmVsZC1;LxY7!K=(;p8z#__xDqqs`aB#ciw9qggJO9&Shj6) z?apVhe)^o*`+7pNy^uVmmObkWtUd8h`Jl#qDKF5wvIxTd&@F`n_-OWH1HBG2T3WPQNXA|b7^{vr*^VhJ)lQE2O#u_j_tOp>7{C5>8~U#N zfLFOEae#E)_OX=xn9mn~U9tXqCinZ^;d|tkzyQ5tLVJ3gN*z;8>`J z)8&~~`br`eV(K9YN_Fn-sSq!3-Ym7E@UXrcqQ{@+K%z2k{dnYP{lf2yV^&ZOd7y;E zx1kHm=oZ6i*(eQr>(Jx0Jp;B2p+9gpHu?)>{lKV}x4DYbYU`>4K6kle5+9QU%{n`9 z>y>~tX?vW#MSuAj+^vZTzDRU1fFk%F;LaZKKq?WnEz_zurj#{w+HupJ=;|V|$)ODN zMuF0qnySq>7O|KT2sbd2OBXoX527^orcTdn5LdleaoaCRg1RUK$s^^-xabHs#`v5( z7#GIH`#0)bGYttL;1;H41R{oDBciezwRbU!E@zBnDpoGuS9uzJe<5Y01A^4yCy{oHP9Q&?N};Zahdw`P*!n5 zY4O&FO%>fB69*ljf^xtwcr6Mof0W54J4OZBw}J8J-q9)1)S&&&w6Zr)9Vbx2XJ(EW zJsuzx5}R6@Th?m9{~58KXF=_@?mCi3xaP0K^1YWrLwj!WE!|*kyDXlK3ABQk)*q>(6LsX7Y>X^`mE^(m5H0pUKvN;D zeAM)}uEd?VYD#QxhA`oBel~7h0m;dB`1e8>@o2o}Iv8U7x0%_=9{}x2D%sIWrZmwcy|75k4waltR`av-vvn zm0lBC-vjCko}uCRn4OdiOTh`0sEm!nw|J%FS8z-r8r7S8Y?HGlZtzC8hR~>lkGvp6_P|FuM$1T5UAVLKoyLrr|9=E$p!7*sN|@v>4uS zhN75h%fp;W*E}&vq|Q}y0p2>g*Sdr4P1R>f^>jF1$Qxh-+}?;JI=owH*Lq?&-2spM zf$h(D3t78&9a>(RsVJUW3M%^cy|4$+bd0tk8R%mc&JUp&QlCWCa3dMARN#f(?Ugk@ z!2MCAmLh?h{K7;{NZA4m@1n|QfAO9TtT_zmsk}D@^$ndJ11B6AX%Doqk)>&X$F@DD zp%XAAeY>8ClxLLQADVl9KBQutR=UTda->mNS(&sPbwUl+{?K;;E1op>aZ}45|2b7g z=i%N210hIlbjX8~1_3n*L8p+CUxX9ZZ?RNVAou3r)oUldV zLc7XhM}Hu$N)_Hs{qe}{-W={=VT0HU?a2qZl$8~+jX|pb?3&)^_4?WdRz_WI#z+htC*~K)tH~Eh*BR74BR3O9$a9|HnQ)|;~ zJDYd`HN7`^3%VC(avF6+9Dv>vD?6=X)Eij*c>e*7myCt~B+;QY`wT>FXiK zUt0RXX+J}>U#UzhCmm3J@T8Q-os@F!k3-#eWd!Rl(E;<4YrP)XS(I(9Z*3%nK;hLo zG9DZXQgoYd_V!-;g6@@NvI`6a;-Ef$q|O~6-3cu0SywwLDB5H?4UrL&P?Qo+4qSs2 zbCk5YZctebIz}mfxkAH)2F!foUtI492x4T$_xi8c+P3*k6pxSVd14nlH^SPs+ToqU ziZ2*PiN+2(K>~fbh@ydT6`rZ36=@n8=3AuQtYq}*iKvL)W{KeefaYh?s@bM-r+{I2 z;KI~6eI8L6#MMizZT5li^E0@EF^+~T;e;&^bv{L#$U)(k2e)2C*mCY;+RD`~WQne*~u7Pq{3Vs3Y% zV?2CC!^LdauGH^BRo|}w;%e=+iUHt4va|Q=-_;oP>#ExI+VA}#X*b)Xw*lx`A!;f{ z_J(lYf&bo%OEoLw@W0|qybG>C*5EFx5ecAT2KyBcN5xLXjBPyp^J2EAe;8%IJO+0J z8XCuG6i0>CrDS-?{e6mXGnGajBzG*djIQzIbuUM$QC4Q;H3uIlm-KD~yDIJ>~Apy6v`{QJz0LQf9?X+=*FnidT!+m6(KtnA^T64PBTYU z_&j<2_Xop?S&~OrSI*N!^wKboeCdopweQfSO{mJ5Q#|V^MY96By&Km8F+lg|o%VpW ze`t16>fVyS%zl1MeXw<4GkiY_2}w1U#se52vRr_k1UG}rGnoF;&oVtx2P`jfneye$ z_d1v`SdWBo$vExvSaxY=RlI}-6splnf58K6xGzo(FAz1|yw*P?CMNcn0L4pcDdoQ( z@-NRnY1jO-;?m3d4m2{By7pM+bT9Js_LPmkTnV3i(^Wm6!ht^?I4QovzHke5JhhTrgpC2=%n;>zJQkCOIq4=_+CBm#n}K@+d7YpHqv z0oO-R8=OHeAVz9MtjGi-{eBI;#@p`_@h(555$v=ldC&u=T^P7lFRM58H{JsXDQW4O z8E9(mt(4Q|Cv=rp_+0w9mtjM?w)u)7%) z##z00Zt#P;!ZDD@5FFqhZ`Fg`!_2yifmWOjM)vG*F1Sn6QlbqLQ!bWq?fbQ00L?f# z@Y_OwnCWK~7dtv?aR)U*j;2DWYRoEY!9>8AEXW3Z2^wf6o+TXB0{sUIuP=_RoO zkx+^Lw2NNqV){5v3H3lbv6|7-8N!6jBGq6?EU0&BBC=QjU8E=q(geYh6?GLv zRJyDZq`F9x_WR!5h39?VKY#zexu4G_xcA<3=FFKhXXZO|W|yqsd|htdQ+O9&@DSYC zPu6V6IeHxdi2}X6&5F?*Ad#0b&O$=niqlZKQujGLz&l)HI=Bo^Om(1fD zn?4)%%}4=&r$t+1^J!QcHu>x*k&jxyuc~M1b-%Co=dyxuk1g->O$ApjPGFQF_Q87# z!#&o`L{L4cv2eu&^U|M?VbzX7H^O2#(X45Z?)?iDN>%yvws;L;?No4M4FZ<6e|g;K z=~A#St)Q2Eu(j+G8TPIzd-Zr`ah0ZEAvNFAuZg3|9|i?}bD=>Zw|^e9GRHWNNZPa86C}ko}i1 zkM_v+-qkwmQqE_Kvy_ZPx8-O1yvb~yeXuaiO=0{}Y!p!!E7J{&T!;sIMq3)xhR@tF3jwB3rY~S8*S&_1G_{gs6 zqZMiVk}!kx9C40(YGshyowktIF-w~>7iw$oG0*gLw6}kgdA8LK|8%+&xTQW%E9;|C zRFBfoq2UwFfj-Tw$9r7=el~gd%4v8)Qa$p>0@J!gkO8HzlXN*hIIwG;BuB48WZK zjDChcZO)#*AHjFkiT&nRFsoV9&jP0PKg_rG;EvWJC>^!NYU{;|Cz7`?*!~1jFGThrfYg9zw?_A0dK(FgN=K zmV<$Nq+-ZUI=h&$H5G0xDGnimBOa&~TjbMwVE0#ROYvPIDxz(RwsV}wmoiR--g3G- zZpT?P;y@ioaP2|)SPN{4K5WW80Q)L zHy%C5s$-wH$QogXK3wYBs@5)buBeT?M@ty^ZED8JB7&nH+zkz0G~p`~+Hb%G;2 zd>$j|0=YLmg}Z>;>ycJS)|BMcJ))F@;!pARxD>qnOC(it`WwJa3(CmNtNMZUWi!vn^7TNn30E zqzOHj=2+;D&SL~Iw6DBs4ajLNZr1dm+}2Q9CDU#`0se=Kr)mhqCd2JC=5j_en?*$- z((R>qW#6w<0m&(=F9;4{A@HJukusUt`zcRor>S%%t0bfc59m>80{Sq!=m0LAr-eqp zs$<+WQ%eraO6}_66FEN#E^w)X2wm(eAK+6Bo)E(T9!&KG1%4SnQ zEj$~;@zEy5$;9w7K?*nEvX|nvS7c3uXrr1!Vaz9kov(L~rBgjqTjUNjB3X)U76>!m zB13cV_t{7cq1C#wT3$!T3qt+xIzl0)zKVdq@)ci?!>6TmwIw_l)AJ%lGVbhy9`}qu z9YHZwl~mc>Kjqi>yBPQ&(PPCqL$qtf7JsUYyFWGA+LGf9adpE7DJktLZSUxiK^?Il zNYobp@fDfhw3L4Anvq3hr+dp=oNpyfY=O^8robW|asy>P3>gphqLjGeDL=BTcp-|l0@G1O@&VU`zfuk_CHZN^;%_FTJ6D& zfYY{1%=h|Zc7cN=)v#p62T{gRuKkyKqQ{(b0c|7x(LSz-g?+vs4YV)mz1eX};h62I zG;236){}|&t`;Kmx@aZCAI}s3*5E~oju0~_Cnx7_mMlMM})|MjElZ%qrc~CfCiv|yktmg zlJ`@6Kupy{8UiUZxK$dVWm{)Qh(a!JAp{@DnrIQNpDPo#GP)mnsfv>j4qQXkT8jJ0 zFdfH-E-Q2dj@&#AL51ePFWLQ?1_-Dv30Npd0@{1JV-QJ$+Z2N0btRHZJ2sAF9Fo9> zRtOsOREMi__LM((7kQu5=p<_}T;Zb4#X1VEfA{a9goy9g3hRD->#ms{^fJBaOFogd zUcA=sog5c3@q=AYC(-_dE$YN17NmFyuf;mi0j!H1a?{c| zNJhT0e+#99OtYPm>M^g*?uSAJL)lLP})It|%UnpKm z@5{`-N_3?}&W^nw;ac!r($I}W4{F#_{E1NS{CT$S^<#G5-@`2AFBJqXx%+$9eKJgY z`m&45n0*%GlO6^b3VgBeb>AYdz(Dng5gn!xR(G-nQoKU}AIO$kgbrfEkN$b+JAP_*;Nlaj&|!P@$jo)DZ96I{PAk=_!(vE z)VD%z-f}twiM-T;J&OG_hayBP!BYgR1$9qO9(U^~YVk44wEQzeuXmsL9>G&}S^9Tx zUjP-XJ!|pLYtNs0&{5&2ZYh2#4P$i`Q^xv&XXcrf>7MTUsycTv7iyAmcHk%qcTFx_ z0zkaG_Zv;saTR{|Rihp3JI2B5D{KR9f1Y4&(;WamU4`CLe(4cCRTyv5ZY9pHw?8rw z*#xhN?7;C2yyHan-nW<6_Hm}IGpY5WlnQm=buhQ%MSIGhaB$4Lb}khWz1Ue}c(irM zi?W=q1GUgWG!h1Py`I#(ixKr=F`euV$p^66Q{LOYRP|^By$+GE7JYzThlRJmBU>uh zU6+yLIo|c0$rK$k=a~B^*C$Qk>1Y^K9Nc0EaB;i7A|e%<Y@2`3-Vvr-A_ybWkg|wulK{$@{{_+t|*vF6h@lfYb>(HY~9NhDGp$GJqrv z`cS4?)pE*hV=h#926#11D5Rn4H`Yk1Fys7AUD)RJ{fn?Hrbg2b7L|6B)trpJ6cg@l zx-A9^1wFK|P+LwV)i1DrOh7hWtD9OEYvisK4JaJ*a((;xb)h`_14cH6s#+MTJk4`) zfCts2>c|vi5*N68%*0nN)&Qo@x|n*m=UBzx_&K^`!@sPZ~xg&raI~_Bo~pK)s(t>N6}-YW1hj$B6`a?@yA|^ zKVh9zD;zU5imSxRjOm-(`ZLu@1?ZW}n=~4Hn8dz)Y-{rcB757kb*r+TvP1F{+3)V< zXyXvl^DA+)f&(Hq3ZKAAII~`yO0(@eET0~*trKiZL5K^98^9Pp8Ic}0{RY<-s4%ul zc&D0;Ue{B*H4NO6lJ?&j&d>EU)fGgLpDxzC&h5>dtf$(wC;MF`odbVp>~M64`7u}L z;A-M=YrVlTf!sW++#f@^DF=FDu{&jj-JKY+4J62K(@m}M8|z(699Kkn_?*=*BGjC+ z?{x0pN$GW#By|l`9rW&kh(J02w#mkrPkRmCV_#Unk%DFSrgWC>rMPS$5y1$$D%`+X z6~G=m+K?OX`fQ2~olIrUY3t~FpE?wSMWrd&NTxqfLzB<5PD>T{qYp&lR(0-B| z+ptM1MZ;e^`ZS8mR4UaJf)z3EmvDQ{l3u@rDA(C-EdwoLp;GX@trnR5%Bv1r zc^On54!6A6p$_-)#<9s<hKX~GK*v97)YpZ}>!b9aO zkHVm@8^%|BFAP^aJh8I^V%h=+Y}(S#R_=J4!KkBSC08ipR5l@P>-#=5yTXZ|kiWKcjL~Y`N)BNl9VK*l3>RB${F9)I#+c=?8hYsF8j{K9TC?Po*}JLQ z+Pt8KpPRm|i=quaT!mxlum|#|WuZ-rFd9m+zI7A!LWs&B^v~ufXDuDtuWJ(l1Mt3*{Tt7IF** zYLbF=$v2O}X-g27WKlR#>tM1UJ1Ln5-J3&zC-h(ZOfjL~Kf5Qa30XNx!RHoYH+?jS z_8t7-JNzCvSJ0F&FMi9=0RSfIkS8aJsfU)M8BiJ#q9)oJa-^bQiE37Wrz+IIwkE|L zXR!?pgJ%E7l38akG>aP~UcXum3|=8pPc8ELh$LWz<9iQM>pVaSzjRJv4V^xZE94lo z?ufmPh>>P(M>x-PVYS@WHa&87CS*GZeowoM&#OACwFC=kx{(Ww(*nA)z>?mZggR8+ z)=#$yr5a4k2MqMXNb?{4gK&V!5K94>e2l~=lev2^wyhtV$=T^>+#Jqe$q2WnAVJ5< zLVT813S~q)@}4cCX#KQQU{1rgeNI$AJ(ZV1{=Jd*xBI(L=V>SGiAS0%Sd&;fY%UI^ z&s?~i7r8*F^WwcHq_=OMHZ3-KB0XS+CAJ_%OO6$?!?Riv3>B-E$j3uwF?!ud;8N{pXwZa|kuENHc*Sx-_31!1hXx06 ztr`P`u~f~ev7DfTjO)cnzeeXquYGq z%zDn2rfI5&ZK#1qm}();=iIn){^-%8rBft*6fQv@XNbPjG^_sfNHawuEBiRm=d_)#-!wiZYmf=gb_ah3c2K4Z5P!ZAB|56+ zRKKldjPf4mCdu;*_FJn(v(hbeaE_=FBGyu5&aGM@fFo=#*KRGY!ra6;7>>0MO#Si= z{X)oitipAK0TafGWA|^%1^cjHP^EJixj-MYGzHCE_9DK=OBpy+g zuK0L|kEO9Uk-=5-MqZUBtcs4Nzar!{{k)svj^)l3xMOcCRX1T#jv9RtaA2dBoy#Nu zmK4x3U0SrT@J}4OlMp`rvLr!f9T}!oeM@0Ec5+h)lb0pJ4~px>uHmR5r**$1%s6w^OB@>^Qs?H;>oLD{@hUZ${(A8(xcHK+aY05j zZ6vDG=UY9WJr}Zodx)+lI8J}>Lk<<7)uDsg!3}^AEvQ`0zKcY`MN!>Uj|;!J6Mg-J zXEkQ$HJWw!pUq~FZNH(}Hrj)tn>9GLCR{}mv6h8fTPVVsp3&hO4~#BIa(aHFOwBn@ z&GLj3J0HS9$nylDmFABb4Uz!uCU-~`cl>ip^i6DN10h6?$q$RAKf(*2paM48CgjK`z zmLuP#`!Skq90o>qrH>zT-?E%9SqH#mLljp+q|L=xbp>s$h4sC+S!bcaH_ftv>vF zD|629#<0KxbX?qtDzFe6A**?Z{kSNmpD&fA+4ncP%bM0EH~o=JwLY>(X6Sr@1JdKF zZ$)Kl7|?jKjp0~!0;Ye~MNv69+csz0k$chi-!ww*(HE2O+X6@Fw}_OtOh<0Ok1){t zp)&s=jM==A!K-5M)}%OxUd!EZ>7tR}o=hvF!{pEc!85b08@Gf^ze0NK3uoQRz%*^8 z@_rQPac@s*bmEqA1GEL}xBi%=`L13kN#0x4r{!5XfU?@`kS+2p-LcN(3> zsK<|`eMkBVnW_)1up7qF>68Lek|fTG*SgrW-9(#SmFS_CV)Z0AmJTYVGe) zo1iKK_dD%YD37w7!MO29JyIjqL#B)rO-{bq0&4a?_fjca!Ri^{-gae zUi|p)-!xbL<%3i<{+kcYX7aiFKz;<5ak%H zG#cvpj@(Qt=DaI2CNOJ<-NMT@+8+uHy|idlteC5;_+VlueODICH4ISnr@*fafa~>*9HlkI%7rG${9Vq}1)S{@uT=|(Gv3$x__4-$hr>!4NH5PbZNJLr^Oy$vmkZB)%4usA z_DeklwpeYTFk1DV{h$_!9MI>*jYlZU+>IL9f)2l4tJ8ccOsMufh(To+a*5V2GOKVsi&ajFUl7Pi#Y~uX?fGFl z7Za=v#+9Q&l=_ppu|JM6m(n^>HzPfLL(bvFwyg5xC3nMiZZ=L%ZMJJIskLX7-&9iw zh&y{fLQ7kiiCh4Y`lp4eaV(@yNR)!OqUV1>Z-l~3U2rn96CtGt?Pe9!ywgu%Ve748vXKVIj5 z`V&9@$Nop}S;dU7lZK%-!8MWh%TH7zyd$}^L$&hR>gYU0!R2<4)%c2}^jmFFq9E*N zMgm?1y@AG0#UTxt&dK6 zrOOvz5)Nzh{X*5wkJW1pvl1ur`88nS%Y>~VAS%a_#cH<{AEh(Fii0kY93Ihb!P(AY z1v{`9AL3VC7~*d z6QSI^Tt0tYgyLcHH&*!;NXJq^Fw-E%TV~{Ad0Iq{q4HArKQYgyhbjkkuVJx#*Ng8E z$O@85FayPeC#nLfJL(WN>XRbPi5kQz(luLhlFAnPo1|GHM6ghLvv7ze;^lrw zLQvC$wM7$6PrAg31VB$DSI8ioWQ!|fxC0J2Q4j(7ixxQ~7|Cu%0DZAYPO@eBph$sj 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 RNj7fsSF2xAe`f#j{{X!@gi` Date: Fri, 6 Mar 2026 15:57:56 +0100 Subject: [PATCH 44/55] Update multiqc --- .github/workflows/nf-test.yml | 2 +- modules.json | 4 +- modules/nf-core/multiqc/environment.yml | 2 +- modules/nf-core/multiqc/main.nf | 27 ++-- modules/nf-core/multiqc/meta.yml | 128 +++++++++-------- modules/nf-core/multiqc/tests/main.nf.test | 129 +++++++++++------ .../nf-core/multiqc/tests/main.nf.test.snap | 131 +++++++++++++++--- 7 files changed, 282 insertions(+), 141 deletions(-) diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index 3be635e0..c98d76ec 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -68,7 +68,7 @@ jobs: fail-fast: false matrix: shard: ${{ fromJson(needs.nf-test-changes.outputs.shard) }} - profile: [singularity] + profile: [conda, docker, singularity] isMain: - ${{ github.base_ref == 'master' || github.base_ref == 'main' }} # Exclude conda and singularity on dev diff --git a/modules.json b/modules.json index ac2fb377..921caeb7 100644 --- a/modules.json +++ b/modules.json @@ -62,7 +62,7 @@ }, "multiqc": { "branch": "master", - "git_sha": "af27af1be706e6a2bb8fe454175b0cdf77f47b49", + "git_sha": "2c73cc8fa92cf48de3da0b643fdf357a8a290b36", "installed_by": ["modules"] }, "pairix": { @@ -146,7 +146,7 @@ }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "4b406a74dc0449c0401ed87d5bfff4252fd277fd", + "git_sha": "fdc08b8b1ae74f56686ce21f7ea11ad11990ce57", "installed_by": ["subworkflows"] } } 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 82f89795..5376aea1 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,25 +1,21 @@ process MULTIQC { + 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/8c/8c6c120d559d7ee04c7442b61ad7cf5a9e8970be5feefb37d68eeaa60c1034eb/data' : - 'community.wave.seqera.io/library/multiqc:1.32--d58f60e4deb769bf' }" + 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: - 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 @@ -27,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}" : '' @@ -38,7 +33,6 @@ process MULTIQC { ${args} \\ ${config} \\ ${prefix} \\ - ${extra_config} \\ ${logo} \\ ${replace} \\ ${samples} \\ @@ -50,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/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 3d4cb8b6..c022701f 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,41 +1,130 @@ { - "sarscov2 single-end [fastqc]": { + "sarscov2 single-end [fastqc] [multiple configs]": { "content": [ - [ - "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" - ] + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + { + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } ], "meta": { "nf-test": "0.9.3", - "nextflow": "24.10.4" + "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-10-27T13:33:24.356715" + "timestamp": "2026-02-26T15:10:36.019680076" }, "sarscov2 single-end [fastqc] - stub": { "content": [ - [ - "multiqc_report.html", - "multiqc_data", - "multiqc_plots", - "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" - ] + { + "data": [ + [ + { + "id": "FASTQC" + }, + [ + ".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": "24.10.4" + "nf-test": "0.9.4", + "nextflow": "25.10.4" }, - "timestamp": "2025-10-27T13:34:11.103619" + "timestamp": "2026-02-26T15:14:39.789193051" }, "sarscov2 single-end [fastqc] [config]": { "content": [ - [ - "versions.yml:md5,737bb2c7cad54ffc2ec020791dc48b8f" - ] + "multiqc_report.html", + "multiqc_data", + "multiqc_plots", + { + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.33" + ] + ] + } ], "meta": { - "nf-test": "0.9.3", - "nextflow": "24.10.4" + "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-10-27T13:34:04.615233" + "timestamp": "2026-02-26T15:10:43.419877592" } } \ No newline at end of file From e176c00aeb9fd61d9fbe7d042bbe28561c0e01d6 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 6 Mar 2026 15:58:05 +0100 Subject: [PATCH 45/55] Update utils_nfschema_plugin --- subworkflows/nf-core/utils_nfschema_plugin/main.nf | 2 +- .../nf-core/utils_nfschema_plugin/tests/nextflow.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 5ded8cb97fadf547440adbcf3951d5e83d6a8f1d Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Fri, 6 Mar 2026 16:41:18 +0100 Subject: [PATCH 46/55] Remove versions channels --- subworkflows/local/hicpro/main.nf | 10 ------- subworkflows/local/hicpro_mapping/main.nf | 8 ----- workflows/hic.nf | 36 ----------------------- 3 files changed, 54 deletions(-) diff --git a/subworkflows/local/hicpro/main.nf b/subworkflows/local/hicpro/main.nf index aeecdef4..85667d0e 100644 --- a/subworkflows/local/hicpro/main.nf +++ b/subworkflows/local/hicpro/main.nf @@ -32,7 +32,6 @@ workflow HICPRO { map_res // values main: - ch_versions = channel.empty() // Fastq to paired-end bam HICPRO_MAPPING( @@ -41,7 +40,6 @@ workflow HICPRO { index, ligation_site ) - ch_versions = ch_versions.mix(HICPRO_MAPPING.out.versions) //*************************************** // DIGESTION PROTOCOLS @@ -51,7 +49,6 @@ workflow HICPRO { HICPRO_MAPPING.out.bam, fragments.collect() ) - ch_versions = ch_versions.mix(GET_VALID_INTERACTION.out.versions) ch_valid_pairs = GET_VALID_INTERACTION.out.valid_pairs ch_valid_stats = GET_VALID_INTERACTION.out.stats @@ -63,7 +60,6 @@ workflow HICPRO { GET_VALID_INTERACTION_DNASE ( HICPRO_MAPPING.out.bam ) - ch_versions = ch_versions.mix(GET_VALID_INTERACTION_DNASE.out.versions) ch_valid_pairs = GET_VALID_INTERACTION_DNASE.out.valid_pairs ch_valid_stats = GET_VALID_INTERACTION_DNASE.out.stats } @@ -82,7 +78,6 @@ workflow HICPRO { MERGE_VALID_INTERACTION ( ch_valid_pairs ) - ch_versions = ch_versions.mix(MERGE_VALID_INTERACTION.out.versions) ch_hicpro_mappingstats = HICPRO_MAPPING.out.mapstats @@ -106,7 +101,6 @@ workflow HICPRO { MERGE_STATS( ch_hicpro_mappingstats.concat(ch_hicpro_pairstats, ch_hicpro_validstats) ) - ch_versions = ch_versions.mix(MERGE_STATS.out.versions) //*************************************** // CONVERTS TO PAIRS @@ -115,7 +109,6 @@ workflow HICPRO { MERGE_VALID_INTERACTION.out.valid_pairs, chrsize.collect() ) - ch_versions = ch_versions.mix(HICPRO2PAIRS.out.versions) //*************************************** // CONTACT MAPS @@ -128,14 +121,12 @@ workflow HICPRO { chrsize.collect() ) ch_hicpro_raw_maps = BUILD_CONTACT_MAPS.out.maps - ch_versions = ch_versions.mix(BUILD_CONTACT_MAPS.out.versions) // run_ice ICE_NORMALIZATION( BUILD_CONTACT_MAPS.out.maps ) ch_hicpro_iced_maps = ICE_NORMALIZATION.out.maps - ch_versions = ch_versions.mix(ICE_NORMALIZATION.out.versions) }else{ ch_hicpro_raw_maps = channel.empty() @@ -143,7 +134,6 @@ workflow HICPRO { } emit: - versions = ch_versions pairs = HICPRO2PAIRS.out.pairs mqc = MERGE_VALID_INTERACTION.out.mqc.concat(MERGE_STATS.out.mqc) raw_maps = ch_hicpro_raw_maps diff --git a/subworkflows/local/hicpro_mapping/main.nf b/subworkflows/local/hicpro_mapping/main.nf index 665861bd..fb34f310 100644 --- a/subworkflows/local/hicpro_mapping/main.nf +++ b/subworkflows/local/hicpro_mapping/main.nf @@ -20,7 +20,6 @@ workflow HICPRO_MAPPING { ligation_site // value main: - ch_versions = channel.empty() // Align each mates separetly and add mates information in [meta] ch_reads_r1 = reads @@ -45,7 +44,6 @@ workflow HICPRO_MAPPING { true, false ) - ch_versions = ch_versions.mix(BOWTIE2_ALIGN.out.versions) if (!params.no_digestion){ @@ -54,7 +52,6 @@ workflow HICPRO_MAPPING { BOWTIE2_ALIGN.out.fastq, ligation_site.collect() ) - ch_versions = ch_versions.mix(TRIM_READS.out.versions) // bowtie2 on trimmed reads - save_unaligned=false - sort_bam=false BOWTIE2_ALIGN_TRIMMED( @@ -64,7 +61,6 @@ workflow HICPRO_MAPPING { false, false ) - ch_versions = ch_versions.mix(BOWTIE2_ALIGN_TRIMMED.out.versions) // Merge the two mapping steps ch_bowtie2_align = BOWTIE2_ALIGN.out.bam @@ -73,7 +69,6 @@ workflow HICPRO_MAPPING { MERGE_BOWTIE2( ch_bowtie2_align ) - ch_versions = ch_versions.mix(MERGE_BOWTIE2.out.versions) ch_mapping_stats = MERGE_BOWTIE2.out.stats ch_bams = MERGE_BOWTIE2.out.bam @@ -88,7 +83,6 @@ workflow HICPRO_MAPPING { MAPPING_STATS_DNASE( BOWTIE2_ALIGN.out.aligned ) - ch_versions = ch_versions.mix(MAPPING_STATS_DNASE.out.versions) ch_mapping_stats = MAPPING_STATS_DNASE.out.stats ch_bams = BOWTIE2_ALIGN.out.aligned @@ -101,10 +95,8 @@ workflow HICPRO_MAPPING { COMBINE_MATES ( ch_bams ) - ch_versions = ch_versions.mix(COMBINE_MATES.out.versions) emit: - versions = ch_versions bam = COMBINE_MATES.out.bam mapstats = ch_mapping_stats pairstats = COMBINE_MATES.out.stats diff --git a/workflows/hic.nf b/workflows/hic.nf index f51c46fd..61c2ebc7 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -82,7 +82,6 @@ workflow HIC { ch_map_res = ch_map_res.unique() - ch_versions = channel.empty() ch_multiqc_files = channel.empty() // @@ -117,7 +116,6 @@ workflow HIC { ch_ligation_site, ch_map_res ) - ch_versions = ch_versions.mix(HICPRO.out.versions) ch_pairs = HICPRO.out.pairs ch_process_mqc = HICPRO.out.mqc }else if (params.processing == 'pairtools'){ @@ -154,7 +152,6 @@ workflow HIC { HIC_PLOT_DIST_VS_COUNTS( ch_distdecay ) - ch_versions = ch_versions.mix(HIC_PLOT_DIST_VS_COUNTS.out.versions) } // @@ -172,7 +169,6 @@ workflow HIC { ch_fasta, ch_chromosome_size ) - ch_versions = ch_versions.mix(COMPARTMENTS.out.versions) } // @@ -188,39 +184,8 @@ workflow HIC { TADS( ch_cool_tads ) - ch_versions = ch_versions.mix(TADS.out.versions) } - // - // 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_core_' + 'hic_software_' + 'mqc_' + 'versions.yml', - sort: true, - newLine: true - ).set { ch_collated_versions } - - // // MODULE: MultiQC // @@ -244,7 +209,6 @@ workflow HIC { 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', From 928c484012dd1e524685bf82099aba55eec0b655 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Mar 2026 09:09:42 +0100 Subject: [PATCH 47/55] Update multiqc input structure --- workflows/hic.nf | 85 ++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/workflows/hic.nf b/workflows/hic.nf index 61c2ebc7..2b5d291f 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -81,7 +81,7 @@ workflow HIC { } ch_map_res = ch_map_res.unique() - + ch_versions = channel.empty() ch_multiqc_files = channel.empty() // @@ -186,50 +186,65 @@ workflow HIC { ) } + // + // 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')}" + } + ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + .mix(topic_versions_string) + // // 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_methods_description.collectFile( - name: 'methods_description_mqc.yaml', - sort: true - ) - ) + + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + + def ch_summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + def ch_workflow_summary = channel.value(paramsSummaryMultiqc(ch_summary_params)) + ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + + def 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) + def ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true)) if (params.processing == 'hicpro'){ ch_multiqc_files = ch_multiqc_files.mix(HICPRO.out.mqc) } - MULTIQC ( - ch_multiqc_files.collect(), - ch_multiqc_config.toList(), - ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList(), - [], - [] + MULTIQC( + ch_multiqc_files.flatten().collect().map { files -> + [ + [id: '{{ hic }}'], + files, + params.multiqc_config + ? file(params.multiqc_config, checkIfExists: true) + : file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true), + params.multiqc_logo ? file(params.multiqc_logo, checkIfExists: true) : [], + [], + [], + ] + } ) - emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + emit: + multiqc_report = MULTIQC.out.report.map { _meta, report -> [report] }.toList() // channel: /path/to/multiqc_report.html } From 15cd6a2094c3c46603f7ce57c475451614c46b63 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Mar 2026 11:00:50 +0100 Subject: [PATCH 48/55] Fix multiqc input channel --- workflows/hic.nf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflows/hic.nf b/workflows/hic.nf index 2b5d291f..1d3a078b 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -211,8 +211,8 @@ workflow HIC { // // MODULE: MultiQC // - - ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions.collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_hic_software_mqc_versions.yml', sort: true, newLine: true)) def ch_summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") def ch_workflow_summary = channel.value(paramsSummaryMultiqc(ch_summary_params)) From e0aff04ee982ed35505e6ae661b95c224a67a413 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Mar 2026 11:03:48 +0100 Subject: [PATCH 49/55] Update snapshot --- tests/default.nf.test.snap | 216 ++++++++++++++----------------------- 1 file changed, 79 insertions(+), 137 deletions(-) diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index e3bc71e2..15a38eab 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -3,68 +3,35 @@ "content": [ { "BOWTIE2_ALIGN": { - "bowtie2": "2.5.2", - "pigz": 2.6, - "samtools": 1.18 + "bowtie2": "2.5.4", + "pigz": 2.8, + "samtools": 1.21 }, "BOWTIE2_ALIGN_TRIMMED": { - "bowtie2": "2.5.2", - "pigz": 2.6, - "samtools": 1.18 + "bowtie2": "2.5.4", + "pigz": 2.8, + "samtools": 1.21 }, - "COMBINE_MATES": { - "python": "3.9.12" + "BOWTIE2_BUILD": { + "bowtie2": "2.5.4" }, "COOLER_BALANCE": { - "cooler": "0.9.2" + "cooler": "0.10.4" }, "COOLER_CLOAD": { - "cooler": "0.9.2" + "cooler": "0.10.4" }, "COOLER_DUMP": { - "cooler": "0.9.2" + "cooler": "0.10.3" }, "COOLER_MAKEBINS": { - "cooler": "0.9.2" - }, - "COOLER_ZOOMIFY": { - "cooler": "0.9.2" - }, - "COOLTOOLS_EIGSCIS": { - "cooltools": "0.5.1" - }, - "COOLTOOLS_INSULATION": { - "cooltools": "0.5.1" + "cooler": "0.10.4" }, "FASTQC": { "fastqc": "0.12.1" }, - "GET_VALID_INTERACTION": { - "python": "3.9.12" - }, - "HICPRO2PAIRS": { - "pairix": "0.3.7" - }, - "HIC_FIND_TADS": { - "hicexplorer": "3.7.2" - }, - "HIC_PLOT_DIST_VS_COUNTS": { - "hicexplorer": "3.7.2" - }, - "MERGE_BOWTIE2": { - "samtools": "1.15.1" - }, - "MERGE_STATS": { - "python": "3.9.12" - }, - "MERGE_VALID_INTERACTION": { - "sort": 8.3 - }, - "SPLIT_COOLER_DUMP": { - "cooler": null - }, - "TRIM_READS": { - "gzip": 1.1 + "SAMTOOLS_FAIDX": { + "samtools": "1.22.1" }, "Workflow": { "nf-core/hic": "v2.2.0dev" @@ -82,7 +49,6 @@ "contact_maps/cool", "contact_maps/cool/SRR4292758.1000_balanced.cool", "contact_maps/cool/SRR4292758.2000_balanced.cool", - "contact_maps/cool/SRR4292758.mcool", "contact_maps/txt", "contact_maps/txt/SRR4292758.1000_balanced.txt", "contact_maps/txt/SRR4292758.2000_balanced.txt", @@ -136,6 +102,7 @@ "multiqc/multiqc_data/multiqc_sources.txt", "multiqc/multiqc_plots", "multiqc/multiqc_plots/pdf", + "multiqc/multiqc_plots/pdf/fastqc-status-check-heatmap.pdf", "multiqc/multiqc_plots/pdf/fastqc_adapter_content_plot.pdf", "multiqc/multiqc_plots/pdf/fastqc_per_base_n_content_plot.pdf", "multiqc/multiqc_plots/pdf/fastqc_per_base_sequence_quality_plot.pdf", @@ -156,6 +123,7 @@ "multiqc/multiqc_plots/pdf/hicpro_pairing_stats_plot-cnt.pdf", "multiqc/multiqc_plots/pdf/hicpro_pairing_stats_plot-pct.pdf", "multiqc/multiqc_plots/png", + "multiqc/multiqc_plots/png/fastqc-status-check-heatmap.png", "multiqc/multiqc_plots/png/fastqc_adapter_content_plot.png", "multiqc/multiqc_plots/png/fastqc_per_base_n_content_plot.png", "multiqc/multiqc_plots/png/fastqc_per_base_sequence_quality_plot.png", @@ -176,6 +144,7 @@ "multiqc/multiqc_plots/png/hicpro_pairing_stats_plot-cnt.png", "multiqc/multiqc_plots/png/hicpro_pairing_stats_plot-pct.png", "multiqc/multiqc_plots/svg", + "multiqc/multiqc_plots/svg/fastqc-status-check-heatmap.svg", "multiqc/multiqc_plots/svg/fastqc_adapter_content_plot.svg", "multiqc/multiqc_plots/svg/fastqc_per_base_n_content_plot.svg", "multiqc/multiqc_plots/svg/fastqc_per_base_sequence_quality_plot.svg", @@ -198,6 +167,9 @@ "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_hic_software_mqc_versions.yml", + "samtools", + "samtools/W303_SGD_2015_JRIU00000000.fsa.fai", + "samtools/W303_SGD_2015_JRIU00000000.fsa.sizes", "tads", "tads/hicExplorer", "tads/hicExplorer/SRR4292758.1000_balanced_hicfindtads_boundaries.bed", @@ -212,99 +184,68 @@ [ "cooler_bins_1000.bed:md5,69b3eee6a4826015108e29487cd6288f", "cooler_bins_2000.bed:md5,b5b5c94246c99473376d4cfc4580645d", - "SRR4292758.1000_balanced.txt:md5,6d6f9dd0e2faef74c6bbcdd8ea8b8907", - "SRR4292758.2000_balanced.txt:md5,a868a2aea0b6a194ab19c2d8a72f99f8", - "SRR4292758_distcount.png:md5,5314c9ad16a1e857682fde4e584103bc", - "SRR4292758_distcount.txt:md5,bac196d56bcb489c2ef6fe2ea26e07c9", - "SRR4292758_allValidPairs.mergestat:md5,b0a81a4d69ea8e44495a714ac87701e8", - "SRR4292758.allValidPairs:md5,55e00a772766779f5d5c2bf2b6fcef6d", - "SRR4292758_contacts.pairs.gz:md5,201d59212cf443fe5da09dbddeef8677", - "SRR4292758_contacts.pairs.gz.px2:md5,6275247d930753121aa026870864aa25", + "SRR4292758.1000_balanced.txt:md5,7e6fad9ffca70a6f72c8a8727ca23251", + "SRR4292758.2000_balanced.txt:md5,853427e47ba03d0c723c9fba2e7813b3", + "SRR4292758_distcount.png:md5,421161f55fc6312dfafcab76ca943d0d", + "SRR4292758_distcount.txt:md5,ba63d855abcaab7bd8c93f48f47e6c7c", + "SRR4292758_allValidPairs.mergestat:md5,161d7d9c2f63a952edc0d25359015d96", + "SRR4292758.allValidPairs:md5,824f389cb55656139a56d8185ea3f0f4", + "SRR4292758_contacts.pairs.gz:md5,27eabbaedf0b55d675addf05e165eda2", + "SRR4292758_contacts.pairs.gz.px2:md5,db3653be8c0229a0f32d6d0f0e7fcf24", "fastqc-status-check-heatmap.txt:md5,755d1909854791c227d1000b38c977e9", - "hicpro_contact_plot.txt:md5,4a0ae6c30b400f3f7e5d14c5b4db0d5c", + "hicpro_contact_plot.txt:md5,026bd3f93ce85d7b695f2cc332ef1551", "hicpro_pairing_stats_plot.txt:md5,b2f918d8f9919aaa30a0ea15f4522876", "multiqc_citations.txt:md5,76bcbb4e4103209b523ed9da8fef74bc", + "W303_SGD_2015_JRIU00000000.fsa.fai:md5,85017cce3858d13e8731f776bd639a35", + "W303_SGD_2015_JRIU00000000.fsa.sizes:md5,a88ab0b08622c99b9dba93752bda41d4", "SRR4292758.1000_balanced_hicfindtads_boundaries.bed:md5,d41d8cd98f00b204e9800998ecf8427e", "SRR4292758.1000_balanced_hicfindtads_boundaries.gff:md5,d41d8cd98f00b204e9800998ecf8427e", "SRR4292758.1000_balanced_hicfindtads_domains.bed:md5,d41d8cd98f00b204e9800998ecf8427e", - "SRR4292758.1000_balanced_hicfindtads_score.bedgraph:md5,da38c91d9b23820e290d2c987f27ab70", - "SRR4292758.1000_balanced_hicfindtads_tad_score.bm:md5,81b33e5cd3ff14efac94c2065ac68fe1", - "SRR4292758.1000_balanced_insulation.tsv:md5,fd0a37e94600e9da4c8de0c58f07e3ed" + "SRR4292758.1000_balanced_hicfindtads_score.bedgraph:md5,e12e13b248914e62c34aff42204ea262", + "SRR4292758.1000_balanced_hicfindtads_tad_score.bm:md5,b7dfaa33f19ebea0983e428298317664", + "SRR4292758.1000_balanced_insulation.tsv:md5,e2ce1056f11fc3bf432de642341cc6ab" ] ], "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-03-04T13:28:11.720729278" + "timestamp": "2026-03-10T10:53:26.768807069" }, "Should split fastqs": { "content": [ - 69, + 68, { "BOWTIE2_ALIGN": { - "bowtie2": "2.5.2", - "pigz": 2.6, - "samtools": 1.18 + "bowtie2": "2.5.4", + "pigz": 2.8, + "samtools": 1.21 }, "BOWTIE2_ALIGN_TRIMMED": { - "bowtie2": "2.5.2", - "pigz": 2.6, - "samtools": 1.18 + "bowtie2": "2.5.4", + "pigz": 2.8, + "samtools": 1.21 }, - "COMBINE_MATES": { - "python": "3.9.12" + "BOWTIE2_BUILD": { + "bowtie2": "2.5.4" }, "COOLER_BALANCE": { - "cooler": "0.9.2" + "cooler": "0.10.4" }, "COOLER_CLOAD": { - "cooler": "0.9.2" + "cooler": "0.10.4" }, "COOLER_DUMP": { - "cooler": "0.9.2" + "cooler": "0.10.3" }, "COOLER_MAKEBINS": { - "cooler": "0.9.2" - }, - "COOLER_ZOOMIFY": { - "cooler": "0.9.2" - }, - "COOLTOOLS_EIGSCIS": { - "cooltools": "0.5.1" - }, - "COOLTOOLS_INSULATION": { - "cooltools": "0.5.1" + "cooler": "0.10.4" }, "FASTQC": { "fastqc": "0.12.1" }, - "GET_VALID_INTERACTION": { - "python": "3.9.12" - }, - "HICPRO2PAIRS": { - "pairix": "0.3.7" - }, - "HIC_FIND_TADS": { - "hicexplorer": "3.7.2" - }, - "HIC_PLOT_DIST_VS_COUNTS": { - "hicexplorer": "3.7.2" - }, - "MERGE_BOWTIE2": { - "samtools": "1.15.1" - }, - "MERGE_STATS": { - "python": "3.9.12" - }, - "MERGE_VALID_INTERACTION": { - "sort": 8.3 - }, - "SPLIT_COOLER_DUMP": { - "cooler": null - }, - "TRIM_READS": { - "gzip": 1.1 + "SAMTOOLS_FAIDX": { + "samtools": "1.22.1" } }, [ @@ -319,7 +260,6 @@ "contact_maps/cool", "contact_maps/cool/SRR4292758.1000_balanced.cool", "contact_maps/cool/SRR4292758.2000_balanced.cool", - "contact_maps/cool/SRR4292758.mcool", "contact_maps/txt", "contact_maps/txt/SRR4292758.1000_balanced.txt", "contact_maps/txt/SRR4292758.2000_balanced.txt", @@ -361,8 +301,7 @@ "multiqc/multiqc_data/fastqc_sequence_duplication_levels_plot.txt", "multiqc/multiqc_data/hicpro_contact_plot.txt", "multiqc/multiqc_data/hicpro_filtering_plot.txt", - "multiqc/multiqc_data/hicpro_mapping_stats_plot_Read_1.txt", - "multiqc/multiqc_data/hicpro_mapping_stats_plot_Read_2.txt", + "multiqc/multiqc_data/hicpro_mapping_stats_plot.txt", "multiqc/multiqc_data/hicpro_pairing_stats_plot.txt", "multiqc/multiqc_data/llms-full.txt", "multiqc/multiqc_data/multiqc.log", @@ -376,6 +315,7 @@ "multiqc/multiqc_data/multiqc_sources.txt", "multiqc/multiqc_plots", "multiqc/multiqc_plots/pdf", + "multiqc/multiqc_plots/pdf/fastqc-status-check-heatmap.pdf", "multiqc/multiqc_plots/pdf/fastqc_adapter_content_plot.pdf", "multiqc/multiqc_plots/pdf/fastqc_per_base_n_content_plot.pdf", "multiqc/multiqc_plots/pdf/fastqc_per_base_sequence_quality_plot.pdf", @@ -389,13 +329,12 @@ "multiqc/multiqc_plots/pdf/hicpro_contact_plot-pct.pdf", "multiqc/multiqc_plots/pdf/hicpro_filtering_plot-cnt.pdf", "multiqc/multiqc_plots/pdf/hicpro_filtering_plot-pct.pdf", - "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_1-cnt.pdf", - "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_1-pct.pdf", - "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_2-cnt.pdf", - "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_2-pct.pdf", + "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot-cnt.pdf", + "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot-pct.pdf", "multiqc/multiqc_plots/pdf/hicpro_pairing_stats_plot-cnt.pdf", "multiqc/multiqc_plots/pdf/hicpro_pairing_stats_plot-pct.pdf", "multiqc/multiqc_plots/png", + "multiqc/multiqc_plots/png/fastqc-status-check-heatmap.png", "multiqc/multiqc_plots/png/fastqc_adapter_content_plot.png", "multiqc/multiqc_plots/png/fastqc_per_base_n_content_plot.png", "multiqc/multiqc_plots/png/fastqc_per_base_sequence_quality_plot.png", @@ -409,13 +348,12 @@ "multiqc/multiqc_plots/png/hicpro_contact_plot-pct.png", "multiqc/multiqc_plots/png/hicpro_filtering_plot-cnt.png", "multiqc/multiqc_plots/png/hicpro_filtering_plot-pct.png", - "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_1-cnt.png", - "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_1-pct.png", - "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_2-cnt.png", - "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_2-pct.png", + "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot-cnt.png", + "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot-pct.png", "multiqc/multiqc_plots/png/hicpro_pairing_stats_plot-cnt.png", "multiqc/multiqc_plots/png/hicpro_pairing_stats_plot-pct.png", "multiqc/multiqc_plots/svg", + "multiqc/multiqc_plots/svg/fastqc-status-check-heatmap.svg", "multiqc/multiqc_plots/svg/fastqc_adapter_content_plot.svg", "multiqc/multiqc_plots/svg/fastqc_per_base_n_content_plot.svg", "multiqc/multiqc_plots/svg/fastqc_per_base_sequence_quality_plot.svg", @@ -429,15 +367,16 @@ "multiqc/multiqc_plots/svg/hicpro_contact_plot-pct.svg", "multiqc/multiqc_plots/svg/hicpro_filtering_plot-cnt.svg", "multiqc/multiqc_plots/svg/hicpro_filtering_plot-pct.svg", - "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_1-cnt.svg", - "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_1-pct.svg", - "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_2-cnt.svg", - "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_2-pct.svg", + "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot-cnt.svg", + "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot-pct.svg", "multiqc/multiqc_plots/svg/hicpro_pairing_stats_plot-cnt.svg", "multiqc/multiqc_plots/svg/hicpro_pairing_stats_plot-pct.svg", "multiqc/multiqc_report.html", "pipeline_info", "pipeline_info/nf_core_hic_software_mqc_versions.yml", + "samtools", + "samtools/W303_SGD_2015_JRIU00000000.fsa.fai", + "samtools/W303_SGD_2015_JRIU00000000.fsa.sizes", "tads", "tads/hicExplorer", "tads/hicExplorer/SRR4292758.1000_balanced_hicfindtads_boundaries.bed", @@ -452,30 +391,33 @@ [ "cooler_bins_1000.bed:md5,69b3eee6a4826015108e29487cd6288f", "cooler_bins_2000.bed:md5,b5b5c94246c99473376d4cfc4580645d", - "SRR4292758.1000_balanced.txt:md5,6d6f9dd0e2faef74c6bbcdd8ea8b8907", - "SRR4292758.2000_balanced.txt:md5,a868a2aea0b6a194ab19c2d8a72f99f8", - "SRR4292758_distcount.png:md5,5314c9ad16a1e857682fde4e584103bc", - "SRR4292758_distcount.txt:md5,bac196d56bcb489c2ef6fe2ea26e07c9", - "SRR4292758_allValidPairs.mergestat:md5,b0a81a4d69ea8e44495a714ac87701e8", - "SRR4292758.allValidPairs:md5,55e00a772766779f5d5c2bf2b6fcef6d", - "SRR4292758_contacts.pairs.gz:md5,201d59212cf443fe5da09dbddeef8677", - "SRR4292758_contacts.pairs.gz.px2:md5,6275247d930753121aa026870864aa25", + "SRR4292758.1000_balanced.txt:md5,7e6fad9ffca70a6f72c8a8727ca23251", + "SRR4292758.2000_balanced.txt:md5,853427e47ba03d0c723c9fba2e7813b3", + "SRR4292758_distcount.png:md5,421161f55fc6312dfafcab76ca943d0d", + "SRR4292758_distcount.txt:md5,ba63d855abcaab7bd8c93f48f47e6c7c", + "SRR4292758_allValidPairs.mergestat:md5,161d7d9c2f63a952edc0d25359015d96", + "SRR4292758.allValidPairs:md5,824f389cb55656139a56d8185ea3f0f4", + "SRR4292758_contacts.pairs.gz:md5,27eabbaedf0b55d675addf05e165eda2", + "SRR4292758_contacts.pairs.gz.px2:md5,db3653be8c0229a0f32d6d0f0e7fcf24", "fastqc-status-check-heatmap.txt:md5,755d1909854791c227d1000b38c977e9", - "hicpro_contact_plot.txt:md5,4a0ae6c30b400f3f7e5d14c5b4db0d5c", + "hicpro_contact_plot.txt:md5,026bd3f93ce85d7b695f2cc332ef1551", + "hicpro_mapping_stats_plot.txt:md5,e0a21abcaacacab43968f1eff715a1c6", "hicpro_pairing_stats_plot.txt:md5,b2f918d8f9919aaa30a0ea15f4522876", "multiqc_citations.txt:md5,76bcbb4e4103209b523ed9da8fef74bc", + "W303_SGD_2015_JRIU00000000.fsa.fai:md5,85017cce3858d13e8731f776bd639a35", + "W303_SGD_2015_JRIU00000000.fsa.sizes:md5,a88ab0b08622c99b9dba93752bda41d4", "SRR4292758.1000_balanced_hicfindtads_boundaries.bed:md5,d41d8cd98f00b204e9800998ecf8427e", "SRR4292758.1000_balanced_hicfindtads_boundaries.gff:md5,d41d8cd98f00b204e9800998ecf8427e", "SRR4292758.1000_balanced_hicfindtads_domains.bed:md5,d41d8cd98f00b204e9800998ecf8427e", - "SRR4292758.1000_balanced_hicfindtads_score.bedgraph:md5,da38c91d9b23820e290d2c987f27ab70", - "SRR4292758.1000_balanced_hicfindtads_tad_score.bm:md5,81b33e5cd3ff14efac94c2065ac68fe1", - "SRR4292758.1000_balanced_insulation.tsv:md5,fd0a37e94600e9da4c8de0c58f07e3ed" + "SRR4292758.1000_balanced_hicfindtads_score.bedgraph:md5,e12e13b248914e62c34aff42204ea262", + "SRR4292758.1000_balanced_hicfindtads_tad_score.bm:md5,b7dfaa33f19ebea0983e428298317664", + "SRR4292758.1000_balanced_insulation.tsv:md5,e2ce1056f11fc3bf432de642341cc6ab" ] ], "meta": { "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-03-04T13:31:03.874257745" + "timestamp": "2026-03-10T10:54:36.481540622" } } \ No newline at end of file From 871008e340eb8173870c6d2c68490af7cb4eca92 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Mar 2026 11:12:46 +0100 Subject: [PATCH 50/55] Fix typo --- workflows/hic.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/hic.nf b/workflows/hic.nf index 1d3a078b..f69c8ded 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -231,7 +231,7 @@ workflow HIC { MULTIQC( ch_multiqc_files.flatten().collect().map { files -> [ - [id: '{{ hic }}'], + [id: 'hic'], files, params.multiqc_config ? file(params.multiqc_config, checkIfExists: true) From 9bcf5a7af1e3d4024add2bb571b276d2b0a719d6 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Mar 2026 11:37:03 +0100 Subject: [PATCH 51/55] Fix logo again --- assets/nf-core-hic_logo_light.png | Bin 59369 -> 61022 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/nf-core-hic_logo_light.png b/assets/nf-core-hic_logo_light.png index fe97c0d3d57b3a8478a9d79f9ad5abb48014e6b9..4bd4656d9a30dd0f0aac271993efe7eac7c2a37d 100644 GIT binary patch literal 61022 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%0DZAYPO@eBph$sj z^($Tn1p5j#;M|0BgY?Dz0EsL6gj5scL)d~9zBovxY9bY)!e8jF-`ZebN6~}iUAvAi z!jy8|Ovq%fNz(VzaV#Zd=W7yYh32snu)!@7R8ljYM@Db&M~~hgB5dP7>FE#AuY;ZUyh&B7gEhk`M-{5vSDu&<0$BrMP{K%E)sZQbc`W5=u`vdwW0CKcpHi?)pN z`X!iU|7AwP82f$7fkoD^WSl<8gun(PVZY2r8JH!5LG*zX8J%lO=0yrb2ca*Dgk zyShAJ8g-kRsUJ{j#_^`MQZtPL{2Pdh89N8P@8ax5WElIQg=nHF7KWzZ=BBU(FH7n= zzxWk5GRfzboPCtmfzPiT2J))!y{o*!buty~Gg_H)ZjdYMbTR4*b;U-BPLlWHL^H^H z8!NibYxT)NKzz*v|hT)YVL` z!&Czz0WfM0rEHtK>XZ2V85$6ku!-qQLpOe0r`J345Ij1&(}tH*n|aJW zKT4;yHxr8M){1X(+$n!%cHgy1X@9D&*b0IX&v7PexFT~OXPxjGi9r~U*BZ0oU_ngq~hV~-i+Qpe^=*NQ2~{=T)>2B82Rk&oqD0hg=0b^E(E9< z0qJaEN9)9duhNd@3nw2-4`^ii*-*n6PxDd71G{_w_`Hq^pr2;;B`a8s``j=TQ$6>u z`$D(qYsx{#uAF&{)8*006pRI+G)bw=T9bNOxb+i0FD!-{sn!;FD)L+xMoW#NRdTz{ zSy)(l%YU^E$C*V^g1Raay_Ds`;HG;NcSD@oS&K zx}4P7npZc4sjqwnFXp5UC#E)6YMiHYG)ykK`M+HvC4Viz;qE4iYv&2NsMuJM`BB;CV2{#;>Ha(m&hea7bx4+-`QsZ`L64qbpKV z5J})lVpOM`WA86mzWiGAS6E_g)7lo$^IYyTcq=Eh{j5lnbfMgA>b0em+XB-XxHXwF z-goe_Fba)E=A;TOIR%90!s;c*JT@4HOx0V=93cFxP?DoNlVDD<&PK5!H5DJ{;rP_% z0)F$?wPahYXex>a#7b9mA!>mgPB1wydhO#}kc~PEuY8=Den^OzU%g~|SPG=HX~G*= z)UG9Un-)dB3l|OfIGchCo#u~EW#pt5Y^dnk&z;E?{e`H}3TbpHWDuLNd42*dUty{V zIjJfzF&h-Dg4pc6RD;>N^tqZJj_?o|QeBf~$tlT6HFYw)N@6N7^5qpigUuuoM3DJ^ z!%MaW(nsmc7t-a6dZ?!;UotNvVa$&tmg;=EK+vgkT3q8Rsm--1&0kNHF1EC-=;~?C z3EDD#%;Q=!@yjAo%DWZ~m@m8hn?ip3lv5KY!bx$5oNX2}ZNRg|6PW`8+o@vIf%z+g zTZOjlP{)MuarQ)$16|jK#vFrkptzLrkAi;g9xX@N{3+7fGy42Ht^CxF?Rs}> znx`eKnZzklYN)$JBAfJRpi$^e;kbk~i5s0OCX*)m0n#C;DkJ+dA#vykkGS4^$dM}0 zuHN|O98~^yr%mdaf_bPH)Lo4zpX4gkK{?KZ*bco-63tLm$ z{A(9P-=%(*8UZ1$+c8}R_3qbIP_*kB&ES_J<)Aj+Rg}Dn&xXu68p_OtN9VxDZ5ya06yz#Ly5F_JFH-Yqov*Jrb1aSushTWcDIr)b~#tRMM1Y?n!JwvwWw(Z z<5qoSBMR9k?YuE+a9v_&|A)F#Ig2#-gVCa6D5_+?UL2c~+6-`7a_OSb8+!pPDof`I z*vKi~>*T=9^tmyIiiEf0+B!ed@;yrHMS9LpGvBtHRzhK=!n)%W%F^xkL+Egp)W~31 z(sHjh(DIJ1Oy#u-+x;&#*1g$|D55w-FB!xSCD$rtx@;oOsoW82pmdummh6UKSghsi zIo>D;mpfmuV8pD5Um&Hhhy#@;qvO;1OQ*v%dO3Qzq;nWrBB#vVmUsUEX;*^%p~YMp^{g(m4iI!3UM`#qrD-IBa)L)5qA+^X;$f9 zq#1r@bi|tQogtPP?vS*QZJ@jN>v}M1R2W9@(+POc>CWi&3pf%MI_nxC#r}VONlVn=8mE{cav-i*rT(=ul+TgnS={x}`r`^+>4<8KiaZ$cyI_ z?+f3K64^u(8LA$C1e)vAi*f(`J&Mq}?Zl5F9FI~|y%Z!1rZaY+HkUoVT{ZDI6y=`3sY1*K)BZ^&{G5QK}7XpJ%4hZ9X38c&S!(_1Sjd)FA%ygo)Ee+}$LrUf5iH^u3btA(H`987fi28pI_P&xuWFkZtm1QSj(xjb_ zv=x6O1&bG|Q$|w^&hcT)T=D?{WF8rj?9V7+- zg0!34&<$)#d6ZlmDY=IQD8l#Ir({%0Bun-_=)wzJlt3JvcN|!tmyf3TJXn3rhjvpZ zVOzY(M{q?tep!QZW(FCks5@xJVy*k%ie?Nq;XCGlLSO+NK+VUl(Z%(Plu04KVJXw~ zKc)OGG@;D^%!X70%p9mn8l66RXM|M6hoh=t)eS!15#eje6_P03i>2b<{&|#nJJAr+ z$JwY}em<-PWG?p&c2)*no%~Kgt##zHjUrYFWEA0_6Z-8u~ zHZ|j6xlgq@3aZQ+H!EE9pSEMAZDY{yCz_Jt0=m@YX`p<-6{N#{MDH4qZQVtQfsmnL zCsz65QOai0Z%YOa-xSuJjsQ5o4+q>RUyOZ2)3?$lQ~{=>|2@&PaK*kS)|}(Sj1k5a z-o^C7ebDur?pGvy(GOkt7ZV`wx`cU&&Hy#w$)QB7v=O=%*h#0Rai_RA%n^@@g}s2t zQ1<2l4dB@VB4Yv{uevz`k&TgdiI)9~teq>6u8#7)(e_-?Ug!XwSxXiIm;tZ`h^~uJ z(u$Sp(86-*L^2vao=zC^=x;zqfR~g}WDux#svWDmK%>utVm?TlDwXL+l*&H#IqYg; z{ceeE`L%?6j^Yk$k#z)kbLg`7-&X+*JOI3NUbGI?3Geqv5q8E_EMj-*4D}ozbaeKf+Dd6l9Das>;&xyK^$^Zw+ zUO-Q{J)E!xHK+UsZGda0koO=w#Yus^0EG^t(|dfrHPc|Fpp%+uyF$8bL#CoC;YkoJ zwkZ9l0q1X~zqjK)W%g}mv8*x1pQ`khU`+ze11@+dkm}^-83?MM*h;4(eL6i_6t3Ub z?Mf~~#nrQ}G-Bs&$Lh+0+kM;n#jb1oT@ZjCaBV4_^Uo6r_Qgm+)xux!s|=`He^@|! zm4NtJl#RKs{tF)@zzBQ+g~LG90qprG;Y#;97OP@boXeL-bcvpNqTqsP^R^P1tViGs z23^%&Ue$L7cfb$umg3H9l~Z`ZH~63Y$svFaQ~*D<`J~ygR+7bPB~VnffatO0B;Wc~ z+Cn%?8_AM(heu9QIjOlU7P8BO7gaBj^DqpE^zJeC+hx0%g0QEIf51|;pru+bJTjIq@|+>LppwiQP)rNlSJNgfWQArSFYPO z$;r3316VYsz@3LSpeXW9-BT){9ypaSh3mOlN~OI z(vh_+x#rzOjlNUZSRi%rTcPSesr=>3>;siRdZcLj1U;rFX zlnRvX@Tc$#1lpVgl^62?3FyObYLmXgpaDEum1_#G@;bOVsjfWHn*Rw1(sCdd^Qnoh z7|#mW%m<8ebhy|VM6PCSWCt>`--foS3db? zMW2z>JOUu!SR~yO;$H#}_))MG1(Qb+*p>8P>pQIVY1g%&4* z*NcZnHr~Qd(%+{5D}2BTl6HaP!bOiqA@2y;W?^v(F*yryJfRXfg3H@VSVa%-x^cZb zkeq@GZh@56UQNn%FJG%H?0(#A1!FHis1*Rs92u4u|>0Nut zoHeNwK7b-n=b`|t?8ckm5&eweVFrRt*GjX+87~e>?-V|m5f(IbeFRcXZ>Rf#A&H-f zhl4mg+*)mYEn(cON1xsGYbIPiyZMLj&hMB(UYUPl!*`q4zMT8+NM`D?h)ufGhu`Bb znqsyeW) zC|~7yRBfdZ72wkw{)SU8f8fky)5c4!IL;I<>U}3$ zwjukK(NmrLiu8BL%R|PTgTGAHJ4(lzrhho+lJ4)+o6Xoe94-1t^rVh9YII*|Pj<(c znFsgsJpCQ1O3FB^TNdc43;qw4PFFK~H2vI--^*I|uO z$P{l`)-qcqXwk;yCR|kNo9*f^i$eX_d$`Q+s!E~5?Lh}>232+Os+Lf?T0+KHV&sbk z3fuP8yDQxZywvLa_K2y{4P%*ksi-aMarQft*WIs)ET%zb_iUE~LXEydlupV@DOesd zMfz0kh8|H!+G65N{L+t-e~m7-CebJ_+|GD zGL_``E~{Wiw>A;j1tK$#SDwh0KG>~>c0ssgRNPGFyP62g-p*$ef;A1}L|)5O0`FCI zpO28KJg;fenX3E#PT;N9Mhg3l3gXs&-#2!zqRwnr{yKA~|L-4GN?VQ%t&`7m>OEZD zP$V>aXHwR^`>oRecGY#ZaSww1mkE3+r`qn+W(Pic`-;q2Z0zgM+aY}FCe+Q#{uT^S=PBWqrD+w2X_9U11LDy`SE8U26ONrb0=eWg6t_^x&dlTHg| zQhCAU8|8}|$ToA1YvtqDvt@Qo0xeOHU8nJTd6pb&%0F@&nA!Sv?5c`X!#!CukwU*` zF3&Y>r4*75$=B#Tyig^G-E+4iLwE;dJSTh?m2d(nCElTYqo5#__ij`zk!>nC!yUMs zQm|V(e4|e<1YDEJ-!QtPwmIMo;TqC}me4c@-T;1Lb*s8j&FL} z!V+YN_!8M4UNt8Yb}89AH6C+~!$nbKP@JefbM`tZ(CWpQ7{mzK7`e?LTy%_Rx8!VH zw)jOQH}B9x2Y<}560?uB?3{4T-r?JAGU@G}jOKM~ZfV;Q*~>2UHa;Re%~6)G!fn`P z%vXP^mf2UWmUe|4dhyzHr*r@Vu79XA*hvdZ#P9Yr@RGTCa|F#)-q5L@WXj2JV(lk4 z3WqS33bS?VGCecNpG9d1w5;=aLtU2$9nGD~wg{Wr z_f}5bE`3lk5NUr5_E~x|N3K}Y5g>rUP?#%CYsS5h)njG45r=6o?<0?o|4w=U0sk)i z5roSw)n7&s0R|&~H^Ve1sSOvgKcCk;%fpi|Ak7A`^xGJ1Teho5X9ovSx-U RNj7fsSF2xAe`f#j{{X!@gi`aqzrc0^?y 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 From bb9d3a17cc93090ffa547136df2c7ed355a51ca3 Mon Sep 17 00:00:00 2001 From: Thibault-Poinsignon Date: Tue, 10 Mar 2026 11:53:12 +0100 Subject: [PATCH 52/55] Update snapshot #2 --- tests/default.nf.test.snap | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index 15a38eab..2c5c17fe 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -301,7 +301,8 @@ "multiqc/multiqc_data/fastqc_sequence_duplication_levels_plot.txt", "multiqc/multiqc_data/hicpro_contact_plot.txt", "multiqc/multiqc_data/hicpro_filtering_plot.txt", - "multiqc/multiqc_data/hicpro_mapping_stats_plot.txt", + "multiqc/multiqc_data/hicpro_mapping_stats_plot_Read_1.txt", + "multiqc/multiqc_data/hicpro_mapping_stats_plot_Read_2.txt", "multiqc/multiqc_data/hicpro_pairing_stats_plot.txt", "multiqc/multiqc_data/llms-full.txt", "multiqc/multiqc_data/multiqc.log", @@ -329,8 +330,10 @@ "multiqc/multiqc_plots/pdf/hicpro_contact_plot-pct.pdf", "multiqc/multiqc_plots/pdf/hicpro_filtering_plot-cnt.pdf", "multiqc/multiqc_plots/pdf/hicpro_filtering_plot-pct.pdf", - "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot-cnt.pdf", - "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot-pct.pdf", + "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_1-cnt.pdf", + "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_1-pct.pdf", + "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_2-cnt.pdf", + "multiqc/multiqc_plots/pdf/hicpro_mapping_stats_plot_Read_2-pct.pdf", "multiqc/multiqc_plots/pdf/hicpro_pairing_stats_plot-cnt.pdf", "multiqc/multiqc_plots/pdf/hicpro_pairing_stats_plot-pct.pdf", "multiqc/multiqc_plots/png", @@ -348,8 +351,10 @@ "multiqc/multiqc_plots/png/hicpro_contact_plot-pct.png", "multiqc/multiqc_plots/png/hicpro_filtering_plot-cnt.png", "multiqc/multiqc_plots/png/hicpro_filtering_plot-pct.png", - "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot-cnt.png", - "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot-pct.png", + "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_1-cnt.png", + "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_1-pct.png", + "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_2-cnt.png", + "multiqc/multiqc_plots/png/hicpro_mapping_stats_plot_Read_2-pct.png", "multiqc/multiqc_plots/png/hicpro_pairing_stats_plot-cnt.png", "multiqc/multiqc_plots/png/hicpro_pairing_stats_plot-pct.png", "multiqc/multiqc_plots/svg", @@ -367,8 +372,10 @@ "multiqc/multiqc_plots/svg/hicpro_contact_plot-pct.svg", "multiqc/multiqc_plots/svg/hicpro_filtering_plot-cnt.svg", "multiqc/multiqc_plots/svg/hicpro_filtering_plot-pct.svg", - "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot-cnt.svg", - "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot-pct.svg", + "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_1-cnt.svg", + "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_1-pct.svg", + "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_2-cnt.svg", + "multiqc/multiqc_plots/svg/hicpro_mapping_stats_plot_Read_2-pct.svg", "multiqc/multiqc_plots/svg/hicpro_pairing_stats_plot-cnt.svg", "multiqc/multiqc_plots/svg/hicpro_pairing_stats_plot-pct.svg", "multiqc/multiqc_report.html", @@ -401,7 +408,6 @@ "SRR4292758_contacts.pairs.gz.px2:md5,db3653be8c0229a0f32d6d0f0e7fcf24", "fastqc-status-check-heatmap.txt:md5,755d1909854791c227d1000b38c977e9", "hicpro_contact_plot.txt:md5,026bd3f93ce85d7b695f2cc332ef1551", - "hicpro_mapping_stats_plot.txt:md5,e0a21abcaacacab43968f1eff715a1c6", "hicpro_pairing_stats_plot.txt:md5,b2f918d8f9919aaa30a0ea15f4522876", "multiqc_citations.txt:md5,76bcbb4e4103209b523ed9da8fef74bc", "W303_SGD_2015_JRIU00000000.fsa.fai:md5,85017cce3858d13e8731f776bd639a35", @@ -418,6 +424,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-03-10T10:54:36.481540622" + "timestamp": "2026-03-10T11:50:05.416293782" } } \ No newline at end of file From 305af879f51b05fb7116cbc0cf5c38df8bb6301e Mon Sep 17 00:00:00 2001 From: samuelruizperez Date: Wed, 11 Mar 2026 15:46:48 +0100 Subject: [PATCH 53/55] `fix`: `--res_zoomify` (#229) --- nextflow_schema.json | 2 +- subworkflows/local/cooler/main.nf | 28 +++++++++++----------------- workflows/hic.nf | 7 +++++-- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/nextflow_schema.json b/nextflow_schema.json index 862077f7..a2f9a76b 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -296,7 +296,7 @@ "default": "--force" }, "res_zoomify": { - "type": "string", + "type": ["string", "integer"], "description": "Maximum resolution to build mcool file" }, "save_raw_maps": { diff --git a/subworkflows/local/cooler/main.nf b/subworkflows/local/cooler/main.nf index 0089d2b1..c5abcc03 100644 --- a/subworkflows/local/cooler/main.nf +++ b/subworkflows/local/cooler/main.nf @@ -16,9 +16,10 @@ include { SPLIT_COOLER_DUMP } from '../../../modules/local/split_cooler_dump' workflow COOLER { take: - pairs // [meta, pairs, index] - chromsize // [meta, chromsize] - cool_bins + ch_pairs // [meta, pairs, index] + ch_chromsize // [meta, chromsize] + ch_cools_bins + ch_zoom_res main: @@ -26,23 +27,23 @@ workflow COOLER { // FILTER CHROMOSOMES ON SIZE if( params.min_size ) { - chromsize = chromsize | FILTER_CHROMSIZE + ch_chromsize = ch_chromsize | FILTER_CHROMSIZE } //***************************************** // EXPORT BINS COOLER_MAKEBINS( - chromsize.combine(cool_bins) + ch_chromsize.combine(ch_cools_bins) ) //***************************************** // BUILD COOL FILE PER RESOLUTION COOLER_CLOAD( - pairs.collect(), - chromsize.collect(), + ch_pairs.collect(), + ch_chromsize.collect(), "pairs", - cool_bins + ch_cools_bins ) // Add resolution in meta @@ -57,16 +58,9 @@ workflow COOLER { ch_cool.map{[it[0], it[1], ""]} ) - // Zoomify at minimum bin resolution - if (!params.res_zoomify){ - ch_res_zoomify = cool_bins.min() - }else{ - ch_res_zoomify = channel.from(params.res_zoomify).splitCsv().flatten().unique().toInteger() - } - ch_cool - .combine(ch_res_zoomify) - .filter{ it[2] == it[3] } + .combine(ch_zoom_res) + .filter{ meta, cool, zoom_res -> meta.resolution == zoom_res } .map{ it->[it[0], it[1]] } .set{ ch_cool_zoomify } diff --git a/workflows/hic.nf b/workflows/hic.nf index f69c8ded..1df493f8 100644 --- a/workflows/hic.nf +++ b/workflows/hic.nf @@ -46,8 +46,10 @@ workflow HIC { ch_map_res = channel.from( params.bin_size.toString()).splitCsv().flatten().toInteger() if (params.res_zoomify){ - ch_zoom_res = channel.from( params.res_zoomify ).splitCsv().flatten().toInteger() + ch_zoom_res = channel.from( params.res_zoomify.toString()).splitCsv().flatten().toInteger() ch_map_res = ch_map_res.concat(ch_zoom_res) + } else { + ch_zoom_res = ch_map_res.min() } if (params.res_tads && !params.skip_tads){ @@ -136,7 +138,8 @@ workflow HIC { COOLER ( ch_pairs, ch_chromosome_size, - ch_map_res + ch_map_res, + ch_zoom_res ) // From 1ce0aad8d0badf35677523053920e9af037ce3b1 Mon Sep 17 00:00:00 2001 From: CANCINO AGUIRRE Ignacia Date: Thu, 12 Mar 2026 14:09:20 +0100 Subject: [PATCH 54/55] fix: simplify PAIRTOOLS_PARSE chromsizes input and use of nf-core module --- subworkflows/local/pairtools/main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subworkflows/local/pairtools/main.nf b/subworkflows/local/pairtools/main.nf index 471fba19..4f13e83f 100644 --- a/subworkflows/local/pairtools/main.nf +++ b/subworkflows/local/pairtools/main.nf @@ -7,7 +7,7 @@ //include { BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' include { BWA_MEM } from '../../../modules/nf-core/bwa/mem/main' include { PAIRTOOLS_DEDUP } from '../../../modules/nf-core/pairtools/dedup/main' -//include { PAIRTOOLS_PARSE } from '../../../modules/nf-core/pairtools/parse/main' +include { PAIRTOOLS_PARSE } from '../../../modules/nf-core/pairtools/parse/main' include { PAIRTOOLS_RESTRICT } from '../../../modules/nf-core/pairtools/restrict/main' include { PAIRTOOLS_SELECT } from '../../../modules/nf-core/pairtools/select/main' include { PAIRTOOLS_SORT } from '../../../modules/nf-core/pairtools/sort/main' @@ -21,7 +21,7 @@ include { PAIRIX } from '../../../modules/nf-core/pairix/main' //include { PAIRTOOLS_MERGE } from '../../../modules/local/pairtools/pairtools_merge' include { PAIRTOOLS_SPLIT } from '../../../modules/local/pairtools/pairtools_split' //include { PAIRTOOLS_STATS } from '../../../modules/local/pairtools/pairtools_stats' -include { PAIRTOOLS_PARSE } from '../../../modules/local/pairtools/pairtools_parse' + workflow PAIRTOOLS { @@ -43,7 +43,7 @@ workflow PAIRTOOLS { PAIRTOOLS_PARSE( BWA_MEM.out.bam, - chrsize.collect() + chrsize.map{ it[1] }.collect() ) PAIRTOOLS_RESTRICT( From 0c65d086b25fe273a85eed7ad9ad7391db946c18 Mon Sep 17 00:00:00 2001 From: samuelruizperez Date: Thu, 12 Mar 2026 14:44:24 +0100 Subject: [PATCH 55/55] move pairtools fix to another branch. --- subworkflows/local/pairtools/main.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subworkflows/local/pairtools/main.nf b/subworkflows/local/pairtools/main.nf index 4f13e83f..471fba19 100644 --- a/subworkflows/local/pairtools/main.nf +++ b/subworkflows/local/pairtools/main.nf @@ -7,7 +7,7 @@ //include { BWAMEM2_MEM } from '../../../modules/nf-core/bwamem2/mem/main' include { BWA_MEM } from '../../../modules/nf-core/bwa/mem/main' include { PAIRTOOLS_DEDUP } from '../../../modules/nf-core/pairtools/dedup/main' -include { PAIRTOOLS_PARSE } from '../../../modules/nf-core/pairtools/parse/main' +//include { PAIRTOOLS_PARSE } from '../../../modules/nf-core/pairtools/parse/main' include { PAIRTOOLS_RESTRICT } from '../../../modules/nf-core/pairtools/restrict/main' include { PAIRTOOLS_SELECT } from '../../../modules/nf-core/pairtools/select/main' include { PAIRTOOLS_SORT } from '../../../modules/nf-core/pairtools/sort/main' @@ -21,7 +21,7 @@ include { PAIRIX } from '../../../modules/nf-core/pairix/main' //include { PAIRTOOLS_MERGE } from '../../../modules/local/pairtools/pairtools_merge' include { PAIRTOOLS_SPLIT } from '../../../modules/local/pairtools/pairtools_split' //include { PAIRTOOLS_STATS } from '../../../modules/local/pairtools/pairtools_stats' - +include { PAIRTOOLS_PARSE } from '../../../modules/local/pairtools/pairtools_parse' workflow PAIRTOOLS { @@ -43,7 +43,7 @@ workflow PAIRTOOLS { PAIRTOOLS_PARSE( BWA_MEM.out.bam, - chrsize.map{ it[1] }.collect() + chrsize.collect() ) PAIRTOOLS_RESTRICT(