From 192513c4d3b35a8045adf7e7ea219a24af70c012 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Fri, 30 Jun 2023 16:12:48 +0000 Subject: [PATCH 1/4] Template update for nf-core/tools version 2.9 --- .github/CONTRIBUTING.md | 1 - .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/awsfulltest.yml | 11 +- .github/workflows/awstest.yml | 10 +- .github/workflows/ci.yml | 2 +- .gitpod.yml | 5 + CHANGELOG.md | 2 +- CITATIONS.md | 6 + README.md | 6 +- assets/methods_description_template.yml | 12 +- assets/multiqc_config.yml | 4 +- assets/nf-core-bamtofastq_logo_light.png | Bin 11951 -> 79715 bytes assets/slackreport.json | 2 +- conf/test_full.config | 2 - docs/usage.md | 6 +- lib/NfcoreSchema.groovy | 530 ----------------------- lib/NfcoreTemplate.groovy | 2 +- lib/WorkflowBamtofastq.groovy | 45 +- lib/WorkflowMain.groovy | 37 -- main.nf | 16 + nextflow.config | 54 ++- nextflow_schema.json | 36 +- workflows/bamtofastq.nf | 25 +- 23 files changed, 177 insertions(+), 639 deletions(-) delete mode 100755 lib/NfcoreSchema.groovy diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5971c09e..aaf5c358 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -116,4 +116,3 @@ To get started: Devcontainer specs: - [DevContainer config](.devcontainer/devcontainer.json) -- [Dockerfile](.devcontainer/Dockerfile) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f914c8f1..6a156907 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -42,7 +42,7 @@ body: attributes: label: System information description: | - * Nextflow version _(eg. 22.10.1)_ + * Nextflow version _(eg. 23.04.0)_ * Hardware _(eg. HPC, Desktop, Cloud)_ * Executor _(eg. slurm, local, awsbatch)_ * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter, Charliecloud, or Apptainer)_ diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index d035b8ad..3679cfed 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v1 + uses: seqeralabs/action-tower-launch@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 @@ -22,13 +22,18 @@ jobs: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/bamtofastq/work-${{ github.sha }} parameters: | { + "hook_url": "${{ secrets.MEGATESTS_ALERTS_SLACK_HOOK_URL }}", "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/bamtofastq/results-${{ github.sha }}" } - profiles: test_full,aws_tower + profiles: test_full + - uses: actions/upload-artifact@v3 with: name: Tower debug log file - path: tower_action_*.log + path: | + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index dcb66ede..cc53429c 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,18 +12,22 @@ jobs: steps: # Launch workflow using Tower CLI tool action - name: Launch workflow via tower - uses: seqeralabs/action-tower-launch@v1 + uses: seqeralabs/action-tower-launch@v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/bamtofastq/work-${{ github.sha }} parameters: | { "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/bamtofastq/results-test-${{ github.sha }}" } - profiles: test,aws_tower + profiles: test + - uses: actions/upload-artifact@v3 with: name: Tower debug log file - path: tower_action_*.log + path: | + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82b4d57f..5d4f43ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: NXF_VER: - - "22.10.1" + - "23.04.0" - "latest-everything" steps: - name: Check out pipeline code diff --git a/.gitpod.yml b/.gitpod.yml index 85d95ecc..25488dcc 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,4 +1,9 @@ image: nfcore/gitpod:latest +tasks: + - name: Update Nextflow and setup pre-commit + command: | + pre-commit install --install-hooks + nextflow self-update vscode: extensions: # based on nf-core.nf-core-extensionpack diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a21eaac..938fee84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## v2.0.0dev - [date] +## v2.0.0 - [date] Initial release of nf-core/bamtofastq, created with the [nf-core](https://nf-co.re/) template. diff --git a/CITATIONS.md b/CITATIONS.md index 72318474..8333a48f 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -12,7 +12,10 @@ - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) + > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. Available online https://www.bioinformatics.babraham.ac.uk/projects/fastqc/. + - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) + > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. ## Software packaging/containerisation tools @@ -31,5 +34,8 @@ - [Docker](https://dl.acm.org/doi/10.5555/2600239.2600241) + > Merkel, D. (2014). Docker: lightweight linux containers for consistent development and deployment. Linux Journal, 2014(239), 2. doi: 10.5555/2600239.2600241. + - [Singularity](https://pubmed.ncbi.nlm.nih.gov/28494014/) + > Kurtzer GM, Sochat V, Bauer MW. Singularity: Scientific containers for mobility of compute. PLoS One. 2017 May 11;12(5):e0177459. doi: 10.1371/journal.pone.0177459. eCollection 2017. PubMed PMID: 28494014; PubMed Central PMCID: PMC5426675. diff --git a/README.md b/README.md index 8b9b0046..fc3cc7df 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/bamtofastq/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A522.10.1-23aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) @@ -66,11 +66,11 @@ nextflow run nf-core/bamtofastq \ > provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; > see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). -For more details, please refer to the [usage documentation](https://nf-co.re/bamtofastq/usage) and the [parameter documentation](https://nf-co.re/bamtofastq/parameters). +For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/bamtofastq/usage) and the [parameter documentation](https://nf-co.re/bamtofastq/parameters). ## Pipeline output -To see the the results of a test run with a full size dataset refer to the [results](https://nf-co.re/bamtofastq/results) tab on the nf-core website pipeline page. +To see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/bamtofastq/results) tab on the nf-core website pipeline page. For more details about the output files and reports, please refer to the [output documentation](https://nf-co.re/bamtofastq/output). diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml index 8e9e4f83..43c19864 100644 --- a/assets/methods_description_template.yml +++ b/assets/methods_description_template.yml @@ -3,17 +3,21 @@ description: "Suggested text and references to use when describing pipeline usag section_name: "nf-core/bamtofastq Methods Description" section_href: "https://github.com/nf-core/bamtofastq" plot_type: "html" -## TODO nf-core: Update the HTML below to your prefered methods description, e.g. add publication citation for this pipeline +## TODO nf-core: Update the HTML below to your preferred methods description, e.g. add publication citation for this pipeline ## You inject any metadata in the Nextflow '${workflow}' object data: |

