diff --git a/.github/actions/nf-test/action.yml b/.github/actions/nf-test/action.yml
index c024d3a..96e748c 100644
--- a/.github/actions/nf-test/action.yml
+++ b/.github/actions/nf-test/action.yml
@@ -38,11 +38,16 @@ runs:
- name: Setup apptainer
if: contains(inputs.profile, 'singularity')
uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0
+ with:
+ apptainer-version: 1.5.3
- name: Set up Singularity
if: contains(inputs.profile, 'singularity')
shell: bash
run: |
+ # The runner image restricts unprivileged user namespaces, which non-suid
+ # apptainer needs to start a container at all.
+ sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true
mkdir -p $NXF_SINGULARITY_CACHEDIR
mkdir -p $NXF_SINGULARITY_LIBRARYDIR
diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml
index 91f761d..4f60919 100644
--- a/.github/workflows/awsfulltest.yml
+++ b/.github/workflows/awsfulltest.yml
@@ -24,7 +24,6 @@ jobs:
- name: Launch workflow via Seqera Platform
uses: seqeralabs/action-tower-launch@51565b514bff1827cf34620de25d0055759f1fc9 # v2
- # TODO nf-core: You can customise AWS full pipeline tests as required
# Add full size test data (but still relatively small datasets for few samples)
# on the `test_full.config` test runs with only one set of parameters
with:
diff --git a/.nf-core.yml b/.nf-core.yml
index d33098c..de98ff1 100644
--- a/.nf-core.yml
+++ b/.nf-core.yml
@@ -3,7 +3,9 @@ lint:
- assets/nf-core-funcprofiler_logo_light.png
- .github/PULL_REQUEST_TEMPLATE.md
- .github/workflows/linting.yml
- - .github/workflows/linting_comment.yml
+ # The 4.0.3 template renders `HEAD_REPO:` with two spaces, which the prettier
+ # pin used by prek collapses to one, so this file can never match the template.
+ - .github/workflows/branch.yml
- .gitignore
nf_core_version: 4.0.3
repository_type: pipeline
diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml
index d1de92d..7900625 100644
--- a/assets/methods_description_template.yml
+++ b/assets/methods_description_template.yml
@@ -3,7 +3,6 @@ description: "Suggested text and references to use when describing pipeline usag
section_name: "nf-core/funcprofiler Methods Description"
section_href: "https://github.com/nf-core/funcprofiler"
plot_type: "html"
-## TODO nf-core: Update the HTML below to your preferred methods description, e.g. add publication citation for this pipeline
## You inject any metadata in the Nextflow '${workflow}' object
data: |
Methods
diff --git a/conf/base.config b/conf/base.config
index f61c036..49af73f 100644
--- a/conf/base.config
+++ b/conf/base.config
@@ -10,7 +10,6 @@
process {
- // TODO nf-core: Check the defaults for all processes
cpus = { 1 * task.attempt }
memory = { 6.GB * task.attempt }
time = { 4.h * task.attempt }
@@ -24,7 +23,6 @@ process {
// These labels are used and recognised by default in DSL2 files hosted on nf-core/modules.
// If possible, it would be nice to keep the same label naming convention when
// adding in your local modules too.
- // TODO nf-core: Customise requirements for specific processes.
// See https://www.nextflow.io/docs/latest/config.html#config-process-selectors
withLabel:process_single {
cpus = { 1 }
diff --git a/conf/test.config b/conf/test.config
index 347dec0..7d055c2 100644
--- a/conf/test.config
+++ b/conf/test.config
@@ -21,11 +21,8 @@ process {
params {
config_profile_name = 'Test profile'
config_profile_description = 'Minimal test dataset to check pipeline function'
- //input = params.pipelines_testdata_base_path + 'samplesheets/test.csv'
- input = 'https://github.com/nickp60/test-datasets/raw/refs/heads/funcprofiler/samplesheets/test.csv'
+ input = params.pipelines_testdata_base_path + 'samplesheets/test.csv'
databases = params.pipelines_testdata_base_path + 'database.csv'
- outdir = "tmp"
- cleanup = false
run_fmhfunprofiler = true
run_humann_v3 = true
run_mifaser = true
diff --git a/conf/test_full.config b/conf/test_full.config
index 340f238..148780b 100644
--- a/conf/test_full.config
+++ b/conf/test_full.config
@@ -13,12 +13,8 @@
params {
config_profile_name = 'Full test profile'
config_profile_description = 'Full test dataset to check pipeline function'
-// input = params.pipelines_testdata_base_path + 'samplesheets/test.csv'
-// databases = params.pipelines_testdata_base_path + 'database_full.csv'
input = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/taxprofiler/samplesheet_shortreadsonly.csv'
- databases = 'https://raw.githubusercontent.com/nickp60/test-datasets/refs/heads/funcprofiler/database_full.csv'
- outdir = "fulltest_results"
- cleanup = false
+ databases = params.pipelines_testdata_base_path + 'database_full.csv'
run_fmhfunprofiler = true
run_humann_v3 = true
run_mifaser = true
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 30309b6..95b80c6 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -182,4 +182,9 @@ If you update images or graphics, follow the nf-core [style guidelines](https://
## Pipeline specific contribution guidelines
-
+When adding a new profiler:
+
+- Add it to [nf-core/modules](https://github.com/nf-core/modules) rather than to `modules/local`. A local module is only a stopgap for tools that are not yet packaged on Bioconda.
+- Gate it behind a `run_` parameter, and take its database from the database sheet so it is grouped by `dbprep` like every other tool.
+- Add it to the `profile` subworkflow, to `docs/output.md`, and to `CITATIONS.md`.
+- Cover it with an nf-test, and regenerate snapshots with `nf-test test --update-snapshot`.
diff --git a/main.nf b/main.nf
index cfb7114..d45ad6e 100644
--- a/main.nf
+++ b/main.nf
@@ -38,7 +38,7 @@ workflow NFCORE_FUNCPROFILER {
//
// WORKFLOW: Run pipeline
//
- FUNCPROFILER (
+ FUNCPROFILER(
samplesheet,
databases,
params.multiqc_config,
diff --git a/modules.json b/modules.json
index 1189520..68fa76c 100644
--- a/modules.json
+++ b/modules.json
@@ -12,7 +12,7 @@
},
"diamond/blastx": {
"branch": "master",
- "git_sha": "1b534ad2336876dbe82e9fea2773334cb624b426",
+ "git_sha": "83ce9b314157a24d9a92f17a07ed5d55f30b78f9",
"installed_by": ["modules"]
},
"eggnogmapper": {
@@ -32,7 +32,7 @@
},
"gunzip": {
"branch": "master",
- "git_sha": "96c57dfd98a0641886a67bd449fe33ee2ec0e374",
+ "git_sha": "0902eac3012baaf4f9ab6513c8c55acc9353c96c",
"installed_by": ["modules"]
},
"humann3/humann": {
@@ -57,7 +57,7 @@
},
"mifaser": {
"branch": "master",
- "git_sha": "6b43745037429413ca11e0e4a1029d90493c3135",
+ "git_sha": "522d0a5709833aaa28c58d4464b4348d03316a62",
"installed_by": ["modules"]
},
"multiqc": {
@@ -77,12 +77,12 @@
},
"seqkit/fq2fa": {
"branch": "master",
- "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
+ "git_sha": "d07a945f421a4a91ce4e5a22db63e0e7f8741607",
"installed_by": ["modules"]
},
"untar": {
"branch": "master",
- "git_sha": "447f7bc0fa41dfc2400c8cad4c0291880dc060cf",
+ "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
"installed_by": ["modules"]
}
}
@@ -101,7 +101,7 @@
},
"utils_nfschema_plugin": {
"branch": "master",
- "git_sha": "ce3424257de288c0ca25f097a68d3a289da23f12",
+ "git_sha": "a7b27fd25bfa8dcc07d299e88bd790585901a436",
"installed_by": ["subworkflows"]
}
}
diff --git a/modules/local/humann4/humann/main.nf b/modules/local/humann4/humann/main.nf
index ad5b87d..861ef5e 100644
--- a/modules/local/humann4/humann/main.nf
+++ b/modules/local/humann4/humann/main.nf
@@ -1,6 +1,6 @@
// Taken 98% from https://github.com/nf-core/modules/pull/1089/files
process HUMANN4 {
- tag "$meta.id"
+ tag "${meta.id}"
label 'process_high'
conda "${moduleDir}/environment.yml"
@@ -14,10 +14,10 @@ process HUMANN4 {
path utility_db
output:
- tuple val(meta), path("*_genefamilies.tsv.gz") , emit: genefamilies
+ tuple val(meta), path("*_genefamilies.tsv.gz"), emit: genefamilies
tuple val(meta), path("*_pathabundance.tsv.gz"), emit: pathabundance
- tuple val(meta), path("*_reactions.tsv.gz") , emit: reactions
- tuple val(meta), path("*.log") , emit: log
+ tuple val(meta), path("*_reactions.tsv.gz"), emit: reactions
+ tuple val(meta), path("*.log"), emit: log
tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions
tuple val("${task.process}"), val('MetaPHLan'), eval("metaphlan --version 2>&1 | sed 's/metaphlan v//'"), emit: versions_metaphlan, topic: versions
@@ -39,13 +39,13 @@ process HUMANN4 {
find \${NUCS_DB}
humann \\
- $args \\
+ ${args} \\
--threads ${task.cpus} \\
- --input $input \\
+ --input ${input} \\
--protein-database \${PROTS_DB} \\
--nucleotide-database \${NUCS_DB} \\
- --output-basename $prefix \\
- $pangenome_string \\
+ --output-basename ${prefix} \\
+ ${pangenome_string} \\
${args} \\
--o-log ${prefix}.log \\
--output .
@@ -54,11 +54,12 @@ process HUMANN4 {
gzip -n *.tsv
"""
+
stub:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"
"""
- echo $args
+ echo ${args}
for suf in genefamilies.tsv.gz pathabundance.tsv.gz reactions.tsv.gz
do
diff --git a/modules/nf-core/diamond/blastx/environment.yml b/modules/nf-core/diamond/blastx/environment.yml
index cca5cbb..5dc13ad 100644
--- a/modules/nf-core/diamond/blastx/environment.yml
+++ b/modules/nf-core/diamond/blastx/environment.yml
@@ -4,4 +4,4 @@ channels:
- conda-forge
- bioconda
dependencies:
- - bioconda::diamond=2.1.24
+ - bioconda::diamond=2.2.1
diff --git a/modules/nf-core/diamond/blastx/main.nf b/modules/nf-core/diamond/blastx/main.nf
index 2b03de0..453170c 100644
--- a/modules/nf-core/diamond/blastx/main.nf
+++ b/modules/nf-core/diamond/blastx/main.nf
@@ -4,8 +4,8 @@ process DIAMOND_BLASTX {
conda "${moduleDir}/environment.yml"
container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
- ? 'https://depot.galaxyproject.org/singularity/diamond:2.1.24--hf93d47f_0'
- : 'quay.io/biocontainers/diamond:2.1.24--hf93d47f_0'}"
+ ? 'https://depot.galaxyproject.org/singularity/diamond:2.2.1--he361c42_0'
+ : 'quay.io/biocontainers/diamond:2.2.1--he361c42_0'}"
input:
tuple val(meta), path(fasta)
diff --git a/modules/nf-core/diamond/blastx/meta.yml b/modules/nf-core/diamond/blastx/meta.yml
index e00b8fa..019a3e9 100644
--- a/modules/nf-core/diamond/blastx/meta.yml
+++ b/modules/nf-core/diamond/blastx/meta.yml
@@ -176,3 +176,4 @@ maintainers:
- "@jfy133"
- "@mjamy"
- "@vagkaratzas"
+ - "@sofstam"
diff --git a/modules/nf-core/diamond/blastx/tests/main.nf.test.snap b/modules/nf-core/diamond/blastx/tests/main.nf.test.snap
index 80340d2..b3cf211 100644
--- a/modules/nf-core/diamond/blastx/tests/main.nf.test.snap
+++ b/modules/nf-core/diamond/blastx/tests/main.nf.test.snap
@@ -6,16 +6,16 @@
[
"DIAMOND_BLASTX",
"diamond",
- "2.1.24"
+ "2.2.1"
]
]
}
],
+ "timestamp": "2026-06-09T15:06:53.562101168",
"meta": {
- "nf-test": "0.9.3",
- "nextflow": "25.10.4"
- },
- "timestamp": "2026-04-22T15:47:51.928317786"
+ "nf-test": "0.9.5",
+ "nextflow": "26.04.3"
+ }
},
"Should search for transcriptome hits against a DIAMOND db and return the default tab separated output file of hits": {
"content": [
@@ -32,15 +32,15 @@
[
"DIAMOND_BLASTX",
"diamond",
- "2.1.24"
+ "2.2.1"
]
]
}
],
+ "timestamp": "2026-06-09T15:06:47.844654623",
"meta": {
- "nf-test": "0.9.3",
- "nextflow": "25.10.4"
- },
- "timestamp": "2026-04-22T15:47:45.383426326"
+ "nf-test": "0.9.5",
+ "nextflow": "26.04.3"
+ }
}
}
\ No newline at end of file
diff --git a/modules/nf-core/gunzip/main.nf b/modules/nf-core/gunzip/main.nf
index a8533e7..6edffc5 100644
--- a/modules/nf-core/gunzip/main.nf
+++ b/modules/nf-core/gunzip/main.nf
@@ -3,7 +3,7 @@ process GUNZIP {
label 'process_single'
conda "${moduleDir}/environment.yml"
- container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data'
: 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}"
@@ -19,8 +19,9 @@ process GUNZIP {
script:
def args = task.ext.args ?: ''
- def extension = (archive.toString() - '.gz').tokenize('.')[-1]
- def name = archive.toString() - '.gz' - ".${extension}"
+ def nameWithoutGz = archive.extension == 'gz' ? archive.baseName : archive.name
+ def extension = file(nameWithoutGz).extension
+ def name = file(nameWithoutGz).baseName
def prefix = task.ext.prefix ?: name
gunzip = prefix + ".${extension}"
"""
@@ -35,8 +36,9 @@ process GUNZIP {
"""
stub:
- def extension = (archive.toString() - '.gz').tokenize('.')[-1]
- def name = archive.toString() - '.gz' - ".${extension}"
+ def nameWithoutGz = archive.extension == 'gz' ? archive.baseName : archive.name
+ def extension = file(nameWithoutGz).extension
+ def name = file(nameWithoutGz).baseName
def prefix = task.ext.prefix ?: name
gunzip = prefix + ".${extension}"
"""
diff --git a/modules/nf-core/gunzip/tests/main.nf.test b/modules/nf-core/gunzip/tests/main.nf.test
index 776211a..33cb75a 100644
--- a/modules/nf-core/gunzip/tests/main.nf.test
+++ b/modules/nf-core/gunzip/tests/main.nf.test
@@ -89,6 +89,60 @@ nextflow_process {
}
+ test("Should decompress file with extension appearing multiple times in filename") {
+
+ when {
+ params {
+ outdir = "$outputDir"
+ }
+ process {
+ """
+ input[0] = Channel.of([
+ [],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true).copyTo('test.fa.v1.fa.gz')
+ ]
+ )
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert process.success },
+ { assert file(process.out.gunzip[0][1]).name == 'test.fa.v1.fa' }
+ )
+ }
+
+ }
+
+ test("Should decompress file with extension appearing multiple times in filename - prefix") {
+
+ config './nextflow.config'
+
+ when {
+ params {
+ outdir = "$outputDir"
+ }
+ process {
+ """
+ input[0] = Channel.of([
+ [ id: 'test' ],
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true).copyTo('test.fa.v1.fa.gz')
+ ]
+ )
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert process.success },
+ { assert snapshot(process.out).match() }
+ )
+ }
+
+ }
+
test("Should run without failures - prefix - stub") {
options '-stub'
diff --git a/modules/nf-core/gunzip/tests/main.nf.test.snap b/modules/nf-core/gunzip/tests/main.nf.test.snap
index 111ba1b..980e95a 100644
--- a/modules/nf-core/gunzip/tests/main.nf.test.snap
+++ b/modules/nf-core/gunzip/tests/main.nf.test.snap
@@ -1,4 +1,45 @@
{
+ "Should decompress file with extension appearing multiple times in filename - prefix": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test"
+ },
+ "test.xyz.fa:md5,4161df271f9bfcd25d5845a1e220dbec"
+ ]
+ ],
+ "1": [
+ [
+ "GUNZIP",
+ "gunzip",
+ "1.13"
+ ]
+ ],
+ "gunzip": [
+ [
+ {
+ "id": "test"
+ },
+ "test.xyz.fa:md5,4161df271f9bfcd25d5845a1e220dbec"
+ ]
+ ],
+ "versions_gunzip": [
+ [
+ "GUNZIP",
+ "gunzip",
+ "1.13"
+ ]
+ ]
+ }
+ ],
+ "timestamp": "2026-04-15T15:20:52.59447",
+ "meta": {
+ "nf-test": "0.9.5",
+ "nextflow": "25.10.4"
+ }
+ },
"Should run without failures - prefix - stub": {
"content": [
{
@@ -34,11 +75,11 @@
]
}
],
+ "timestamp": "2026-01-19T17:21:56.633550769",
"meta": {
"nf-test": "0.9.3",
"nextflow": "25.10.2"
- },
- "timestamp": "2026-01-19T17:21:56.633550769"
+ }
},
"Should run without failures - stub": {
"content": [
@@ -75,11 +116,11 @@
]
}
],
+ "timestamp": "2026-01-19T17:21:51.435621199",
"meta": {
"nf-test": "0.9.3",
"nextflow": "25.10.2"
- },
- "timestamp": "2026-01-19T17:21:51.435621199"
+ }
},
"Should run without failures": {
"content": [
@@ -116,11 +157,11 @@
]
}
],
+ "timestamp": "2026-01-19T17:21:40.613975821",
"meta": {
"nf-test": "0.9.3",
"nextflow": "25.10.2"
- },
- "timestamp": "2026-01-19T17:21:40.613975821"
+ }
},
"Should run without failures - prefix": {
"content": [
@@ -157,10 +198,10 @@
]
}
],
+ "timestamp": "2026-01-19T17:21:46.086880414",
"meta": {
"nf-test": "0.9.3",
"nextflow": "25.10.2"
- },
- "timestamp": "2026-01-19T17:21:46.086880414"
+ }
}
}
\ No newline at end of file
diff --git a/modules/nf-core/mifaser/tests/main.nf.test b/modules/nf-core/mifaser/tests/main.nf.test
index fa7a239..954ba2b 100644
--- a/modules/nf-core/mifaser/tests/main.nf.test
+++ b/modules/nf-core/mifaser/tests/main.nf.test
@@ -33,7 +33,7 @@ nextflow_process {
[ id:'test', single_end:true ],
[ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ]
]
- input[1] = UNTAR.out.untar.map{ meta, dir -> dir.resolve("database/mifaser/GS-24-all") }
+ input[1] = UNTAR.out.untar.map { it[1] }
"""
}
}
diff --git a/modules/nf-core/seqkit/fq2fa/environment.yml b/modules/nf-core/seqkit/fq2fa/environment.yml
index b26fb1e..09abb79 100644
--- a/modules/nf-core/seqkit/fq2fa/environment.yml
+++ b/modules/nf-core/seqkit/fq2fa/environment.yml
@@ -4,4 +4,4 @@ channels:
- conda-forge
- bioconda
dependencies:
- - bioconda::seqkit=2.9.0
+ - bioconda::seqkit=2.13.0
diff --git a/modules/nf-core/seqkit/fq2fa/main.nf b/modules/nf-core/seqkit/fq2fa/main.nf
index 313af89..0722455 100644
--- a/modules/nf-core/seqkit/fq2fa/main.nf
+++ b/modules/nf-core/seqkit/fq2fa/main.nf
@@ -1,11 +1,11 @@
process SEQKIT_FQ2FA {
- tag "$meta.id"
+ tag "${meta.id}"
label 'process_single'
conda "${moduleDir}/environment.yml"
- container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ?
- 'https://depot.galaxyproject.org/singularity/seqkit:2.9.0--h9ee0642_0' :
- 'quay.io/biocontainers/seqkit:2.9.0--h9ee0642_0' }"
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
+ ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/4f/4fe272ab9a519cf418160471a485b5ef50ea3f571a8e4555a826f70a4d8243ae/data'
+ : 'community.wave.seqera.io/library/seqkit:2.13.0--05c0a96bf9fb2751'}"
input:
tuple val(meta), path(fastq)
@@ -20,19 +20,21 @@ process SEQKIT_FQ2FA {
script:
def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"
-
"""
seqkit \\
fq2fa \\
- $args \\
- -j $task.cpus \\
+ ${args} \\
+ -j ${task.cpus} \\
-o ${prefix}.fa.gz \\
- $fastq
+ ${fastq}
"""
stub:
+ def args = task.ext.args ?: ''
def prefix = task.ext.prefix ?: "${meta.id}"
"""
+ echo ${args}
+
echo "" | gzip > ${prefix}.fa.gz
"""
}
diff --git a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test
index 08f399e..b20ac23 100644
--- a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test
+++ b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test
@@ -10,47 +10,44 @@ nextflow_process {
tag "seqkit/fq2fa"
test("sarscov2 - bam") {
-
when {
process {
"""
- input[0] = [[ id:'test', single_end:false ], // meta map
- [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ]
+ input[0] = [
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)
]
"""
}
}
then {
+ assert process.success
assertAll(
- { assert process.success },
- { assert snapshot(process.out).match() }
+ { assert snapshot(sanitizeOutput(process.out)).match() }
)
}
-
}
test("sarscov2 - bam - stub") {
-
- options "-stub"
+ options '-stub'
when {
process {
"""
- input[0] = [[ id:'test', single_end:false ], // meta map
- [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ]
+ input[0] = [
+ [ id:'test', single_end:false ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)
]
"""
}
}
then {
+ assert process.success
assertAll(
- { assert process.success },
- { assert snapshot(process.out).match() }
+ { assert snapshot(sanitizeOutput(process.out)).match() }
)
}
-
}
-
}
diff --git a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap
index b96e153..ea4763d 100644
--- a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap
+++ b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap
@@ -2,22 +2,6 @@
"sarscov2 - bam - stub": {
"content": [
{
- "0": [
- [
- {
- "id": "test",
- "single_end": false
- },
- "test.fa.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
- ]
- ],
- "1": [
- [
- "SEQKIT_FQ2FA",
- "seqkit",
- "2.9.0"
- ]
- ],
"fasta": [
[
{
@@ -31,36 +15,20 @@
[
"SEQKIT_FQ2FA",
"seqkit",
- "2.9.0"
+ "2.13.0"
]
]
}
],
- "timestamp": "2026-03-12T13:05:56.983767141",
+ "timestamp": "2026-06-15T10:19:21.836507096",
"meta": {
- "nf-test": "0.9.4",
- "nextflow": "25.10.4"
+ "nf-test": "0.9.5",
+ "nextflow": "26.04.3"
}
},
"sarscov2 - bam": {
"content": [
{
- "0": [
- [
- {
- "id": "test",
- "single_end": false
- },
- "test.fa.gz:md5,f0c5c9110ce19e9ebbc9a6b6baf9e105"
- ]
- ],
- "1": [
- [
- "SEQKIT_FQ2FA",
- "seqkit",
- "2.9.0"
- ]
- ],
"fasta": [
[
{
@@ -74,15 +42,15 @@
[
"SEQKIT_FQ2FA",
"seqkit",
- "2.9.0"
+ "2.13.0"
]
]
}
],
- "timestamp": "2026-03-12T13:05:49.874408711",
+ "timestamp": "2026-06-12T17:24:20.019577498",
"meta": {
- "nf-test": "0.9.4",
- "nextflow": "25.10.4"
+ "nf-test": "0.9.5",
+ "nextflow": "26.04.3"
}
}
}
\ No newline at end of file
diff --git a/modules/nf-core/untar/main.nf b/modules/nf-core/untar/main.nf
index b9c324d..bf2c056 100644
--- a/modules/nf-core/untar/main.nf
+++ b/modules/nf-core/untar/main.nf
@@ -3,7 +3,7 @@ process UNTAR {
label 'process_single'
conda "${moduleDir}/environment.yml"
- container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container
+ container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container
? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data'
: 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}"
diff --git a/nextflow_schema.json b/nextflow_schema.json
index f63b96f..e855d7e 100644
--- a/nextflow_schema.json
+++ b/nextflow_schema.json
@@ -129,19 +129,16 @@
},
"run_rgi": {
"type": "boolean",
- "description": "Turn on profiling with RGI. Requires database to be present CSV file passed to --databases",
- "default": false
+ "description": "Turn on profiling with RGI. Requires database to be present CSV file passed to --databases"
},
"run_mifaser": {
"type": "boolean",
- "description": "Turn on profiling with mi-faser. Requires database to be present CSV file passed to --databases",
- "default": false
+ "description": "Turn on profiling with mi-faser. Requires database to be present CSV file passed to --databases"
},
"run_eggnogmapper": {
"type": "boolean",
"fa_icon": "fas fa-toggle-on",
- "description": "Turn on functional annotation with EggNOG-mapper. Requires `eggnogmapper`-tagged database entries in the CSV file passed to --databases",
- "default": false
+ "description": "Turn on functional annotation with EggNOG-mapper. Requires `eggnogmapper`-tagged database entries in the CSV file passed to --databases"
}
}
},
diff --git a/subworkflows/local/dataprep/meta.yml b/subworkflows/local/dataprep/meta.yml
index 40b2a5f..915faa4 100644
--- a/subworkflows/local/dataprep/meta.yml
+++ b/subworkflows/local/dataprep/meta.yml
@@ -1,50 +1,42 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json
name: "dataprep"
-## TODO nf-core: Add a description of the subworkflow and list keywords
-description: Sort SAM/BAM/CRAM file
+description: |
+ Validate the input samplesheet and prepare read channels for profiling. Sets
+ `single_end`, `run_accession` and `instrument_platform` on the meta map, merges
+ multiple runs belonging to the same sample, and produces an additional channel
+ in which read pairs are concatenated into a single file for tools that cannot
+ take paired input.
keywords:
- - sort
- - bam
- - sam
- - cram
-## TODO nf-core: Add a list of the modules and/or subworkflows used in the subworkflow
+ - samplesheet
+ - fastq
+ - merging
+ - concatenation
+ - metagenome
components:
- - samtools/sort
- - samtools/index
-## TODO nf-core: List all of the channels used as input with a description and their structure
+ - cat/fastq
input:
- - ch_bam:
+ - samplesheet:
type: file
description: |
- The input channel containing the BAM/CRAM/SAM files
- Structure: [ val(meta), path(bam) ]
- pattern: "*.{bam/cram/sam}"
-## TODO nf-core: List all of the channels used as output with a descriptions and their structure
+ Channel of validated samplesheet rows. Long-read (`OXFORD_NANOPORE`)
+ platforms and FASTA input are rejected, and `fastq_1` is required.
+ Structure: [ val(meta), val(run_accession), val(instrument_platform), path(fastq_1), path(fastq_2), path(fasta) ]
+ pattern: "*.{fq,fastq}{,.gz}"
output:
- - bam:
+ - reads:
type: file
description: |
- Channel containing BAM files
- Structure: [ val(meta), path(bam) ]
- pattern: "*.bam"
- - bai:
+ Channel of reads per sample, with runs merged where a sample has more
+ than one. Paired-end samples carry two files, single-end samples one.
+ Structure: [ val(meta), [ path(reads) ] ]
+ pattern: "*.{fq,fastq}{,.gz}"
+ - reads_concat:
type: file
description: |
- Channel containing indexed BAM (BAI) files
- Structure: [ val(meta), path(bai) ]
- pattern: "*.bai"
- - csi:
- type: file
- description: |
- Channel containing CSI files
- Structure: [ val(meta), path(csi) ]
- pattern: "*.csi"
- - versions:
- type: file
- description: |
- File containing software versions
- Structure: [ path(versions.yml) ]
- pattern: "versions.yml"
+ Channel of the same reads concatenated into a single file per sample,
+ with `single_end` forced to `true`, for tools that accept only one FASTQ.
+ Structure: [ val(meta), [ path(reads) ] ]
+ pattern: "*.{fq,fastq}{,.gz}"
authors:
- "@nickp60"
maintainers:
diff --git a/subworkflows/local/dbprep/meta.yml b/subworkflows/local/dbprep/meta.yml
index c915730..89e987e 100644
--- a/subworkflows/local/dbprep/meta.yml
+++ b/subworkflows/local/dbprep/meta.yml
@@ -1,50 +1,35 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json
name: "dbprep"
-## TODO nf-core: Add a description of the subworkflow and list keywords
-description: Sort SAM/BAM/CRAM file
+description: |
+ Prepare the databases declared in the database sheet. Archives are decompressed
+ once per file and only for tools the user has enabled, then all entities
+ belonging to the same database are grouped so that each profiler receives a
+ single entry per database name and parameter combination.
keywords:
- - sort
- - bam
- - sam
- - cram
-## TODO nf-core: Add a list of the modules and/or subworkflows used in the subworkflow
+ - database
+ - untar
+ - decompression
+ - metagenome
components:
- - samtools/sort
- - samtools/index
-## TODO nf-core: List all of the channels used as input with a description and their structure
+ - untar
input:
- - ch_bam:
+ - databases:
type: file
description: |
- The input channel containing the BAM/CRAM/SAM files
- Structure: [ val(meta), path(bam) ]
- pattern: "*.{bam/cram/sam}"
-## TODO nf-core: List all of the channels used as output with a descriptions and their structure
+ Channel of database entries from the database sheet. `meta.tool` selects
+ which profiler the database belongs to, `meta.db_entity` names the part
+ of a multi-file database, and `meta.db_params` carries tool-specific
+ arguments. Entries ending in `.tar`, `.tar.gz`, `.tar.bz2` or `.tar.xz`
+ are decompressed, the rest are passed through untouched.
+ Structure: [ val(meta), path(database) ]
+ pattern: "*.{tar,tar.gz,tar.bz2,tar.xz}"
output:
- - bam:
+ - dbs:
type: file
description: |
- Channel containing BAM files
- Structure: [ val(meta), path(bam) ]
- pattern: "*.bam"
- - bai:
- type: file
- description: |
- Channel containing indexed BAM (BAI) files
- Structure: [ val(meta), path(bai) ]
- pattern: "*.bai"
- - csi:
- type: file
- description: |
- Channel containing CSI files
- Structure: [ val(meta), path(csi) ]
- pattern: "*.csi"
- - versions:
- type: file
- description: |
- File containing software versions
- Structure: [ path(versions.yml) ]
- pattern: "versions.yml"
+ Channel of databases grouped by tool, name and parameters. The second
+ element is a list of maps, each holding the entity name and its path.
+ Structure: [ val(meta), [ [ db_entity: val(entity), db_path: path(db) ] ] ]
authors:
- "@nickp60"
maintainers:
diff --git a/subworkflows/local/profile/main.nf b/subworkflows/local/profile/main.nf
index 931005b..21ddf47 100644
--- a/subworkflows/local/profile/main.nf
+++ b/subworkflows/local/profile/main.nf
@@ -2,21 +2,23 @@
// Run profiling
//
-include { MIFASER } from '../../../modules/nf-core/mifaser/main'
-include { HUMANN3_HUMANN } from '../../../modules/nf-core/humann3/humann/main'
-include { HUMANN4 } from '../../../modules/local/humann4/humann/main'
-include { HUMANN3_REGROUP } from '../../../modules/nf-core/humann3/regroup/main'
-include { HUMANN4_REGROUP } from '../../../modules/local/humann4/regroup/main'
+include { MIFASER } from '../../../modules/nf-core/mifaser/main'
+include { HUMANN3_HUMANN } from '../../../modules/nf-core/humann3/humann/main'
+include { HUMANN4 } from '../../../modules/local/humann4/humann/main'
+include { HUMANN3_REGROUP } from '../../../modules/nf-core/humann3/regroup/main'
+include { HUMANN4_REGROUP } from '../../../modules/local/humann4/regroup/main'
//include { FMHFUNPROFILER } from '../../../modules/local/fmhfunprofiler/main'
-include { FMHFUNPROFILER } from '../../../modules/nf-core/fmhfunprofiler/main'
-include { METAPHLAN_METAPHLAN as MPAHUMANN3;
- METAPHLAN_METAPHLAN as MPAHUMANN4 } from '../../../modules/nf-core/metaphlan/metaphlan/main'
-include { DIAMOND_BLASTX } from '../../../modules/nf-core/diamond/blastx/main'
-include { RGI_BWT } from '../../../modules/nf-core/rgi/bwt/main'
-include { RGI_CARDANNOTATION } from '../../../modules/nf-core/rgi/cardannotation/main'
-include { EGGNOGMAPPER } from '../../../modules/nf-core/eggnogmapper/main'
-include { SEQKIT_FQ2FA } from '../../../modules/nf-core/seqkit/fq2fa/main'
-include { GUNZIP } from '../../../modules/nf-core/gunzip/main'
+include { FMHFUNPROFILER } from '../../../modules/nf-core/fmhfunprofiler/main'
+include {
+ METAPHLAN_METAPHLAN as MPAHUMANN3 ;
+ METAPHLAN_METAPHLAN as MPAHUMANN4
+} from '../../../modules/nf-core/metaphlan/metaphlan/main'
+include { DIAMOND_BLASTX } from '../../../modules/nf-core/diamond/blastx/main'
+include { RGI_BWT } from '../../../modules/nf-core/rgi/bwt/main'
+include { RGI_CARDANNOTATION } from '../../../modules/nf-core/rgi/cardannotation/main'
+include { EGGNOGMAPPER } from '../../../modules/nf-core/eggnogmapper/main'
+include { SEQKIT_FQ2FA } from '../../../modules/nf-core/seqkit/fq2fa/main'
+include { GUNZIP } from '../../../modules/nf-core/gunzip/main'
// Custom Functions
@@ -31,11 +33,13 @@ include { GUNZIP } from '../../../modules
* @return A multiMap'ed output channel with two sub channels, one with the profile and the other with the db
*/
def sanitizeId(str) {
- return str.toString()
- .replaceAll(/_/, '-') // underscore to hyphens
- .replaceAll(/\s+/, '-') // spaces to hyphens
- .replaceAll(/[^\w\-.]/, '') // remove special chars
- .replaceAll(/-+/, '-') // collapse multiple hyphens
+ return str
+ .toString()
+ // underscores to hyphens, spaces to hyphens, drop special chars, collapse hyphens
+ .replaceAll(/_/, '-')
+ .replaceAll(/\s+/, '-')
+ .replaceAll(/[^\w\-.]/, '')
+ .replaceAll(/-+/, '-')
}
def prepareInputs(pairedreads, databases, tool_name, singleFqTool = false) {
/*
@@ -53,52 +57,45 @@ def prepareInputs(pairedreads, databases, tool_name, singleFqTool = false) {
*/
// Step 1: Filter databases to only the requested tool, then group by db_name and db_params
def ch_dbs_grouped = databases
- .flatMap { meta_db, file_list ->
+ .flatMap { meta_db, file_list ->
// Flatten: emit one tuple per file object
file_list.collect { file_obj ->
- // Merge the file object's db_entity into the metadata
- def meta_with_entity = meta_db + [db_entity: file_obj.db_entity]
- [meta_with_entity, file_obj]
+ // Merge the file object's db_entity into the metadata
+ def meta_with_entity = meta_db + [db_entity: file_obj.db_entity]
+ [meta_with_entity, file_obj]
}
- }
- .filter { meta_db, file ->
+ }
+ .filter { meta_db, file ->
meta_db.tool == tool_name
- }
- .map { meta_db, file ->
+ }
+ .map { meta_db, file ->
// Create grouping key: [tool, db_name, db_params]
- def group_key = [
- meta_db.tool,
- meta_db.db_name ?: '',
- meta_db.db_params ?: ''
- ]
+ def group_key = [meta_db.tool, meta_db.db_name ?: '', meta_db.db_params ?: '']
[group_key, meta_db, file]
- }
- .groupTuple() // Group all files for same tool+db_name+db_params
- .map { group_key, meta_db_list, files ->
- def tool = group_key[0]
- def db_name = group_key[1]
- def db_params = group_key[2]
-
- // Convert files list to Map keyed by db_entity for deterministic snapshots
- // Map structure: entity_name -> db_path (entity is already in the key)
- def files_map = [:]
- [meta_db_list, files].transpose().each { meta_db, file ->
- files_map[meta_db.db_entity] = file.db_path // Store only the path
}
-
- // Create consolidated metadata with db_entities as a Set
- def meta_db_grouped = [
- id: sanitizeId("${tool}--${db_name}--${db_params}"),
- tool: tool,
- db_name: db_name,
- db_params: db_params,
- db_entities: files_map.keySet() as Set, // Set of entity names
- num_files: files_map.size()
- ]
-
- // Return files as map
+ // Group all files for same tool+db_name+db_params
+ .groupTuple()
+ .map { group_key, meta_db_list, files ->
+ def tool = group_key[0]
+ def db_name = group_key[1]
+ def db_params = group_key[2]
+
+ // Convert files list to Map keyed by db_entity for deterministic snapshots
+ // Map structure: entity_name -> db_path (entity is already in the key)
+ def files_map = [:]
+ [meta_db_list, files]
+ .transpose()
+ .each { meta_db, file ->
+ // Store only the path
+ files_map[meta_db.db_entity] = file.db_path
+ }
+
+ // Create consolidated metadata with db_entities as a Set
+ def meta_db_grouped = [id: sanitizeId("${tool}--${db_name}--${db_params}"), tool: tool, db_name: db_name, db_params: db_params, db_entities: files_map.keySet() as Set, num_files: files_map.size()]
+
+ // Return files as map
[meta_db_grouped, files_map.toSorted()]
- }
+ }
// Step 2: Combine reads with ALL grouped databases (cartesian product)
// Each sample will get one entry per unique db_name+db_params combination for this tool
def reads_with_dbs = pairedreads
@@ -120,44 +117,43 @@ def prepareInputs(pairedreads, databases, tool_name, singleFqTool = false) {
}
[meta, reads, db_meta, db_files]
}
- .multiMap { it ->
- reads: [it[0] , it[1]]
- db: [ it[2], it[3]]
+ .multiMap { it ->
+ reads: [it[0], it[1]]
+ db: [it[2], it[3]]
}
return result
-
}
-def getDbPath(groupeddb, entity='main', asTuple=false){
+def getDbPath(groupeddb, entity = 'main', asTuple = false) {
// Extract the relevant database file path by entity key from the files map
- def dbpath = groupeddb
- .map { meta_db, files_map ->
- // files_map is now a Map[entity -> db_path], so direct lookup
- if (!files_map.containsKey(entity)) {
- error("No entity '${entity}' file found in database ${meta_db.id}")
- }
+ def dbpath = groupeddb.map { meta_db, files_map ->
+ // files_map is now a Map[entity -> db_path], so direct lookup
+ if (!files_map.containsKey(entity)) {
+ error("No entity '${entity}' file found in database ${meta_db.id}")
+ }
- def db_path = files_map[entity] // Direct access to path
+ def db_path = files_map[entity]
+ // Direct access to path
- if (asTuple){
- return [meta_db, db_path]
- } else {
- return db_path
- }
+ if (asTuple) {
+ return [meta_db, db_path]
+ }
+ else {
+ return db_path
}
+ }
return dbpath
}
workflow PROFILING {
take:
- reads // [ [ meta ], [ reads ] ]
- reads_concat // [ [ meta ], [ reads ] ]
- databases // [ [ meta ], path ]
+ reads // [ [ meta ], [ reads ] ]
+ reads_concat // [ [ meta ], [ reads ] ]
+ databases // [ [ meta ], path ]
main:
- ch_versions = Channel.empty()
- ch_multiqc_files = Channel.empty()
- ch_raw_profiles = Channel.empty() // These are count tables
+ // These are count tables
+ ch_raw_profiles = channel.empty()
/*
COMBINE READS WITH POSSIBLE DATABASES
@@ -178,109 +174,109 @@ workflow PROFILING {
ch_input_for_humann_v4 = prepareInputs(reads_concat, databases, 'humann_v4', true)
ch_input_for_mifaser = prepareInputs(reads_concat, databases, 'mifaser', true)
- if ( params.run_fmhfunprofiler ) {
- // this tool needs the db_params at runtime, so it takes a [[meta], path] tuple instead of just a path
- getDbPath(ch_input_for_fmhfunprofiler.db, "main", true)
- .multiMap { db_meta, db_path ->
- def args = db_meta.db_params.split(" ")
-
- if (args.size() != 2) {
- throw new IllegalArgumentException("fmh-funcprofiler's db_params must be configured with 2 ints (kmer and sketch db args) , but got ${args.size()}: ${db_meta.db_params}")
- }
- db_path: db_path
- kmer: args[0]
- sketch: args[1]
- }
- .set {fmh_db}
- FMHFUNPROFILER (
+ if (params.run_fmhfunprofiler) {
+ // this tool needs the db_params at runtime, so it takes a [[meta], path] tuple instead of just a path
+ getDbPath(ch_input_for_fmhfunprofiler.db, "main", true)
+ .multiMap { db_meta, db_path ->
+ def args = db_meta.db_params.split(" ")
+
+ if (args.size() != 2) {
+ throw new IllegalArgumentException("fmh-funcprofiler's db_params must be configured with 2 ints (kmer and sketch db args) , but got ${args.size()}: ${db_meta.db_params}")
+ }
+ db_path: db_path
+ kmer: args[0]
+ sketch: args[1]
+ }
+ .set { fmh_db }
+ FMHFUNPROFILER(
ch_input_for_fmhfunprofiler.reads,
fmh_db.db_path,
fmh_db.kmer,
- fmh_db.sketch
-
- )
- ch_raw_profiles = ch_raw_profiles.mix( FMHFUNPROFILER.out.csv )
+ fmh_db.sketch,
+ )
+ ch_raw_profiles = ch_raw_profiles.mix(FMHFUNPROFILER.out.csv)
}
- if ( params.run_mifaser ) {
- ch_input_for_mifaser = prepareInputs(reads_concat, databases, 'mifaser', true)
- MIFASER ( ch_input_for_mifaser.reads, getDbPath(ch_input_for_mifaser.db, 'main'))
- ch_raw_profiles = ch_raw_profiles.mix( MIFASER.out.ec_counts )
+ if (params.run_mifaser) {
+ ch_input_for_mifaser = prepareInputs(reads_concat, databases, 'mifaser', true)
+ MIFASER(ch_input_for_mifaser.reads, getDbPath(ch_input_for_mifaser.db, 'main'))
+ ch_raw_profiles = ch_raw_profiles.mix(MIFASER.out.ec_counts)
}
- if ( params.run_humann_v3 ) {
- MPAHUMANN3 (
- ch_input_for_humann_v3.reads,
- getDbPath(ch_input_for_humann_v3.db, 'humann_metaphlan'),false
- )
- // JOIN the original reads with the profile output
- ch_humann3_input = ch_input_for_humann_v3.reads
- .join(MPAHUMANN3.out.profile, by: 0) // Join on meta map
+ if (params.run_humann_v3) {
+ MPAHUMANN3(
+ ch_input_for_humann_v3.reads,
+ getDbPath(ch_input_for_humann_v3.db, 'humann_metaphlan'),
+ false,
+ )
+ // JOIN the original reads with the profile output
+ ch_humann3_input = ch_input_for_humann_v3.reads.join(MPAHUMANN3.out.profile, by: 0)
+ // Join on meta map
HUMANN3_HUMANN(
- ch_humann3_input.map { it -> [it[0], it[1]] }, // Extract reads
- ch_humann3_input.map { it -> [it[0], it[2]] }, // Extract profile
+ ch_humann3_input.map { it -> [it[0], it[1]] },
+ ch_humann3_input.map { it -> [it[0], it[2]] },
getDbPath(ch_input_for_humann_v3.db, 'humann_nucleotide'),
getDbPath(ch_input_for_humann_v3.db, 'humann_protein'),
getDbPath(ch_input_for_humann_v3.db, 'humann_utility'),
)
- HUMANN3_REGROUP(HUMANN3_HUMANN.out.genefamilies, "uniref90_level4ec", getDbPath(ch_input_for_humann_v3.db, 'humann_utility'))
- ch_raw_profiles = ch_raw_profiles.mix( MPAHUMANN3.out.profile )
- ch_raw_profiles = ch_raw_profiles.mix( HUMANN3_HUMANN.out.pathabundance )
- .mix( HUMANN3_HUMANN.out.genefamilies )
- .mix( HUMANN3_HUMANN.out.pathcoverage )
+ HUMANN3_REGROUP(HUMANN3_HUMANN.out.genefamilies, "uniref90_level4ec", getDbPath(ch_input_for_humann_v3.db, 'humann_utility'))
+ ch_raw_profiles = ch_raw_profiles.mix(MPAHUMANN3.out.profile)
+ ch_raw_profiles = ch_raw_profiles
+ .mix(HUMANN3_HUMANN.out.pathabundance)
+ .mix(HUMANN3_HUMANN.out.genefamilies)
+ .mix(HUMANN3_HUMANN.out.pathcoverage)
}
- if ( params.run_humann_v4 ) {
- MPAHUMANN4 (
- ch_input_for_humann_v4.reads,
- getDbPath(ch_input_for_humann_v4.db, 'humann_metaphlan'),false
- )
- ch_humann4_input = ch_input_for_humann_v4.reads
- .join(MPAHUMANN4.out.profile, by: 0) // Join on meta map
+ if (params.run_humann_v4) {
+ MPAHUMANN4(
+ ch_input_for_humann_v4.reads,
+ getDbPath(ch_input_for_humann_v4.db, 'humann_metaphlan'),
+ false,
+ )
+ ch_humann4_input = ch_input_for_humann_v4.reads.join(MPAHUMANN4.out.profile, by: 0)
+ // Join on meta map
HUMANN4(
- ch_humann4_input.map { it -> [it[0], it[1]] }, // Extract reads
- ch_humann4_input.map { it -> [it[0], it[2]] }, // Extract profile
+ ch_humann4_input.map { it -> [it[0], it[1]] },
+ ch_humann4_input.map { it -> [it[0], it[2]] },
getDbPath(ch_input_for_humann_v4.db, 'humann_nucleotide'),
getDbPath(ch_input_for_humann_v4.db, 'humann_protein'),
getDbPath(ch_input_for_humann_v4.db, 'humann_utility'),
)
- HUMANN4_REGROUP(HUMANN4.out.genefamilies, "uniclust90_level4ec", getDbPath(ch_input_for_humann_v4.db, 'humann_utility'))
- ch_raw_profiles = ch_raw_profiles.mix( HUMANN4.out.pathabundance )
- .mix( HUMANN4.out.genefamilies )
- .mix( HUMANN4.out.reactions )
+ HUMANN4_REGROUP(HUMANN4.out.genefamilies, "uniclust90_level4ec", getDbPath(ch_input_for_humann_v4.db, 'humann_utility'))
+ ch_raw_profiles = ch_raw_profiles
+ .mix(HUMANN4.out.pathabundance)
+ .mix(HUMANN4.out.genefamilies)
+ .mix(HUMANN4.out.reactions)
}
- if ( params.run_diamond ) {
- DIAMOND_BLASTX ( ch_input_for_diamond.reads, getDbPath(ch_input_for_diamond.db, "main"), 'tsv', '' )
- ch_raw_profiles = ch_raw_profiles.mix( DIAMOND_BLASTX.out.tsv )
+ if (params.run_diamond) {
+ DIAMOND_BLASTX(ch_input_for_diamond.reads, getDbPath(ch_input_for_diamond.db, "main"), 'tsv', '')
+ ch_raw_profiles = ch_raw_profiles.mix(DIAMOND_BLASTX.out.tsv)
}
- if ( params.run_rgi ) {
+ if (params.run_rgi) {
RGI_CARDANNOTATION(getDbPath(ch_input_for_rgi.db, "main"))
- RGI_BWT( ch_input_for_rgi.reads, RGI_CARDANNOTATION.out.db, [] )
- ch_raw_profiles = ch_raw_profiles.mix( RGI_BWT.out.tsv )
+ RGI_BWT(ch_input_for_rgi.reads, RGI_CARDANNOTATION.out.db, [])
+ ch_raw_profiles = ch_raw_profiles.mix(RGI_BWT.out.tsv)
}
- if ( params.run_eggnogmapper ) {
- SEQKIT_FQ2FA(ch_input_for_eggnogmapper.reads)
- GUNZIP(SEQKIT_FQ2FA.out.fasta)
- EGGNOGMAPPER (
+ if (params.run_eggnogmapper) {
+ SEQKIT_FQ2FA(ch_input_for_eggnogmapper.reads)
+ GUNZIP(SEQKIT_FQ2FA.out.fasta)
+ EGGNOGMAPPER(
GUNZIP.out.gunzip,
- getDbPath(ch_input_for_eggnogmapper.db, "eggnogmapper_db"),
- getDbPath(ch_input_for_eggnogmapper.db, "")
+ getDbPath(ch_input_for_eggnogmapper.db, "eggnogmapper_db"),
+ getDbPath(ch_input_for_eggnogmapper.db, ""),
)
- ch_raw_profiles = ch_raw_profiles.mix( EGGNOGMAPPER.out.annotations )
-
+ ch_raw_profiles = ch_raw_profiles.mix(EGGNOGMAPPER.out.annotations)
}
-
emit:
- profiles = ch_raw_profiles // channel: [ val(meta), [ reads ] ] - should be text files or biom
- versions = ch_versions // channel: [ versions.yml ]
- mqc = ch_multiqc_files
+ profiles = ch_raw_profiles // channel: [ val(meta), path(profile) ]
+ // Software versions are published to the `versions` topic by each module
}
+// due to https://github.com/askimed/nf-test/issues/309
workflow TEST_PREPAREINPUTS_WRAPPER {
- // due to https://github.com/askimed/nf-test/issues/309)
take:
reads
databases
@@ -289,7 +285,8 @@ workflow TEST_PREPAREINPUTS_WRAPPER {
main:
testresult = prepareInputs(reads, databases, tool_name, singleFqTool)
+
emit:
reads = testresult.reads
- db = testresult.db
+ db = testresult.db
}
diff --git a/subworkflows/local/profile/meta.yml b/subworkflows/local/profile/meta.yml
index 78bc923..d69de4d 100644
--- a/subworkflows/local/profile/meta.yml
+++ b/subworkflows/local/profile/meta.yml
@@ -1,57 +1,60 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json
name: "profile"
-##
-description: Execute functional profiling tools
+description: |
+ Run the enabled read-based functional profilers. Reads are combined with every
+ database matching the tool, so a sample is profiled once per database name and
+ parameter combination. Tools that take paired input read from `reads`, tools
+ that take a single FASTQ read from `reads_concat`, and each profiler runs only
+ when its `run_` parameter is set.
keywords:
- microbiome
- metagenome
- fastq
- - function
+ - functional profiling
components:
- - humann/humann
- fmhfunprofiler
- mifaser
+ - humann3/humann
+ - humann3/regroup
+ - humann4
+ - humann4/regroup
+ - metaphlan/metaphlan
+ - diamond/blastx
- rgi/bwt
-
-## TODO nf-core: List all of the channels used as input with a description and their structure
+ - rgi/cardannotation
+ - eggnogmapper
+ - seqkit/fq2fa
+ - gunzip
input:
- reads:
type: file
description: |
- The input channel containing paired fastq files
- Structure: [ val(meta), path(fastq) ]
- pattern: "*.{.fastq}*"
+ Channel of paired-end (or single-end) reads, used by the profilers that
+ accept a read pair.
+ Structure: [ val(meta), [ path(reads) ] ]
+ pattern: "*.{fq,fastq}{,.gz}"
- reads_concat:
type: file
description: |
- The input channel containing concatenated fastq pairs as a single fastq
- Structure: [ val(meta), path(fastq) ]
- pattern: "*.{.fastq}*"
+ Channel of reads concatenated into a single file per sample, used by the
+ profilers that accept only one FASTQ.
+ Structure: [ val(meta), [ path(reads) ] ]
+ pattern: "*.{fq,fastq}{,.gz}"
- databases:
type: file
description: |
- The input channel containing the database files
- Structure: [ val(meta), path(file) ]
-## TODO nf-core: List all of the channels used as output with a descriptions and their structure
+ Channel of grouped databases as emitted by the `dbprep` subworkflow.
+ Structure: [ val(meta), [ [ db_entity: val(entity), db_path: path(db) ] ] ]
output:
- profiles:
type: file
description: |
- Channel containing tabular profiling results
- Structure: [ val(meta), path(paths) ]
- pattern: "*.bam"
- - versions:
- type: file
- description: |
- File containing software versions
- Structure: [ path(versions.yml) ]
- pattern: "versions.yml"
- - mqc:
- type: file
- description: |
- File containing MultiQC files
- Structure: [ path(file) ]
- pattern: "*"
+ Channel of the tabular profiles produced by each enabled tool. The meta
+ map identifies the sample, the tool and the database used.
+ Structure: [ val(meta), path(profile) ]
+ pattern: "*.{tsv,csv,txt}"
+# Software versions are published to the `versions` topic by each module rather
+# than emitted as a channel.
authors:
- "@nickp60"
maintainers:
diff --git a/subworkflows/local/profile/tests/main.nf.test.snap b/subworkflows/local/profile/tests/main.nf.test.snap
index d34209d..071f27e 100644
--- a/subworkflows/local/profile/tests/main.nf.test.snap
+++ b/subworkflows/local/profile/tests/main.nf.test.snap
@@ -48,26 +48,26 @@
"content": [
[
"minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129",
- "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,16b7196a90c1d2fd3e3109c8d252cd08"
+ "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,1081039ab9e9b378d2dfd3206e96e917"
]
],
- "timestamp": "2026-07-23T16:38:21.384784",
+ "timestamp": "2026-07-29T16:20:47.621463",
"meta": {
"nf-test": "0.9.5",
- "nextflow": "26.04.4"
+ "nextflow": "26.04.6"
}
},
"run multisampleinputs - grouped databases (humann_v3)": {
"content": [
[
"minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129",
- "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,16b7196a90c1d2fd3e3109c8d252cd08"
+ "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,1081039ab9e9b378d2dfd3206e96e917"
]
],
- "timestamp": "2026-07-24T09:47:36.521206",
+ "timestamp": "2026-07-29T16:20:29.367839",
"meta": {
"nf-test": "0.9.5",
- "nextflow": "26.04.4"
+ "nextflow": "26.04.6"
}
}
}
\ No newline at end of file
diff --git a/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf b/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf
index 9d65ed8..a261053 100644
--- a/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf
+++ b/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf
@@ -99,13 +99,15 @@ workflow PIPELINE_INITIALISATION {
// Create channel from input file provided through params.input
//
- Channel.fromList(samplesheetToList(params.input, "assets/schema_input.json"))
+ Channel
+ .fromList(samplesheetToList(params.input, "assets/schema_input.json"))
.set { ch_samplesheet }
//
// Create channel from databases file provided through params.databases
//
- Channel.fromList(samplesheetToList(params.databases, "assets/schema_database.json"))
+ Channel
+ .fromList(samplesheetToList(params.databases, "assets/schema_database.json"))
.set { ch_databases }
emit:
@@ -182,9 +184,7 @@ def validateInputSamplesheet(input) {
//
def toolCitationText() {
- def text_qc = [
- "Sequencing quality control was performed with FastQC (Andrews 2010)."
- ].join(' ').trim()
+ def text_qc = ["Sequencing quality control was performed with FastQC (Andrews 2010)."].join(' ').trim()
def text_humann = [
"Functional profiling was performed with",
@@ -196,25 +196,15 @@ def toolCitationText() {
"using MetaPhlAn (Blanco-Míguez et al. 2023) for taxonomic marker-based profiling.",
].join(' ').trim()
- def text_diamond = [
- "Protein-level sequence alignment was performed with DIAMOND (Buchfink et al. 2021)."
- ].join(' ').trim()
+ def text_diamond = ["Protein-level sequence alignment was performed with DIAMOND (Buchfink et al. 2021)."].join(' ').trim()
- def text_fmhfunprofiler = [
- "Functional profiling was additionally performed with fmhfunprofiler (Hera et al. 2024)."
- ].join(' ').trim()
+ def text_fmhfunprofiler = ["Functional profiling was additionally performed with fmhfunprofiler (Hera et al. 2024)."].join(' ').trim()
- def text_mifaser = [
- "Enzyme function annotation was performed with mi-faser (Zhu et al. 2017)."
- ].join(' ').trim()
+ def text_mifaser = ["Enzyme function annotation was performed with mi-faser (Zhu et al. 2017)."].join(' ').trim()
- def text_eggnogmapper = [
- "Functional Annotation, Orthology Assignments, and Domain Prediction was performed with eggNOG-mapper v2 (Cantalapiedra et. al 2021)"
- ].join(' ').trim()
+ def text_eggnogmapper = ["Functional Annotation, Orthology Assignments, and Domain Prediction was performed with eggNOG-mapper v2 (Cantalapiedra et. al 2021)"].join(' ').trim()
- def text_rgi = [
- "Resistome prediction was performed using RGI (Alcock et. al 2023)"
- ].join(' ').trim()
+ def text_rgi = ["Resistome prediction was performed using RGI (Alcock et. al 2023)"].join(' ').trim()
def citation_text = [
"Tools used in the workflow included:",
@@ -233,22 +223,16 @@ def toolCitationText() {
def toolBibliographyText() {
- def text_qc = [
- !params.skip_preprocessing_qc ? "Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available at: http://www.bioinformatics.babraham.ac.uk/projects/fastqc/" : ""
- ].join(' ').trim()
+ def text_qc = [!params.skip_preprocessing_qc ? "Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available at: http://www.bioinformatics.babraham.ac.uk/projects/fastqc/" : ""].join(' ').trim()
def text_humann = [
params.run_humann_v3 || params.run_humann_v4 ? "Beghini, F., McIver, L. J., Blanco-M\u00edguez, A., Dubois, L., Asnicar, F., Maharjan, S., Mailyan, A., Thomas, A. M., Manghi, P., Valles-Colomer, M., Weingart, G., Zhang, Y., Zolfo, M., Huttenhower, C., Franzosa, E. A., & Segata, N. (2021). Integrating taxonomic, functional, and strain-level profiling of diverse microbial communities with bioBakery 3. eLife, 10, e65088. 10.7554/eLife.65088" : "",
params.run_humann_v3 || params.run_humann_v4 ? "Blanco-M\u00edguez, A., Beghini, F., Cumbo, F., McIver, L. J., Thompson, K. N., Zolfo, M., Manghi, P., Dubois, L., Huang, K. D., Thomas, A. M., Nickols, W. A., Piccinno, G., Piperni, E., Pun\u010doch\u00e1\u0159, M., Valles-Colomer, M., Tett, A., Giordano, F., Davies, R., Wolf, J., \u2026 Segata, N. (2023). Extending and improving metagenomic taxonomic profiling with uncharacterized species using MetaPhlAn 4. Nature Biotechnology, 41, 1633\u20131645. 10.1038/s41587-023-01688-w" : "",
].join(' ').trim()
- def text_diamond = [
- params.run_diamond ? "Buchfink, B., Reuter, K., & Drost, H.-G. (2021). Sensitive protein alignments at tree-of-life scale using DIAMOND. Nature Methods, 18(4), 366–368. 10.1038/s41592-021-01101-x" : ""
- ].join(' ').trim()
+ def text_diamond = [params.run_diamond ? "Buchfink, B., Reuter, K., & Drost, H.-G. (2021). Sensitive protein alignments at tree-of-life scale using DIAMOND. Nature Methods, 18(4), 366–368. 10.1038/s41592-021-01101-x" : ""].join(' ').trim()
- def text_fmhfunprofiler = [
- params.run_fmhfunprofiler ? "Hera, M. R., Liu, S., Wei, W., Rodriguez, J. S., Ma, C., & Koslicki, D. (2024). Metagenomic functional profiling: to sketch or not to sketch? Bioinformatics, 40(Suppl 2), ii165–ii173. 10.1093/bioinformatics/btae397" : ""
- ].join(' ').trim()
+ def text_fmhfunprofiler = [params.run_fmhfunprofiler ? "Hera, M. R., Liu, S., Wei, W., Rodriguez, J. S., Ma, C., & Koslicki, D. (2024). Metagenomic functional profiling: to sketch or not to sketch? Bioinformatics, 40(Suppl 2), ii165–ii173. 10.1093/bioinformatics/btae397" : ""].join(' ').trim()
def text_mifaser = [
params.run_mifaser ? "Zhu, C., Miller, M., Marpaka, S., Vaysberg, P., R\u00fchlemann, M. C., Wu, G., Heinsen, F.-A., Tempel, M., Woodhouse, L., Burkhardt, L., Tams, R., Knecht, C., Heinig, M., Franke, A., Huser, T., & Bromberg, Y. (2017). Functional sequencing read annotation for high precision microbiome analysis. Nucleic Acids Research, 46(4), e23. 10.1093/nar/gkx1209" : "",
@@ -256,13 +240,9 @@ def toolBibliographyText() {
params.run_mifaser ? "Zhu, C., Delmont, T. O., Vogel, T. M., & Bromberg, Y. (2015). Functional basis of microorganism classification. PLoS Computational Biology, 11(8), e1004472. 10.1371/journal.pcbi.1004472" : "",
].join(' ').trim()
- def text_eggnggmapper = [
- params.run_eggnogmapper ? "Carlos P Cantalapiedra, Ana Hernández-Plaza, Ivica Letunic, Peer Bork, Jaime Huerta-Cepas, eggNOG-mapper v2: Functional Annotation, Orthology Assignments, and Domain Prediction at the Metagenomic Scale, Molecular Biology and Evolution, Volume 38, Issue 12, December 2021, 0.1093/molbev/msab293" : ""
- ].join(' ').trim()
+ def text_eggnggmapper = [params.run_eggnogmapper ? "Carlos P Cantalapiedra, Ana Hernández-Plaza, Ivica Letunic, Peer Bork, Jaime Huerta-Cepas, eggNOG-mapper v2: Functional Annotation, Orthology Assignments, and Domain Prediction at the Metagenomic Scale, Molecular Biology and Evolution, Volume 38, Issue 12, December 2021, 0.1093/molbev/msab293" : ""].join(' ').trim()
- def text_rgi = [
- params.run_rgi ? "Alcock et al. 2023. CARD 2023: expanded curation, support for machine learning, and resistome prediction at the Comprehensive Antibiotic Resistance Database. Nucleic Acids Researchpubmed.ncbi.nlm.nih.gov/36263822" : ""
- ].join(' ').trim()
+ def text_rgi = [params.run_rgi ? "Alcock et al. 2023. CARD 2023: expanded curation, support for machine learning, and resistome prediction at the Comprehensive Antibiotic Resistance Database. Nucleic Acids Researchpubmed.ncbi.nlm.nih.gov/36263822" : ""].join(' ').trim()
def reference_text = [
text_qc,
diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf
index 0d9d4e0..9ff0681 100644
--- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf
+++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf
@@ -35,7 +35,7 @@ workflow UTILS_NFSCHEMA_PLUGIN {
fullHelp: help_full,
]
if(parameters_schema) {
- help_options << [parametersSchema: parameters_schema]
+ help_options << [parameters_schema: parameters_schema]
}
log.info paramsHelp(
help_options,
@@ -51,7 +51,7 @@ workflow UTILS_NFSCHEMA_PLUGIN {
summary_options = [:]
if(parameters_schema) {
- summary_options << [parametersSchema: parameters_schema]
+ summary_options << [parameters_schema: parameters_schema]
}
log.info before_text
log.info paramsSummaryLog(summary_options, input_workflow)
@@ -64,10 +64,10 @@ workflow UTILS_NFSCHEMA_PLUGIN {
if(validate_params) {
validateOptions = [:]
if(parameters_schema) {
- validateOptions << [parametersSchema: parameters_schema]
+ validateOptions << [parameters_schema: parameters_schema]
}
if(cli_typecast != null) {
- validateOptions << [cliTypecast: cli_typecast]
+ validateOptions << [cast_cli_params: cli_typecast]
}
validateParameters(validateOptions)
}
diff --git a/tests/nextflow.config b/tests/nextflow.config
index 3dc70e4..25639c6 100644
--- a/tests/nextflow.config
+++ b/tests/nextflow.config
@@ -4,8 +4,6 @@
========================================================================================
*/
-// TODO nf-core: Specify any additional parameters here
-// Or any resources requirements
params {
modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/'
pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/'
diff --git a/workflows/funcprofiler.nf b/workflows/funcprofiler.nf
index cebaf4b..a68d6f6 100644
--- a/workflows/funcprofiler.nf
+++ b/workflows/funcprofiler.nf
@@ -3,9 +3,9 @@
IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-include { MULTIQC } from '../modules/nf-core/multiqc/main'
-include { paramsSummaryMap } from 'plugin/nf-schema'
-include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline'
+include { MULTIQC } from '../modules/nf-core/multiqc/main'
+include { paramsSummaryMap } from 'plugin/nf-schema'
+include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline'
include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline'
include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_funcprofiler_pipeline'
@@ -35,16 +35,15 @@ include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_func
//
// MODULE: Installed directly from nf-core/modules
//
-include { UNTAR } from '../modules/nf-core/untar/main'
-include { PROFILING } from '../subworkflows/local/profile/main'
-include { DATAPREP } from '../subworkflows/local/dataprep/main'
-include { DBPREP } from '../subworkflows/local/dbprep/main'
+include { UNTAR } from '../modules/nf-core/untar/main'
+include { PROFILING } from '../subworkflows/local/profile/main'
+include { DATAPREP } from '../subworkflows/local/dataprep/main'
+include { DBPREP } from '../subworkflows/local/dbprep/main'
workflow FUNCPROFILER {
-
take:
samplesheet // channel: samplesheet read in from --input
databases // channel: databases from --databases
@@ -58,25 +57,47 @@ workflow FUNCPROFILER {
ch_versions = Channel.empty()
ch_multiqc_files = Channel.empty()
- DATAPREP (
- samplesheet
+ DATAPREP(
+ samplesheet
)
- DBPREP (
- databases
+ DBPREP(
+ databases
)
- PROFILING (
- DATAPREP.out.reads,
- DATAPREP.out.reads_concat,
- DBPREP.out.dbs
+ PROFILING(
+ DATAPREP.out.reads,
+ DATAPREP.out.reads_concat,
+ DBPREP.out.dbs,
)
- def ch_collated_versions = softwareVersionsToYAML(ch_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')}"
+ }
+
+ def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file))
+ .mix(topic_versions_string)
.collectFile(
storeDir: "${outdir}/pipeline_info",
- name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml',
+ name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml',
sort: true,
- newLine: true
+ newLine: true,
)
//
@@ -108,11 +129,5 @@ workflow FUNCPROFILER {
emit:
multiqc_report = MULTIQC.out.report.map { _meta, report -> [report] }.toList() // channel: /path/to/multiqc_report.html
- versions = ch_versions // channel: [ path(versions.yml) ]
+ versions = ch_versions // channel: [ path(versions.yml) ]
}
-
-/*
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- THE END
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-*/