Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
"
- ].join(' ').trim()
-
- return reference_text
- }
-
- public static String methodsDescriptionText(run_workflow, mqc_methods_yaml, params) {
- // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file
- def meta = [:]
- meta.workflow = run_workflow.toMap()
- meta["manifest_map"] = run_workflow.manifest.toMap()
-
- // Pipeline DOI
- meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : ""
- meta["nodoi_text"] = meta.manifest_map.doi ? "": "
If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
"
-
- // Tool references
- meta["tool_citations"] = ""
- meta["tool_bibliography"] = ""
-
- // TODO Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled!
- //meta["tool_citations"] = toolCitationText(params).replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".")
- //meta["tool_bibliography"] = toolBibliographyText(params)
-
-
- def methods_text = mqc_methods_yaml.text
-
- def engine = new SimpleTemplateEngine()
- def description_html = engine.createTemplate(methods_text).make(meta)
-
- return description_html
- }
-
- //
- // Exit pipeline if incorrect --genome key provided
- //
- private static void genomeExistsError(params, log) {
- if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) {
- def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
- " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" +
- " Currently, the available genome keys are:\n" +
- " ${params.genomes.keySet().join(", ")}\n" +
- "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
- Nextflow.error(error_string)
- }
- }
-}
diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy
deleted file mode 100755
index 3a7b45c..0000000
--- a/lib/WorkflowMain.groovy
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// This file holds several functions specific to the main.nf workflow in the nf-core/createpanelrefs pipeline
-//
-
-import nextflow.Nextflow
-
-class WorkflowMain {
-
- //
- // Citation string for pipeline
- //
- public static String citation(workflow) {
- return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" +
- // TODO nf-core: Add Zenodo DOI for pipeline after first release
- //"* The pipeline\n" +
- //" https://doi.org/10.5281/zenodo.XXXXXXX\n\n" +
- "* The nf-core framework\n" +
- " https://doi.org/10.1038/s41587-020-0439-x\n\n" +
- "* Software dependencies\n" +
- " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md"
- }
-
-
- //
- // Validate parameters and print summary to screen
- //
- public static void initialise(workflow, params, log) {
-
- // Print workflow version and exit on --version
- if (params.version) {
- String workflow_version = NfcoreTemplate.version(workflow)
- log.info "${workflow.manifest.name} ${workflow_version}"
- System.exit(0)
- }
-
- // Check that a -profile or Nextflow config has been provided to run the pipeline
- NfcoreTemplate.checkConfigProvided(workflow, log)
-
- // Check that conda channels are set-up correctly
- if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) {
- Utils.checkCondaChannels(log)
- }
-
- // Check AWS batch settings
- NfcoreTemplate.awsBatch(workflow, params)
-
- // Check input has been provided
- if (!params.input) {
- Nextflow.error("Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'")
- }
- }
- //
- // Get attribute from genome config file e.g. fasta
- //
- public static Object getGenomeAttribute(params, attribute) {
- if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) {
- if (params.genomes[ params.genome ].containsKey(attribute)) {
- return params.genomes[ params.genome ][ attribute ]
- }
- }
- return null
- }
-}
diff --git a/lib/nfcore_external_java_deps.jar b/lib/nfcore_external_java_deps.jar
deleted file mode 100644
index 805c8bb..0000000
Binary files a/lib/nfcore_external_java_deps.jar and /dev/null differ
diff --git a/main.nf b/main.nf
index 5ed2a9c..71b8149 100644
--- a/main.nf
+++ b/main.nf
@@ -13,67 +13,100 @@ nextflow.enable.dsl = 2
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- GENOME PARAMETER VALUES
+ IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS / WORKFLOWS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-params.fasta = WorkflowMain.getGenomeAttribute(params, 'fasta')
-params.fai = WorkflowMain.getGenomeAttribute(params, 'fai')
-params.dict = WorkflowMain.getGenomeAttribute(params, 'dict')
-params.target_bed = WorkflowMain.getGenomeAttribute(params, 'target_bed')
-params.target_interval_list = WorkflowMain.getGenomeAttribute(params, 'target_interval_list')
-params.exclude_bed = WorkflowMain.getGenomeAttribute(params, 'exclude_bed')
-params.exclude_interval_list = WorkflowMain.getGenomeAttribute(params, 'exclude_interval_list')
+include { CREATEPANELREFS } from './workflows/createpanelrefs'
+include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_createpanelrefs_pipeline'
+include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_createpanelrefs_pipeline'
+
+include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_createpanelrefs_pipeline'
+
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- VALIDATE & PRINT PARAMETER SUMMARY
+ GENOME PARAMETER VALUES
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-include { validateParameters; paramsHelp } from 'plugin/nf-validation'
-
-// Print help message if needed
-if (params.help) {
- def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs)
- def citation = '\n' + WorkflowMain.citation(workflow) + '\n'
- def String command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker"
- log.info logo + paramsHelp(command) + citation + NfcoreTemplate.dashedLine(params.monochrome_logs)
- System.exit(0)
-}
-
-// Validate input parameters
-if (params.validate_params) {
- validateParameters()
-}
-
-WorkflowMain.initialise(workflow, params, log)
+// This is an example of how to use getGenomeAttribute() to fetch parameters
+// from igenomes.config using `--genome`
+params.fasta = getGenomeAttribute('fasta')
+params.fai = getGenomeAttribute('fai')
+params.dict = getGenomeAttribute('dict')
+params.target_bed = getGenomeAttribute('target_bed')
+params.target_interval_list = getGenomeAttribute('target_interval_list')
+params.exclude_bed = getGenomeAttribute('exclude_bed')
+params.exclude_interval_list = getGenomeAttribute('exclude_interval_list')
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- NAMED WORKFLOW FOR PIPELINE
+ NAMED WORKFLOWS FOR PIPELINE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-include { CREATEPANELREFS } from './workflows/createpanelrefs'
-
//
-// WORKFLOW: Run main nf-core/createpanelrefs analysis pipeline
+// WORKFLOW: Run main analysis pipeline depending on type of input
//
workflow NFCORE_CREATEPANELREFS {
- CREATEPANELREFS ()
-}
+ take:
+ samplesheet // channel: samplesheet read in from --input
+
+ main:
+
+ //
+ // WORKFLOW: Run pipeline
+ //
+ CREATEPANELREFS (
+ samplesheet
+ )
+
+ emit:
+ multiqc_report = CREATEPANELREFS.out.multiqc_report // channel: /path/to/multiqc_report.html
+
+}
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- RUN ALL WORKFLOWS
+ RUN MAIN WORKFLOW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-//
-// WORKFLOW: Execute a single named workflow for the pipeline
-// See: https://github.com/nf-core/rnaseq/issues/619
-//
workflow {
- NFCORE_CREATEPANELREFS ()
+
+ main:
+
+ //
+ // SUBWORKFLOW: Run initialisation tasks
+ //
+ PIPELINE_INITIALISATION (
+ params.version,
+ params.help,
+ params.validate_params,
+ params.monochrome_logs,
+ args,
+ params.outdir,
+ params.input
+ )
+
+ //
+ // WORKFLOW: Run main workflow
+ //
+ NFCORE_CREATEPANELREFS (
+ PIPELINE_INITIALISATION.out.samplesheet
+ )
+
+ //
+ // SUBWORKFLOW: Run completion tasks
+ //
+ PIPELINE_COMPLETION (
+ params.email,
+ params.email_on_fail,
+ params.plaintext_email,
+ params.outdir,
+ params.monochrome_logs,
+ params.hook_url,
+ NFCORE_CREATEPANELREFS.out.multiqc_report
+ )
}
/*
diff --git a/modules.json b/modules.json
index bb06eb2..0479098 100644
--- a/modules.json
+++ b/modules.json
@@ -10,11 +10,6 @@
"git_sha": "a64788f5ad388f1d2ac5bd5f1f3f8fc81476148c",
"installed_by": ["modules"]
},
- "custom/dumpsoftwareversions": {
- "branch": "master",
- "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93",
- "installed_by": ["modules"]
- },
"gatk4/annotateintervals": {
"branch": "master",
"git_sha": "42ae163c3c6eb23646189c30c07a889ad39c9b0e",
@@ -57,7 +52,7 @@
},
"multiqc": {
"branch": "master",
- "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93",
+ "git_sha": "ccacf6f5de6df3bc6d73b665c1fd2933d8bbc290",
"installed_by": ["modules"]
},
"picard/createsequencedictionary": {
@@ -76,6 +71,25 @@
"installed_by": ["modules"]
}
}
+ },
+ "subworkflows": {
+ "nf-core": {
+ "utils_nextflow_pipeline": {
+ "branch": "master",
+ "git_sha": "cd08c91373cd00a73255081340e4914485846ba1",
+ "installed_by": ["subworkflows"]
+ },
+ "utils_nfcore_pipeline": {
+ "branch": "master",
+ "git_sha": "262b17ed2aad591039f914951659177e6c39a8d8",
+ "installed_by": ["subworkflows"]
+ },
+ "utils_nfvalidation_plugin": {
+ "branch": "master",
+ "git_sha": "cd08c91373cd00a73255081340e4914485846ba1",
+ "installed_by": ["subworkflows"]
+ }
+ }
}
}
}
diff --git a/modules/nf-core/custom/dumpsoftwareversions/environment.yml b/modules/nf-core/custom/dumpsoftwareversions/environment.yml
deleted file mode 100644
index 9b3272b..0000000
--- a/modules/nf-core/custom/dumpsoftwareversions/environment.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-name: custom_dumpsoftwareversions
-channels:
- - conda-forge
- - bioconda
- - defaults
-dependencies:
- - bioconda::multiqc=1.19
diff --git a/modules/nf-core/custom/dumpsoftwareversions/main.nf b/modules/nf-core/custom/dumpsoftwareversions/main.nf
deleted file mode 100644
index f218761..0000000
--- a/modules/nf-core/custom/dumpsoftwareversions/main.nf
+++ /dev/null
@@ -1,24 +0,0 @@
-process CUSTOM_DUMPSOFTWAREVERSIONS {
- label 'process_single'
-
- // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container
- conda "${moduleDir}/environment.yml"
- container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ?
- 'https://depot.galaxyproject.org/singularity/multiqc:1.19--pyhdfd78af_0' :
- 'biocontainers/multiqc:1.19--pyhdfd78af_0' }"
-
- input:
- path versions
-
- output:
- path "software_versions.yml" , emit: yml
- path "software_versions_mqc.yml", emit: mqc_yml
- path "versions.yml" , emit: versions
-
- when:
- task.ext.when == null || task.ext.when
-
- script:
- def args = task.ext.args ?: ''
- template 'dumpsoftwareversions.py'
-}
diff --git a/modules/nf-core/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/custom/dumpsoftwareversions/meta.yml
deleted file mode 100644
index 5f15a5f..0000000
--- a/modules/nf-core/custom/dumpsoftwareversions/meta.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json
-name: custom_dumpsoftwareversions
-description: Custom module used to dump software versions within the nf-core pipeline template
-keywords:
- - custom
- - dump
- - version
-tools:
- - custom:
- description: Custom module used to dump software versions within the nf-core pipeline template
- homepage: https://github.com/nf-core/tools
- documentation: https://github.com/nf-core/tools
- licence: ["MIT"]
-input:
- - versions:
- type: file
- description: YML file containing software versions
- pattern: "*.yml"
-output:
- - yml:
- type: file
- description: Standard YML file containing software versions
- pattern: "software_versions.yml"
- - mqc_yml:
- type: file
- description: MultiQC custom content YML file containing software versions
- pattern: "software_versions_mqc.yml"
- - versions:
- type: file
- description: File containing software versions
- pattern: "versions.yml"
-authors:
- - "@drpatelh"
- - "@grst"
-maintainers:
- - "@drpatelh"
- - "@grst"
diff --git a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py
deleted file mode 100755
index da03340..0000000
--- a/modules/nf-core/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env python
-
-
-"""Provide functions to merge multiple versions.yml files."""
-
-
-import yaml
-import platform
-from textwrap import dedent
-
-
-def _make_versions_html(versions):
- """Generate a tabular HTML output of all versions for MultiQC."""
- html = [
- dedent(
- """\\
-
-
-
-
-
Process Name
-
Software
-
Version
-
-
- """
- )
- ]
- for process, tmp_versions in sorted(versions.items()):
- html.append("")
- for i, (tool, version) in enumerate(sorted(tmp_versions.items())):
- html.append(
- dedent(
- f"""\\
-
-
{process if (i == 0) else ''}
-
{tool}
-
{version}
-
- """
- )
- )
- html.append("")
- html.append("
")
- return "\\n".join(html)
-
-
-def main():
- """Load all version files and generate merged output."""
- versions_this_module = {}
- versions_this_module["${task.process}"] = {
- "python": platform.python_version(),
- "yaml": yaml.__version__,
- }
-
- with open("$versions") as f:
- versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module
-
- # aggregate versions by the module name (derived from fully-qualified process name)
- versions_by_module = {}
- for process, process_versions in versions_by_process.items():
- module = process.split(":")[-1]
- try:
- if versions_by_module[module] != process_versions:
- raise AssertionError(
- "We assume that software versions are the same between all modules. "
- "If you see this error-message it means you discovered an edge-case "
- "and should open an issue in nf-core/tools. "
- )
- except KeyError:
- versions_by_module[module] = process_versions
-
- versions_by_module["Workflow"] = {
- "Nextflow": "$workflow.nextflow.version",
- "$workflow.manifest.name": "$workflow.manifest.version",
- }
-
- versions_mqc = {
- "id": "software_versions",
- "section_name": "${workflow.manifest.name} Software Versions",
- "section_href": "https://github.com/${workflow.manifest.name}",
- "plot_type": "html",
- "description": "are collected at run time from the software output.",
- "data": _make_versions_html(versions_by_module),
- }
-
- with open("software_versions.yml", "w") as f:
- yaml.dump(versions_by_module, f, default_flow_style=False)
- with open("software_versions_mqc.yml", "w") as f:
- yaml.dump(versions_mqc, f, default_flow_style=False)
-
- with open("versions.yml", "w") as f:
- yaml.dump(versions_this_module, f, default_flow_style=False)
-
-
-if __name__ == "__main__":
- main()
diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test
deleted file mode 100644
index b1e1630..0000000
--- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test
+++ /dev/null
@@ -1,43 +0,0 @@
-nextflow_process {
-
- name "Test Process CUSTOM_DUMPSOFTWAREVERSIONS"
- script "../main.nf"
- process "CUSTOM_DUMPSOFTWAREVERSIONS"
- tag "modules"
- tag "modules_nfcore"
- tag "custom"
- tag "dumpsoftwareversions"
- tag "custom/dumpsoftwareversions"
-
- test("Should run without failures") {
- when {
- process {
- """
- def tool1_version = '''
- TOOL1:
- tool1: 0.11.9
- '''.stripIndent()
-
- def tool2_version = '''
- TOOL2:
- tool2: 1.9
- '''.stripIndent()
-
- input[0] = Channel.of(tool1_version, tool2_version).collectFile()
- """
- }
- }
-
- then {
- assertAll(
- { assert process.success },
- { assert snapshot(
- process.out.versions,
- file(process.out.mqc_yml[0]).readLines()[0..10],
- file(process.out.yml[0]).readLines()[0..7]
- ).match()
- }
- )
- }
- }
-}
diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap b/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap
deleted file mode 100644
index 5f59a93..0000000
--- a/modules/nf-core/custom/dumpsoftwareversions/tests/main.nf.test.snap
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "Should run without failures": {
- "content": [
- [
- "versions.yml:md5,76d454d92244589d32455833f7c1ba6d"
- ],
- [
- "data: \"\\n
\\n \\n
\\n
Process Name
\\n
\\",
- " \\ Software
\\n
Version
\\n
\\n \\n\\",
- " \\n\\n
\\n
CUSTOM_DUMPSOFTWAREVERSIONS
\\n
python
\\n\\",
- " \\
3.11.7
\\n
\\n\\n
\\n
\\n \\",
- " \\
yaml
\\n
5.4.1
\\n
\\n\\n\\n\\",
- " \\n
\\n
TOOL1
\\n
tool1
\\n\\",
- " \\
0.11.9
\\n
\\n\\n\\n\\n
\\n
TOOL2
\\n\\",
- " \\
tool2
\\n
1.9
\\n
\\n\\n\\n\\",
- " \\n
\\n
Workflow
\\n
Nextflow
\\n\\"
- ],
- [
- "CUSTOM_DUMPSOFTWAREVERSIONS:",
- " python: 3.11.7",
- " yaml: 5.4.1",
- "TOOL1:",
- " tool1: 0.11.9",
- "TOOL2:",
- " tool2: '1.9'",
- "Workflow:"
- ]
- ],
- "timestamp": "2024-01-09T23:01:18.710682"
- }
-}
\ No newline at end of file
diff --git a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml b/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml
deleted file mode 100644
index 405aa24..0000000
--- a/modules/nf-core/custom/dumpsoftwareversions/tests/tags.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-custom/dumpsoftwareversions:
- - modules/nf-core/custom/dumpsoftwareversions/**
diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml
index 7625b75..2212096 100644
--- a/modules/nf-core/multiqc/environment.yml
+++ b/modules/nf-core/multiqc/environment.yml
@@ -4,4 +4,4 @@ channels:
- bioconda
- defaults
dependencies:
- - bioconda::multiqc=1.19
+ - bioconda::multiqc=1.20
diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf
index 1b9f7c4..354f443 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.19--pyhdfd78af_0' :
- 'biocontainers/multiqc:1.19--pyhdfd78af_0' }"
+ 'https://depot.galaxyproject.org/singularity/multiqc:1.20--pyhdfd78af_0' :
+ 'biocontainers/multiqc:1.20--pyhdfd78af_0' }"
input:
path multiqc_files, stageAs: "?/*"
diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test
index d0438ed..f1c4242 100644
--- a/modules/nf-core/multiqc/tests/main.nf.test
+++ b/modules/nf-core/multiqc/tests/main.nf.test
@@ -3,6 +3,7 @@ nextflow_process {
name "Test Process MULTIQC"
script "../main.nf"
process "MULTIQC"
+
tag "modules"
tag "modules_nfcore"
tag "multiqc"
@@ -12,7 +13,7 @@ nextflow_process {
when {
process {
"""
- input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)])
+ 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] = []
@@ -25,7 +26,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("versions") }
+ { assert snapshot(process.out.versions).match("multiqc_versions_single") }
)
}
@@ -36,7 +37,7 @@ nextflow_process {
when {
process {
"""
- input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)])
+ 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] = []
@@ -49,7 +50,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("versions") }
+ { assert snapshot(process.out.versions).match("multiqc_versions_config") }
)
}
}
@@ -61,7 +62,7 @@ nextflow_process {
when {
process {
"""
- input[0] = Channel.of([file(params.test_data['sarscov2']['illumina']['test_1_fastq_gz_fastqc_zip'], checkIfExists: true)])
+ 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] = []
@@ -75,7 +76,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() }
+ process.out.versions ).match("multiqc_stub") }
)
}
diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap
index d37e730..c204b48 100644
--- a/modules/nf-core/multiqc/tests/main.nf.test.snap
+++ b/modules/nf-core/multiqc/tests/main.nf.test.snap
@@ -1,21 +1,41 @@
{
- "versions": {
+ "multiqc_versions_single": {
"content": [
[
- "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d"
+ "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186"
]
],
- "timestamp": "2024-01-09T23:02:49.911994"
+ "meta": {
+ "nf-test": "0.8.4",
+ "nextflow": "23.10.1"
+ },
+ "timestamp": "2024-02-14T09:28:51.744211298"
},
- "sarscov2 single-end [fastqc] - stub": {
+ "multiqc_stub": {
"content": [
[
"multiqc_report.html",
"multiqc_data",
"multiqc_plots",
- "versions.yml:md5,14e9a2661241abd828f4f06a7b5c222d"
+ "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186"
]
],
- "timestamp": "2024-01-09T23:03:14.524346"
+ "meta": {
+ "nf-test": "0.8.4",
+ "nextflow": "23.10.1"
+ },
+ "timestamp": "2024-02-14T09:29:28.847433492"
+ },
+ "multiqc_versions_config": {
+ "content": [
+ [
+ "versions.yml:md5,d320d4c37e349c5588e07e7a31cd4186"
+ ]
+ ],
+ "meta": {
+ "nf-test": "0.8.4",
+ "nextflow": "23.10.1"
+ },
+ "timestamp": "2024-02-14T09:29:13.223621555"
}
}
\ No newline at end of file
diff --git a/nextflow.config b/nextflow.config
index cb43412..7964229 100644
--- a/nextflow.config
+++ b/nextflow.config
@@ -15,6 +15,9 @@ params {
genome = null
igenomes_base = 's3://ngi-igenomes/igenomes/'
igenomes_ignore = false
+ fasta = null
+ fai = null
+ dict = null
// Building Panel of Normals and models
tools = null // No default, must be specified
@@ -84,7 +87,7 @@ try {
}
// Load nf-core/createpanelrefs custom profiles from different institutions.
-// Warning: Uncomment only if a pipeline-specific instititutional config already exists on nf-core/configs!
+// Warning: Uncomment only if a pipeline-specific institutional config already exists on nf-core/configs!
// try {
// includeConfig "${params.custom_config_base}/pipeline/createpanelrefs.config"
// } catch (Exception e) {
@@ -104,6 +107,7 @@ profiles {
podman.enabled = false
shifter.enabled = false
charliecloud.enabled = false
+ channels = ['conda-forge', 'bioconda', 'defaults']
apptainer.enabled = false
}
mamba {
diff --git a/pyproject.toml b/pyproject.toml
index 0d62beb..5611062 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,15 @@
-# Config file for Python. Mostly used to configure linting of bin/check_samplesheet.py with Black.
+# Config file for Python. Mostly used to configure linting of bin/*.py with Ruff.
# Should be kept the same as nf-core/tools to avoid fighting with template synchronisation.
-[tool.black]
+[tool.ruff]
line-length = 120
-target_version = ["py37", "py38", "py39", "py310"]
+target-version = "py38"
+cache-dir = "~/.cache/ruff"
-[tool.isort]
-profile = "black"
-known_first_party = ["nf_core"]
-multi_line_output = 3
+[tool.ruff.lint]
+select = ["I", "E1", "E4", "E7", "E9", "F", "UP", "N"]
+
+[tool.ruff.lint.isort]
+known-first-party = ["nf_core"]
+
+[tool.ruff.lint.per-file-ignores]
+"__init__.py" = ["E402", "F401"]
diff --git a/subworkflows/local/germlinecnvcaller_cohort.nf b/subworkflows/local/germlinecnvcaller_cohort.nf
index facab74..77303b6 100644
--- a/subworkflows/local/germlinecnvcaller_cohort.nf
+++ b/subworkflows/local/germlinecnvcaller_cohort.nf
@@ -29,9 +29,9 @@ workflow GERMLINECNVCALLER_COHORT {
//
// Prepare references
//
- SAMTOOLS_FAIDX (ch_fasta, [[:],[]])
+ SAMTOOLS_FAIDX ( ch_fasta, [[:],[]] )
- PICARD_CREATESEQUENCEDICTIONARY (ch_fasta)
+ PICARD_CREATESEQUENCEDICTIONARY ( ch_fasta )
ch_user_dict
.mix(PICARD_CREATESEQUENCEDICTIONARY.out.reference_dict)
@@ -80,11 +80,11 @@ workflow GERMLINECNVCALLER_COHORT {
ch_target_interval_list,
ch_exclude_interval_list)
- GATK4_ANNOTATEINTERVALS (GATK4_PREPROCESSINTERVALS.out.interval_list,
- ch_fasta,
- ch_fai,
- ch_dict,
- [[:],[]], [[:],[]], [[:],[]], [[:],[]])
+ GATK4_ANNOTATEINTERVALS ( GATK4_PREPROCESSINTERVALS.out.interval_list,
+ ch_fasta,
+ ch_fai,
+ ch_dict,
+ [[:],[]], [[:],[]], [[:],[]], [[:],[]])
//
// Filter out files that lack indices, and generate them
@@ -98,11 +98,11 @@ workflow GERMLINECNVCALLER_COHORT {
}
.set { ch_for_mix }
- SAMTOOLS_INDEX (ch_for_mix.alignment_without_index)
+ SAMTOOLS_INDEX ( ch_for_mix.alignment_without_index )
SAMTOOLS_INDEX.out.bai
- .mix(SAMTOOLS_INDEX.out.crai)
- .set { ch_index }
+ .mix(SAMTOOLS_INDEX.out.crai)
+ .set { ch_index }
//
// Collect alignment files and their indices
@@ -116,10 +116,10 @@ workflow GERMLINECNVCALLER_COHORT {
//
// Collect read counts, and generate models
//
- GATK4_COLLECTREADCOUNTS (ch_readcounts_in,
- ch_fasta,
- ch_fai,
- ch_dict)
+ GATK4_COLLECTREADCOUNTS ( ch_readcounts_in,
+ ch_fasta,
+ ch_fai,
+ ch_dict )
GATK4_COLLECTREADCOUNTS.out.tsv
.mix(GATK4_COLLECTREADCOUNTS.out.hdf5)
@@ -128,11 +128,11 @@ workflow GERMLINECNVCALLER_COHORT {
.set { ch_readcounts_out }
- GATK4_FILTERINTERVALS (GATK4_PREPROCESSINTERVALS.out.interval_list,
- ch_readcounts_out,
- GATK4_ANNOTATEINTERVALS.out.annotated_intervals)
+ GATK4_FILTERINTERVALS ( GATK4_PREPROCESSINTERVALS.out.interval_list,
+ ch_readcounts_out,
+ GATK4_ANNOTATEINTERVALS.out.annotated_intervals )
- GATK4_INTERVALLISTTOOLS(GATK4_FILTERINTERVALS.out.interval_list)
+ GATK4_INTERVALLISTTOOLS ( GATK4_FILTERINTERVALS.out.interval_list )
.interval_list
.map {meta, it -> it}
.flatten()
@@ -143,9 +143,9 @@ workflow GERMLINECNVCALLER_COHORT {
.map{ meta, counts, meta2, il -> [meta, counts, il, []] }
.set {ch_contigploidy_in}
- GATK4_DETERMINEGERMLINECONTIGPLOIDY (ch_contigploidy_in,
- [[:],[]],
- ch_ploidy_priors)
+ GATK4_DETERMINEGERMLINECONTIGPLOIDY ( ch_contigploidy_in,
+ [[:],[]],
+ ch_ploidy_priors )
ch_readcounts_out
.combine(ch_intervallist_out)
@@ -153,7 +153,7 @@ workflow GERMLINECNVCALLER_COHORT {
.map{ meta, counts, il, meta2, calls -> [meta + [id:il.baseName], counts, il, calls, []] }
.set {ch_cnvcaller_in}
- GATK4_GERMLINECNVCALLER (ch_cnvcaller_in)
+ GATK4_GERMLINECNVCALLER ( ch_cnvcaller_in )
ch_versions = ch_versions.mix(SAMTOOLS_FAIDX.out.versions)
ch_versions = ch_versions.mix(PICARD_CREATESEQUENCEDICTIONARY.out.versions)
diff --git a/subworkflows/local/utils_nfcore_createpanelrefs_pipeline/main.nf b/subworkflows/local/utils_nfcore_createpanelrefs_pipeline/main.nf
new file mode 100644
index 0000000..a1e5d89
--- /dev/null
+++ b/subworkflows/local/utils_nfcore_createpanelrefs_pipeline/main.nf
@@ -0,0 +1,231 @@
+//
+// Subworkflow with functionality specific to the nf-core/createpanelrefs pipeline
+//
+
+/*
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*/
+
+include { UTILS_NFVALIDATION_PLUGIN } from '../../nf-core/utils_nfvalidation_plugin'
+include { paramsSummaryMap } from 'plugin/nf-validation'
+include { fromSamplesheet } from 'plugin/nf-validation'
+include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline'
+include { completionEmail } from '../../nf-core/utils_nfcore_pipeline'
+include { completionSummary } from '../../nf-core/utils_nfcore_pipeline'
+include { dashedLine } from '../../nf-core/utils_nfcore_pipeline'
+include { nfCoreLogo } from '../../nf-core/utils_nfcore_pipeline'
+include { imNotification } from '../../nf-core/utils_nfcore_pipeline'
+include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline'
+include { workflowCitation } from '../../nf-core/utils_nfcore_pipeline'
+
+/*
+========================================================================================
+ SUBWORKFLOW TO INITIALISE PIPELINE
+========================================================================================
+*/
+
+workflow PIPELINE_INITIALISATION {
+
+ take:
+ version // boolean: Display version and exit
+ help // boolean: Display help text
+ validate_params // boolean: Boolean whether to validate parameters against the schema at runtime
+ monochrome_logs // boolean: Do not use coloured log outputs
+ nextflow_cli_args // array: List of positional nextflow CLI args
+ outdir // string: The output directory where the results will be saved
+ input // string: Path to input samplesheet
+
+ main:
+
+ ch_versions = Channel.empty()
+
+ //
+ // Print version and exit if required and dump pipeline parameters to JSON file
+ //
+ UTILS_NEXTFLOW_PIPELINE (
+ version,
+ true,
+ outdir,
+ workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1
+ )
+
+ //
+ // Validate parameters and generate parameter summary to stdout
+ //
+ pre_help_text = nfCoreLogo(monochrome_logs)
+ post_help_text = '\n' + workflowCitation() + '\n' + dashedLine(monochrome_logs)
+ def String workflow_command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir "
+ UTILS_NFVALIDATION_PLUGIN (
+ help,
+ workflow_command,
+ pre_help_text,
+ post_help_text,
+ validate_params,
+ "nextflow_schema.json"
+ )
+
+ //
+ // Check config provided to the pipeline
+ //
+ UTILS_NFCORE_PIPELINE (
+ nextflow_cli_args
+ )
+ //
+ // Custom validation for pipeline parameters
+ //
+ validateInputParameters()
+
+ //
+ // Create channel from input file provided through params.input
+ //
+ Channel
+ .fromSamplesheet("input")
+ .set { ch_samplesheet }
+
+ emit:
+ samplesheet = ch_samplesheet
+ versions = ch_versions
+}
+
+/*
+========================================================================================
+ SUBWORKFLOW FOR PIPELINE COMPLETION
+========================================================================================
+*/
+
+workflow PIPELINE_COMPLETION {
+
+ take:
+ email // string: email address
+ email_on_fail // string: email address sent on pipeline failure
+ plaintext_email // boolean: Send plain-text email instead of HTML
+ outdir // path: Path to output directory where results will be published
+ monochrome_logs // boolean: Disable ANSI colour codes in log output
+ hook_url // string: hook URL for notifications
+ multiqc_report // string: Path to MultiQC report
+
+ main:
+
+ summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json")
+
+ //
+ // Completion email and summary
+ //
+ workflow.onComplete {
+ if (email || email_on_fail) {
+ completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs, multiqc_report.toList())
+ }
+
+ completionSummary(monochrome_logs)
+
+ if (hook_url) {
+ imNotification(summary_params, hook_url)
+ }
+ }
+}
+
+/*
+========================================================================================
+ FUNCTIONS
+========================================================================================
+*/
+//
+// Check and validate pipeline parameters
+//
+def validateInputParameters() {
+ genomeExistsError()
+}//
+// Validate channels from input samplesheet
+//
+def validateInputSamplesheet(input) {
+ def (metas, fastqs) = input[1..2]
+
+ // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end
+ def endedness_ok = metas.collect{ it.single_end }.unique().size == 1
+ if (!endedness_ok) {
+ error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}")
+ }
+
+ return [ metas[0], fastqs ]
+}
+//
+// Get attribute from genome config file e.g. fasta
+//
+def getGenomeAttribute(attribute) {
+ if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) {
+ if (params.genomes[ params.genome ].containsKey(attribute)) {
+ return params.genomes[ params.genome ][ attribute ]
+ }
+ }
+ return null
+}
+
+//
+// Exit pipeline if incorrect --genome key provided
+//
+def genomeExistsError() {
+ if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) {
+ def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" +
+ " Currently, the available genome keys are:\n" +
+ " ${params.genomes.keySet().join(", ")}\n" +
+ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+ error(error_string)
+ }
+}//
+// Generate methods description for MultiQC
+//
+def toolCitationText() {
+ // TODO nf-core: Optionally add in-text citation tools to this list.
+ // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "",
+ // Uncomment function in methodsDescriptionText to render in MultiQC report
+ def citation_text = [
+ "Tools used in the workflow included:",
+ "FastQC (Andrews 2010),",
+ "MultiQC (Ewels et al. 2016)",
+ "."
+ ].join(' ').trim()
+
+ return citation_text
+}
+
+def toolBibliographyText() {
+ // TODO nf-core: Optionally add bibliographic entries to this list.
+ // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
Author (2023) Pub name, Journal, DOI
" : "",
+ // Uncomment function in methodsDescriptionText to render in MultiQC report
+ def reference_text = [
+ "
Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
"
+ ].join(' ').trim()
+
+ return reference_text
+}
+
+def methodsDescriptionText(mqc_methods_yaml) {
+ // Convert to a named map so can be used as with familar NXF ${workflow} variable syntax in the MultiQC YML file
+ def meta = [:]
+ meta.workflow = workflow.toMap()
+ meta["manifest_map"] = workflow.manifest.toMap()
+
+ // Pipeline DOI
+ meta["doi_text"] = meta.manifest_map.doi ? "(doi: ${meta.manifest_map.doi})" : ""
+ meta["nodoi_text"] = meta.manifest_map.doi ? "": "
If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
"
+
+ // Tool references
+ meta["tool_citations"] = ""
+ meta["tool_bibliography"] = ""
+
+ // TODO nf-core: Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled!
+ // meta["tool_citations"] = toolCitationText().replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".")
+ // meta["tool_bibliography"] = toolBibliographyText()
+
+
+ def methods_text = mqc_methods_yaml.text
+
+ def engine = new groovy.text.SimpleTemplateEngine()
+ def description_html = engine.createTemplate(methods_text).make(meta)
+
+ return description_html.toString()
+}
diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf
new file mode 100644
index 0000000..ac31f28
--- /dev/null
+++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf
@@ -0,0 +1,126 @@
+//
+// Subworkflow with functionality that may be useful for any Nextflow pipeline
+//
+
+import org.yaml.snakeyaml.Yaml
+import groovy.json.JsonOutput
+import nextflow.extension.FilesEx
+
+/*
+========================================================================================
+ SUBWORKFLOW DEFINITION
+========================================================================================
+*/
+
+workflow UTILS_NEXTFLOW_PIPELINE {
+
+ take:
+ print_version // boolean: print version
+ dump_parameters // boolean: dump parameters
+ outdir // path: base directory used to publish pipeline results
+ check_conda_channels // boolean: check conda channels
+
+ main:
+
+ //
+ // Print workflow version and exit on --version
+ //
+ if (print_version) {
+ log.info "${workflow.manifest.name} ${getWorkflowVersion()}"
+ System.exit(0)
+ }
+
+ //
+ // Dump pipeline parameters to a JSON file
+ //
+ if (dump_parameters && outdir) {
+ dumpParametersToJSON(outdir)
+ }
+
+ //
+ // When running with Conda, warn if channels have not been set-up appropriately
+ //
+ if (check_conda_channels) {
+ checkCondaChannels()
+ }
+
+ emit:
+ dummy_emit = true
+}
+
+/*
+========================================================================================
+ FUNCTIONS
+========================================================================================
+*/
+
+//
+// Generate version string
+//
+def getWorkflowVersion() {
+ String version_string = ""
+ if (workflow.manifest.version) {
+ def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : ''
+ version_string += "${prefix_v}${workflow.manifest.version}"
+ }
+
+ if (workflow.commitId) {
+ def git_shortsha = workflow.commitId.substring(0, 7)
+ version_string += "-g${git_shortsha}"
+ }
+
+ return version_string
+}
+
+//
+// Dump pipeline parameters to a JSON file
+//
+def dumpParametersToJSON(outdir) {
+ def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss')
+ def filename = "params_${timestamp}.json"
+ def temp_pf = new File(workflow.launchDir.toString(), ".${filename}")
+ def jsonStr = JsonOutput.toJson(params)
+ temp_pf.text = JsonOutput.prettyPrint(jsonStr)
+
+ FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json")
+ temp_pf.delete()
+}
+
+//
+// When running with -profile conda, warn if channels have not been set-up appropriately
+//
+def checkCondaChannels() {
+ Yaml parser = new Yaml()
+ def channels = []
+ try {
+ def config = parser.load("conda config --show channels".execute().text)
+ channels = config.channels
+ } catch(NullPointerException | IOException e) {
+ log.warn "Could not verify conda channel configuration."
+ return
+ }
+
+ // Check that all channels are present
+ // This channel list is ordered by required channel priority.
+ def required_channels_in_order = ['conda-forge', 'bioconda', 'defaults']
+ def channels_missing = ((required_channels_in_order as Set) - (channels as Set)) as Boolean
+
+ // Check that they are in the right order
+ def channel_priority_violation = false
+ def n = required_channels_in_order.size()
+ for (int i = 0; i < n - 1; i++) {
+ channel_priority_violation |= !(channels.indexOf(required_channels_in_order[i]) < channels.indexOf(required_channels_in_order[i+1]))
+ }
+
+ if (channels_missing | channel_priority_violation) {
+ log.warn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ " There is a problem with your Conda configuration!\n\n" +
+ " You will need to set-up the conda-forge and bioconda channels correctly.\n" +
+ " Please refer to https://bioconda.github.io/\n" +
+ " The observed channel order is \n" +
+ " ${channels}\n" +
+ " but the following channel order is required:\n" +
+ " ${required_channels_in_order}\n" +
+ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+ }
+}
diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml
new file mode 100644
index 0000000..e5c3a0a
--- /dev/null
+++ b/subworkflows/nf-core/utils_nextflow_pipeline/meta.yml
@@ -0,0 +1,38 @@
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json
+name: "UTILS_NEXTFLOW_PIPELINE"
+description: Subworkflow with functionality that may be useful for any Nextflow pipeline
+keywords:
+ - utility
+ - pipeline
+ - initialise
+ - version
+components: []
+input:
+ - print_version:
+ type: boolean
+ description: |
+ Print the version of the pipeline and exit
+ - dump_parameters:
+ type: boolean
+ description: |
+ Dump the parameters of the pipeline to a JSON file
+ - output_directory:
+ type: directory
+ description: Path to output dir to write JSON file to.
+ pattern: "results/"
+ - check_conda_channel:
+ type: boolean
+ description: |
+ Check if the conda channel priority is correct.
+output:
+ - dummy_emit:
+ type: boolean
+ description: |
+ Dummy emit to make nf-core subworkflows lint happy
+authors:
+ - "@adamrtalbot"
+ - "@drpatelh"
+maintainers:
+ - "@adamrtalbot"
+ - "@drpatelh"
+ - "@maxulysse"
diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test
new file mode 100644
index 0000000..8ed4310
--- /dev/null
+++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test
@@ -0,0 +1,54 @@
+
+nextflow_function {
+
+ name "Test Functions"
+ script "subworkflows/nf-core/utils_nextflow_pipeline/main.nf"
+ config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config"
+ tag 'subworkflows'
+ tag 'utils_nextflow_pipeline'
+ tag 'subworkflows/utils_nextflow_pipeline'
+
+ test("Test Function getWorkflowVersion") {
+
+ function "getWorkflowVersion"
+
+ then {
+ assertAll(
+ { assert function.success },
+ { assert snapshot(function.result).match() }
+ )
+ }
+ }
+
+ test("Test Function dumpParametersToJSON") {
+
+ function "dumpParametersToJSON"
+
+ when {
+ function {
+ """
+ // define inputs of the function here. Example:
+ input[0] = "$outputDir"
+ """.stripIndent()
+ }
+ }
+
+ then {
+ assertAll(
+ { assert function.success }
+ )
+ }
+ }
+
+ test("Test Function checkCondaChannels") {
+
+ function "checkCondaChannels"
+
+ then {
+ assertAll(
+ { assert function.success },
+ { assert snapshot(function.result).match() }
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap
new file mode 100644
index 0000000..db2030f
--- /dev/null
+++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.function.nf.test.snap
@@ -0,0 +1,12 @@
+{
+ "Test Function getWorkflowVersion": {
+ "content": [
+ "v9.9.9"
+ ],
+ "timestamp": "2024-01-19T11:32:36.031083"
+ },
+ "Test Function checkCondaChannels": {
+ "content": null,
+ "timestamp": "2024-01-19T11:32:50.456"
+ }
+}
\ No newline at end of file
diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test
new file mode 100644
index 0000000..f7c54bc
--- /dev/null
+++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/main.workflow.nf.test
@@ -0,0 +1,123 @@
+nextflow_workflow {
+
+ name "Test Workflow UTILS_NEXTFLOW_PIPELINE"
+ script "../main.nf"
+ config "subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config"
+ workflow "UTILS_NEXTFLOW_PIPELINE"
+ tag 'subworkflows'
+ tag 'utils_nextflow_pipeline'
+ tag 'subworkflows/utils_nextflow_pipeline'
+
+ test("Should run no inputs") {
+
+ when {
+ params {
+ outdir = "tests/results"
+ }
+ workflow {
+ """
+ print_version = false
+ dump_parameters = false
+ outdir = null
+ check_conda_channels = false
+
+ input[0] = print_version
+ input[1] = dump_parameters
+ input[2] = outdir
+ input[3] = check_conda_channels
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert workflow.success }
+ )
+ }
+ }
+
+ test("Should print version") {
+
+ when {
+ params {
+ outdir = "tests/results"
+ }
+ workflow {
+ """
+ print_version = true
+ dump_parameters = false
+ outdir = null
+ check_conda_channels = false
+
+ input[0] = print_version
+ input[1] = dump_parameters
+ input[2] = outdir
+ input[3] = check_conda_channels
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert workflow.success },
+ { assert workflow.stdout.contains("nextflow_workflow v9.9.9") }
+ )
+ }
+ }
+
+ test("Should dump params") {
+
+ when {
+ params {
+ outdir = "$outputDir"
+ }
+ workflow {
+ """
+ print_version = false
+ dump_parameters = true
+ outdir = params.outdir
+ check_conda_channels = false
+
+ input[0] = false
+ input[1] = true
+ input[2] = params.outdir
+ input[3] = false
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert workflow.success }
+ )
+ }
+ }
+
+ test("Should not create params JSON if no output directory") {
+
+ when {
+ params {
+ outdir = "$outputDir"
+ }
+ workflow {
+ """
+ print_version = false
+ dump_parameters = true
+ outdir = params.outdir
+ check_conda_channels = false
+
+ input[0] = false
+ input[1] = true
+ input[2] = null
+ input[3] = false
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ { assert workflow.success }
+ )
+ }
+ }
+}
diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config
new file mode 100644
index 0000000..53574ff
--- /dev/null
+++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config
@@ -0,0 +1,9 @@
+manifest {
+ name = 'nextflow_workflow'
+ author = """nf-core"""
+ homePage = 'https://127.0.0.1'
+ description = """Dummy pipeline"""
+ nextflowVersion = '!>=23.04.0'
+ version = '9.9.9'
+ doi = 'https://doi.org/10.5281/zenodo.5070524'
+}
\ No newline at end of file
diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml
new file mode 100644
index 0000000..f847611
--- /dev/null
+++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml
@@ -0,0 +1,2 @@
+subworkflows/utils_nextflow_pipeline:
+ - subworkflows/nf-core/utils_nextflow_pipeline/**
diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf
new file mode 100644
index 0000000..a8b55d6
--- /dev/null
+++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf
@@ -0,0 +1,440 @@
+//
+// Subworkflow with utility functions specific to the nf-core pipeline template
+//
+
+import org.yaml.snakeyaml.Yaml
+import nextflow.extension.FilesEx
+
+/*
+========================================================================================
+ SUBWORKFLOW DEFINITION
+========================================================================================
+*/
+
+workflow UTILS_NFCORE_PIPELINE {
+
+ take:
+ nextflow_cli_args
+
+ main:
+ valid_config = checkConfigProvided()
+ checkProfileProvided(nextflow_cli_args)
+
+ emit:
+ valid_config
+}
+
+/*
+========================================================================================
+ FUNCTIONS
+========================================================================================
+*/
+
+//
+// Warn if a -profile or Nextflow config has not been provided to run the pipeline
+//
+def checkConfigProvided() {
+ valid_config = true
+ if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) {
+ log.warn "[$workflow.manifest.name] You are attempting to run the pipeline without any custom configuration!\n\n" +
+ "This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" +
+ " (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" +
+ " (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" +
+ " (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" +
+ "Please refer to the quick start section and usage docs for the pipeline.\n "
+ valid_config = false
+ }
+ return valid_config
+}
+
+//
+// Exit pipeline if --profile contains spaces
+//
+def checkProfileProvided(nextflow_cli_args) {
+ if (workflow.profile.endsWith(',')) {
+ error "The `-profile` option cannot end with a trailing comma, please remove it and re-run the pipeline!\n" +
+ "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n"
+ }
+ if (nextflow_cli_args[0]) {
+ log.warn "nf-core pipelines do not accept positional arguments. The positional argument `${nextflow_cli_args[0]}` has been detected.\n" +
+ "HINT: A common mistake is to provide multiple values separated by spaces e.g. `-profile test, docker`.\n"
+ }
+}
+
+//
+// Citation string for pipeline
+//
+def workflowCitation() {
+ return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" +
+ "* The pipeline\n" +
+ " ${workflow.manifest.doi}\n\n" +
+ "* The nf-core framework\n" +
+ " https://doi.org/10.1038/s41587-020-0439-x\n\n" +
+ "* Software dependencies\n" +
+ " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md"
+}
+
+//
+// Generate workflow version string
+//
+def getWorkflowVersion() {
+ String version_string = ""
+ if (workflow.manifest.version) {
+ def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : ''
+ version_string += "${prefix_v}${workflow.manifest.version}"
+ }
+
+ if (workflow.commitId) {
+ def git_shortsha = workflow.commitId.substring(0, 7)
+ version_string += "-g${git_shortsha}"
+ }
+
+ return version_string
+}
+
+//
+// Get software versions for pipeline
+//
+def processVersionsFromYAML(yaml_file) {
+ Yaml yaml = new Yaml()
+ versions = yaml.load(yaml_file).collectEntries { k, v -> [ k.tokenize(':')[-1], v ] }
+ return yaml.dumpAsMap(versions).trim()
+}
+
+//
+// Get workflow version for pipeline
+//
+def workflowVersionToYAML() {
+ return """
+ Workflow:
+ $workflow.manifest.name: ${getWorkflowVersion()}
+ Nextflow: $workflow.nextflow.version
+ """.stripIndent().trim()
+}
+
+//
+// Get channel of software versions used in pipeline in YAML format
+//
+def softwareVersionsToYAML(ch_versions) {
+ return ch_versions
+ .unique()
+ .map { processVersionsFromYAML(it) }
+ .unique()
+ .mix(Channel.of(workflowVersionToYAML()))
+}
+
+//
+// Get workflow summary for MultiQC
+//
+def paramsSummaryMultiqc(summary_params) {
+ def summary_section = ''
+ for (group in summary_params.keySet()) {
+ def group_params = summary_params.get(group) // This gets the parameters of that particular group
+ if (group_params) {
+ summary_section += "
$group
\n"
+ summary_section += "
\n"
+ for (param in group_params.keySet()) {
+ summary_section += "