Methods

-

Data was processed using nf-core/bamtofastq v${workflow.manifest.version} ${doi_text} of the nf-core collection of workflows (Ewels et al., 2020).

+

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

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

${workflow.commandLine}
+

${tool_citations}

References

Notes:
diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index d4704948..899dcc26 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,7 @@ report_comment: > - This report has been generated by the nf-core/bamtofastq + This report has been generated by the nf-core/bamtofastq analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: "nf-core-bamtofastq-methods-description": order: -1000 diff --git a/assets/nf-core-bamtofastq_logo_light.png b/assets/nf-core-bamtofastq_logo_light.png index d3aec53e2a1394f4d2fb91b190cf78d5c0e56e22..a05647429e309396018292e0aa96aaa819cdd3d8 100644 GIT binary patch literal 79715 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%0A%TGV3zy`a}c`h>3 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 literal 11951 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 } else { %>danger<%} %>", - "author_name": "sanger-tol/readmapping v${version} - ${runName}", + "author_name": "nf-core/bamtofastq v${version} - ${runName}", "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", "fields": [ diff --git a/conf/test_full.config b/conf/test_full.config index 66268d4c..2e25fb71 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -10,8 +10,6 @@ ---------------------------------------------------------------------------------------- */ -cleanup = true - params { config_profile_name = 'Full test profile' config_profile_description = 'Full test dataset to check pipeline function' diff --git a/docs/usage.md b/docs/usage.md index faff59e2..335717a6 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -57,7 +57,7 @@ An [example samplesheet](../assets/samplesheet.csv) has been provided with the p The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/bamtofastq --input samplesheet.csv --outdir --genome GRCh37 -profile docker +nextflow run nf-core/bamtofastq --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -76,7 +76,8 @@ If you wish to repeatedly use the same parameters for multiple runs, rather than Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. > ⚠️ Do not use `-c ` to specify parameters as this will result in errors. Custom config files specified with `-c` must only be used for [tuning process resource specifications](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources), other infrastructural tweaks (such as output directories), or module arguments (args). -> The above pipeline run specified with a params file in yaml format: + +The above pipeline run specified with a params file in yaml format: ```bash nextflow run nf-core/bamtofastq -profile docker -params-file params.yaml @@ -88,7 +89,6 @@ with `params.yaml` containing: input: './samplesheet.csv' outdir: './results/' genome: 'GRCh37' -input: 'data' <...> ``` diff --git a/lib/NfcoreSchema.groovy b/lib/NfcoreSchema.groovy deleted file mode 100755 index 9b34804d..00000000 --- a/lib/NfcoreSchema.groovy +++ /dev/null @@ -1,530 +0,0 @@ -// -// This file holds several functions used to perform JSON parameter validation, help and summary rendering for the nf-core pipeline template. -// - -import nextflow.Nextflow -import org.everit.json.schema.Schema -import org.everit.json.schema.loader.SchemaLoader -import org.everit.json.schema.ValidationException -import org.json.JSONObject -import org.json.JSONTokener -import org.json.JSONArray -import groovy.json.JsonSlurper -import groovy.json.JsonBuilder - -class NfcoreSchema { - - // - // Resolve Schema path relative to main workflow directory - // - public static String getSchemaPath(workflow, schema_filename='nextflow_schema.json') { - return "${workflow.projectDir}/${schema_filename}" - } - - // - // Function to loop over all parameters defined in schema and check - // whether the given parameters adhere to the specifications - // - /* groovylint-disable-next-line UnusedPrivateMethodParameter */ - public static void validateParameters(workflow, params, log, schema_filename='nextflow_schema.json') { - def has_error = false - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Check for nextflow core params and unexpected params - def json = new File(getSchemaPath(workflow, schema_filename=schema_filename)).text - def Map schemaParams = (Map) new JsonSlurper().parseText(json).get('definitions') - def nf_params = [ - // Options for base `nextflow` command - 'bg', - 'c', - 'C', - 'config', - 'd', - 'D', - 'dockerize', - 'h', - 'log', - 'q', - 'quiet', - 'syslog', - 'v', - - // Options for `nextflow run` command - 'ansi', - 'ansi-log', - 'bg', - 'bucket-dir', - 'c', - 'cache', - 'config', - 'dsl2', - 'dump-channels', - 'dump-hashes', - 'E', - 'entry', - 'latest', - 'lib', - 'main-script', - 'N', - 'name', - 'offline', - 'params-file', - 'pi', - 'plugins', - 'poll-interval', - 'pool-size', - 'profile', - 'ps', - 'qs', - 'queue-size', - 'r', - 'resume', - 'revision', - 'stdin', - 'stub', - 'stub-run', - 'test', - 'w', - 'with-apptainer', - 'with-charliecloud', - 'with-conda', - 'with-dag', - 'with-docker', - 'with-mpi', - 'with-notification', - 'with-podman', - 'with-report', - 'with-singularity', - 'with-timeline', - 'with-tower', - 'with-trace', - 'with-weblog', - 'without-docker', - 'without-podman', - 'work-dir' - ] - def unexpectedParams = [] - - // Collect expected parameters from the schema - def expectedParams = [] - def enums = [:] - for (group in schemaParams) { - for (p in group.value['properties']) { - expectedParams.push(p.key) - if (group.value['properties'][p.key].containsKey('enum')) { - enums[p.key] = group.value['properties'][p.key]['enum'] - } - } - } - - for (specifiedParam in params.keySet()) { - // nextflow params - if (nf_params.contains(specifiedParam)) { - log.error "ERROR: You used a core Nextflow option with two hyphens: '--${specifiedParam}'. Please resubmit with '-${specifiedParam}'" - has_error = true - } - // unexpected params - def params_ignore = params.schema_ignore_params.split(',') + 'schema_ignore_params' - def expectedParamsLowerCase = expectedParams.collect{ it.replace("-", "").toLowerCase() } - def specifiedParamLowerCase = specifiedParam.replace("-", "").toLowerCase() - def isCamelCaseBug = (specifiedParam.contains("-") && !expectedParams.contains(specifiedParam) && expectedParamsLowerCase.contains(specifiedParamLowerCase)) - if (!expectedParams.contains(specifiedParam) && !params_ignore.contains(specifiedParam) && !isCamelCaseBug) { - // Temporarily remove camelCase/camel-case params #1035 - def unexpectedParamsLowerCase = unexpectedParams.collect{ it.replace("-", "").toLowerCase()} - if (!unexpectedParamsLowerCase.contains(specifiedParamLowerCase)){ - unexpectedParams.push(specifiedParam) - } - } - } - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Validate parameters against the schema - InputStream input_stream = new File(getSchemaPath(workflow, schema_filename=schema_filename)).newInputStream() - JSONObject raw_schema = new JSONObject(new JSONTokener(input_stream)) - - // Remove anything that's in params.schema_ignore_params - raw_schema = removeIgnoredParams(raw_schema, params) - - Schema schema = SchemaLoader.load(raw_schema) - - // Clean the parameters - def cleanedParams = cleanParameters(params) - - // Convert to JSONObject - def jsonParams = new JsonBuilder(cleanedParams) - JSONObject params_json = new JSONObject(jsonParams.toString()) - - // Validate - try { - schema.validate(params_json) - } catch (ValidationException e) { - println '' - log.error 'ERROR: Validation of pipeline parameters failed!' - JSONObject exceptionJSON = e.toJSON() - printExceptions(exceptionJSON, params_json, log, enums) - println '' - has_error = true - } - - // Check for unexpected parameters - if (unexpectedParams.size() > 0) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - println '' - def warn_msg = 'Found unexpected parameters:' - for (unexpectedParam in unexpectedParams) { - warn_msg = warn_msg + "\n* --${unexpectedParam}: ${params[unexpectedParam].toString()}" - } - log.warn warn_msg - log.info "- ${colors.dim}Ignore this warning: params.schema_ignore_params = \"${unexpectedParams.join(',')}\" ${colors.reset}" - println '' - } - - if (has_error) { - Nextflow.error('Exiting!') - } - } - - // - // Beautify parameters for --help - // - public static String paramsHelp(workflow, params, command, schema_filename='nextflow_schema.json') { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - Integer num_hidden = 0 - String output = '' - output += 'Typical pipeline command:\n\n' - output += " ${colors.cyan}${command}${colors.reset}\n\n" - Map params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - Integer max_chars = paramsMaxChars(params_map) + 1 - Integer desc_indent = max_chars + 14 - Integer dec_linewidth = 160 - desc_indent - for (group in params_map.keySet()) { - Integer num_params = 0 - String group_output = colors.underlined + colors.bold + group + colors.reset + '\n' - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (group_params.get(param).hidden && !params.show_hidden_params) { - num_hidden += 1 - continue; - } - def type = '[' + group_params.get(param).type + ']' - def description = group_params.get(param).description - def defaultValue = group_params.get(param).default != null ? " [default: " + group_params.get(param).default.toString() + "]" : '' - def description_default = description + colors.dim + defaultValue + colors.reset - // Wrap long description texts - // Loosely based on https://dzone.com/articles/groovy-plain-text-word-wrap - if (description_default.length() > dec_linewidth){ - List olines = [] - String oline = "" // " " * indent - description_default.split(" ").each() { wrd -> - if ((oline.size() + wrd.size()) <= dec_linewidth) { - oline += wrd + " " - } else { - olines += oline - oline = wrd + " " - } - } - olines += oline - description_default = olines.join("\n" + " " * desc_indent) - } - group_output += " --" + param.padRight(max_chars) + colors.dim + type.padRight(10) + colors.reset + description_default + '\n' - num_params += 1 - } - group_output += '\n' - if (num_params > 0){ - output += group_output - } - } - if (num_hidden > 0){ - output += colors.dim + "!! Hiding $num_hidden params, use --show_hidden_params to show them !!\n" + colors.reset - } - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Groovy Map summarising parameters/workflow options used by the pipeline - // - public static LinkedHashMap paramsSummaryMap(workflow, params, schema_filename='nextflow_schema.json') { - // Get a selection of core Nextflow workflow options - def Map workflow_summary = [:] - if (workflow.revision) { - workflow_summary['revision'] = workflow.revision - } - workflow_summary['runName'] = workflow.runName - if (workflow.containerEngine) { - workflow_summary['containerEngine'] = workflow.containerEngine - } - if (workflow.container) { - workflow_summary['container'] = workflow.container - } - workflow_summary['launchDir'] = workflow.launchDir - workflow_summary['workDir'] = workflow.workDir - workflow_summary['projectDir'] = workflow.projectDir - workflow_summary['userName'] = workflow.userName - workflow_summary['profile'] = workflow.profile - workflow_summary['configFiles'] = workflow.configFiles.join(', ') - - // Get pipeline parameters defined in JSON Schema - def Map params_summary = [:] - def params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) - for (group in params_map.keySet()) { - def sub_params = new LinkedHashMap() - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (params.containsKey(param)) { - def params_value = params.get(param) - def schema_value = group_params.get(param).default - def param_type = group_params.get(param).type - if (schema_value != null) { - if (param_type == 'string') { - if (schema_value.contains('$projectDir') || schema_value.contains('${projectDir}')) { - def sub_string = schema_value.replace('\$projectDir', '') - sub_string = sub_string.replace('\${projectDir}', '') - if (params_value.contains(sub_string)) { - schema_value = params_value - } - } - if (schema_value.contains('$params.outdir') || schema_value.contains('${params.outdir}')) { - def sub_string = schema_value.replace('\$params.outdir', '') - sub_string = sub_string.replace('\${params.outdir}', '') - if ("${params.outdir}${sub_string}" == params_value) { - schema_value = params_value - } - } - } - } - - // We have a default in the schema, and this isn't it - if (schema_value != null && params_value != schema_value) { - sub_params.put(param, params_value) - } - // No default in the schema, and this isn't empty - else if (schema_value == null && params_value != "" && params_value != null && params_value != false) { - sub_params.put(param, params_value) - } - } - } - params_summary.put(group, sub_params) - } - return [ 'Core Nextflow options' : workflow_summary ] << params_summary - } - - // - // Beautify parameters for summary and return as string - // - public static String paramsSummaryLog(workflow, params) { - Map colors = NfcoreTemplate.logColours(params.monochrome_logs) - String output = '' - def params_map = paramsSummaryMap(workflow, params) - def max_chars = paramsMaxChars(params_map) - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - if (group_params) { - output += colors.bold + group + colors.reset + '\n' - for (param in group_params.keySet()) { - output += " " + colors.blue + param.padRight(max_chars) + ": " + colors.green + group_params.get(param) + colors.reset + '\n' - } - output += '\n' - } - } - output += "!! Only displaying parameters that differ from the pipeline defaults !!\n" - output += NfcoreTemplate.dashedLine(params.monochrome_logs) - return output - } - - // - // Loop over nested exceptions and print the causingException - // - private static void printExceptions(ex_json, params_json, log, enums, limit=5) { - def causingExceptions = ex_json['causingExceptions'] - if (causingExceptions.length() == 0) { - def m = ex_json['message'] =~ /required key \[([^\]]+)\] not found/ - // Missing required param - if (m.matches()) { - log.error "* Missing required parameter: --${m[0][1]}" - } - // Other base-level error - else if (ex_json['pointerToViolation'] == '#') { - log.error "* ${ex_json['message']}" - } - // Error with specific param - else { - def param = ex_json['pointerToViolation'] - ~/^#\// - def param_val = params_json[param].toString() - if (enums.containsKey(param)) { - def error_msg = "* --${param}: '${param_val}' is not a valid choice (Available choices" - if (enums[param].size() > limit) { - log.error "${error_msg} (${limit} of ${enums[param].size()}): ${enums[param][0..limit-1].join(', ')}, ... )" - } else { - log.error "${error_msg}: ${enums[param].join(', ')})" - } - } else { - log.error "* --${param}: ${ex_json['message']} (${param_val})" - } - } - } - for (ex in causingExceptions) { - printExceptions(ex, params_json, log, enums) - } - } - - // - // Remove an element from a JSONArray - // - private static JSONArray removeElement(json_array, element) { - def list = [] - int len = json_array.length() - for (int i=0;i - if(raw_schema.keySet().contains('definitions')){ - raw_schema.definitions.each { definition -> - for (key in definition.keySet()){ - if (definition[key].get("properties").keySet().contains(ignore_param)){ - // Remove the param to ignore - definition[key].get("properties").remove(ignore_param) - // If the param was required, change this - if (definition[key].has("required")) { - def cleaned_required = removeElement(definition[key].required, ignore_param) - definition[key].put("required", cleaned_required) - } - } - } - } - } - if(raw_schema.keySet().contains('properties') && raw_schema.get('properties').keySet().contains(ignore_param)) { - raw_schema.get("properties").remove(ignore_param) - } - if(raw_schema.keySet().contains('required') && raw_schema.required.contains(ignore_param)) { - def cleaned_required = removeElement(raw_schema.required, ignore_param) - raw_schema.put("required", cleaned_required) - } - } - return raw_schema - } - - // - // Clean and check parameters relative to Nextflow native classes - // - private static Map cleanParameters(params) { - def new_params = params.getClass().newInstance(params) - for (p in params) { - // remove anything evaluating to false - if (!p['value']) { - new_params.remove(p.key) - } - // Cast MemoryUnit to String - if (p['value'].getClass() == nextflow.util.MemoryUnit) { - new_params.replace(p.key, p['value'].toString()) - } - // Cast Duration to String - if (p['value'].getClass() == nextflow.util.Duration) { - new_params.replace(p.key, p['value'].toString().replaceFirst(/d(?!\S)/, "day")) - } - // Cast LinkedHashMap to String - if (p['value'].getClass() == LinkedHashMap) { - new_params.replace(p.key, p['value'].toString()) - } - } - return new_params - } - - // - // This function tries to read a JSON params file - // - private static LinkedHashMap paramsLoad(String json_schema) { - def params_map = new LinkedHashMap() - try { - params_map = paramsRead(json_schema) - } catch (Exception e) { - println "Could not read parameters settings from JSON. $e" - params_map = new LinkedHashMap() - } - return params_map - } - - // - // Method to actually read in JSON file using Groovy. - // Group (as Key), values are all parameters - // - Parameter1 as Key, Description as Value - // - Parameter2 as Key, Description as Value - // .... - // Group - // - - private static LinkedHashMap paramsRead(String json_schema) throws Exception { - def json = new File(json_schema).text - def Map schema_definitions = (Map) new JsonSlurper().parseText(json).get('definitions') - def Map schema_properties = (Map) new JsonSlurper().parseText(json).get('properties') - /* Tree looks like this in nf-core schema - * definitions <- this is what the first get('definitions') gets us - group 1 - title - description - properties - parameter 1 - type - description - parameter 2 - type - description - group 2 - title - description - properties - parameter 1 - type - description - * properties <- parameters can also be ungrouped, outside of definitions - parameter 1 - type - description - */ - - // Grouped params - def params_map = new LinkedHashMap() - schema_definitions.each { key, val -> - def Map group = schema_definitions."$key".properties // Gets the property object of the group - def title = schema_definitions."$key".title - def sub_params = new LinkedHashMap() - group.each { innerkey, value -> - sub_params.put(innerkey, value) - } - params_map.put(title, sub_params) - } - - // Ungrouped params - def ungrouped_params = new LinkedHashMap() - schema_properties.each { innerkey, value -> - ungrouped_params.put(innerkey, value) - } - params_map.put("Other parameters", ungrouped_params) - - return params_map - } - - // - // Get maximum number of characters across all parameter names - // - private static Integer paramsMaxChars(params_map) { - Integer max_chars = 0 - for (group in params_map.keySet()) { - def group_params = params_map.get(group) // This gets the parameters of that particular group - for (param in group_params.keySet()) { - if (param.size() > max_chars) { - max_chars = param.size() - } - } - } - return max_chars - } -} diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy index 25a0a74a..408951ae 100755 --- a/lib/NfcoreTemplate.groovy +++ b/lib/NfcoreTemplate.groovy @@ -128,7 +128,7 @@ class NfcoreTemplate { def email_html = html_template.toString() // Render the sendmail template - def max_multiqc_email_size = params.max_multiqc_email_size as nextflow.util.MemoryUnit + def max_multiqc_email_size = (params.containsKey('max_multiqc_email_size') ? params.max_multiqc_email_size : 0) as nextflow.util.MemoryUnit def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "$projectDir", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] def sf = new File("$projectDir/assets/sendmail_template.txt") def sendmail_template = engine.createTemplate(sf).make(smail_fields) diff --git a/lib/WorkflowBamtofastq.groovy b/lib/WorkflowBamtofastq.groovy index 81617e12..27ce966b 100755 --- a/lib/WorkflowBamtofastq.groovy +++ b/lib/WorkflowBamtofastq.groovy @@ -11,6 +11,7 @@ class WorkflowBamtofastq { // Check and validate parameters // public static void initialise(params, log) { + genomeExistsError(params, log) @@ -46,15 +47,57 @@ class WorkflowBamtofastq { return yaml_file_text } - public static String methodsDescriptionText(run_workflow, mqc_methods_yaml) { + // + // Generate methods description for MultiQC + // + + public static String toolCitationText(params) { + + // TODO 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 + } + + public static String toolBibliographyText(params) { + + // TODO Optionally add bibliographic entries to this list. + // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", + // Uncomment function in methodsDescriptionText to render in MultiQC report + def reference_text = [ + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() + + return reference_text + } + + 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() diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index f130de31..4fcf04da 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -20,40 +20,11 @@ class WorkflowMain { " https://github.com/${workflow.manifest.name}/blob/master/CITATIONS.md" } - // - // Generate help string - // - public static String help(workflow, params) { - def command = "nextflow run ${workflow.manifest.name} --input samplesheet.csv --genome GRCh37 -profile docker" - def help_string = '' - help_string += NfcoreTemplate.logo(workflow, params.monochrome_logs) - help_string += NfcoreSchema.paramsHelp(workflow, params, command) - help_string += '\n' + citation(workflow) + '\n' - help_string += NfcoreTemplate.dashedLine(params.monochrome_logs) - return help_string - } - - // - // Generate parameter summary log string - // - public static String paramsSummaryLog(workflow, params) { - def summary_log = '' - summary_log += NfcoreTemplate.logo(workflow, params.monochrome_logs) - summary_log += NfcoreSchema.paramsSummaryLog(workflow, params) - summary_log += '\n' + citation(workflow) + '\n' - summary_log += NfcoreTemplate.dashedLine(params.monochrome_logs) - return summary_log - } // // Validate parameters and print summary to screen // public static void initialise(workflow, params, log) { - // Print help to screen if required - if (params.help) { - log.info help(workflow, params) - System.exit(0) - } // Print workflow version and exit on --version if (params.version) { @@ -62,14 +33,6 @@ class WorkflowMain { System.exit(0) } - // Print parameter summary log to screen - log.info paramsSummaryLog(workflow, params) - - // Validate workflow parameters via the JSON schema - if (params.validate_params) { - NfcoreSchema.validateParameters(workflow, params, log) - } - // Check that a -profile or Nextflow config has been provided to run the pipeline NfcoreTemplate.checkConfigProvided(workflow, log) diff --git a/main.nf b/main.nf index 37e6aa09..c67346f2 100644 --- a/main.nf +++ b/main.nf @@ -25,6 +25,22 @@ params.fasta = WorkflowMain.getGenomeAttribute(params, 'fasta') ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +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) /* diff --git a/nextflow.config b/nextflow.config index 9204d8ba..5b2537ca 100644 --- a/nextflow.config +++ b/nextflow.config @@ -12,12 +12,12 @@ params { // TODO nf-core: Specify your pipeline's command line flags // Input options input = null - - // References genome = null igenomes_base = 's3://ngi-igenomes/igenomes' igenomes_ignore = false + + // MultiQC options multiqc_config = null multiqc_title = null @@ -27,7 +27,6 @@ params { // Boilerplate options outdir = null - tracedir = "${params.outdir}/pipeline_info" publish_dir_mode = 'copy' email = null email_on_fail = null @@ -36,19 +35,15 @@ params { hook_url = null help = false version = false - validate_params = true - show_hidden_params = false - schema_ignore_params = 'genomes' - // Config options + config_profile_name = null + config_profile_description = null custom_config_version = 'master' custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" - config_profile_description = null config_profile_contact = null config_profile_url = null - config_profile_name = null - + // Max resource options // Defaults only, expecting to be overwritten @@ -56,6 +51,13 @@ params { max_cpus = 16 max_time = '240.h' + // Schema validation default options + validationFailUnrecognisedParams = false + validationLenientMode = false + validationSchemaIgnoreParams = 'genomes' + validationShowHiddenParams = false + validate_params = true + } // Load base.config by default for all pipelines @@ -75,13 +77,11 @@ try { // } catch (Exception e) { // System.err.println("WARNING: Could not load nf-core/config/bamtofastq profiles: ${params.custom_config_base}/pipeline/bamtofastq.config") // } - - profiles { debug { dumpHashes = true process.beforeScript = 'echo $HOSTNAME' - cleanup = false + cleanup = false } conda { conda.enabled = true @@ -104,7 +104,6 @@ profiles { } docker { docker.enabled = true - docker.registry = 'quay.io' docker.userEmulation = true conda.enabled = false singularity.enabled = false @@ -128,7 +127,6 @@ profiles { } podman { podman.enabled = true - podman.registry = 'quay.io' conda.enabled = false docker.enabled = false singularity.enabled = false @@ -172,6 +170,18 @@ profiles { test_full { includeConfig 'conf/test_full.config' } } +// Set default registry for Apptainer, Docker, Podman and Singularity independent of -profile +// Will not be used unless Apptainer / Docker / Podman / Singularity are enabled +// Set to your registry if you have a mirror of containers +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' + +// Nextflow plugins +plugins { + id 'nf-validation' // Validation of pipeline parameters and creation of an input channel from a sample sheet +} // Load igenomes.config if required if (!params.igenomes_ignore) { @@ -179,8 +189,6 @@ if (!params.igenomes_ignore) { } else { params.genomes = [:] } - - // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. @@ -198,19 +206,19 @@ process.shell = ['/bin/bash', '-euo', 'pipefail'] def trace_timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss') timeline { enabled = true - file = "${params.tracedir}/execution_timeline_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_timeline_${trace_timestamp}.html" } report { enabled = true - file = "${params.tracedir}/execution_report_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/execution_report_${trace_timestamp}.html" } trace { enabled = true - file = "${params.tracedir}/execution_trace_${trace_timestamp}.txt" + file = "${params.outdir}/pipeline_info/execution_trace_${trace_timestamp}.txt" } dag { enabled = true - file = "${params.tracedir}/pipeline_dag_${trace_timestamp}.html" + file = "${params.outdir}/pipeline_info/pipeline_dag_${trace_timestamp}.html" } manifest { @@ -219,8 +227,8 @@ manifest { homePage = 'https://github.com/nf-core/bamtofastq' description = """Workflow converts one or multiple bam/cram files to fastq format""" mainScript = 'main.nf' - nextflowVersion = '!>=22.10.1' - version = '2.0.0dev' + nextflowVersion = '!>=23.04.0' + version = '2.0.0' doi = '' } diff --git a/nextflow_schema.json b/nextflow_schema.json index 5be05a7b..70ee384e 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -15,9 +15,9 @@ "input": { "type": "string", "format": "file-path", + "exists": true, "mimetype": "text/csv", "pattern": "^\\S+\\.csv$", - "schema": "assets/schema_input.json", "description": "Path to comma-separated file containing information about the samples in the experiment.", "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row. See [usage docs](https://nf-co.re/bamtofastq/usage#samplesheet-input).", "fa_icon": "fas fa-file-csv" @@ -57,6 +57,7 @@ "fasta": { "type": "string", "format": "file-path", + "exists": true, "mimetype": "text/plain", "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", "description": "Path to FASTA genome file.", @@ -157,7 +158,7 @@ "description": "Maximum amount of time that can be requested for any single job.", "default": "240.h", "fa_icon": "far fa-clock", - "pattern": "^(\\d+\\.?\\s*(s|m|h|day)\\s*)+$", + "pattern": "^(\\d+\\.?\\s*(s|m|h|d|day)\\s*)+$", "hidden": true, "help_text": "Use to set an upper-limit for the time requirement for each process. Should be a string in the format integer-unit e.g. `--max_time '2.h'`" } @@ -174,12 +175,14 @@ "type": "boolean", "description": "Display help text.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "version": { "type": "boolean", "description": "Display version and exit.", "fa_icon": "fas fa-question-circle", + "default": false, "hidden": true }, "publish_dir_mode": { @@ -203,6 +206,7 @@ "type": "boolean", "description": "Send plain-text email instead of HTML.", "fa_icon": "fas fa-remove-format", + "default": false, "hidden": true }, "max_multiqc_email_size": { @@ -217,6 +221,7 @@ "type": "boolean", "description": "Do not use coloured log outputs.", "fa_icon": "fas fa-palette", + "default": false, "hidden": true }, "hook_url": { @@ -228,6 +233,7 @@ }, "multiqc_config": { "type": "string", + "format": "file-path", "description": "Custom config file to supply to MultiQC.", "fa_icon": "fas fa-cog", "hidden": true @@ -243,13 +249,6 @@ "description": "Custom MultiQC yaml file containing HTML including a methods description.", "fa_icon": "fas fa-cog" }, - "tracedir": { - "type": "string", - "description": "Directory to keep pipeline Nextflow logs and reports.", - "default": "${params.outdir}/pipeline_info", - "fa_icon": "fas fa-cogs", - "hidden": true - }, "validate_params": { "type": "boolean", "description": "Boolean whether to validate parameters against the schema at runtime", @@ -257,12 +256,29 @@ "fa_icon": "fas fa-check-square", "hidden": true }, - "show_hidden_params": { + "validationShowHiddenParams": { "type": "boolean", "fa_icon": "far fa-eye-slash", "description": "Show all params when using `--help`", + "default": false, "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." + }, + "validationFailUnrecognisedParams": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters fails when an unrecognised parameter is found.", + "default": false, + "hidden": true, + "help_text": "By default, when an unrecognised parameter is found, it returns a warinig." + }, + "validationLenientMode": { + "type": "boolean", + "fa_icon": "far fa-check-circle", + "description": "Validation of parameters in lenient more.", + "default": false, + "hidden": true, + "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." } } } diff --git a/workflows/bamtofastq.nf b/workflows/bamtofastq.nf index 932f37eb..18e87139 100644 --- a/workflows/bamtofastq.nf +++ b/workflows/bamtofastq.nf @@ -1,21 +1,19 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - VALIDATE INPUTS + PRINT PARAMS SUMMARY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -def summary_params = NfcoreSchema.paramsSummaryMap(workflow, params) +include { paramsSummaryLog; paramsSummaryMap } from 'plugin/nf-validation' -// Validate input parameters -WorkflowBamtofastq.initialise(params, log) +def logo = NfcoreTemplate.logo(workflow, params.monochrome_logs) +def citation = '\n' + WorkflowMain.citation(workflow) + '\n' +def summary_params = paramsSummaryMap(workflow) -// TODO nf-core: Add all file path parameters for the pipeline to the list below -// Check input path parameters to see if they exist -def checkPathParamList = [ params.input, params.multiqc_config, params.fasta ] -for (param in checkPathParamList) { if (param) { file(param, checkIfExists: true) } } +// Print parameter summary log to screen +log.info logo + paramsSummaryLog(workflow) + citation -// Check mandatory parameters -if (params.input) { ch_input = file(params.input) } else { exit 1, 'Input samplesheet not specified!' } +WorkflowBamtofastq.initialise(params, log) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -69,9 +67,12 @@ workflow BAMTOFASTQ { // SUBWORKFLOW: Read in samplesheet, validate and stage input files // INPUT_CHECK ( - ch_input + file(params.input) ) ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) + // TODO: OPTIONAL, you can use nf-validation plugin to create an input channel from the samplesheet with Channel.fromSamplesheet("input") + // See the documentation https://nextflow-io.github.io/nf-validation/samplesheets/fromSamplesheet/ + // ! There is currently no tooling to help you write a sample sheet schema // // MODULE: Run FastQC @@ -91,7 +92,7 @@ workflow BAMTOFASTQ { workflow_summary = WorkflowBamtofastq.paramsSummaryMultiqc(workflow, summary_params) ch_workflow_summary = Channel.value(workflow_summary) - methods_description = WorkflowBamtofastq.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description) + methods_description = WorkflowBamtofastq.methodsDescriptionText(workflow, ch_multiqc_custom_methods_description, params) ch_methods_description = Channel.value(methods_description) ch_multiqc_files = Channel.empty() From 3eaea230f04106a69b4f67ecdb114ebb771ce515 Mon Sep 17 00:00:00 2001 From: SusiJo <43847534+SusiJo@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:13:23 +0200 Subject: [PATCH 2/4] Update assets/multiqc_config.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Júlia Mir Pedrol --- assets/multiqc_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index e065163e..304d1cbc 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,5 +1,5 @@ report_comment: > - This report has been generated by the nf-core/bamtofastq + This report has been generated by the nf-core/bamtofastq analysis pipeline. For information about how to interpret these results, please see the documentation. report_section_order: From 95edcf42be2b6049d099c013c0b148e83baa634a Mon Sep 17 00:00:00 2001 From: SusiJo <43847534+SusiJo@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:13:43 +0200 Subject: [PATCH 3/4] Update assets/multiqc_config.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Júlia Mir Pedrol --- assets/multiqc_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 304d1cbc..70f11347 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,7 @@ report_comment: > This report has been generated by the nf-core/bamtofastq analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: "nf-core-bamtofastq-methods-description": order: -1000 From e6910441a62b9ff933b9701baf01dc61d9ed531b Mon Sep 17 00:00:00 2001 From: "susanne.jodoin@gmx.de" Date: Mon, 17 Jul 2023 11:27:26 +0200 Subject: [PATCH 4/4] apply review suggestions --- .github/workflows/awsfulltest.yml | 3 --- CHANGELOG.md | 2 ++ nextflow_schema.json | 12 ++++-------- workflows/bamtofastq.nf | 18 ++++-------------- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 3679cfed..81fcd1e7 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -15,9 +15,6 @@ jobs: steps: - name: Launch workflow via tower uses: seqeralabs/action-tower-launch@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: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 9488efd9..2b9829a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### `Added` +- [#61](https://github.com/nf-core/bamtofastq/pull/61) Sync TEMPLATE with tools 2.9 + ### `Changed` ### `Fixed` diff --git a/nextflow_schema.json b/nextflow_schema.json index b7681493..3155f2b1 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -38,7 +38,6 @@ "properties": { "chr": { "type": "string", - "default": "None", "fa_icon": "fas fa-clock", "description": "Only use reads mapping to a specific chromosome/region. Has to be specified as in bam: i.e chr1, chr{1..22} (gets all reads mapping to chr1 to 22), 1, \"X Y\", incorrect naming will lead to a potentially silent error." }, @@ -90,6 +89,7 @@ "fasta_fai": { "type": "string", "format": "file-path", + "exists": true, "mimetype": "text/plain", "pattern": "^\\S+\\.fn?a(sta).fai?(\\.gz)?$", "description": "Path to FASTA FAI genome index file.", @@ -207,14 +207,12 @@ "type": "boolean", "description": "Display help text.", "fa_icon": "fas fa-question-circle", - "default": false, "hidden": true }, "version": { "type": "boolean", "description": "Display version and exit.", "fa_icon": "fas fa-question-circle", - "default": false, "hidden": true }, "publish_dir_mode": { @@ -245,7 +243,6 @@ "type": "boolean", "description": "Send plain-text email instead of HTML.", "fa_icon": "fas fa-remove-format", - "default": false, "hidden": true }, "max_multiqc_email_size": { @@ -260,7 +257,6 @@ "type": "boolean", "description": "Do not use coloured log outputs.", "fa_icon": "fas fa-palette", - "default": false, "hidden": true }, "hook_url": { @@ -277,6 +273,7 @@ }, "multiqc_config": { "type": "string", + "exists": true, "format": "file-path", "description": "Custom config file to supply to MultiQC.", "fa_icon": "fas fa-cog", @@ -284,12 +281,14 @@ }, "multiqc_logo": { "type": "string", + "exists": true, "description": "Custom logo file to supply to MultiQC. File name must also be set in the MultiQC config file", "fa_icon": "fas fa-image", "hidden": true }, "multiqc_methods_description": { "type": "string", + "exists": true, "description": "Custom MultiQC yaml file containing HTML including a methods description.", "fa_icon": "fas fa-cog" }, @@ -304,7 +303,6 @@ "type": "boolean", "fa_icon": "far fa-eye-slash", "description": "Show all params when using `--help`", - "default": false, "hidden": true, "help_text": "By default, parameters set as _hidden_ in the schema are not shown on the command line when a user runs with `--help`. Specifying this option will tell the pipeline to show all parameters." }, @@ -312,7 +310,6 @@ "type": "boolean", "fa_icon": "far fa-check-circle", "description": "Validation of parameters fails when an unrecognised parameter is found.", - "default": false, "hidden": true, "help_text": "By default, when an unrecognised parameter is found, it returns a warinig." }, @@ -320,7 +317,6 @@ "type": "boolean", "fa_icon": "far fa-check-circle", "description": "Validation of parameters in lenient more.", - "default": false, "hidden": true, "help_text": "Allows string values that are parseable as numbers or booleans. For further information see [JSONSchema docs](https://github.com/everit-org/json-schema#lenient-mode)." } diff --git a/workflows/bamtofastq.nf b/workflows/bamtofastq.nf index 8b723b50..ff1ca50e 100644 --- a/workflows/bamtofastq.nf +++ b/workflows/bamtofastq.nf @@ -15,18 +15,8 @@ log.info logo + paramsSummaryLog(workflow) + citation WorkflowBamtofastq.initialise(params, log) -// Check input path parameters to see if they exist -def checkPathParamList = [ - params.fasta, - params.fasta_fai, - params.input, - params.multiqc_config - ] - -for (param in checkPathParamList) { if (param) { file(param, checkIfExists: true) } } - // Check mandatory parameters -if (params.input) { ch_input = extract_csv(file(params.input, checkIfExists: true)) } else { exit 1, 'Input samplesheet not specified!' } +ch_input = extract_csv(file(params.input)) // Initialize file channels based on params @@ -43,9 +33,9 @@ chr = params.chr ?: Channel.empty() */ ch_multiqc_config = Channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) -ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath( params.multiqc_config, checkIfExists: true ) : Channel.empty() -ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath( params.multiqc_logo, checkIfExists: true ) : Channel.empty() -ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) +ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath( params.multiqc_config ) : Channel.empty() +ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath( params.multiqc_logo ) : Channel.empty() +ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~