From 607dd932817deb9563c31398db4959eaaf4cb976 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Mon, 14 Oct 2024 14:31:08 +0100 Subject: [PATCH 01/34] update quantms-utils=0.0.12 thermorawfileparser=1.4.5 --- CHANGELOG.md | 2 ++ modules/local/thermorawfileparser/main.nf | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d006dfd28..920bfe1d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### `Changed` - [#423](https://github.com/bigbio/quantms/pull/423) Updated OpenMS==3.2.0 +- [#423]() Update thermorawfileparser==1.4.5 +- [#423]() Update quantms-utils==0.0.12 ### `Fixed` diff --git a/modules/local/thermorawfileparser/main.nf b/modules/local/thermorawfileparser/main.nf index dba9e3284..83b30dbf3 100644 --- a/modules/local/thermorawfileparser/main.nf +++ b/modules/local/thermorawfileparser/main.nf @@ -4,10 +4,10 @@ process THERMORAWFILEPARSER { label 'process_single' label 'error_retry' - conda "conda-forge::mono bioconda::thermorawfileparser=1.4.3" + conda "conda-forge::mono bioconda::thermorawfileparser=1.4.5" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/thermorawfileparser:1.4.3--ha8f3691_0' : - 'biocontainers/thermorawfileparser:1.4.3--ha8f3691_0' }" + 'https://depot.galaxyproject.org/singularity/thermorawfileparser:1.4.5--ha8f3691_0' : + 'biocontainers/thermorawfileparser:1.4.5--ha8f3691_0' }" stageInMode { if (task.attempt == 1) { From 50515a3f33f6fb2b17028913578834a160c5833d Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 11:53:37 +0100 Subject: [PATCH 02/34] change schema to https --- assets/schema_input.json | 2 +- nextflow_schema.json | 2 +- .../utils_nfvalidation_plugin/tests/nextflow_schema.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/schema_input.json b/assets/schema_input.json index 83c023e52..8b1ddd111 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft-07/schema", "$id": "https://raw.githubusercontent.com/nf-core/quantms/master/assets/schema_input.json", "title": "nf-core/quantms pipeline - params.input schema", "description": "Schema for the file provided with params.input", diff --git a/nextflow_schema.json b/nextflow_schema.json index 70933632e..d4e6350b2 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft-07/schema", "$id": "https://raw.githubusercontent.com/nf-core/quantms/master/nextflow_schema.json", "title": "nf-core/quantms pipeline parameters", "description": "Quantitative Mass Spectrometry nf-core workflow", diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json index 7626c1c93..b7af0b577 100644 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json +++ b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft-07/schema", "$id": "https://raw.githubusercontent.com/./master/nextflow_schema.json", "title": ". pipeline parameters", "description": "", From de7c4eed09ff4f7839420682f8ea4f5b088c8ef1 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 11:55:42 +0100 Subject: [PATCH 03/34] change schema to https --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 920bfe1d6..1be5825e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#386](https://github.com/bigbio/quantms/pull/386) Make validation of ontology terms optional - [#398](https://github.com/bigbio/quantms/pull/398) Python scripts moved to quantms-utils package - [#389](https://github.com/bigbio/quantms/pull/389) Introduction to DIANN 1.9.1 to the pipeline, only available in Singularity. -- [#396](https://github.com/bigbio/quantms/pull/396) Adds verification step to unpacking tar archives in the DECOMPRESS process +- [#396](https://github.com/bigbio/quantms/pull/396) Adds a verification step to unpacking tar archives in the DECOMPRESS process - [#397](https://github.com/bigbio/quantms/pull/397) More options included in SDRF validation. - [#404](https://github.com/bigbio/quantms/pull/404) Add spectrum SNR features to rescore From 9a3a724163c0646b679cac98847fbc4c74c55279 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 12:09:57 +0100 Subject: [PATCH 04/34] linting changes --- .github/workflows/linting.yml | 23 +++++++++++++++++++---- .github/workflows/linting_comment.yml | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 1fcafe880..b882838af 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,6 +1,6 @@ name: nf-core linting # This workflow is triggered on pushes and PRs to the repository. -# It runs the `nf-core lint` and markdown lint tests to ensure +# It runs the `nf-core pipelines lint` and markdown lint tests to ensure # that the code meets the nf-core guidelines. on: push: @@ -41,17 +41,32 @@ jobs: python-version: "3.12" architecture: "x64" + - name: read .nf-core.yml + uses: pietrobolcato/action-read-yaml@1.0.0 + id: read_yml + with: + config: ${{ github.workspace }}/.nf-core.yaml + - name: Install dependencies run: | python -m pip install --upgrade pip - pip install nf-core + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Run nf-core pipelines lint + if: ${{ github.base_ref != 'master' }} + env: + GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} + run: nf-core -l lint_log.txt pipelines lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - - name: Run nf-core lint + - name: Run nf-core pipelines lint --release + if: ${{ github.base_ref == 'master' }} env: GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} - run: nf-core -l lint_log.txt lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md + run: nf-core -l lint_log.txt pipelines lint --release --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - name: Save PR number if: ${{ always() }} diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 40acc23f5..42e519bfa 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3 + uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6 with: workflow: linting.yml workflow_conclusion: completed From 52054b7e18ea19684a19075d3fbbf6133e46cd38 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 12:13:02 +0100 Subject: [PATCH 05/34] linting changes --- .github/workflows/linting.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index b882838af..a502573c5 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -42,10 +42,10 @@ jobs: architecture: "x64" - name: read .nf-core.yml - uses: pietrobolcato/action-read-yaml@1.0.0 + uses: pietrobolcato/action-read-yaml@1.1.0 id: read_yml with: - config: ${{ github.workspace }}/.nf-core.yaml + config: ${{ github.workspace }}/.nf-core.yml - name: Install dependencies run: | From d3f05390be10ff68101d5867d8c200f83768abc8 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 12:18:28 +0100 Subject: [PATCH 06/34] Template update for nf-core/tools version 3.0.2 --- .editorconfig | 6 +- .github/CONTRIBUTING.md | 12 +- .github/PULL_REQUEST_TEMPLATE.md | 4 +- .github/workflows/awsfulltest.yml | 35 +- .github/workflows/awstest.yml | 12 +- .github/workflows/ci.yml | 61 ++- .github/workflows/download_pipeline.yml | 73 +++- .github/workflows/fix-linting.yml | 6 +- .github/workflows/linting.yml | 42 +- .github/workflows/linting_comment.yml | 2 +- .github/workflows/release-announcements.yml | 6 +- .../workflows/template_version_comment.yml | 46 +++ .gitignore | 1 + .gitpod.yml | 7 +- .nf-core.yml | 26 ++ .pre-commit-config.yaml | 5 +- CHANGELOG.md | 2 +- CITATIONS.md | 4 +- README.md | 7 +- assets/nf-core-quantms_logo_light.png | Bin 74651 -> 74647 bytes assets/schema_input.json | 2 +- conf/base.config | 37 +- conf/igenomes_ignored.config | 9 + conf/modules.config | 9 - conf/test.config | 15 +- conf/test_full.config | 2 +- docs/images/mqc_fastqc_adapter.png | Bin 23458 -> 0 bytes docs/images/mqc_fastqc_counts.png | Bin 33918 -> 0 bytes docs/images/mqc_fastqc_quality.png | Bin 55769 -> 0 bytes docs/images/nf-core-quantms_logo_dark.png | Bin 27122 -> 27119 bytes docs/images/nf-core-quantms_logo_light.png | Bin 23385 -> 23358 bytes docs/output.md | 10 - docs/usage.md | 14 +- main.nf | 8 - modules.json | 12 +- modules/nf-core/fastqc/environment.yml | 2 - modules/nf-core/fastqc/main.nf | 9 + modules/nf-core/fastqc/meta.yml | 57 +-- modules/nf-core/fastqc/tests/main.nf.test | 225 ++++++++--- .../nf-core/fastqc/tests/main.nf.test.snap | 370 ++++++++++++++++-- modules/nf-core/multiqc/environment.yml | 4 +- modules/nf-core/multiqc/main.nf | 16 +- modules/nf-core/multiqc/meta.yml | 78 ++-- modules/nf-core/multiqc/tests/main.nf.test | 8 + .../nf-core/multiqc/tests/main.nf.test.snap | 24 +- modules/nf-core/multiqc/tests/nextflow.config | 5 + nextflow.config | 310 ++++++++------- nextflow_schema.json | 88 +---- pyproject.toml | 15 - .../utils_nfcore_quantms_pipeline/main.nf | 78 ++-- .../nf-core/utils_nextflow_pipeline/main.nf | 70 ++-- .../tests/nextflow.config | 2 +- .../nf-core/utils_nfcore_pipeline/main.nf | 306 ++++++++------- .../nf-core/utils_nfschema_plugin/main.nf | 46 +++ .../nf-core/utils_nfschema_plugin/meta.yml | 35 ++ .../utils_nfschema_plugin/tests/main.nf.test | 117 ++++++ .../tests/nextflow.config | 8 + .../tests/nextflow_schema.json | 8 +- .../nf-core/utils_nfvalidation_plugin/main.nf | 62 --- .../utils_nfvalidation_plugin/meta.yml | 44 --- .../tests/main.nf.test | 200 ---------- .../utils_nfvalidation_plugin/tests/tags.yml | 2 - workflows/quantms.nf | 59 ++- 63 files changed, 1612 insertions(+), 1111 deletions(-) create mode 100644 .github/workflows/template_version_comment.yml create mode 100644 conf/igenomes_ignored.config delete mode 100755 docs/images/mqc_fastqc_adapter.png delete mode 100755 docs/images/mqc_fastqc_counts.png delete mode 100755 docs/images/mqc_fastqc_quality.png create mode 100644 modules/nf-core/multiqc/tests/nextflow.config delete mode 100644 pyproject.toml create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/main.nf create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/meta.yml create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test create mode 100644 subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config rename subworkflows/nf-core/{utils_nfvalidation_plugin => utils_nfschema_plugin}/tests/nextflow_schema.json (95%) delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/main.nf delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test delete mode 100644 subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml diff --git a/.editorconfig b/.editorconfig index dd9ffa538..72dda289a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -28,10 +28,6 @@ indent_style = unset [/assets/email*] indent_size = unset -# ignore Readme -[README.md] -indent_style = unset - -# ignore python +# ignore python and markdown [*.{py,md}] indent_style = unset diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index de8d5a870..d5352bc50 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -19,7 +19,7 @@ If you'd like to write some code for nf-core/quantms, the standard workflow is a 1. Check that there isn't already an issue about your idea in the [nf-core/quantms issues](https://github.com/nf-core/quantms/issues) to avoid duplicating work. If there isn't one already, please create one so that others know you're working on this 2. [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the [nf-core/quantms repository](https://github.com/nf-core/quantms) to your GitHub account 3. Make the necessary changes / additions within your forked repository following [Pipeline conventions](#pipeline-contribution-conventions) -4. Use `nf-core schema build` and add any new parameters to the pipeline JSON schema (requires [nf-core tools](https://github.com/nf-core/tools) >= 1.10). +4. Use `nf-core pipelines schema build` and add any new parameters to the pipeline JSON schema (requires [nf-core tools](https://github.com/nf-core/tools) >= 1.10). 5. Submit a Pull Request against the `dev` branch and wait for the code to be reviewed and merged If you're not used to this workflow with git, you can start with some [docs from GitHub](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests) or even their [excellent `git` resources](https://try.github.io/). @@ -40,7 +40,7 @@ There are typically two types of tests that run: ### Lint tests `nf-core` has a [set of guidelines](https://nf-co.re/developers/guidelines) which all pipelines must adhere to. -To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core lint ` command. +To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core pipelines lint ` command. If any failures or warnings are encountered, please follow the listed URL for more documentation. @@ -75,7 +75,7 @@ If you wish to contribute a new step, please use the following coding standards: 2. Write the process block (see below). 3. Define the output channel if needed (see below). 4. Add any new parameters to `nextflow.config` with a default (see below). -5. Add any new parameters to `nextflow_schema.json` with help text (via the `nf-core schema build` tool). +5. Add any new parameters to `nextflow_schema.json` with help text (via the `nf-core pipelines schema build` tool). 6. Add sanity checks and validation for all relevant parameters. 7. Perform local tests to validate that the new code works as expected. 8. If applicable, add a new test command in `.github/workflow/ci.yml`. @@ -86,11 +86,11 @@ If you wish to contribute a new step, please use the following coding standards: Parameters should be initialised / defined with default values in `nextflow.config` under the `params` scope. -Once there, use `nf-core schema build` to add to `nextflow_schema.json`. +Once there, use `nf-core pipelines schema build` to add to `nextflow_schema.json`. ### Default processes resource requirements -Sensible defaults for process resource requirements (CPUs / memory / time) for a process should be defined in `conf/base.config`. These should generally be specified generic with `withLabel:` selectors so they can be shared across multiple processes/steps of the pipeline. A nf-core standard set of labels that should be followed where possible can be seen in the [nf-core pipeline template](https://github.com/nf-core/tools/blob/master/nf_core/pipeline-template/conf/base.config), which has the default process as a single core-process, and then different levels of multi-core configurations for increasingly large memory requirements defined with standardised labels. +Sensible defaults for process resource requirements (CPUs / memory / time) for a process should be defined in `conf/base.config`. These should generally be specified generic with `withLabel:` selectors so they can be shared across multiple processes/steps of the pipeline. A nf-core standard set of labels that should be followed where possible can be seen in the [nf-core pipeline template](https://github.com/nf-core/tools/blob/main/nf_core/pipeline-template/conf/base.config), which has the default process as a single core-process, and then different levels of multi-core configurations for increasingly large memory requirements defined with standardised labels. The process resources can be passed on to the tool dynamically within the process with the `${task.cpus}` and `${task.memory}` variables in the `script:` block. @@ -103,7 +103,7 @@ Please use the following naming schemes, to make it easy to understand what is g ### Nextflow version bumping -If you are using a new feature from core Nextflow, you may bump the minimum required version of nextflow in the pipeline with: `nf-core bump-version --nextflow . [min-nf-version]` +If you are using a new feature from core Nextflow, you may bump the minimum required version of nextflow in the pipeline with: `nf-core pipelines bump-version --nextflow . [min-nf-version]` ### Images and figures diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6e6e8ffe3..195e7b5ea 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -17,8 +17,8 @@ Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/quan - [ ] If you've fixed a bug or added code that should be tested, add tests! - [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/quantms/tree/master/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/quantms _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. -- [ ] Make sure your code lints (`nf-core lint`). -- [ ] Ensure the test suite passes (`nf-test test main.nf.test -profile test,docker`). +- [ ] Make sure your code lints (`nf-core pipelines lint`). +- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). - [ ] Check for unexpected warnings in debug mode (`nextflow run . -profile debug,test,docker --outdir `). - [ ] Usage Documentation in `docs/usage.md` is updated. - [ ] Output Documentation in `docs/output.md` is updated. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index d47fb0e56..50500c920 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -1,19 +1,36 @@ name: nf-core AWS full size tests -# This workflow is triggered on published releases. +# This workflow is triggered on PRs opened against the master branch. # It can be additionally triggered manually with GitHub actions workflow dispatch button. # It runs the -profile 'test_full' on AWS batch on: - release: - types: [published] + pull_request: + branches: + - master workflow_dispatch: + pull_request_review: + types: [submitted] + jobs: - run-tower: + run-platform: name: Run AWS full tests - if: github.repository == 'nf-core/quantms' + # run only if the PR is approved by at least 2 reviewers and against the master branch or manually triggered + if: github.repository == 'nf-core/quantms' && github.event.review.state == 'approved' && github.event.pull_request.base.ref == 'master' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - - name: Launch workflow via tower + - uses: octokit/request-action@v2.x + id: check_approvals + with: + route: GET /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - id: test_variables + if: github.event_name != 'workflow_dispatch' + run: | + JSON_RESPONSE='${{ steps.check_approvals.outputs.data }}' + CURRENT_APPROVALS_COUNT=$(echo $JSON_RESPONSE | jq -c '[.[] | select(.state | contains("APPROVED")) ] | length') + test $CURRENT_APPROVALS_COUNT -ge 2 || exit 1 # At least 2 approvals are required + - name: Launch workflow via Seqera Platform 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) @@ -33,7 +50,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: Tower debug log file + name: Seqera Platform debug log file path: | - tower_action_*.log - tower_action_*.json + seqera_platform_action_*.log + seqera_platform_action_*.json diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index fe39ac983..fc6b10f70 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -5,13 +5,13 @@ name: nf-core AWS test on: workflow_dispatch: jobs: - run-tower: + run-platform: name: Run AWS tests if: github.repository == 'nf-core/quantms' runs-on: ubuntu-latest steps: - # Launch workflow using Tower CLI tool action - - name: Launch workflow via tower + # Launch workflow using Seqera Platform CLI tool action + - name: Launch workflow via Seqera Platform uses: seqeralabs/action-tower-launch@v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} @@ -27,7 +27,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: Tower debug log file + name: Seqera Platform debug log file path: | - tower_action_*.log - tower_action_*.json + seqera_platform_action_*.log + seqera_platform_action_*.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dda50a239..1b025a779 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,9 +7,12 @@ on: pull_request: release: types: [published] + workflow_dispatch: env: NXF_ANSI_LOG: false + NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity + NXF_SINGULARITY_LIBRARYDIR: ${{ github.workspace }}/.singularity concurrency: group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" @@ -17,30 +20,66 @@ concurrency: jobs: test: - name: Run pipeline with test data + name: "Run pipeline with test data (${{ matrix.NXF_VER }} | ${{ matrix.test_name }} | ${{ matrix.profile }})" # Only run on push if this is the nf-core dev branch (merged PRs) if: "${{ github.event_name != 'push' || (github.event_name == 'push' && github.repository == 'nf-core/quantms') }}" runs-on: ubuntu-latest strategy: matrix: NXF_VER: - - "23.04.0" + - "24.04.2" - "latest-everything" + profile: + - "conda" + - "docker" + - "singularity" + test_name: + - "test" + isMaster: + - ${{ github.base_ref == 'master' }} + # Exclude conda and singularity on dev + exclude: + - isMaster: false + profile: "conda" + - isMaster: false + profile: "singularity" steps: - name: Check out pipeline code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 - - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + - name: Set up Nextflow + uses: nf-core/setup-nextflow@v2 with: version: "${{ matrix.NXF_VER }}" - - name: Disk space cleanup + - name: Set up Apptainer + if: matrix.profile == 'singularity' + uses: eWaterCycle/setup-apptainer@main + + - name: Set up Singularity + if: matrix.profile == 'singularity' + run: | + mkdir -p $NXF_SINGULARITY_CACHEDIR + mkdir -p $NXF_SINGULARITY_LIBRARYDIR + + - name: Set up Miniconda + if: matrix.profile == 'conda' + uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3 + with: + miniconda-version: "latest" + auto-update-conda: true + conda-solver: libmamba + channels: conda-forge,bioconda + + - name: Set up Conda + if: matrix.profile == 'conda' + run: | + echo $(realpath $CONDA)/condabin >> $GITHUB_PATH + echo $(realpath python) >> $GITHUB_PATH + + - name: Clean up Disk space uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 - - name: Run pipeline with test data - # TODO nf-core: You can customise CI pipeline run tests as required - # For example: adding multiple test runs with different parameters - # Remember that you can parallelise this by using strategy.matrix + - name: "Run pipeline with test data ${{ matrix.NXF_VER }} | ${{ matrix.test_name }} | ${{ matrix.profile }}" run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results + nextflow run ${GITHUB_WORKSPACE} -profile ${{ matrix.test_name }},${{ matrix.profile }} --outdir ./results diff --git a/.github/workflows/download_pipeline.yml b/.github/workflows/download_pipeline.yml index 08622fd51..713dc3e73 100644 --- a/.github/workflows/download_pipeline.yml +++ b/.github/workflows/download_pipeline.yml @@ -1,4 +1,4 @@ -name: Test successful pipeline download with 'nf-core download' +name: Test successful pipeline download with 'nf-core pipelines download' # Run the workflow when: # - dispatched manually @@ -8,12 +8,14 @@ on: workflow_dispatch: inputs: testbranch: - description: "The specific branch you wish to utilize for the test execution of nf-core download." + description: "The specific branch you wish to utilize for the test execution of nf-core pipelines download." required: true default: "dev" pull_request: types: - opened + - edited + - synchronize branches: - master pull_request_target: @@ -28,15 +30,20 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@v2 - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: "3.11" + python-version: "3.12" architecture: "x64" - - uses: eWaterCycle/setup-singularity@931d4e31109e875b13309ae1d07c70ca8fbc8537 # v7 + + - name: Setup Apptainer + uses: eWaterCycle/setup-apptainer@4bb22c52d4f63406c49e94c804632975787312b3 # v2.0.0 with: - singularity-version: 3.8.3 + apptainer-version: 1.3.4 - name: Install dependencies run: | @@ -49,24 +56,64 @@ jobs: echo "REPOTITLE_LOWERCASE=$(basename ${GITHUB_REPOSITORY,,})" >> ${GITHUB_ENV} echo "REPO_BRANCH=${{ github.event.inputs.testbranch || 'dev' }}" >> ${GITHUB_ENV} + - name: Make a cache directory for the container images + run: | + mkdir -p ./singularity_container_images + - name: Download the pipeline env: - NXF_SINGULARITY_CACHEDIR: ./ + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images run: | - nf-core download ${{ env.REPO_LOWERCASE }} \ + nf-core pipelines download ${{ env.REPO_LOWERCASE }} \ --revision ${{ env.REPO_BRANCH }} \ --outdir ./${{ env.REPOTITLE_LOWERCASE }} \ --compress "none" \ --container-system 'singularity' \ - --container-library "quay.io" -l "docker.io" -l "ghcr.io" \ + --container-library "quay.io" -l "docker.io" -l "community.wave.seqera.io" \ --container-cache-utilisation 'amend' \ - --download-configuration + --download-configuration 'yes' - name: Inspect download run: tree ./${{ env.REPOTITLE_LOWERCASE }} - - name: Run the downloaded pipeline + - name: Count the downloaded number of container images + id: count_initial + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Initial container image count: $image_count" + echo "IMAGE_COUNT_INITIAL=$image_count" >> ${GITHUB_ENV} + + - name: Run the downloaded pipeline (stub) + id: stub_run_pipeline + continue-on-error: true env: - NXF_SINGULARITY_CACHEDIR: ./ + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images NXF_SINGULARITY_HOME_MOUNT: true run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -stub -profile test,singularity --outdir ./results + - name: Run the downloaded pipeline (stub run not supported) + id: run_pipeline + if: ${{ job.steps.stub_run_pipeline.status == failure() }} + env: + NXF_SINGULARITY_CACHEDIR: ./singularity_container_images + NXF_SINGULARITY_HOME_MOUNT: true + run: nextflow run ./${{ env.REPOTITLE_LOWERCASE }}/$( sed 's/\W/_/g' <<< ${{ env.REPO_BRANCH }}) -profile test,singularity --outdir ./results + + - name: Count the downloaded number of container images + id: count_afterwards + run: | + image_count=$(ls -1 ./singularity_container_images | wc -l | xargs) + echo "Post-pipeline run container image count: $image_count" + echo "IMAGE_COUNT_AFTER=$image_count" >> ${GITHUB_ENV} + + - name: Compare container image counts + run: | + if [ "${{ env.IMAGE_COUNT_INITIAL }}" -ne "${{ env.IMAGE_COUNT_AFTER }}" ]; then + initial_count=${{ env.IMAGE_COUNT_INITIAL }} + final_count=${{ env.IMAGE_COUNT_AFTER }} + difference=$((final_count - initial_count)) + echo "$difference additional container images were \n downloaded at runtime . The pipeline has no support for offline runs!" + tree ./singularity_container_images + exit 1 + else + echo "The pipeline can be downloaded successfully!" + fi diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml index 4549bf44c..0b0d5e658 100644 --- a/.github/workflows/fix-linting.yml +++ b/.github/workflows/fix-linting.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 with: token: ${{ secrets.nf_core_bot_auth_token }} @@ -32,9 +32,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} # Install and run pre-commit - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: 3.11 + python-version: "3.12" - name: Install pre-commit run: pip install pre-commit diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 073e18767..a502573c5 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,6 +1,6 @@ name: nf-core linting # This workflow is triggered on pushes and PRs to the repository. -# It runs the `nf-core lint` and markdown lint tests to ensure +# It runs the `nf-core pipelines lint` and markdown lint tests to ensure # that the code meets the nf-core guidelines. on: push: @@ -14,13 +14,12 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 - - name: Set up Python 3.11 - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - name: Set up Python 3.12 + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: 3.11 - cache: "pip" + python-version: "3.12" - name: Install pre-commit run: pip install pre-commit @@ -32,27 +31,42 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 - name: Install Nextflow - uses: nf-core/setup-nextflow@v1 + uses: nf-core/setup-nextflow@v2 - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: - python-version: "3.11" + python-version: "3.12" architecture: "x64" + - name: read .nf-core.yml + uses: pietrobolcato/action-read-yaml@1.1.0 + id: read_yml + with: + config: ${{ github.workspace }}/.nf-core.yml + - name: Install dependencies run: | python -m pip install --upgrade pip - pip install nf-core + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Run nf-core pipelines lint + if: ${{ github.base_ref != 'master' }} + env: + GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} + run: nf-core -l lint_log.txt pipelines lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - - name: Run nf-core lint + - name: Run nf-core pipelines lint --release + if: ${{ github.base_ref == 'master' }} env: GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_PR_COMMIT: ${{ github.event.pull_request.head.sha }} - run: nf-core -l lint_log.txt lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md + run: nf-core -l lint_log.txt pipelines lint --release --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - name: Save PR number if: ${{ always() }} @@ -60,7 +74,7 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4 with: name: linting-logs path: | diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index b706875fc..42e519bfa 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@f6b0bace624032e30a85a8fd9c1a7f8f611f5737 # v3 + uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6 with: workflow: linting.yml workflow_conclusion: completed diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index d468aeaae..c6ba35df4 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -12,7 +12,7 @@ jobs: - name: get topics and convert to hashtags id: get_topics run: | - curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ' >> $GITHUB_OUTPUT + echo "topics=$(curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ')" | sed 's/-//g' >> $GITHUB_OUTPUT - uses: rzr/fediverse-action@master with: @@ -25,13 +25,13 @@ jobs: Please see the changelog: ${{ github.event.release.html_url }} - ${{ steps.get_topics.outputs.GITHUB_OUTPUT }} #nfcore #openscience #nextflow #bioinformatics + ${{ steps.get_topics.outputs.topics }} #nfcore #openscience #nextflow #bioinformatics send-tweet: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 with: python-version: "3.10" - name: Install dependencies diff --git a/.github/workflows/template_version_comment.yml b/.github/workflows/template_version_comment.yml new file mode 100644 index 000000000..e8aafe44d --- /dev/null +++ b/.github/workflows/template_version_comment.yml @@ -0,0 +1,46 @@ +name: nf-core template version comment +# This workflow is triggered on PRs to check if the pipeline template version matches the latest nf-core version. +# It posts a comment to the PR, even if it comes from a fork. + +on: pull_request_target + +jobs: + template_version: + runs-on: ubuntu-latest + steps: + - name: Check out pipeline code + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Read template version from .nf-core.yml + uses: nichmor/minimal-read-yaml@v0.0.2 + id: read_yml + with: + config: ${{ github.workspace }}/.nf-core.yml + + - name: Install nf-core + run: | + python -m pip install --upgrade pip + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + + - name: Check nf-core outdated + id: nf_core_outdated + run: echo "OUTPUT=$(pip list --outdated | grep nf-core)" >> ${GITHUB_ENV} + + - name: Post nf-core template version comment + uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 + if: | + contains(env.OUTPUT, 'nf-core') + with: + repo-token: ${{ secrets.NF_CORE_BOT_AUTH_TOKEN }} + allow-repeats: false + message: | + > [!WARNING] + > Newer version of the nf-core template is available. + > + > Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. + > Please update your pipeline to the latest version. + > + > For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). + # diff --git a/.gitignore b/.gitignore index 5124c9ac7..a42ce0162 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ results/ testing/ testing* *.pyc +null/ diff --git a/.gitpod.yml b/.gitpod.yml index 105a1821a..461186376 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -4,17 +4,14 @@ tasks: command: | pre-commit install --install-hooks nextflow self-update - - name: unset JAVA_TOOL_OPTIONS - command: | - unset JAVA_TOOL_OPTIONS vscode: extensions: # based on nf-core.nf-core-extensionpack - - esbenp.prettier-vscode # Markdown/CommonMark linting and style checking for Visual Studio Code + #- esbenp.prettier-vscode # Markdown/CommonMark linting and style checking for Visual Studio Code - EditorConfig.EditorConfig # override user/workspace settings with settings found in .editorconfig files - Gruntfuggly.todo-tree # Display TODO and FIXME in a tree view in the activity bar - mechatroner.rainbow-csv # Highlight columns in csv files in different colors - # - nextflow.nextflow # Nextflow syntax highlighting + - nextflow.nextflow # Nextflow syntax highlighting - oderwat.indent-rainbow # Highlight indentation level - streetsidesoftware.code-spell-checker # Spelling checker for source code - charliermarsh.ruff # Code linter Ruff diff --git a/.nf-core.yml b/.nf-core.yml index 3805dc81c..7f2f983e6 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1 +1,27 @@ +bump_version: null +lint: + files_exist: + - conf/igenomes.config + - conf/test_full.config + - conf/test.config + - .github/workflows/awstest.yml + - .github/workflows/awsfulltest.yml + files_unchanged: + - .github/PULL_REQUEST_TEMPLATE.md + - .github/CONTRIBUTING.md + - docs/README.md + multiqc_config: false +nf_core_version: 3.0.2 +org_path: null repository_type: pipeline +template: + author: Yasset Perez-Riverol + description: Quantitative Mass Spectrometry nf-core workflow + force: false + is_nfcore: true + name: quantms + org: nf-core + outdir: . + skip_features: null + version: 1.3.1dev +update: null diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index af57081f6..9e9f0e1c4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,8 +3,11 @@ repos: rev: "v3.1.0" hooks: - id: prettier + additional_dependencies: + - prettier@3.2.5 + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python - rev: "2.7.3" + rev: "3.0.3" hooks: - id: editorconfig-checker alias: ec diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d35c1598..8a83258a8 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). -## v1.3.0dev - [date] +## v1.3.1dev - [date] Initial release of nf-core/quantms, created with the [nf-core](https://nf-co.re/) template. diff --git a/CITATIONS.md b/CITATIONS.md index 596f90318..f98356d1e 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -12,11 +12,11 @@ - [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) - > Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. +> Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) - > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. +> 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 diff --git a/README.md b/README.md index 99c71ee8d..880a187c0 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ [![GitHub Actions Linting Status](https://github.com/nf-core/quantms/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/quantms/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/quantms/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) [![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-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/) -[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://tower.nf/launch?pipeline=https://github.com/nf-core/quantms) +[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/quantms) [![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23quantms-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/quantms)[![Follow on Twitter](http://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/nf_core)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core) @@ -67,8 +67,7 @@ nextflow run nf-core/quantms \ ``` > [!WARNING] -> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; -> see [docs](https://nf-co.re/usage/configuration#custom-configuration-files). +> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files). For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/quantms/usage) and the [parameter documentation](https://nf-co.re/quantms/parameters). diff --git a/assets/nf-core-quantms_logo_light.png b/assets/nf-core-quantms_logo_light.png index 66c6e9d1bfb0725ae484beca2e5c4da6df6211f5..e5cd4222a01cbc20f94756de374dcc82a273d7c5 100644 GIT binary patch delta 39609 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 delta 39592 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 diff --git a/assets/schema_input.json b/assets/schema_input.json index 0493921c5..b3fe9935a 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/nf-core/quantms/master/assets/schema_input.json", "title": "nf-core/quantms pipeline - params.input schema", "description": "Schema for the file provided with params.input", diff --git a/conf/base.config b/conf/base.config index cb550d5f0..d127285fd 100644 --- a/conf/base.config +++ b/conf/base.config @@ -11,9 +11,9 @@ process { // TODO nf-core: Check the defaults for all processes - cpus = { check_max( 1 * task.attempt, 'cpus' ) } - memory = { check_max( 6.GB * task.attempt, 'memory' ) } - time = { check_max( 4.h * task.attempt, 'time' ) } + cpus = { 1 * task.attempt } + memory = { 6.GB * task.attempt } + time = { 4.h * task.attempt } errorStrategy = { task.exitStatus in ((130..145) + 104) ? 'retry' : 'finish' } maxRetries = 1 @@ -27,30 +27,30 @@ process { // TODO nf-core: Customise requirements for specific processes. // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors withLabel:process_single { - cpus = { check_max( 1 , 'cpus' ) } - memory = { check_max( 6.GB * task.attempt, 'memory' ) } - time = { check_max( 4.h * task.attempt, 'time' ) } + cpus = { 1 } + memory = { 6.GB * task.attempt } + time = { 4.h * task.attempt } } withLabel:process_low { - cpus = { check_max( 2 * task.attempt, 'cpus' ) } - memory = { check_max( 12.GB * task.attempt, 'memory' ) } - time = { check_max( 4.h * task.attempt, 'time' ) } + cpus = { 2 * task.attempt } + memory = { 12.GB * task.attempt } + time = { 4.h * task.attempt } } withLabel:process_medium { - cpus = { check_max( 6 * task.attempt, 'cpus' ) } - memory = { check_max( 36.GB * task.attempt, 'memory' ) } - time = { check_max( 8.h * task.attempt, 'time' ) } + cpus = { 6 * task.attempt } + memory = { 36.GB * task.attempt } + time = { 8.h * task.attempt } } withLabel:process_high { - cpus = { check_max( 12 * task.attempt, 'cpus' ) } - memory = { check_max( 72.GB * task.attempt, 'memory' ) } - time = { check_max( 16.h * task.attempt, 'time' ) } + cpus = { 12 * task.attempt } + memory = { 72.GB * task.attempt } + time = { 16.h * task.attempt } } withLabel:process_long { - time = { check_max( 20.h * task.attempt, 'time' ) } + time = { 20.h * task.attempt } } withLabel:process_high_memory { - memory = { check_max( 200.GB * task.attempt, 'memory' ) } + memory = { 200.GB * task.attempt } } withLabel:error_ignore { errorStrategy = 'ignore' @@ -59,7 +59,4 @@ process { errorStrategy = 'retry' maxRetries = 2 } - withName:CUSTOM_DUMPSOFTWAREVERSIONS { - cache = false - } } diff --git a/conf/igenomes_ignored.config b/conf/igenomes_ignored.config new file mode 100644 index 000000000..b4034d824 --- /dev/null +++ b/conf/igenomes_ignored.config @@ -0,0 +1,9 @@ +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Nextflow config file for iGenomes paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Empty genomes dictionary to use when igenomes is ignored. +---------------------------------------------------------------------------------------- +*/ + +params.genomes = [:] diff --git a/conf/modules.config b/conf/modules.config index e3ea8fa6c..d266a387f 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -21,15 +21,6 @@ process { withName: FASTQC { ext.args = '--quiet' } - - withName: CUSTOM_DUMPSOFTWAREVERSIONS { - publishDir = [ - path: { "${params.outdir}/pipeline_info" }, - mode: params.publish_dir_mode, - pattern: '*_versions.yml' - ] - } - withName: 'MULTIQC' { ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } publishDir = [ diff --git a/conf/test.config b/conf/test.config index 3b32a92b4..07c6cc4bb 100644 --- a/conf/test.config +++ b/conf/test.config @@ -10,19 +10,22 @@ ---------------------------------------------------------------------------------------- */ +process { + resourceLimits = [ + cpus: 4, + memory: '15.GB', + time: '1.h' + ] +} + params { config_profile_name = 'Test profile' config_profile_description = 'Minimal test dataset to check pipeline function' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = '6.GB' - max_time = '6.h' - // Input data // TODO nf-core: Specify the paths to your test data on nf-core/test-datasets // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv' + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv' // Genome references genome = 'R64-1-1' diff --git a/conf/test_full.config b/conf/test_full.config index bd0ae8275..0a9187c27 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -17,7 +17,7 @@ params { // Input data for full size test // TODO nf-core: Specify the paths to your full test data ( on nf-core/test-datasets or directly in repositories, e.g. SRA) // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = 'https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' + input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' // Genome references genome = 'R64-1-1' diff --git a/docs/images/mqc_fastqc_adapter.png b/docs/images/mqc_fastqc_adapter.png deleted file mode 100755 index 361d0e47acfb424dea1f326590d1eb2f6dfa26b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23458 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 diff --git a/docs/images/mqc_fastqc_quality.png b/docs/images/mqc_fastqc_quality.png deleted file mode 100755 index a4b89bf56ab2ba88cab87841916eb680a816deae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55769 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�)v~C(0C)c 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 M)78&qol`;+0Fu7JivR!s diff --git a/docs/images/nf-core-quantms_logo_dark.png b/docs/images/nf-core-quantms_logo_dark.png index 11938c136c08b92e6ed0a9f767e8585ea33255a8..8984574e25c2aea3482a669e22ff3d9125777814 100644 GIT binary patch literal 27119 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 diff --git a/docs/images/nf-core-quantms_logo_light.png b/docs/images/nf-core-quantms_logo_light.png index 83c08f470bf69467a042e7ebc75369caba00500b..222884d3b0d8b2f51a762e37093e910df2dee860 100644 GIT binary patch literal 23358 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 Lv^Z0G+9~=!0;=^L literal 23385 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 OhA^f!Xo|6C%Krc=jc1Ag diff --git a/docs/output.md b/docs/output.md index 22a15f7d4..8b172c84f 100644 --- a/docs/output.md +++ b/docs/output.md @@ -29,16 +29,6 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d [FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your sequenced reads. It provides information about the quality score distribution across your reads, per base sequence content (%A/T/G/C), adapter contamination and overrepresented sequences. For further reading and documentation see the [FastQC help pages](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/). -![MultiQC - FastQC sequence counts plot](images/mqc_fastqc_counts.png) - -![MultiQC - FastQC mean quality scores plot](images/mqc_fastqc_quality.png) - -![MultiQC - FastQC adapter content plot](images/mqc_fastqc_adapter.png) - -:::note -The FastQC plots displayed in the MultiQC report shows _untrimmed_ reads. They may contain adapter sequence and potentially regions with low quality. -::: - ### MultiQC
diff --git a/docs/usage.md b/docs/usage.md index 32058dd7d..564d45804 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -85,9 +85,9 @@ The above pipeline run specified with a params file in yaml format: nextflow run nf-core/quantms -profile docker -params-file params.yaml ``` -with `params.yaml` containing: +with: -```yaml +```yaml title="params.yaml" input: './samplesheet.csv' outdir: './results/' genome: 'GRCh37' @@ -156,6 +156,8 @@ If `-profile` is not specified, the pipeline will run locally and expect all sof - A generic configuration profile to be used with [Charliecloud](https://hpc.github.io/charliecloud/) - `apptainer` - A generic configuration profile to be used with [Apptainer](https://apptainer.org/) +- `wave` + - A generic configuration profile to enable [Wave](https://seqera.io/wave/) containers. Use together with one of the above (requires Nextflow ` 24.03.0-edge` or later). - `conda` - A generic configuration profile to be used with [Conda](https://conda.io/docs/). Please only use Conda as a last resort i.e. when it's not possible to run the pipeline with Docker, Singularity, Podman, Shifter, Charliecloud, or Apptainer. @@ -197,14 +199,6 @@ See the main [Nextflow documentation](https://www.nextflow.io/docs/latest/config If you have any questions or issues please send us a message on [Slack](https://nf-co.re/join/slack) on the [`#configs` channel](https://nfcore.slack.com/channels/configs). -## Azure Resource Requests - -To be used with the `azurebatch` profile by specifying the `-profile azurebatch`. -We recommend providing a compute `params.vm_type` of `Standard_D16_v3` VMs by default but these options can be changed if required. - -Note that the choice of VM size depends on your quota and the overall workload during the analysis. -For a thorough list, please refer the [Azure Sizes for virtual machines in Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/sizes). - ## Running in the background Nextflow handles job submissions and supervises the running jobs. The Nextflow process must run until the pipeline is finished. diff --git a/main.nf b/main.nf index e09fa3528..973c7e4d4 100644 --- a/main.nf +++ b/main.nf @@ -9,8 +9,6 @@ ---------------------------------------------------------------------------------------- */ -nextflow.enable.dsl = 2 - /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT FUNCTIONS / MODULES / SUBWORKFLOWS / WORKFLOWS @@ -20,7 +18,6 @@ nextflow.enable.dsl = 2 include { QUANTMS } from './workflows/quantms' include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_quantms_pipeline' include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_quantms_pipeline' - include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_quantms_pipeline' /* @@ -56,10 +53,8 @@ workflow NFCORE_QUANTMS { QUANTMS ( samplesheet ) - emit: multiqc_report = QUANTMS.out.multiqc_report // channel: /path/to/multiqc_report.html - } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -70,13 +65,11 @@ workflow NFCORE_QUANTMS { workflow { main: - // // SUBWORKFLOW: Run initialisation tasks // PIPELINE_INITIALISATION ( params.version, - params.help, params.validate_params, params.monochrome_logs, args, @@ -90,7 +83,6 @@ workflow { NFCORE_QUANTMS ( PIPELINE_INITIALISATION.out.samplesheet ) - // // SUBWORKFLOW: Run completion tasks // diff --git a/modules.json b/modules.json index af3a2fc51..0bdd78b1c 100644 --- a/modules.json +++ b/modules.json @@ -7,12 +7,12 @@ "nf-core": { "fastqc": { "branch": "master", - "git_sha": "f4ae1d942bd50c5c0b9bd2de1393ce38315ba57c", + "git_sha": "666652151335353eef2fcd58880bcef5bc2928e1", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "b7ebe95761cd389603f9cc0e0dc384c0f663815a", + "git_sha": "cf17ca47590cc578dfb47db1c2a44ef86f89976d", "installed_by": ["modules"] } } @@ -21,17 +21,17 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", + "git_sha": "3aa0aec1d52d492fe241919f0c6100ebf0074082", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", + "git_sha": "1b6b9a3338d011367137808b49b923515080e3ba", "installed_by": ["subworkflows"] }, - "utils_nfvalidation_plugin": { + "utils_nfschema_plugin": { "branch": "master", - "git_sha": "5caf7640a9ef1d18d765d55339be751bb0969dfa", + "git_sha": "bbd5a41f4535a8defafe6080e00ea74c45f4f96c", "installed_by": ["subworkflows"] } } diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/fastqc/environment.yml index 1787b38a9..691d4c763 100644 --- a/modules/nf-core/fastqc/environment.yml +++ b/modules/nf-core/fastqc/environment.yml @@ -1,7 +1,5 @@ -name: fastqc channels: - conda-forge - bioconda - - defaults dependencies: - bioconda::fastqc=0.12.1 diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf index 9e19a74c5..d8989f481 100644 --- a/modules/nf-core/fastqc/main.nf +++ b/modules/nf-core/fastqc/main.nf @@ -25,6 +25,14 @@ process FASTQC { def old_new_pairs = reads instanceof Path || reads.size() == 1 ? [[ reads, "${prefix}.${reads.extension}" ]] : reads.withIndex().collect { entry, index -> [ entry, "${prefix}_${index + 1}.${entry.extension}" ] } def rename_to = old_new_pairs*.join(' ').join(' ') def renamed_files = old_new_pairs.collect{ old_name, new_name -> new_name }.join(' ') + + // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) + // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 + // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label + def memory_in_mb = MemoryUnit.of("${task.memory}").toUnit('MB') / task.cpus + // FastQC memory value allowed range (100 - 10000) + def fastqc_memory = memory_in_mb > 10000 ? 10000 : (memory_in_mb < 100 ? 100 : memory_in_mb) + """ printf "%s %s\\n" $rename_to | while read old_name new_name; do [ -f "\${new_name}" ] || ln -s \$old_name \$new_name @@ -33,6 +41,7 @@ process FASTQC { fastqc \\ $args \\ --threads $task.cpus \\ + --memory $fastqc_memory \\ $renamed_files cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml index ee5507e06..4827da7af 100644 --- a/modules/nf-core/fastqc/meta.yml +++ b/modules/nf-core/fastqc/meta.yml @@ -16,35 +16,44 @@ tools: homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ licence: ["GPL-2.0-only"] + identifier: biotools:fastqc input: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files of size 1 and 2 for single-end and paired-end data, + respectively. output: - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - html: - type: file - description: FastQC report - pattern: "*_{fastqc.html}" + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.html": + type: file + description: FastQC report + pattern: "*_{fastqc.html}" - zip: - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.zip": + type: file + description: FastQC report archive + pattern: "*_{fastqc.zip}" - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - "@drpatelh" - "@grst" diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test index 70edae4d9..e9d79a074 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ b/modules/nf-core/fastqc/tests/main.nf.test @@ -23,17 +23,14 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. - // looks like this:
Mon 2 Oct 2023
test.gz
- // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 - - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_single") } + { assert process.success }, + // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. + // looks like this:
Mon 2 Oct 2023
test.gz
+ // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -54,16 +51,14 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_paired") } + { assert process.success }, + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -83,13 +78,11 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_interleaved") } + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -109,13 +102,11 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_bam") } + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -138,22 +129,20 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, - { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, - { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_multiple") } + { assert process.success }, + { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, + { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, + { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, + { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, + { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, + { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, + { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, + { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, + { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, + { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } ) } } @@ -173,21 +162,18 @@ nextflow_process { then { assertAll ( - { assert process.success }, - - { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - - { assert snapshot(process.out.versions).match("fastqc_versions_custom_prefix") } + { assert process.success }, + { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, + { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, + { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, + { assert snapshot(process.out.versions).match() } ) } } test("sarscov2 single-end [fastq] - stub") { - options "-stub" - + options "-stub" when { process { """ @@ -201,12 +187,123 @@ nextflow_process { then { assertAll ( - { assert process.success }, - { assert snapshot(process.out.html.collect { file(it[1]).getName() } + - process.out.zip.collect { file(it[1]).getName() } + - process.out.versions ).match("fastqc_stub") } + { assert process.success }, + { assert snapshot(process.out).match() } ) } } + test("sarscov2 paired-end [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 interleaved [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 paired-end [bam] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 multiple [fastq] - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [id: 'test', single_end: false], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("sarscov2 custom_prefix - stub") { + + options "-stub" + when { + process { + """ + input[0] = Channel.of([ + [ id:'mysample', single_end:true ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } } diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap index 86f7c3115..d5db3092f 100644 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ b/modules/nf-core/fastqc/tests/main.nf.test.snap @@ -1,88 +1,392 @@ { - "fastqc_versions_interleaved": { + "sarscov2 custom_prefix": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:40:07.293713" + "timestamp": "2024-07-22T11:02:16.374038" }, - "fastqc_stub": { + "sarscov2 single-end [fastq] - stub": { "content": [ - [ - "test.html", - "test.zip", - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": true + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": true + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:24.993809" + }, + "sarscov2 custom_prefix - stub": { + "content": [ + { + "0": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "mysample", + "single_end": true + }, + "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:31:01.425198" + "timestamp": "2024-07-22T11:03:10.93942" }, - "fastqc_versions_multiple": { + "sarscov2 interleaved [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:40:55.797907" + "timestamp": "2024-07-22T11:01:42.355718" }, - "fastqc_versions_bam": { + "sarscov2 paired-end [bam]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:40:26.795862" + "timestamp": "2024-07-22T11:01:53.276274" }, - "fastqc_versions_single": { + "sarscov2 multiple [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:39:27.043675" + "timestamp": "2024-07-22T11:02:05.527626" }, - "fastqc_versions_paired": { + "sarscov2 paired-end [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:31.188871" + }, + "sarscov2 paired-end [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:34.273566" + }, + "sarscov2 multiple [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:39:47.584191" + "timestamp": "2024-07-22T11:03:02.304411" }, - "fastqc_versions_custom_prefix": { + "sarscov2 single-end [fastq]": { "content": [ [ "versions.yml:md5,e1cc25ca8af856014824abd842e93978" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:01:19.095607" + }, + "sarscov2 interleaved [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" + }, + "timestamp": "2024-07-22T11:02:44.640184" + }, + "sarscov2 paired-end [bam] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "html": [ + [ + { + "id": "test", + "single_end": false + }, + "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + "versions.yml:md5,e1cc25ca8af856014824abd842e93978" + ], + "zip": [ + [ + { + "id": "test", + "single_end": false + }, + "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.3" }, - "timestamp": "2024-01-31T17:41:14.576531" + "timestamp": "2024-07-22T11:02:53.550742" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index ca39fb67e..6f5b867b7 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -1,7 +1,5 @@ -name: multiqc channels: - conda-forge - bioconda - - defaults dependencies: - - bioconda::multiqc=1.21 + - bioconda::multiqc=1.25.1 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 47ac352f9..cc0643e1d 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -3,14 +3,16 @@ process MULTIQC { conda "${moduleDir}/environment.yml" container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.21--pyhdfd78af_0' : - 'biocontainers/multiqc:1.21--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.25.1--pyhdfd78af_0' : + 'biocontainers/multiqc:1.25.1--pyhdfd78af_0' }" input: path multiqc_files, stageAs: "?/*" path(multiqc_config) path(extra_multiqc_config) path(multiqc_logo) + path(replace_names) + path(sample_names) output: path "*multiqc_report.html", emit: report @@ -23,16 +25,22 @@ process MULTIQC { script: def args = task.ext.args ?: '' + def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' def config = multiqc_config ? "--config $multiqc_config" : '' def extra_config = extra_multiqc_config ? "--config $extra_multiqc_config" : '' - def logo = multiqc_logo ? /--cl-config 'custom_logo: "${multiqc_logo}"'/ : '' + def logo = multiqc_logo ? "--cl-config 'custom_logo: \"${multiqc_logo}\"'" : '' + def replace = replace_names ? "--replace-names ${replace_names}" : '' + def samples = sample_names ? "--sample-names ${sample_names}" : '' """ multiqc \\ --force \\ $args \\ $config \\ + $prefix \\ $extra_config \\ $logo \\ + $replace \\ + $samples \\ . cat <<-END_VERSIONS > versions.yml @@ -44,7 +52,7 @@ process MULTIQC { stub: """ mkdir multiqc_data - touch multiqc_plots + mkdir multiqc_plots touch multiqc_report.html cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index 45a9bc35e..b16c18792 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,5 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into a single report +description: Aggregate results from bioinformatics analyses across many samples into + a single report keywords: - QC - bioinformatics tools @@ -12,40 +13,59 @@ tools: homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ licence: ["GPL-3.0-or-later"] + identifier: biotools:multiqc input: - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections in multiqc_config. - pattern: "*.{yml,yaml}" - - multiqc_logo: - type: file - description: Optional logo file for MultiQC - pattern: "*.{png}" + - - multiqc_files: + type: file + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC + - - multiqc_config: + type: file + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + - - extra_multiqc_config: + type: file + description: Second optional config yml for MultiQC. Will override common sections + in multiqc_config. + pattern: "*.{yml,yaml}" + - - multiqc_logo: + type: file + description: Optional logo file for MultiQC + pattern: "*.{png}" + - - replace_names: + type: file + description: | + Optional two-column sample renaming file. First column a set of + patterns, second column a set of corresponding replacements. Passed via + MultiQC's `--replace-names` option. + pattern: "*.{tsv}" + - - sample_names: + type: file + description: | + Optional TSV file with headers, passed to the MultiQC --sample_names + argument. + pattern: "*.{tsv}" output: - report: - type: file - description: MultiQC report file - pattern: "multiqc_report.html" + - "*multiqc_report.html": + type: file + description: MultiQC report file + pattern: "multiqc_report.html" - data: - type: directory - description: MultiQC data dir - pattern: "multiqc_data" + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" - plots: - type: file - description: Plots created by MultiQC - pattern: "*_data" + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_data" - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - "@abhi18av" - "@bunop" diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index f1c4242ef..33316a7dd 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -8,6 +8,8 @@ nextflow_process { tag "modules_nfcore" tag "multiqc" + config "./nextflow.config" + test("sarscov2 single-end [fastqc]") { when { @@ -17,6 +19,8 @@ nextflow_process { input[1] = [] input[2] = [] input[3] = [] + input[4] = [] + input[5] = [] """ } } @@ -41,6 +45,8 @@ nextflow_process { input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) input[2] = [] input[3] = [] + input[4] = [] + input[5] = [] """ } } @@ -66,6 +72,8 @@ nextflow_process { input[1] = [] input[2] = [] input[3] = [] + input[4] = [] + input[5] = [] """ } } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index bfebd8029..2fcbb5ff7 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -2,14 +2,14 @@ "multiqc_versions_single": { "content": [ [ - "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.4" }, - "timestamp": "2024-02-29T08:48:55.657331" + "timestamp": "2024-10-02T17:51:46.317523" }, "multiqc_stub": { "content": [ @@ -17,25 +17,25 @@ "multiqc_report.html", "multiqc_data", "multiqc_plots", - "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.4" }, - "timestamp": "2024-02-29T08:49:49.071937" + "timestamp": "2024-10-02T17:52:20.680978" }, "multiqc_versions_config": { "content": [ [ - "versions.yml:md5,21f35ee29416b9b3073c28733efe4b7d" + "versions.yml:md5,41f391dcedce7f93ca188f3a3ffa0916" ] ], "meta": { - "nf-test": "0.8.4", - "nextflow": "23.10.1" + "nf-test": "0.9.0", + "nextflow": "24.04.4" }, - "timestamp": "2024-02-29T08:49:25.457567" + "timestamp": "2024-10-02T17:52:09.185842" } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config new file mode 100644 index 000000000..c537a6a3e --- /dev/null +++ b/modules/nf-core/multiqc/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: 'MULTIQC' { + ext.prefix = null + } +} diff --git a/nextflow.config b/nextflow.config index b79aea52f..977aa9bed 100644 --- a/nextflow.config +++ b/nextflow.config @@ -12,11 +12,13 @@ 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 - fasta = null// MultiQC options + + // MultiQC options multiqc_config = null multiqc_title = null multiqc_logo = null @@ -24,171 +26,157 @@ params { multiqc_methods_description = null // Boilerplate options - outdir = null - publish_dir_mode = 'copy' - email = null - email_on_fail = null - plaintext_email = false - monochrome_logs = false - hook_url = null - help = false - version = false + outdir = null + publish_dir_mode = 'copy' + email = null + email_on_fail = null + plaintext_email = false + monochrome_logs = false + hook_url = null + help = false + help_full = false + show_hidden = false + version = false + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' // Config options config_profile_name = null config_profile_description = null + custom_config_version = 'master' custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" config_profile_contact = null config_profile_url = null - // Max resource options - // Defaults only, expecting to be overwritten - max_memory = '128.GB' - max_cpus = 16 - max_time = '240.h' - // Schema validation default options - validationFailUnrecognisedParams = false - validationLenientMode = false - validationSchemaIgnoreParams = 'genomes,igenomes_base' - validationShowHiddenParams = false - validate_params = true - + validate_params = true } // Load base.config by default for all pipelines includeConfig 'conf/base.config' -// Load nf-core custom profiles from different Institutions -try { - includeConfig "${params.custom_config_base}/nfcore_custom.config" -} catch (Exception e) { - System.err.println("WARNING: Could not load nf-core/config profiles: ${params.custom_config_base}/nfcore_custom.config") -} - -// Load nf-core/quantms custom profiles from different institutions. -// Warning: Uncomment only if a pipeline-specific institutional config already exists on nf-core/configs! -// try { -// includeConfig "${params.custom_config_base}/pipeline/quantms.config" -// } catch (Exception e) { -// System.err.println("WARNING: Could not load nf-core/config/quantms profiles: ${params.custom_config_base}/pipeline/quantms.config") -// } profiles { debug { - dumpHashes = true - process.beforeScript = 'echo $HOSTNAME' - cleanup = false + dumpHashes = true + process.beforeScript = 'echo $HOSTNAME' + cleanup = false nextflow.enable.configProcessNamesValidation = true } conda { - conda.enabled = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - channels = ['conda-forge', 'bioconda', 'defaults'] - apptainer.enabled = false + conda.enabled = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + conda.channels = ['conda-forge', 'bioconda'] + apptainer.enabled = false } mamba { - conda.enabled = true - conda.useMamba = true - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + conda.enabled = true + conda.useMamba = true + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } docker { - docker.enabled = true - conda.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false - docker.runOptions = '-u $(id -u):$(id -g)' + docker.enabled = true + conda.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false + docker.runOptions = '-u $(id -u):$(id -g)' } arm { - docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' } singularity { - singularity.enabled = true - singularity.autoMounts = true - conda.enabled = false - docker.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + singularity.enabled = true + singularity.autoMounts = true + conda.enabled = false + docker.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } podman { - podman.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - shifter.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + podman.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + shifter.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } shifter { - shifter.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - charliecloud.enabled = false - apptainer.enabled = false + shifter.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + charliecloud.enabled = false + apptainer.enabled = false } charliecloud { - charliecloud.enabled = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - apptainer.enabled = false + charliecloud.enabled = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + apptainer.enabled = false } apptainer { - apptainer.enabled = true - apptainer.autoMounts = true - conda.enabled = false - docker.enabled = false - singularity.enabled = false - podman.enabled = false - shifter.enabled = false - charliecloud.enabled = false + apptainer.enabled = true + apptainer.autoMounts = true + conda.enabled = false + docker.enabled = false + singularity.enabled = false + podman.enabled = false + shifter.enabled = false + charliecloud.enabled = false + } + wave { + apptainer.ociAutoPull = true + singularity.ociAutoPull = true + wave.enabled = true + wave.freeze = true + wave.strategy = 'conda,container' } gitpod { - executor.name = 'local' - executor.cpus = 4 - executor.memory = 8.GB + executor.name = 'local' + executor.cpus = 4 + executor.memory = 8.GB } test { includeConfig 'conf/test.config' } 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' +// Load nf-core custom profiles from different Institutions +includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/nfcore_custom.config" : "/dev/null" -// Nextflow plugins -plugins { - id 'nf-validation@1.1.3' // Validation of pipeline parameters and creation of an input channel from a sample sheet -} +// Load nf-core/quantms custom profiles from different institutions. +// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs +// includeConfig !System.getenv('NXF_OFFLINE') && params.custom_config_base ? "${params.custom_config_base}/pipeline/quantms.config" : "/dev/null" + +// Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile +// Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled +// Set to your registry if you have a mirror of containers +apptainer.registry = 'quay.io' +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' +charliecloud.registry = 'quay.io' // Load igenomes.config if required -if (!params.igenomes_ignore) { - includeConfig 'conf/igenomes.config' -} else { - params.genomes = [:] -} +includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' + // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. @@ -200,8 +188,15 @@ env { JULIA_DEPOT_PATH = "/usr/local/share/julia" } -// Capture exit codes from upstream processes when piping -process.shell = ['/bin/bash', '-euo', 'pipefail'] +// Set bash options +process.shell = """\ +bash + +set -e # Exit if a tool returns a non-zero status/exit code +set -u # Treat unset variables and parameters as an error +set -o pipefail # Returns the status of the last command to exit with a non-zero status or zero if all successfully execute +set -C # No clobber - prevent output redirection from overwriting files. +""" // Disable process selector warnings by default. Use debug profile to enable warnings. nextflow.enable.configProcessNamesValidation = false @@ -230,43 +225,46 @@ manifest { homePage = 'https://github.com/nf-core/quantms' description = """Quantitative Mass Spectrometry nf-core workflow""" mainScript = 'main.nf' - nextflowVersion = '!>=23.04.0' - version = '1.3.0dev' + nextflowVersion = '!>=24.04.2' + version = '1.3.1dev' doi = '' } -// Load modules.config for DSL2 module specific options -includeConfig 'conf/modules.config' +// Nextflow plugins +plugins { + id 'nf-schema@2.1.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet +} -// Function to ensure that resource requirements don't go beyond -// a maximum limit -def check_max(obj, type) { - if (type == 'memory') { - try { - if (obj.compareTo(params.max_memory as nextflow.util.MemoryUnit) == 1) - return params.max_memory as nextflow.util.MemoryUnit - else - return obj - } catch (all) { - println " ### ERROR ### Max memory '${params.max_memory}' is not valid! Using default value: $obj" - return obj - } - } else if (type == 'time') { - try { - if (obj.compareTo(params.max_time as nextflow.util.Duration) == 1) - return params.max_time as nextflow.util.Duration - else - return obj - } catch (all) { - println " ### ERROR ### Max time '${params.max_time}' is not valid! Using default value: $obj" - return obj - } - } else if (type == 'cpus') { - try { - return Math.min( obj, params.max_cpus as int ) - } catch (all) { - println " ### ERROR ### Max cpus '${params.max_cpus}' is not valid! Using default value: $obj" - return obj - } +validation { + defaultIgnoreParams = ["genomes"] + help { + enabled = true + command = "nextflow run $manifest.name -profile --input samplesheet.csv --outdir " + fullParameter = "help_full" + showHiddenParameter = "show_hidden" + beforeText = """ +-\033[2m----------------------------------------------------\033[0m- + \033[0;32m,--.\033[0;30m/\033[0;32m,-.\033[0m +\033[0;34m ___ __ __ __ ___ \033[0;32m/,-._.--~\'\033[0m +\033[0;34m |\\ | |__ __ / ` / \\ |__) |__ \033[0;33m} {\033[0m +\033[0;34m | \\| | \\__, \\__/ | \\ |___ \033[0;32m\\`-._,-`-,\033[0m + \033[0;32m`._,._,\'\033[0m +\033[0;35m ${manifest.name} ${manifest.version}\033[0m +-\033[2m----------------------------------------------------\033[0m- +""" + afterText = """${manifest.doi ? "* The pipeline\n" : ""}${manifest.doi.tokenize(",").collect { " https://doi.org/${it.trim().replace('https://doi.org/','')}"}.join("\n")}${manifest.doi ? "\n" : ""} +* The nf-core framework + https://doi.org/10.1038/s41587-020-0439-x + +* Software dependencies + https://github.com/${manifest.name}/blob/master/CITATIONS.md +""" + } + summary { + beforeText = validation.help.beforeText + afterText = validation.help.afterText } } + +// Load modules.config for DSL2 module specific options +includeConfig 'conf/modules.config' diff --git a/nextflow_schema.json b/nextflow_schema.json index f643948eb..30028e50c 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -1,10 +1,10 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/nf-core/quantms/master/nextflow_schema.json", "title": "nf-core/quantms pipeline parameters", "description": "Quantitative Mass Spectrometry nf-core workflow", "type": "object", - "definitions": { + "$defs": { "input_output_options": { "title": "Input/output options", "type": "object", @@ -71,6 +71,14 @@ "fa_icon": "fas fa-ban", "hidden": true, "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." + }, + "igenomes_base": { + "type": "string", + "format": "directory-path", + "description": "The base path to the igenomes reference files", + "fa_icon": "fas fa-ban", + "hidden": true, + "default": "s3://ngi-igenomes/igenomes/" } } }, @@ -122,41 +130,6 @@ } } }, - "max_job_request_options": { - "title": "Max job request options", - "type": "object", - "fa_icon": "fab fa-acquisitions-incorporated", - "description": "Set the top limit for requested resources for any single job.", - "help_text": "If you are running on a smaller system, a pipeline step requesting more resources than are available may cause the Nextflow to stop the run with an error. These options allow you to cap the maximum resources requested by any single job so that the pipeline will run on your system.\n\nNote that you can not _increase_ the resources requested by any job using these options. For that you will need your own configuration file. See [the nf-core website](https://nf-co.re/usage/configuration) for details.", - "properties": { - "max_cpus": { - "type": "integer", - "description": "Maximum number of CPUs that can be requested for any single job.", - "default": 16, - "fa_icon": "fas fa-microchip", - "hidden": true, - "help_text": "Use to set an upper-limit for the CPU requirement for each process. Should be an integer e.g. `--max_cpus 1`" - }, - "max_memory": { - "type": "string", - "description": "Maximum amount of memory that can be requested for any single job.", - "default": "128.GB", - "fa_icon": "fas fa-memory", - "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", - "hidden": true, - "help_text": "Use to set an upper-limit for the memory requirement for each process. Should be a string in the format integer-unit e.g. `--max_memory '8.GB'`" - }, - "max_time": { - "type": "string", - "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|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'`" - } - } - }, "generic_options": { "title": "Generic options", "type": "object", @@ -164,12 +137,6 @@ "description": "Less common options for the pipeline, typically set in a config file.", "help_text": "These options are common to all nf-core pipelines and allow you to customise some of the core preferences for how the pipeline runs.\n\nTypically these options would be set in a Nextflow config file loaded for all pipeline runs, such as `~/.nextflow/config`.", "properties": { - "help": { - "type": "boolean", - "description": "Display help text.", - "fa_icon": "fas fa-question-circle", - "hidden": true - }, "version": { "type": "boolean", "description": "Display version and exit.", @@ -245,45 +212,28 @@ "fa_icon": "fas fa-check-square", "hidden": true }, - "validationShowHiddenParams": { - "type": "boolean", - "fa_icon": "far fa-eye-slash", - "description": "Show all params when using `--help`", - "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.", - "hidden": true, - "help_text": "By default, when an unrecognised parameter is found, it returns a warinig." - }, - "validationLenientMode": { - "type": "boolean", + "pipelines_testdata_base_path": { + "type": "string", "fa_icon": "far fa-check-circle", - "description": "Validation of parameters in lenient more.", - "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)." + "description": "Base URL or local path to location of pipeline test dataset files", + "default": "https://raw.githubusercontent.com/nf-core/test-datasets/", + "hidden": true } } } }, "allOf": [ { - "$ref": "#/definitions/input_output_options" - }, - { - "$ref": "#/definitions/reference_genome_options" + "$ref": "#/$defs/input_output_options" }, { - "$ref": "#/definitions/institutional_config_options" + "$ref": "#/$defs/reference_genome_options" }, { - "$ref": "#/definitions/max_job_request_options" + "$ref": "#/$defs/institutional_config_options" }, { - "$ref": "#/definitions/generic_options" + "$ref": "#/$defs/generic_options" } ] } diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 56110621e..000000000 --- a/pyproject.toml +++ /dev/null @@ -1,15 +0,0 @@ -# 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.ruff] -line-length = 120 -target-version = "py38" -cache-dir = "~/.cache/ruff" - -[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/utils_nfcore_quantms_pipeline/main.nf b/subworkflows/local/utils_nfcore_quantms_pipeline/main.nf index 2a03b6fa3..f6771f2e7 100644 --- a/subworkflows/local/utils_nfcore_quantms_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_quantms_pipeline/main.nf @@ -8,29 +8,25 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -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 { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { dashedLine } from '../../nf-core/utils_nfcore_pipeline' -include { nfCoreLogo } from '../../nf-core/utils_nfcore_pipeline' include { imNotification } from '../../nf-core/utils_nfcore_pipeline' include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' -include { workflowCitation } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_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 @@ -54,16 +50,10 @@ workflow PIPELINE_INITIALISATION { // // 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, + UTILS_NFSCHEMA_PLUGIN ( + workflow, validate_params, - "nextflow_schema.json" + null ) // @@ -72,6 +62,7 @@ workflow PIPELINE_INITIALISATION { UTILS_NFCORE_PIPELINE ( nextflow_cli_args ) + // // Custom validation for pipeline parameters // @@ -80,8 +71,9 @@ workflow PIPELINE_INITIALISATION { // // Create channel from input file provided through params.input // + Channel - .fromSamplesheet("input") + .fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json")) .map { meta, fastq_1, fastq_2 -> if (!fastq_2) { @@ -91,8 +83,8 @@ workflow PIPELINE_INITIALISATION { } } .groupTuple() - .map { - validateInputSamplesheet(it) + .map { samplesheet -> + validateInputSamplesheet(samplesheet) } .map { meta, fastqs -> @@ -106,9 +98,9 @@ workflow PIPELINE_INITIALISATION { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUBWORKFLOW FOR PIPELINE COMPLETION -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow PIPELINE_COMPLETION { @@ -123,7 +115,6 @@ workflow PIPELINE_COMPLETION { multiqc_report // string: Path to MultiQC report main: - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") // @@ -131,21 +122,32 @@ workflow PIPELINE_COMPLETION { // workflow.onComplete { if (email || email_on_fail) { - completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs, multiqc_report.toList()) + 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) } } + + workflow.onError { + log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + } } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // // Check and validate pipeline parameters @@ -161,7 +163,7 @@ 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 + def endedness_ok = metas.collect{ meta -> meta.single_end }.unique().size == 1 if (!endedness_ok) { error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") } @@ -193,7 +195,6 @@ def genomeExistsError() { error(error_string) } } - // // Generate methods description for MultiQC // @@ -230,8 +231,18 @@ def methodsDescriptionText(mqc_methods_yaml) { 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.
  • " + if (meta.manifest_map.doi) { + // Using a loop to handle multiple DOIs + // Removing `https://doi.org/` to handle pipelines using DOIs vs DOI resolvers + // Removing ` ` since the manifest.doi is a string and not a proper list + def temp_doi_ref = "" + def manifest_doi = meta.manifest_map.doi.tokenize(",") + manifest_doi.each { doi_ref -> + temp_doi_ref += "(doi: ${doi_ref.replace("https://doi.org/", "").replace(" ", "")}), " + } + meta["doi_text"] = temp_doi_ref.substring(0, temp_doi_ref.length() - 2) + } else meta["doi_text"] = "" + meta["nodoi_text"] = meta.manifest_map.doi ? "" : "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " // Tool references meta["tool_citations"] = "" @@ -249,3 +260,4 @@ def methodsDescriptionText(mqc_methods_yaml) { return description_html.toString() } + diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index ac31f28f6..0fcbf7b3f 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -2,18 +2,13 @@ // 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 @@ -26,7 +21,7 @@ workflow UTILS_NEXTFLOW_PIPELINE { // Print workflow version and exit on --version // if (print_version) { - log.info "${workflow.manifest.name} ${getWorkflowVersion()}" + log.info("${workflow.manifest.name} ${getWorkflowVersion()}") System.exit(0) } @@ -49,16 +44,16 @@ workflow UTILS_NEXTFLOW_PIPELINE { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // // Generate version string // def getWorkflowVersion() { - String version_string = "" + def version_string = "" as String if (workflow.manifest.version) { def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' version_string += "${prefix_v}${workflow.manifest.version}" @@ -76,13 +71,13 @@ def getWorkflowVersion() { // 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) + def timestamp = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') + def filename = "params_${timestamp}.json" + def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") + def jsonStr = groovy.json.JsonOutput.toJson(params) + temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) - FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") + nextflow.extension.FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") temp_pf.delete() } @@ -90,37 +85,40 @@ def dumpParametersToJSON(outdir) { // When running with -profile conda, warn if channels have not been set-up appropriately // def checkCondaChannels() { - Yaml parser = new Yaml() + def parser = new org.yaml.snakeyaml.Yaml() def channels = [] try { def config = parser.load("conda config --show channels".execute().text) channels = config.channels - } catch(NullPointerException | IOException e) { - log.warn "Could not verify conda channel configuration." - return + } + catch (NullPointerException e) { + log.warn("Could not verify conda channel configuration.") + return null + } + catch (IOException e) { + log.warn("Could not verify conda channel configuration.") + return null } // Check that all channels are present // This channel list is ordered by required channel priority. - def required_channels_in_order = ['conda-forge', 'bioconda', 'defaults'] + def required_channels_in_order = ['conda-forge', 'bioconda'] def channels_missing = ((required_channels_in_order as Set) - (channels as Set)) as Boolean // Check that they are in the right order - def channel_priority_violation = 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])) - } + def channel_priority_violation = required_channels_in_order != channels.findAll { ch -> ch in required_channels_in_order } if (channels_missing | channel_priority_violation) { - log.warn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\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" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + log.warn """\ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + There is a problem with your Conda configuration! + You will need to set-up the conda-forge and bioconda channels correctly. + Please refer to https://bioconda.github.io/ + The observed channel order is + ${channels} + but the following channel order is required: + ${required_channels_in_order} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + """.stripIndent(true) } } diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config index d0a926bf6..a09572e5b 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config @@ -3,7 +3,7 @@ manifest { author = """nf-core""" homePage = 'https://127.0.0.1' description = """Dummy pipeline""" - nextflowVersion = '!>=23.04.0' + nextflowVersion = '!>=23.04.0' version = '9.9.9' doi = 'https://doi.org/10.5281/zenodo.5070524' } diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index a8b55d6fe..5cb7bafef 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -2,17 +2,13 @@ // 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 @@ -25,23 +21,20 @@ workflow UTILS_NFCORE_PIPELINE { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTIONS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // // Warn if a -profile or Nextflow config has not been provided to run the pipeline // def checkConfigProvided() { - valid_config = true + def valid_config = true as Boolean if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) { - log.warn "[$workflow.manifest.name] You are attempting to run the pipeline without any custom configuration!\n\n" + - "This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" + - " (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" + - " (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" + - " (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" + - "Please refer to the quick start section and usage docs for the pipeline.\n " + 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 @@ -52,12 +45,14 @@ def checkConfigProvided() { // 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" + 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" + 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" + ) } } @@ -65,20 +60,22 @@ def checkProfileProvided(nextflow_cli_args) { // 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" + def temp_doi_ref = "" + def manifest_doi = workflow.manifest.doi.tokenize(",") + // Handling multiple DOIs + // Removing `https://doi.org/` to handle pipelines using DOIs vs DOI resolvers + // Removing ` ` since the manifest.doi is a string and not a proper list + manifest_doi.each { doi_ref -> + temp_doi_ref += " https://doi.org/${doi_ref.replace('https://doi.org/', '').replace(' ', '')}\n" + } + return "If you use ${workflow.manifest.name} for your analysis please cite:\n\n" + "* The pipeline\n" + temp_doi_ref + "\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 = "" + def version_string = "" as String if (workflow.manifest.version) { def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : '' version_string += "${prefix_v}${workflow.manifest.version}" @@ -96,8 +93,8 @@ def getWorkflowVersion() { // 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 ] } + def yaml = new org.yaml.snakeyaml.Yaml() + def versions = yaml.load(yaml_file).collectEntries { k, v -> [k.tokenize(':')[-1], v] } return yaml.dumpAsMap(versions).trim() } @@ -107,8 +104,8 @@ def processVersionsFromYAML(yaml_file) { def workflowVersionToYAML() { return """ Workflow: - $workflow.manifest.name: ${getWorkflowVersion()} - Nextflow: $workflow.nextflow.version + ${workflow.manifest.name}: ${getWorkflowVersion()} + Nextflow: ${workflow.nextflow.version} """.stripIndent().trim() } @@ -116,11 +113,7 @@ def workflowVersionToYAML() { // 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())) + return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) } // @@ -128,25 +121,31 @@ def softwareVersionsToYAML(ch_versions) { // 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 += "
    $param
    ${group_params.get(param) ?: 'N/A'}
    \n" + summary_params + .keySet() + .each { group -> + def group_params = summary_params.get(group) + // This gets the parameters of that particular group + if (group_params) { + summary_section += "

    ${group}

    \n" + summary_section += "
    \n" + group_params + .keySet() + .sort() + .each { param -> + summary_section += "
    ${param}
    ${group_params.get(param) ?: 'N/A'}
    \n" + } + summary_section += "
    \n" } - summary_section += "
    \n" } - } - String yaml_file_text = "id: '${workflow.manifest.name.replace('/','-')}-summary'\n" - yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" - yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" - yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" - yaml_file_text += "plot_type: 'html'\n" - yaml_file_text += "data: |\n" - yaml_file_text += "${summary_section}" + def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String + yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n" + yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n" + yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n" + yaml_file_text += "plot_type: 'html'\n" + yaml_file_text += "data: |\n" + yaml_file_text += "${summary_section}" return yaml_file_text } @@ -155,7 +154,7 @@ def paramsSummaryMultiqc(summary_params) { // nf-core logo // def nfCoreLogo(monochrome_logs=true) { - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map String.format( """\n ${dashedLine(monochrome_logs)} @@ -174,7 +173,7 @@ def nfCoreLogo(monochrome_logs=true) { // Return dashed line // def dashedLine(monochrome_logs=true) { - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map return "-${colors.dim}----------------------------------------------------${colors.reset}-" } @@ -182,7 +181,7 @@ def dashedLine(monochrome_logs=true) { // ANSII colours used for terminal logging // def logColours(monochrome_logs=true) { - Map colorcodes = [:] + def colorcodes = [:] as Map // Reset / Meta colorcodes['reset'] = monochrome_logs ? '' : "\033[0m" @@ -194,54 +193,54 @@ def logColours(monochrome_logs=true) { colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m" // Regular Colors - colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" - colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" - colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" - colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" - colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" - colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" - colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" - colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" + colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m" + colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m" + colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m" + colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m" + colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m" + colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m" + colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m" + colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m" // Bold - colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" - colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" - colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" - colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" - colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" - colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" - colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" - colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" + colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m" + colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m" + colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m" + colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m" + colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m" + colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m" + colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m" + colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m" // Underline - colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" - colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" - colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" - colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" - colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" - colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" - colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" - colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" + colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m" + colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m" + colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m" + colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m" + colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m" + colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m" + colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m" + colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m" // High Intensity - colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" - colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" - colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" - colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" - colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" - colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" - colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" - colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" + colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m" + colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m" + colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m" + colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m" + colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m" + colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m" + colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m" + colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m" // Bold High Intensity - colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" - colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" - colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" - colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" - colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" - colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" - colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" - colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" + colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m" + colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m" + colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m" + colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m" + colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m" + colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m" + colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m" + colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m" return colorcodes } @@ -256,14 +255,15 @@ def attachMultiqcReport(multiqc_report) { mqc_report = multiqc_report.getVal() if (mqc_report.getClass() == ArrayList && mqc_report.size() >= 1) { if (mqc_report.size() > 1) { - log.warn "[$workflow.manifest.name] Found multiple reports from process 'MULTIQC', will use only one" + log.warn("[${workflow.manifest.name}] Found multiple reports from process 'MULTIQC', will use only one") } mqc_report = mqc_report[0] } } - } catch (all) { + } + catch (Exception all) { if (multiqc_report) { - log.warn "[$workflow.manifest.name] Could not attach MultiQC report to summary email" + log.warn("[${workflow.manifest.name}] Could not attach MultiQC report to summary email") } } return mqc_report @@ -275,26 +275,35 @@ def attachMultiqcReport(multiqc_report) { def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdir, monochrome_logs=true, multiqc_report=null) { // Set up the e-mail variables - def subject = "[$workflow.manifest.name] Successful: $workflow.runName" + def subject = "[${workflow.manifest.name}] Successful: ${workflow.runName}" if (!workflow.success) { - subject = "[$workflow.manifest.name] FAILED: $workflow.runName" + subject = "[${workflow.manifest.name}] FAILED: ${workflow.runName}" } def summary = [:] - for (group in summary_params.keySet()) { - summary << summary_params[group] - } + summary_params + .keySet() + .sort() + .each { group -> + summary << summary_params[group] + } def misc_fields = [:] misc_fields['Date Started'] = workflow.start misc_fields['Date Completed'] = workflow.complete misc_fields['Pipeline script file path'] = workflow.scriptFile misc_fields['Pipeline script hash ID'] = workflow.scriptId - if (workflow.repository) misc_fields['Pipeline repository Git URL'] = workflow.repository - if (workflow.commitId) misc_fields['Pipeline repository Git Commit'] = workflow.commitId - if (workflow.revision) misc_fields['Pipeline Git branch/tag'] = workflow.revision - misc_fields['Nextflow Version'] = workflow.nextflow.version - misc_fields['Nextflow Build'] = workflow.nextflow.build + if (workflow.repository) { + misc_fields['Pipeline repository Git URL'] = workflow.repository + } + if (workflow.commitId) { + misc_fields['Pipeline repository Git Commit'] = workflow.commitId + } + if (workflow.revision) { + misc_fields['Pipeline Git branch/tag'] = workflow.revision + } + misc_fields['Nextflow Version'] = workflow.nextflow.version + misc_fields['Nextflow Build'] = workflow.nextflow.build misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp def email_fields = [:] @@ -332,39 +341,41 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi // Render the sendmail template 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: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ] + def smail_fields = [email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "${workflow.projectDir}", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes()] def sf = new File("${workflow.projectDir}/assets/sendmail_template.txt") def sendmail_template = engine.createTemplate(sf).make(smail_fields) def sendmail_html = sendmail_template.toString() // Send the HTML e-mail - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map if (email_address) { try { - if (plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') } + if (plaintext_email) { +new org.codehaus.groovy.GroovyException('Send plaintext e-mail, not HTML') } // Try to send HTML e-mail using sendmail def sendmail_tf = new File(workflow.launchDir.toString(), ".sendmail_tmp.html") sendmail_tf.withWriter { w -> w << sendmail_html } - [ 'sendmail', '-t' ].execute() << sendmail_html - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-" - } catch (all) { + ['sendmail', '-t'].execute() << sendmail_html + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Sent summary e-mail to ${email_address} (sendmail)-") + } + catch (Exception all) { // Catch failures and try with plaintext - def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ] + def mail_cmd = ['mail', '-s', subject, '--content-type=text/html', email_address] mail_cmd.execute() << email_html - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (mail)-" + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Sent summary e-mail to ${email_address} (mail)-") } } // Write summary e-mail HTML to a file def output_hf = new File(workflow.launchDir.toString(), ".pipeline_report.html") output_hf.withWriter { w -> w << email_html } - FilesEx.copyTo(output_hf.toPath(), "${outdir}/pipeline_info/pipeline_report.html"); + nextflow.extension.FilesEx.copyTo(output_hf.toPath(), "${outdir}/pipeline_info/pipeline_report.html") output_hf.delete() // Write summary e-mail TXT to a file def output_tf = new File(workflow.launchDir.toString(), ".pipeline_report.txt") output_tf.withWriter { w -> w << email_txt } - FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt"); + nextflow.extension.FilesEx.copyTo(output_tf.toPath(), "${outdir}/pipeline_info/pipeline_report.txt") output_tf.delete() } @@ -372,15 +383,17 @@ def completionEmail(summary_params, email, email_on_fail, plaintext_email, outdi // Print pipeline summary on completion // def completionSummary(monochrome_logs=true) { - Map colors = logColours(monochrome_logs) + def colors = logColours(monochrome_logs) as Map if (workflow.success) { if (workflow.stats.ignoredCount == 0) { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-" - } else { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.green} Pipeline completed successfully${colors.reset}-") + } + else { + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.yellow} Pipeline completed successfully, but with errored process(es) ${colors.reset}-") } - } else { - log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-" + } + else { + log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } @@ -389,21 +402,30 @@ def completionSummary(monochrome_logs=true) { // def imNotification(summary_params, hook_url) { def summary = [:] - for (group in summary_params.keySet()) { - summary << summary_params[group] - } + summary_params + .keySet() + .sort() + .each { group -> + summary << summary_params[group] + } def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) misc_fields['repository'] = workflow.repository - if (workflow.commitId) misc_fields['commitid'] = workflow.commitId - if (workflow.revision) misc_fields['revision'] = workflow.revision - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp + misc_fields['start'] = workflow.start + misc_fields['complete'] = workflow.complete + misc_fields['scriptfile'] = workflow.scriptFile + misc_fields['scriptid'] = workflow.scriptId + if (workflow.repository) { + misc_fields['repository'] = workflow.repository + } + if (workflow.commitId) { + misc_fields['commitid'] = workflow.commitId + } + if (workflow.revision) { + misc_fields['revision'] = workflow.revision + } + misc_fields['nxf_version'] = workflow.nextflow.version + misc_fields['nxf_build'] = workflow.nextflow.build + misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp def msg_fields = [:] msg_fields['version'] = getWorkflowVersion() @@ -428,13 +450,13 @@ def imNotification(summary_params, hook_url) { def json_message = json_template.toString() // POST - def post = new URL(hook_url).openConnection(); + def post = new URL(hook_url).openConnection() post.setRequestMethod("POST") post.setDoOutput(true) post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")); - def postRC = post.getResponseCode(); - if (! postRC.equals(200)) { - log.warn(post.getErrorStream().getText()); + post.getOutputStream().write(json_message.getBytes("UTF-8")) + def postRC = post.getResponseCode() + if (!postRC.equals(200)) { + log.warn(post.getErrorStream().getText()) } } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf new file mode 100644 index 000000000..4994303ea --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -0,0 +1,46 @@ +// +// Subworkflow that uses the nf-schema plugin to validate parameters and render the parameter summary +// + +include { paramsSummaryLog } from 'plugin/nf-schema' +include { validateParameters } from 'plugin/nf-schema' + +workflow UTILS_NFSCHEMA_PLUGIN { + + take: + input_workflow // workflow: the workflow object used by nf-schema to get metadata from the workflow + validate_params // boolean: validate the parameters + parameters_schema // string: path to the parameters JSON schema. + // this has to be the same as the schema given to `validation.parametersSchema` + // when this input is empty it will automatically use the configured schema or + // "${projectDir}/nextflow_schema.json" as default. This input should not be empty + // for meta pipelines + + main: + + // + // Print parameter summary to stdout. This will display the parameters + // that differ from the default given in the JSON schema + // + if(parameters_schema) { + log.info paramsSummaryLog(input_workflow, parameters_schema:parameters_schema) + } else { + log.info paramsSummaryLog(input_workflow) + } + + // + // Validate the parameters using nextflow_schema.json or the schema + // given via the validation.parametersSchema configuration option + // + if(validate_params) { + if(parameters_schema) { + validateParameters(parameters_schema:parameters_schema) + } else { + validateParameters() + } + } + + emit: + dummy_emit = true +} + diff --git a/subworkflows/nf-core/utils_nfschema_plugin/meta.yml b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml new file mode 100644 index 000000000..f7d9f0288 --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "utils_nfschema_plugin" +description: Run nf-schema to validate parameters and create a summary of changed parameters +keywords: + - validation + - JSON schema + - plugin + - parameters + - summary +components: [] +input: + - input_workflow: + type: object + description: | + The workflow object of the used pipeline. + This object contains meta data used to create the params summary log + - validate_params: + type: boolean + description: Validate the parameters and error if invalid. + - parameters_schema: + type: string + description: | + Path to the parameters JSON schema. + This has to be the same as the schema given to the `validation.parametersSchema` config + option. When this input is empty it will automatically use the configured schema or + "${projectDir}/nextflow_schema.json" as default. The schema should not be given in this way + for meta pipelines. +output: + - dummy_emit: + type: boolean + description: Dummy emit to make nf-core subworkflows lint happy +authors: + - "@nvnieuwk" +maintainers: + - "@nvnieuwk" diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test new file mode 100644 index 000000000..842dc432a --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test @@ -0,0 +1,117 @@ +nextflow_workflow { + + name "Test Subworkflow UTILS_NFSCHEMA_PLUGIN" + script "../main.nf" + workflow "UTILS_NFSCHEMA_PLUGIN" + + tag "subworkflows" + tag "subworkflows_nfcore" + tag "subworkflows/utils_nfschema_plugin" + tag "plugin/nf-schema" + + config "./nextflow.config" + + test("Should run nothing") { + + when { + + params { + test_data = '' + } + + workflow { + """ + validate_params = false + input[0] = workflow + input[1] = validate_params + input[2] = "" + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should validate params") { + + when { + + params { + test_data = '' + outdir = 1 + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "" + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ Validation of pipeline parameters failed!') } } + ) + } + } + + test("Should run nothing - custom schema") { + + when { + + params { + test_data = '' + } + + workflow { + """ + validate_params = false + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } + + test("Should validate params - custom schema") { + + when { + + params { + test_data = '' + outdir = 1 + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + """ + } + } + + then { + assertAll( + { assert workflow.failed }, + { assert workflow.stdout.any { it.contains('ERROR ~ Validation of pipeline parameters failed!') } } + ) + } + } +} diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config new file mode 100644 index 000000000..0907ac58f --- /dev/null +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -0,0 +1,8 @@ +plugins { + id "nf-schema@2.1.0" +} + +validation { + parametersSchema = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + monochromeLogs = true +} \ No newline at end of file diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json similarity index 95% rename from subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json rename to subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json index 7626c1c93..331e0d2f4 100644 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/nextflow_schema.json +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json @@ -1,10 +1,10 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/./master/nextflow_schema.json", "title": ". pipeline parameters", "description": "", "type": "object", - "definitions": { + "$defs": { "input_output_options": { "title": "Input/output options", "type": "object", @@ -87,10 +87,10 @@ }, "allOf": [ { - "$ref": "#/definitions/input_output_options" + "$ref": "#/$defs/input_output_options" }, { - "$ref": "#/definitions/generic_options" + "$ref": "#/$defs/generic_options" } ] } diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf b/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf deleted file mode 100644 index 2585b65d1..000000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/main.nf +++ /dev/null @@ -1,62 +0,0 @@ -// -// Subworkflow that uses the nf-validation plugin to render help text and parameter summary -// - -/* -======================================================================================== - IMPORT NF-VALIDATION PLUGIN -======================================================================================== -*/ - -include { paramsHelp } from 'plugin/nf-validation' -include { paramsSummaryLog } from 'plugin/nf-validation' -include { validateParameters } from 'plugin/nf-validation' - -/* -======================================================================================== - SUBWORKFLOW DEFINITION -======================================================================================== -*/ - -workflow UTILS_NFVALIDATION_PLUGIN { - - take: - print_help // boolean: print help - workflow_command // string: default commmand used to run pipeline - pre_help_text // string: string to be printed before help text and summary log - post_help_text // string: string to be printed after help text and summary log - validate_params // boolean: validate parameters - schema_filename // path: JSON schema file, null to use default value - - main: - - log.debug "Using schema file: ${schema_filename}" - - // Default values for strings - pre_help_text = pre_help_text ?: '' - post_help_text = post_help_text ?: '' - workflow_command = workflow_command ?: '' - - // - // Print help message if needed - // - if (print_help) { - log.info pre_help_text + paramsHelp(workflow_command, parameters_schema: schema_filename) + post_help_text - System.exit(0) - } - - // - // Print parameter summary to stdout - // - log.info pre_help_text + paramsSummaryLog(workflow, parameters_schema: schema_filename) + post_help_text - - // - // Validate parameters relative to the parameter JSON schema - // - if (validate_params){ - validateParameters(parameters_schema: schema_filename) - } - - emit: - dummy_emit = true -} diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml b/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml deleted file mode 100644 index 3d4a6b04f..000000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/meta.yml +++ /dev/null @@ -1,44 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json -name: "UTILS_NFVALIDATION_PLUGIN" -description: Use nf-validation to initiate and validate a pipeline -keywords: - - utility - - pipeline - - initialise - - validation -components: [] -input: - - print_help: - type: boolean - description: | - Print help message and exit - - workflow_command: - type: string - description: | - The command to run the workflow e.g. "nextflow run main.nf" - - pre_help_text: - type: string - description: | - Text to print before the help message - - post_help_text: - type: string - description: | - Text to print after the help message - - validate_params: - type: boolean - description: | - Validate the parameters and error if invalid. - - schema_filename: - type: string - description: | - The filename of the schema to validate against. -output: - - dummy_emit: - type: boolean - description: | - Dummy emit to make nf-core subworkflows lint happy -authors: - - "@adamrtalbot" -maintainers: - - "@adamrtalbot" - - "@maxulysse" diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test deleted file mode 100644 index 5784a33f2..000000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/main.nf.test +++ /dev/null @@ -1,200 +0,0 @@ -nextflow_workflow { - - name "Test Workflow UTILS_NFVALIDATION_PLUGIN" - script "../main.nf" - workflow "UTILS_NFVALIDATION_PLUGIN" - tag "subworkflows" - tag "subworkflows_nfcore" - tag "plugin/nf-validation" - tag "'plugin/nf-validation'" - tag "utils_nfvalidation_plugin" - tag "subworkflows/utils_nfvalidation_plugin" - - test("Should run nothing") { - - when { - - params { - monochrome_logs = true - test_data = '' - } - - workflow { - """ - help = false - workflow_command = null - pre_help_text = null - post_help_text = null - validate_params = false - schema_filename = "$moduleTestDir/nextflow_schema.json" - - input[0] = help - input[1] = workflow_command - input[2] = pre_help_text - input[3] = post_help_text - input[4] = validate_params - input[5] = schema_filename - """ - } - } - - then { - assertAll( - { assert workflow.success } - ) - } - } - - test("Should run help") { - - - when { - - params { - monochrome_logs = true - test_data = '' - } - workflow { - """ - help = true - workflow_command = null - pre_help_text = null - post_help_text = null - validate_params = false - schema_filename = "$moduleTestDir/nextflow_schema.json" - - input[0] = help - input[1] = workflow_command - input[2] = pre_help_text - input[3] = post_help_text - input[4] = validate_params - input[5] = schema_filename - """ - } - } - - then { - assertAll( - { assert workflow.success }, - { assert workflow.exitStatus == 0 }, - { assert workflow.stdout.any { it.contains('Input/output options') } }, - { assert workflow.stdout.any { it.contains('--outdir') } } - ) - } - } - - test("Should run help with command") { - - when { - - params { - monochrome_logs = true - test_data = '' - } - workflow { - """ - help = true - workflow_command = "nextflow run noorg/doesntexist" - pre_help_text = null - post_help_text = null - validate_params = false - schema_filename = "$moduleTestDir/nextflow_schema.json" - - input[0] = help - input[1] = workflow_command - input[2] = pre_help_text - input[3] = post_help_text - input[4] = validate_params - input[5] = schema_filename - """ - } - } - - then { - assertAll( - { assert workflow.success }, - { assert workflow.exitStatus == 0 }, - { assert workflow.stdout.any { it.contains('nextflow run noorg/doesntexist') } }, - { assert workflow.stdout.any { it.contains('Input/output options') } }, - { assert workflow.stdout.any { it.contains('--outdir') } } - ) - } - } - - test("Should run help with extra text") { - - - when { - - params { - monochrome_logs = true - test_data = '' - } - workflow { - """ - help = true - workflow_command = "nextflow run noorg/doesntexist" - pre_help_text = "pre-help-text" - post_help_text = "post-help-text" - validate_params = false - schema_filename = "$moduleTestDir/nextflow_schema.json" - - input[0] = help - input[1] = workflow_command - input[2] = pre_help_text - input[3] = post_help_text - input[4] = validate_params - input[5] = schema_filename - """ - } - } - - then { - assertAll( - { assert workflow.success }, - { assert workflow.exitStatus == 0 }, - { assert workflow.stdout.any { it.contains('pre-help-text') } }, - { assert workflow.stdout.any { it.contains('nextflow run noorg/doesntexist') } }, - { assert workflow.stdout.any { it.contains('Input/output options') } }, - { assert workflow.stdout.any { it.contains('--outdir') } }, - { assert workflow.stdout.any { it.contains('post-help-text') } } - ) - } - } - - test("Should validate params") { - - when { - - params { - monochrome_logs = true - test_data = '' - outdir = 1 - } - workflow { - """ - help = false - workflow_command = null - pre_help_text = null - post_help_text = null - validate_params = true - schema_filename = "$moduleTestDir/nextflow_schema.json" - - input[0] = help - input[1] = workflow_command - input[2] = pre_help_text - input[3] = post_help_text - input[4] = validate_params - input[5] = schema_filename - """ - } - } - - then { - assertAll( - { assert workflow.failed }, - { assert workflow.stdout.any { it.contains('ERROR ~ ERROR: Validation of pipeline parameters failed!') } } - ) - } - } -} diff --git a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml b/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml deleted file mode 100644 index 60b1cfff4..000000000 --- a/subworkflows/nf-core/utils_nfvalidation_plugin/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -subworkflows/utils_nfvalidation_plugin: - - subworkflows/nf-core/utils_nfvalidation_plugin/** diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 7943efea0..21d6ec339 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -3,10 +3,9 @@ IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - include { FASTQC } from '../modules/nf-core/fastqc/main' include { MULTIQC } from '../modules/nf-core/multiqc/main' -include { paramsSummaryMap } from 'plugin/nf-validation' +include { paramsSummaryMap } from 'plugin/nf-schema' include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_quantms_pipeline' @@ -21,12 +20,10 @@ workflow QUANTMS { take: ch_samplesheet // channel: samplesheet read in from --input - main: ch_versions = Channel.empty() ch_multiqc_files = Channel.empty() - // // MODULE: Run FastQC // @@ -40,33 +37,57 @@ workflow QUANTMS { // Collate and save software versions // softwareVersionsToYAML(ch_versions) - .collectFile(storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_pipeline_software_mqc_versions.yml', sort: true, newLine: true) - .set { ch_collated_versions } + .collectFile( + storeDir: "${params.outdir}/pipeline_info", + name: 'nf_core_' + 'pipeline_software_' + 'mqc_' + 'versions.yml', + sort: true, + newLine: true + ).set { ch_collated_versions } + // // MODULE: MultiQC // - ch_multiqc_config = Channel.fromPath("$projectDir/assets/multiqc_config.yml", checkIfExists: true) - ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config, checkIfExists: true) : Channel.empty() - ch_multiqc_logo = params.multiqc_logo ? Channel.fromPath(params.multiqc_logo, checkIfExists: true) : Channel.empty() - summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") - ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? file(params.multiqc_methods_description, checkIfExists: true) : file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) - ch_methods_description = Channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) - ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: false)) + ch_multiqc_config = Channel.fromPath( + "$projectDir/assets/multiqc_config.yml", checkIfExists: true) + ch_multiqc_custom_config = params.multiqc_config ? + Channel.fromPath(params.multiqc_config, checkIfExists: true) : + Channel.empty() + ch_multiqc_logo = params.multiqc_logo ? + Channel.fromPath(params.multiqc_logo, checkIfExists: true) : + Channel.empty() + + summary_params = paramsSummaryMap( + workflow, parameters_schema: "nextflow_schema.json") + ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) + ch_multiqc_files = ch_multiqc_files.mix( + ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + ch_multiqc_custom_methods_description = params.multiqc_methods_description ? + file(params.multiqc_methods_description, checkIfExists: true) : + file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) + ch_methods_description = Channel.value( + methodsDescriptionText(ch_multiqc_custom_methods_description)) + + ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) + ch_multiqc_files = ch_multiqc_files.mix( + ch_methods_description.collectFile( + name: 'methods_description_mqc.yaml', + sort: true + ) + ) MULTIQC ( ch_multiqc_files.collect(), ch_multiqc_config.toList(), ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList() + ch_multiqc_logo.toList(), + [], + [] ) - emit: - multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html + emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html versions = ch_versions // channel: [ path(versions.yml) ] + } /* From f5cf008fc414f7647f068467a6150a4d450654a2 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 15:11:49 +0100 Subject: [PATCH 07/34] update template 3.0.2 --- CHANGELOG.md | 2 +- conf/base.config | 1 + modules.json | 5 +++++ nextflow.config | 17 +++++++++++++++-- nextflow_schema.json | 38 -------------------------------------- 5 files changed, 22 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1be5825e4..f90118cec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -172,7 +172,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#193](https://github.com/bigbio/quantms/pull/193) - Set the `local_input_type` default parameter to `mzML` - [#212](https://github.com/bigbio/quantms/pull/212) - Set the `min_consensus_support` default parameter to `1` to filter in ConsensusID for peptides identified with both search engines -- [#200](https://github.com/bigbio/quantms/pull/200) - Add `export_mztab` parameter to allow to run PROTEINQUANTIFIER TMT without exporting to mzTab +- [#200](https://github.com/bigbio/quantms/pull/200) - Add `export_mztab` parameter to allow torun PROTEINQUANTIFIER TMT without exporting to mzTab ## [1.0] nfcore/quantms - [05/02/2022] - Havana diff --git a/conf/base.config b/conf/base.config index 3720c482e..716af6cf9 100644 --- a/conf/base.config +++ b/conf/base.config @@ -36,6 +36,7 @@ process { cpus = { 4 * task.attempt } memory = { 12.GB * task.attempt } time = { 6.h * task.attempt } + } withLabel:process_very_low { cpus = { 2 * task.attempt} memory = { 6.GB * task.attempt} diff --git a/modules.json b/modules.json index 93543bb52..fbff41a19 100644 --- a/modules.json +++ b/modules.json @@ -10,6 +10,11 @@ "git_sha": "8ec825f465b9c17f9d83000022995b4f7de6fe93", "installed_by": ["modules"] }, + "fastqc": { + "branch": "master", + "git_sha": "49b18b1639f4f7104187058866a8fab33332bdfe", + "installed_by": ["modules"] + }, "multiqc": { "branch": "master", "git_sha": "cf17ca47590cc578dfb47db1c2a44ef86f89976d", diff --git a/nextflow.config b/nextflow.config index 0e3ca471a..d30b69461 100644 --- a/nextflow.config +++ b/nextflow.config @@ -392,8 +392,21 @@ profiles { conda.useMamba = true process.executor = 'lsf' } - test { includeConfig 'conf/test.config' } - test_full { includeConfig 'conf/test_full.config' } + test { includeConfig 'conf/test_lfq.config' } + test_localize { includeConfig 'conf/test_localize.config' } + test_tmt { includeConfig 'conf/test_tmt.config' } + test_tmt_corr { includeConfig 'conf/test_tmt_corr.config' } + test_lfq { includeConfig 'conf/test_lfq.config' } + test_lfq_sage { includeConfig 'conf/test_lfq_sage.config' } + test_dia { includeConfig 'conf/test_dia.config' } + test_latest_dia { includeConfig 'conf/test_latest_dia.config' } + test_full_lfq { includeConfig 'conf/test_full_lfq.config' } + test_full_tmt { includeConfig 'conf/test_full_tmt.config' } + test_full_dia { includeConfig 'conf/test_full_dia.config' } + test_full { includeConfig 'conf/test_full_lfq.config' } + test_dda_id { includeConfig 'conf/test_dda_id.config' } + mambaci { includeConfig 'conf/mambaci.config' } + } // Load nf-core custom profiles from different Institutions diff --git a/nextflow_schema.json b/nextflow_schema.json index c94014f8b..59722a71b 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -1297,41 +1297,6 @@ } } }, - "max_job_request_options": { - "title": "Max job request options", - "type": "object", - "fa_icon": "fab fa-acquisitions-incorporated", - "description": "Set the top limit for requested resources for any single job.", - "help_text": "If you are running on a smaller system, a pipeline step requesting more resources than are available may cause the Nextflow to stop the run with an error. These options allow you to cap the maximum resources requested by any single job so that the pipeline will run on your system.\n\nNote that you can not _increase_ the resources requested by any job using these options. For that you will need your own configuration file. See [the nf-core website](https://nf-co.re/usage/configuration) for details.", - "properties": { - "max_cpus": { - "type": "integer", - "description": "Maximum number of CPUs that can be requested for any single job.", - "default": 16, - "fa_icon": "fas fa-microchip", - "hidden": true, - "help_text": "Use to set an upper-limit for the CPU requirement for each process. Should be an integer e.g. `--max_cpus 1`" - }, - "max_memory": { - "type": "string", - "description": "Maximum amount of memory that can be requested for any single job.", - "default": "128 GB", - "fa_icon": "fas fa-memory", - "pattern": "^\\d+(\\.\\d+)?\\.?\\s*(K|M|G|T)?B$", - "hidden": true, - "help_text": "Use to set an upper-limit for the memory requirement for each process. Should be a string in the format integer-unit e.g. `--max_memory '8.GB'`" - }, - "max_time": { - "type": "string", - "description": "Maximum amount of time that can be requested for any single job.", - "default": "10d", - "fa_icon": "far fa-clock", - "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'`" - } - } - }, "generic_options": { "title": "Generic options", "type": "object", @@ -1488,9 +1453,6 @@ { "$ref": "#/$defs/quality_control" }, - { - "$ref": "#/$defs/reference_genome_options" - }, { "$ref": "#/$defs/institutional_config_options" }, From 66741adf243fc5693cbca59afe95d2095dd8fb15 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 15:14:20 +0100 Subject: [PATCH 08/34] update template 3.0.2 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b25226dd7..995bd0ef8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ test_out lint_log.txt node_modules +/lint_results.md From e12efa091da3536fe09ed09fb8d1ca8e5bad9540 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 15:20:44 +0100 Subject: [PATCH 09/34] update template 3.0.2 --- .github/workflows/awsfulltest.yml | 0 .github/workflows/awstest.yml | 0 .github/workflows/release-announcements.yml | 0 .nf-core.yml | 1 + 4 files changed, 1 insertion(+) delete mode 100644 .github/workflows/awsfulltest.yml delete mode 100644 .github/workflows/awstest.yml delete mode 100644 .github/workflows/release-announcements.yml diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.nf-core.yml b/.nf-core.yml index 8910c3cc0..f332bf02e 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -6,6 +6,7 @@ lint: - conf/test.config - .github/workflows/awstest.yml - .github/workflows/awsfulltest.yml + - .github/workflows/ci.yml files_unchanged: - .github/PULL_REQUEST_TEMPLATE.md - .github/CONTRIBUTING.md From 8c788015d6e295443342ef048e2cf6928a18f538 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 15:23:56 +0100 Subject: [PATCH 10/34] update template 3.0.2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d1110f51..6b07bd840 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![GitHub Actions Linting Status](https://github.com/nf-core/quantms/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/quantms/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/quantms/results)[![Cite with Zenodo](https://img.shields.io/badge/DOI-10.5281/zenodo.7754148-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.7754148) [![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A523.04.0-23aa62.svg)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A524.04.2-23aa62.svg)](https://www.nextflow.io/) [![run with conda](https://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) From bd907050dcf5b24f58b4554a5c0005d93199acc4 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 15:31:40 +0100 Subject: [PATCH 11/34] update template 3.0.2 --- .nf-core.yml | 1 + workflows/quantms.nf | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.nf-core.yml b/.nf-core.yml index f332bf02e..14bda35d2 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -7,6 +7,7 @@ lint: - .github/workflows/awstest.yml - .github/workflows/awsfulltest.yml - .github/workflows/ci.yml + - .gitignore files_unchanged: - .github/PULL_REQUEST_TEMPLATE.md - .github/CONTRIBUTING.md diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 57630bad3..157db2956 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -4,7 +4,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { paramsSummaryMap } from 'plugin/nf-validation' +include { paramsSummaryMap } from 'plugin/nf-schema' include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_quantms_pipeline' From cb7700223beea4a5fdd858de67c38541060fc67f Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 15:36:31 +0100 Subject: [PATCH 12/34] update template 3.0.2 --- .gitignore | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 995bd0ef8..a42ce0162 100644 --- a/.gitignore +++ b/.gitignore @@ -6,17 +6,4 @@ results/ testing/ testing* *.pyc -.idea/ -.idea/* -*.log -/build/ -results*/ -venv/ -node_modules -conversion_inputs -debug_dir -test_out - -lint_log.txt -node_modules -/lint_results.md +null/ From 75b20591a8d8e83575535aace2f7210fe6eff79f Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 15:47:08 +0100 Subject: [PATCH 13/34] update template 3.0.2 --- modules/local/pmultiqc/main.nf | 2 -- subworkflows/local/dda_id.nf | 1 - subworkflows/local/id.nf | 1 - 3 files changed, 4 deletions(-) diff --git a/modules/local/pmultiqc/main.nf b/modules/local/pmultiqc/main.nf index a689c17b0..8636ddd9f 100644 --- a/modules/local/pmultiqc/main.nf +++ b/modules/local/pmultiqc/main.nf @@ -31,10 +31,8 @@ process PMULTIQC { # leaving here to ease debugging ls -lcth * - echo ">>>>>>>>> Experimental Design <<<<<<<<<" cat results/*openms_design.tsv - echo ">>>>>>>>> Running Multiqc <<<<<<<<<" multiqc \\ -f \\ --config ./results/multiqc_config.yml \\ diff --git a/subworkflows/local/dda_id.nf b/subworkflows/local/dda_id.nf index 397a56a6e..fe94e5f44 100644 --- a/subworkflows/local/dda_id.nf +++ b/subworkflows/local/dda_id.nf @@ -1,7 +1,6 @@ // // MODULE: Local to the pipeline // -include { DECOYDATABASE } from '../../modules/local/openms/decoydatabase/main' include { CONSENSUSID } from '../../modules/local/openms/consensusid/main' include { EXTRACTPSMFEATURES } from '../../modules/local/openms/extractpsmfeatures/main' include { PERCOLATOR } from '../../modules/local/openms/thirdparty/percolator/main' diff --git a/subworkflows/local/id.nf b/subworkflows/local/id.nf index b851ab818..d84075d0a 100644 --- a/subworkflows/local/id.nf +++ b/subworkflows/local/id.nf @@ -1,7 +1,6 @@ // // MODULE: Local to the pipeline // -include { DECOYDATABASE } from '../../modules/local/openms/decoydatabase/main' include { CONSENSUSID } from '../../modules/local/openms/consensusid/main' // From 02c7617d3d67292ddaa6becb43dce27e1e382668 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 16:40:46 +0100 Subject: [PATCH 14/34] update template 3.0.2 --- workflows/quantms.nf | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 157db2956..72546f31e 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -74,8 +74,6 @@ workflow QUANTMS { lfq: it[0].labelling_type.contains("label free") } .set{ch_fileprep_result} - - // // WORKFLOW: Run main nf-core/quantms analysis pipeline based on the quantification type // @@ -140,13 +138,9 @@ workflow QUANTMS { // // Collate and save software versions // - ch_versions - .branch { - yaml : it.asBoolean() - other : true - } - .set{ versions_clean } - + ch_versions.subscribe { version -> + println "DEBUG: Version Info: ${version}" + } softwareVersionsToYAML(ch_versions) .collectFile( storeDir: "${params.outdir}/pipeline_info", From e5fe179ad5e910da017b91d8aad1a17565f49788 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 20:01:46 +0100 Subject: [PATCH 15/34] update template 3.0.2 - versions issues --- modules/local/add_sage_feat/main.nf | 2 +- .../local/assemble_empirical_library/main.nf | 2 +- modules/local/decompress_dotd/main.nf | 2 +- .../local/diann_preliminary_analysis/main.nf | 2 +- modules/local/diannconvert/main.nf | 2 +- modules/local/diannsummary/main.nf | 2 +- modules/local/extract_psm/main.nf | 2 +- modules/local/generate_diann_cfg/main.nf | 2 +- .../local/individual_final_analysis/main.nf | 2 +- modules/local/msstats/main.nf | 2 +- modules/local/msstatstmt/main.nf | 2 +- modules/local/mzmlstatistics/main.nf | 2 +- modules/local/openms/consensusid/main.nf | 2 +- modules/local/openms/decoydatabase/main.nf | 2 +- modules/local/openms/epifany/main.nf | 2 +- .../local/openms/extractpsmfeatures/main.nf | 2 +- .../local/openms/falsediscoveryrate/main.nf | 2 +- modules/local/openms/filemerge/main.nf | 2 +- .../local/openms/idconflictresolver/main.nf | 2 +- modules/local/openms/idfilter/main.nf | 2 +- modules/local/openms/idmapper/main.nf | 2 +- modules/local/openms/idmerger/main.nf | 2 +- modules/local/openms/idpep/main.nf | 2 +- modules/local/openms/idripper/main.nf | 2 +- modules/local/openms/idscoreswitcher/main.nf | 2 +- modules/local/openms/indexpeptides/main.nf | 2 +- modules/local/openms/isobaricanalyzer/main.nf | 2 +- modules/local/openms/msstatsconverter/main.nf | 2 +- modules/local/openms/mzmlindexing/main.nf | 2 +- modules/local/openms/openmspeakpicker/main.nf | 2 +- modules/local/openms/proteininference/main.nf | 2 +- .../local/openms/proteinquantifier/main.nf | 2 +- modules/local/openms/proteomicslfq/main.nf | 2 +- .../openms/thirdparty/luciphoradapter/main.nf | 2 +- .../openms/thirdparty/msgfdb_indexing/main.nf | 2 +- .../openms/thirdparty/percolator/main.nf | 2 +- .../thirdparty/searchenginecomet/main.nf | 2 +- .../thirdparty/searchenginemsgf/main.nf | 2 +- .../thirdparty/searchenginesage/main.nf | 2 +- modules/local/sdrfparsing/main.nf | 2 +- modules/local/silicolibrarygeneration/main.nf | 2 +- modules/local/spectrum2features/main.nf | 2 +- modules/local/tdf2mzml/main.nf | 2 +- modules/local/thermorawfileparser/main.nf | 2 +- subworkflows/local/create_input_channel.nf | 8 ++-- subworkflows/local/databasesearchengines.nf | 9 ++-- subworkflows/local/dda_id.nf | 41 ++++++++++--------- subworkflows/local/featuremapper.nf | 6 +-- subworkflows/local/file_preparation.nf | 14 +++---- subworkflows/local/id.nf | 12 +++--- subworkflows/local/input_check.nf | 4 +- subworkflows/local/phosphoscoring.nf | 6 +-- subworkflows/local/proteininference.nf | 8 ++-- subworkflows/local/proteinquant.nf | 9 ++-- subworkflows/local/psmfdrcontrol.nf | 10 ++--- subworkflows/local/psmrescoring.nf | 30 +++++++------- workflows/dia.nf | 16 ++++---- workflows/lfq.nf | 6 +-- workflows/quantms.nf | 9 ++-- workflows/tmt.nf | 12 +++--- 60 files changed, 147 insertions(+), 141 deletions(-) diff --git a/modules/local/add_sage_feat/main.nf b/modules/local/add_sage_feat/main.nf index ce30e5d5e..ce7f53db7 100644 --- a/modules/local/add_sage_feat/main.nf +++ b/modules/local/add_sage_feat/main.nf @@ -12,7 +12,7 @@ process SAGEFEATURE { output: tuple val(meta), path("${id_file.baseName}_feat.idXML"), emit: id_files_feat - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/assemble_empirical_library/main.nf b/modules/local/assemble_empirical_library/main.nf index 69acbcb4f..2aa1d9d53 100644 --- a/modules/local/assemble_empirical_library/main.nf +++ b/modules/local/assemble_empirical_library/main.nf @@ -20,7 +20,7 @@ process ASSEMBLE_EMPIRICAL_LIBRARY { output: path "empirical_library.tsv", emit: empirical_library path "assemble_empirical_library.log", emit: log - path "versions.yml", emit: version + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/decompress_dotd/main.nf b/modules/local/decompress_dotd/main.nf index 7529e17fb..88752b524 100644 --- a/modules/local/decompress_dotd/main.nf +++ b/modules/local/decompress_dotd/main.nf @@ -32,7 +32,7 @@ process DECOMPRESS { output: tuple val(meta), path('*.d'), emit: decompressed_files - path 'versions.yml', emit: version + path 'versions.yml', emit: versions path '*.log', emit: log script: diff --git a/modules/local/diann_preliminary_analysis/main.nf b/modules/local/diann_preliminary_analysis/main.nf index 0d4a5c0da..01699a93f 100644 --- a/modules/local/diann_preliminary_analysis/main.nf +++ b/modules/local/diann_preliminary_analysis/main.nf @@ -16,7 +16,7 @@ process DIANN_PRELIMINARY_ANALYSIS { output: path "*.quant", emit: diann_quant tuple val(meta), path("*_diann.log"), emit: log - path "versions.yml", emit: version + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/diannconvert/main.nf b/modules/local/diannconvert/main.nf index 6f4a78df9..40b273b1d 100644 --- a/modules/local/diannconvert/main.nf +++ b/modules/local/diannconvert/main.nf @@ -22,7 +22,7 @@ process DIANNCONVERT { path "*triqler_in.tsv", emit: out_triqler path "*.mzTab", emit: out_mztab path "*.log", emit: log - path "versions.yml", emit: version + path "versions.yml", emit: versions exec: log.info "DIANNCONVERT is based on the output of DIA-NN 1.8.1 and 1.9.beta.1, other versions of DIA-NN do not support mzTab conversion." diff --git a/modules/local/diannsummary/main.nf b/modules/local/diannsummary/main.nf index dc76e8171..c85476912 100644 --- a/modules/local/diannsummary/main.nf +++ b/modules/local/diannsummary/main.nf @@ -31,7 +31,7 @@ process DIANNSUMMARY { // Different library files format are exported due to different DIA-NN versions path "empirical_library.tsv", emit: final_speclib optional true path "empirical_library.tsv.skyline.speclib", emit: skyline_speclib optional true - path "versions.yml", emit: version + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/extract_psm/main.nf b/modules/local/extract_psm/main.nf index b5f6ff32b..ce166ae33 100644 --- a/modules/local/extract_psm/main.nf +++ b/modules/local/extract_psm/main.nf @@ -13,7 +13,7 @@ process PSMCONVERSION { output: path "*_psm.parquet", emit: psm_info - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/generate_diann_cfg/main.nf b/modules/local/generate_diann_cfg/main.nf index 10aea5e20..3e4b5a916 100644 --- a/modules/local/generate_diann_cfg/main.nf +++ b/modules/local/generate_diann_cfg/main.nf @@ -12,7 +12,7 @@ process GENERATE_DIANN_CFG { output: path 'diann_config.cfg', emit: diann_cfg - path 'versions.yml', emit: version + path 'versions.yml', emit: versions path '*.log' script: diff --git a/modules/local/individual_final_analysis/main.nf b/modules/local/individual_final_analysis/main.nf index cb9036a06..35efa3dab 100644 --- a/modules/local/individual_final_analysis/main.nf +++ b/modules/local/individual_final_analysis/main.nf @@ -16,7 +16,7 @@ process INDIVIDUAL_FINAL_ANALYSIS { output: path "*.quant", emit: diann_quant path "*_final_diann.log", emit: log - path "versions.yml", emit: version + path "versions.yml", emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/local/msstats/main.nf b/modules/local/msstats/main.nf index 53f45d764..1c4467d3d 100644 --- a/modules/local/msstats/main.nf +++ b/modules/local/msstats/main.nf @@ -16,7 +16,7 @@ process MSSTATS { path "*.pdf" optional true path "*.csv", emit: msstats_csv path "*.log", emit: log - path "versions.yml" , emit: version + path "versions.yml" , emit: versions script: def args = task.ext.args ?: '' diff --git a/modules/local/msstatstmt/main.nf b/modules/local/msstatstmt/main.nf index 458704b8a..51f6349d0 100644 --- a/modules/local/msstatstmt/main.nf +++ b/modules/local/msstatstmt/main.nf @@ -16,7 +16,7 @@ process MSSTATSTMT { path "*.pdf" optional true path "*.csv", emit: msstats_csv path "*.log" - path "versions.yml" , emit: version + path "versions.yml" , emit: versions script: def args = task.ext.args ?: '' diff --git a/modules/local/mzmlstatistics/main.nf b/modules/local/mzmlstatistics/main.nf index 3134262e9..295cce780 100644 --- a/modules/local/mzmlstatistics/main.nf +++ b/modules/local/mzmlstatistics/main.nf @@ -14,7 +14,7 @@ process MZMLSTATISTICS { output: path "*_ms_info.parquet", emit: ms_statistics tuple val(meta), path("*_spectrum_df.parquet"), emit: spectrum_df, optional: true - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/consensusid/main.nf b/modules/local/openms/consensusid/main.nf index 4ee09d7a3..323bc0508 100644 --- a/modules/local/openms/consensusid/main.nf +++ b/modules/local/openms/consensusid/main.nf @@ -13,7 +13,7 @@ process CONSENSUSID { output: tuple val(meta), path("${meta.mzml_id}_consensus.idXML"), emit: consensusids - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/decoydatabase/main.nf b/modules/local/openms/decoydatabase/main.nf index de0f9dc91..2f38aec63 100644 --- a/modules/local/openms/decoydatabase/main.nf +++ b/modules/local/openms/decoydatabase/main.nf @@ -12,7 +12,7 @@ process DECOYDATABASE { output: path "*.fasta", emit: db_decoy - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/epifany/main.nf b/modules/local/openms/epifany/main.nf index 9275959ce..0763e0f13 100644 --- a/modules/local/openms/epifany/main.nf +++ b/modules/local/openms/epifany/main.nf @@ -12,7 +12,7 @@ process EPIFANY { output: tuple val(meta), path("${consus_file.baseName}_epi.consensusXML"), emit: epi_inference - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/extractpsmfeatures/main.nf b/modules/local/openms/extractpsmfeatures/main.nf index c6a1dcd6d..8270f4687 100644 --- a/modules/local/openms/extractpsmfeatures/main.nf +++ b/modules/local/openms/extractpsmfeatures/main.nf @@ -14,7 +14,7 @@ process EXTRACTPSMFEATURES { output: tuple val(meta), path("${id_file.baseName}_feat.idXML"), emit: id_files_feat - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/falsediscoveryrate/main.nf b/modules/local/openms/falsediscoveryrate/main.nf index 37316096c..8bb5758e2 100644 --- a/modules/local/openms/falsediscoveryrate/main.nf +++ b/modules/local/openms/falsediscoveryrate/main.nf @@ -14,7 +14,7 @@ process FALSEDISCOVERYRATE { output: tuple val(meta), path("${id_file.baseName}_fdr.idXML"), emit: id_files_idx_ForIDPEP_FDR - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/filemerge/main.nf b/modules/local/openms/filemerge/main.nf index 855c37839..6fee0ebcb 100644 --- a/modules/local/openms/filemerge/main.nf +++ b/modules/local/openms/filemerge/main.nf @@ -13,7 +13,7 @@ process FILEMERGE { output: tuple val([:]), path("ID_mapper_merge.consensusXML"), emit: id_merge - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/idconflictresolver/main.nf b/modules/local/openms/idconflictresolver/main.nf index ee2eb2d44..95a0d5e63 100644 --- a/modules/local/openms/idconflictresolver/main.nf +++ b/modules/local/openms/idconflictresolver/main.nf @@ -12,7 +12,7 @@ process IDCONFLICTRESOLVER { output: path "${consus_file.baseName}_resconf.consensusXML", emit: pro_resconf - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/idfilter/main.nf b/modules/local/openms/idfilter/main.nf index 451cab6c4..c0f5ebe56 100644 --- a/modules/local/openms/idfilter/main.nf +++ b/modules/local/openms/idfilter/main.nf @@ -14,7 +14,7 @@ process IDFILTER { output: tuple val(meta), path("${id_file.baseName}_filter$task.ext.suffix"), emit: id_filtered - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/idmapper/main.nf b/modules/local/openms/idmapper/main.nf index bc155da0f..a03250e3c 100644 --- a/modules/local/openms/idmapper/main.nf +++ b/modules/local/openms/idmapper/main.nf @@ -13,7 +13,7 @@ process IDMAPPER { output: path "${id_file.baseName}_map.consensusXML", emit: id_map - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/idmerger/main.nf b/modules/local/openms/idmerger/main.nf index 2e20d3a8a..2fd67ad3e 100644 --- a/modules/local/openms/idmerger/main.nf +++ b/modules/local/openms/idmerger/main.nf @@ -13,7 +13,7 @@ process IDMERGER { output: tuple val(meta), path("*_merged.idXML"), emit: id_merged - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/idpep/main.nf b/modules/local/openms/idpep/main.nf index f414d7a03..22eda8e56 100644 --- a/modules/local/openms/idpep/main.nf +++ b/modules/local/openms/idpep/main.nf @@ -13,7 +13,7 @@ process IDPEP { output: tuple val(meta), path("${id_file.baseName}_idpep.idXML"), val("q-value_score"), emit: id_files_ForIDPEP - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/idripper/main.nf b/modules/local/openms/idripper/main.nf index bb91d9b17..2a888db4b 100644 --- a/modules/local/openms/idripper/main.nf +++ b/modules/local/openms/idripper/main.nf @@ -15,7 +15,7 @@ process IDRIPPER { val(meta), emit: meta path("*.idXML"), emit: id_rippers val("MS:1001491"), emit: qval_score - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/idscoreswitcher/main.nf b/modules/local/openms/idscoreswitcher/main.nf index 058bbd192..85866af7c 100644 --- a/modules/local/openms/idscoreswitcher/main.nf +++ b/modules/local/openms/idscoreswitcher/main.nf @@ -14,7 +14,7 @@ process IDSCORESWITCHER { output: tuple val(meta), path("${id_file.baseName}_pep.idXML"), emit: id_score_switcher - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/indexpeptides/main.nf b/modules/local/openms/indexpeptides/main.nf index f3830c862..e55f806d9 100644 --- a/modules/local/openms/indexpeptides/main.nf +++ b/modules/local/openms/indexpeptides/main.nf @@ -14,7 +14,7 @@ process INDEXPEPTIDES { output: tuple val(meta), path("${id_file.baseName}_idx.idXML"), emit: id_files_idx - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/isobaricanalyzer/main.nf b/modules/local/openms/isobaricanalyzer/main.nf index 4e12ef00c..3e47ec220 100644 --- a/modules/local/openms/isobaricanalyzer/main.nf +++ b/modules/local/openms/isobaricanalyzer/main.nf @@ -13,7 +13,7 @@ process ISOBARICANALYZER { output: tuple val(meta), path("${mzml_file.baseName}_iso.consensusXML"), emit: id_files_consensusXML - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/msstatsconverter/main.nf b/modules/local/openms/msstatsconverter/main.nf index a5e87f325..4b5e48e97 100644 --- a/modules/local/openms/msstatsconverter/main.nf +++ b/modules/local/openms/msstatsconverter/main.nf @@ -15,7 +15,7 @@ process MSSTATSCONVERTER { output: path "*_msstats_in.csv", emit: out_msstats - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/mzmlindexing/main.nf b/modules/local/openms/mzmlindexing/main.nf index d2504b26a..3ba7a80ac 100644 --- a/modules/local/openms/mzmlindexing/main.nf +++ b/modules/local/openms/mzmlindexing/main.nf @@ -13,7 +13,7 @@ process MZMLINDEXING { output: tuple val(meta), path("out/*.mzML"), emit: mzmls_indexed - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/openmspeakpicker/main.nf b/modules/local/openms/openmspeakpicker/main.nf index d7834b9ef..df1750d58 100644 --- a/modules/local/openms/openmspeakpicker/main.nf +++ b/modules/local/openms/openmspeakpicker/main.nf @@ -13,7 +13,7 @@ process OPENMSPEAKPICKER { output: tuple val(meta), path("*.mzML"), emit: mzmls_picked - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/proteininference/main.nf b/modules/local/openms/proteininference/main.nf index 0ef2e1cdd..8d05ec6af 100644 --- a/modules/local/openms/proteininference/main.nf +++ b/modules/local/openms/proteininference/main.nf @@ -12,7 +12,7 @@ process PROTEININFERENCE { output: tuple val(meta), path("${consus_file.baseName}_epi.consensusXML"), emit: protein_inference - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/proteinquantifier/main.nf b/modules/local/openms/proteinquantifier/main.nf index 33170cd04..a6170c4e5 100644 --- a/modules/local/openms/proteinquantifier/main.nf +++ b/modules/local/openms/proteinquantifier/main.nf @@ -17,7 +17,7 @@ process PROTEINQUANTIFIER { path "*peptide_openms.csv", emit: peptide_out path "*.mzTab", optional: true, emit: out_mztab path "*.log" - path "versions.yml", emit: version + path "versions.yml", emit: versions script: def args = task.ext.args ?: '' diff --git a/modules/local/openms/proteomicslfq/main.nf b/modules/local/openms/proteomicslfq/main.nf index 4f36c98e7..00fecdb50 100644 --- a/modules/local/openms/proteomicslfq/main.nf +++ b/modules/local/openms/proteomicslfq/main.nf @@ -26,7 +26,7 @@ process PROTEOMICSLFQ { path "debug_mergedIDsGreedyResolvedFDRFiltered.idXML", emit: debug_mergedIDsGreedyResolvedFDRFiltered optional true path "debug_mergedIDsFDRFilteredStrictlyUniqueResolved.idXML", emit: debug_mergedIDsFDRFilteredStrictlyUniqueResolved optional true path "*.log", emit: log - path "versions.yml", emit: version + path "versions.yml", emit: versions script: def args = task.ext.args ?: '' diff --git a/modules/local/openms/thirdparty/luciphoradapter/main.nf b/modules/local/openms/thirdparty/luciphoradapter/main.nf index e09172d26..06f67e4c5 100644 --- a/modules/local/openms/thirdparty/luciphoradapter/main.nf +++ b/modules/local/openms/thirdparty/luciphoradapter/main.nf @@ -14,7 +14,7 @@ process LUCIPHORADAPTER { output: tuple val(meta), path("${id_file.baseName}_luciphor.idXML"), emit: ptm_in_id_luciphor - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/thirdparty/msgfdb_indexing/main.nf b/modules/local/openms/thirdparty/msgfdb_indexing/main.nf index fca18e6d1..000f2fa8a 100644 --- a/modules/local/openms/thirdparty/msgfdb_indexing/main.nf +++ b/modules/local/openms/thirdparty/msgfdb_indexing/main.nf @@ -13,7 +13,7 @@ process MSGFDBINDEXING { output: tuple path("${database.baseName}.cnlcp"), path("${database.baseName}.canno"), path("${database.baseName}.csarr"), path("${database.baseName}.cseq"), emit: msgfdb_idx - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/thirdparty/percolator/main.nf b/modules/local/openms/thirdparty/percolator/main.nf index 83cda1a57..98820e1d5 100644 --- a/modules/local/openms/thirdparty/percolator/main.nf +++ b/modules/local/openms/thirdparty/percolator/main.nf @@ -13,7 +13,7 @@ process PERCOLATOR { output: tuple val(meta), path("*_perc.idXML"), val("MS:1001491"), emit: id_files_perc - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/thirdparty/searchenginecomet/main.nf b/modules/local/openms/thirdparty/searchenginecomet/main.nf index 9af0af878..fc5201002 100644 --- a/modules/local/openms/thirdparty/searchenginecomet/main.nf +++ b/modules/local/openms/thirdparty/searchenginecomet/main.nf @@ -13,7 +13,7 @@ process SEARCHENGINECOMET { output: tuple val(meta), path("${mzml_file.baseName}_comet.idXML"), emit: id_files_comet - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/thirdparty/searchenginemsgf/main.nf b/modules/local/openms/thirdparty/searchenginemsgf/main.nf index 641267e88..6a5dace12 100644 --- a/modules/local/openms/thirdparty/searchenginemsgf/main.nf +++ b/modules/local/openms/thirdparty/searchenginemsgf/main.nf @@ -13,7 +13,7 @@ process SEARCHENGINEMSGF { output: tuple val(meta), path("${mzml_file.baseName}_msgf.idXML"), emit: id_files_msgf - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/openms/thirdparty/searchenginesage/main.nf b/modules/local/openms/thirdparty/searchenginesage/main.nf index 1a6359f72..3cfcf1bd8 100644 --- a/modules/local/openms/thirdparty/searchenginesage/main.nf +++ b/modules/local/openms/thirdparty/searchenginesage/main.nf @@ -13,7 +13,7 @@ process SEARCHENGINESAGE { output: tuple val(metas), path(meta_order_files), emit: id_files_sage - path "versions.yml" , emit: version + path "versions.yml" , emit: versions path "*.log" , emit: log script: diff --git a/modules/local/sdrfparsing/main.nf b/modules/local/sdrfparsing/main.nf index 451121e76..53899f0b6 100644 --- a/modules/local/sdrfparsing/main.nf +++ b/modules/local/sdrfparsing/main.nf @@ -14,7 +14,7 @@ process SDRFPARSING { path "${sdrf.baseName}_openms_design.tsv", emit: ch_expdesign path "${sdrf.baseName}_config.tsv" , emit: ch_sdrf_config_file path "*.log" , emit: log - path "versions.yml" , emit: version + path "versions.yml" , emit: versions script: def args = task.ext.args ?: '' diff --git a/modules/local/silicolibrarygeneration/main.nf b/modules/local/silicolibrarygeneration/main.nf index d51ab973f..50b16e782 100644 --- a/modules/local/silicolibrarygeneration/main.nf +++ b/modules/local/silicolibrarygeneration/main.nf @@ -15,7 +15,7 @@ process SILICOLIBRARYGENERATION { file(diann_config) output: - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.predicted.speclib", emit: predict_speclib path "silicolibrarygeneration.log", emit: log diff --git a/modules/local/spectrum2features/main.nf b/modules/local/spectrum2features/main.nf index 7e5a7cc0d..7deaf981e 100644 --- a/modules/local/spectrum2features/main.nf +++ b/modules/local/spectrum2features/main.nf @@ -12,7 +12,7 @@ process SPECTRUM2FEATURES { output: tuple val(meta), path("${id_file.baseName}_snr.idXML"), emit: id_files_snr - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/tdf2mzml/main.nf b/modules/local/tdf2mzml/main.nf index a31332700..3b0521096 100644 --- a/modules/local/tdf2mzml/main.nf +++ b/modules/local/tdf2mzml/main.nf @@ -12,7 +12,7 @@ process TDF2MZML { output: tuple val(meta), path("*.mzML"), emit: mzmls_converted tuple val(meta), path("*.d"), emit: dotd_files - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/modules/local/thermorawfileparser/main.nf b/modules/local/thermorawfileparser/main.nf index 83b30dbf3..8c9e8ab39 100644 --- a/modules/local/thermorawfileparser/main.nf +++ b/modules/local/thermorawfileparser/main.nf @@ -32,7 +32,7 @@ process THERMORAWFILEPARSER { output: tuple val(meta), path("*.mzML"), emit: mzmls_converted - path "versions.yml", emit: version + path "versions.yml", emit: versions path "*.log", emit: log script: diff --git a/subworkflows/local/create_input_channel.nf b/subworkflows/local/create_input_channel.nf index 32f58c1d4..0c25ecfb1 100644 --- a/subworkflows/local/create_input_channel.nf +++ b/subworkflows/local/create_input_channel.nf @@ -20,14 +20,15 @@ workflow CREATE_INPUT_CHANNEL { if (is_sdrf.toString().toLowerCase().contains("true")) { SDRFPARSING ( ch_sdrf_or_design ) - ch_versions = ch_versions.mix(SDRFPARSING.out.version) + ch_versions = ch_versions.mix(SDRFPARSING.out.versions) ch_config = SDRFPARSING.out.ch_sdrf_config_file ch_expdesign = SDRFPARSING.out.ch_expdesign } else { PREPROCESS_EXPDESIGN( ch_sdrf_or_design ) - ch_config = PREPROCESS_EXPDESIGN.out.ch_config + ch_versions = ch_versions.mix(PREPROCESS_EXPDESIGN.out.versions) + ch_config = PREPROCESS_EXPDESIGN.out.ch_config ch_expdesign = PREPROCESS_EXPDESIGN.out.ch_expdesign } @@ -61,8 +62,7 @@ workflow CREATE_INPUT_CHANNEL { ch_meta_config_lfq // [meta, [spectra_files ]] ch_meta_config_dia // [meta, [spectra files ]] ch_expdesign - - version = ch_versions + versions = ch_versions } // Function to get list of [meta, [ spectra_files ]] diff --git a/subworkflows/local/databasesearchengines.nf b/subworkflows/local/databasesearchengines.nf index 0c1209c61..6154b3fa4 100644 --- a/subworkflows/local/databasesearchengines.nf +++ b/subworkflows/local/databasesearchengines.nf @@ -17,14 +17,16 @@ workflow DATABASESEARCHENGINES { if (params.search_engines.contains("msgf")) { MSGFDBINDEXING(ch_searchengine_in_db) + ch_versions = ch_versions.mix(MSGFDBINDEXING.out.versions) + SEARCHENGINEMSGF(ch_mzmls_search.combine(ch_searchengine_in_db).combine(MSGFDBINDEXING.out.msgfdb_idx)) - ch_versions = ch_versions.mix(SEARCHENGINEMSGF.out.version) + ch_versions = ch_versions.mix(SEARCHENGINEMSGF.out.versions) ch_id_msgf = ch_id_msgf.mix(SEARCHENGINEMSGF.out.id_files_msgf) } if (params.search_engines.contains("comet")) { SEARCHENGINECOMET(ch_mzmls_search.combine(ch_searchengine_in_db)) - ch_versions = ch_versions.mix(SEARCHENGINECOMET.out.version) + ch_versions = ch_versions.mix(SEARCHENGINECOMET.out.versions) ch_id_comet = ch_id_comet.mix(SEARCHENGINECOMET.out.id_files_comet) } @@ -61,13 +63,12 @@ workflow DATABASESEARCHENGINES { ch_meta_mzml_db_chunked = ch_meta_mzml_db.groupTuple(by: [0,1]) SEARCHENGINESAGE(ch_meta_mzml_db_chunked.combine(ch_searchengine_in_db)) - ch_versions = ch_versions.mix(SEARCHENGINESAGE.out.version) + ch_versions = ch_versions.mix(SEARCHENGINESAGE.out.versions) // we can safely use merge here since it is the same process ch_id_sage = ch_id_sage.mix(SEARCHENGINESAGE.out.id_files_sage.transpose()) } emit: ch_id_files_idx = ch_id_msgf.mix(ch_id_comet).mix(ch_id_sage) - versions = ch_versions } diff --git a/subworkflows/local/dda_id.nf b/subworkflows/local/dda_id.nf index fe94e5f44..95915fe5b 100644 --- a/subworkflows/local/dda_id.nf +++ b/subworkflows/local/dda_id.nf @@ -39,7 +39,7 @@ workflow DDA_ID { ch_file_preparation_results, ch_database_wdecoy ) - ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versions.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versionss.ifEmpty(null)) ch_id_files = DATABASESEARCHENGINES.out.ch_id_files_idx ch_id_files.branch{ meta, filename -> @@ -59,7 +59,7 @@ workflow DDA_ID { if (params.posterior_probabilities == 'percolator') { if (params.ms2rescore == true) { MS2RESCORE(ch_id_files.combine(ch_file_preparation_results, by: 0)) - ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versions) + ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versionss) MS2RESCORE.out.idxml.join(MS2RESCORE.out.feature_names).branch{ meta, idxml, feature_name -> sage: idxml.name.contains('sage') @@ -71,29 +71,31 @@ workflow DDA_ID { EXTRACTPSMFEATURES(ch_ms2rescore_branched.nosage) SAGEFEATURE(ch_ms2rescore_branched.sage) ch_id_files_feats = EXTRACTPSMFEATURES.out.id_files_feat.mix(SAGEFEATURE.out.id_files_feat) - ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.version) + ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.versions, SAGEFEATURE.out.versions) } else { EXTRACTPSMFEATURES(ch_id_files_branched.nosage) ch_id_files_feats = ch_id_files_branched.sage.mix(EXTRACTPSMFEATURES.out.id_files_feat) - ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.version) + ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.versions) } // Add SNR features to percolator if (params.add_snr_feature_percolator) { SPECTRUM2FEATURES(ch_id_files_feats.combine(ch_file_preparation_results, by: 0)) ch_id_files_feats = SPECTRUM2FEATURES.out.id_files_snr - ch_software_versions = ch_software_versions.mix(SPECTRUM2FEATURES.out.version) + ch_software_versions = ch_software_versions.mix(SPECTRUM2FEATURES.out.versions) } // Rescoring for independent run, Sample or whole experiments if (params.rescore_range == "independent_run") { PERCOLATOR(ch_id_files_feats) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.version) + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) ch_consensus_input = PERCOLATOR.out.id_files_perc } else if (params.rescore_range == "by_sample") { // Sample map GETSAMPLE(ch_expdesign) + ch_software_versions = ch_software_versions.mix(GETSAMPLE.out.versions) + ch_expdesign_sample = GETSAMPLE.out.ch_expdesign_sample ch_expdesign_sample.splitCsv(header: true, sep: '\t') .map { get_sample_map(it) }.set{ sample_map_idv } @@ -117,10 +119,10 @@ workflow DDA_ID { IDMERGER(ch_id_files_feat_branched.comet.groupTuple(by: 2) .mix(ch_id_files_feat_branched.msgf.groupTuple(by: 2)) .mix(ch_id_files_feat_branched.sage.groupTuple(by: 2))) - ch_software_versions = ch_software_versions.mix(IDMERGER.out.version) + ch_software_versions = ch_software_versions.mix(IDMERGER.out.versions) PERCOLATOR(IDMERGER.out.id_merged) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.version) + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) // Currently only ID runs on exactly one mzML file are supported in CONSENSUSID. Split idXML by runs IDRIPPER(PERCOLATOR.out.id_files_perc) @@ -129,7 +131,7 @@ workflow DDA_ID { meta.combine(id_rippers, by: 0) .map{ [it[1], it[2], "MS:1001491"]} .set{ ch_consensus_input } - ch_software_versions = ch_software_versions.mix(IDRIPPER.out.version) + ch_software_versions = ch_software_versions.mix(IDRIPPER.out.versions) } else if (params.rescore_range == "by_project"){ ch_id_files_feats.map {[it[0].experiment_id, it[0], it[1]]}.set { ch_id_files_feats} @@ -148,10 +150,10 @@ workflow DDA_ID { IDMERGER(ch_id_files_feat_branched.comet.groupTuple(by: 2) .mix(ch_id_files_feat_branched.msgf.groupTuple(by: 2)) .mix(ch_id_files_feat_branched.sage.groupTuple(by: 2))) - ch_software_versions = ch_software_versions.mix(IDMERGER.out.version) + ch_software_versions = ch_software_versions.mix(IDMERGER.out.versions) PERCOLATOR(IDMERGER.out.id_merged) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.version) + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) // Currently only ID runs on exactly one mzML file are supported in CONSENSUSID. Split idXML by runs IDRIPPER(PERCOLATOR.out.id_files_perc) @@ -160,7 +162,7 @@ workflow DDA_ID { meta.combine(id_rippers, by: 0) .map{ [it[1], it[2], "MS:1001491"]} .set{ ch_consensus_input } - ch_software_versions = ch_software_versions.mix(IDRIPPER.out.version) + ch_software_versions = ch_software_versions.mix(IDRIPPER.out.versions) } @@ -168,21 +170,21 @@ workflow DDA_ID { } else if (params.posterior_probabilities == 'mokapot') { MS2RESCORE(ch_id_files.combine(ch_file_preparation_results, by: 0)) - ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versions) + ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versionss) IDSCORESWITCHER(MS2RESCORE.out.idxml.combine(Channel.value("PEP"))) - ch_software_versions = ch_software_versions.mix(IDSCORESWITCHER.out.version) + ch_software_versions = ch_software_versions.mix(IDSCORESWITCHER.out.versions) ch_consensus_input = IDSCORESWITCHER.out.id_score_switcher.combine(Channel.value("MS:1001491")) ch_rescoring_results = IDSCORESWITCHER.out.ch_consensus_input } else { ch_fdridpep = Channel.empty() if (params.search_engines.split(",").size() == 1) { FDRIDPEP(ch_id_files) - ch_software_versions = ch_software_versions.mix(FDRIDPEP.out.version) + ch_software_versions = ch_software_versions.mix(FDRIDPEP.out.versions) ch_id_files = Channel.empty() ch_fdridpep = FDRIDPEP.out.id_files_idx_ForIDPEP_FDR } IDPEP(ch_fdridpep.mix(ch_id_files)) - ch_software_versions = ch_software_versions.mix(IDPEP.out.version) + ch_software_versions = ch_software_versions.mix(IDPEP.out.versions) ch_consensus_input = IDPEP.out.id_files_ForIDPEP ch_rescoring_results = ch_consensus_input } @@ -194,7 +196,7 @@ workflow DDA_ID { ch_consensus_results = Channel.empty() if (params.search_engines.split(",").size() > 1) { CONSENSUSID(ch_consensus_input.groupTuple(size: params.search_engines.split(",").size())) - ch_software_versions = ch_software_versions.mix(CONSENSUSID.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(CONSENSUSID.out.versions.ifEmpty(null)) ch_psmfdrcontrol = CONSENSUSID.out.consensusids ch_psmfdrcontrol .map { it -> it[1] } @@ -204,10 +206,11 @@ workflow DDA_ID { } PSMFDRCONTROL(ch_psmfdrcontrol) - ch_software_versions = ch_software_versions.mix(PSMFDRCONTROL.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PSMFDRCONTROL.out.versions.ifEmpty(null)) // Extract PSMs and export parquet format PSMCONVERSION(PSMFDRCONTROL.out.id_filtered.combine(ch_spectrum_data, by: 0)) + ch_software_versions = ch_software_versions.mix(PSMCONVERSION.out.versions) ch_rescoring_results .map { it -> it[1] } @@ -220,7 +223,7 @@ workflow DDA_ID { emit: ch_pmultiqc_ids = ch_pmultiqc_ids ch_pmultiqc_consensus = ch_pmultiqc_consensus - version = ch_software_versions + versions = ch_software_versions } // Function to add file prefix diff --git a/subworkflows/local/featuremapper.nf b/subworkflows/local/featuremapper.nf index 43f27aa90..e924f0338 100644 --- a/subworkflows/local/featuremapper.nf +++ b/subworkflows/local/featuremapper.nf @@ -14,13 +14,13 @@ workflow FEATUREMAPPER { ch_version = Channel.empty() ISOBARICANALYZER(ch_mzml_files) - ch_version = ch_version.mix(ISOBARICANALYZER.out.version) + ch_version = ch_version.mix(ISOBARICANALYZER.out.versions) IDMAPPER(ch_id_files.combine(ISOBARICANALYZER.out.id_files_consensusXML, by: 0)) - ch_version = ch_version.mix(IDMAPPER.out.version) + ch_version = ch_version.mix(IDMAPPER.out.versions) emit: id_map = IDMAPPER.out.id_map - version = ch_version + versions = ch_version } diff --git a/subworkflows/local/file_preparation.nf b/subworkflows/local/file_preparation.nf index 83b15c14c..10b83effd 100644 --- a/subworkflows/local/file_preparation.nf +++ b/subworkflows/local/file_preparation.nf @@ -31,7 +31,7 @@ workflow FILE_PREPARATION { compressed_files = ch_branched_input.dottar.mix(ch_branched_input.dotzip, ch_branched_input.gz) DECOMPRESS(compressed_files) - ch_versions = ch_versions.mix(DECOMPRESS.out.version) + ch_versions = ch_versions.mix(DECOMPRESS.out.versions) ch_rawfiles = ch_branched_input.uncompressed.mix(DECOMPRESS.out.decompressed_files) // @@ -53,7 +53,7 @@ workflow FILE_PREPARATION { if (params.reindex_mzml) { MZMLINDEXING( ch_branched_input.mzML ) - ch_versions = ch_versions.mix(MZMLINDEXING.out.version) + ch_versions = ch_versions.mix(MZMLINDEXING.out.versions) ch_results = ch_results.mix(MZMLINDEXING.out.mzmls_indexed) } else { ch_results = ch_results.mix(ch_branched_input.mzML) @@ -66,7 +66,7 @@ workflow FILE_PREPARATION { // 'log': Path(*.txt)} // Where meta is the same as the input meta - ch_versions = ch_versions.mix(THERMORAWFILEPARSER.out.version) + ch_versions = ch_versions.mix(THERMORAWFILEPARSER.out.versions) ch_results = ch_results.mix(THERMORAWFILEPARSER.out.mzmls_converted) ch_results.map{ it -> [it[0], it[1]] }.set{ indexed_mzml_bundle } @@ -74,7 +74,7 @@ workflow FILE_PREPARATION { // Convert .d files to mzML if (params.convert_dotd) { TDF2MZML( ch_branched_input.dotd ) - ch_versions = ch_versions.mix(TDF2MZML.out.version) + ch_versions = ch_versions.mix(TDF2MZML.out.versions) ch_results = indexed_mzml_bundle.mix(TDF2MZML.out.mzmls_converted) // indexed_mzml_bundle = indexed_mzml_bundle.mix(TDF2MZML.out.mzmls_converted) } else { @@ -86,7 +86,7 @@ workflow FILE_PREPARATION { ch_statistics = ch_statistics.mix(MZMLSTATISTICS.out.ms_statistics.collect()) ch_spectrum_df = ch_spectrum_df.mix(MZMLSTATISTICS.out.spectrum_df) - ch_versions = ch_versions.mix(MZMLSTATISTICS.out.version) + ch_versions = ch_versions.mix(MZMLSTATISTICS.out.versions) if (params.openms_peakpicking) { // If the peak picker is enabled, it will over-write not bypass the .d files @@ -94,7 +94,7 @@ workflow FILE_PREPARATION { indexed_mzml_bundle ) - ch_versions = ch_versions.mix(OPENMSPEAKPICKER.out.version) + ch_versions = ch_versions.mix(OPENMSPEAKPICKER.out.versions) ch_results = OPENMSPEAKPICKER.out.mzmls_picked } @@ -102,7 +102,7 @@ workflow FILE_PREPARATION { results = ch_results // channel: [val(mzml_id), indexedmzml|.d.tar] statistics = ch_statistics // channel: [ *_ms_info.parquet ] spectrum_data = ch_spectrum_df // channel: [val(mzml_id), *_spectrum_df.parquet] - version = ch_versions // channel: [ *.version.txt ] + versions = ch_versions // channel: [ *.version.txt ] } // diff --git a/subworkflows/local/id.nf b/subworkflows/local/id.nf index d84075d0a..a51e4c723 100644 --- a/subworkflows/local/id.nf +++ b/subworkflows/local/id.nf @@ -28,13 +28,13 @@ workflow ID { ch_file_preparation_results, ch_database_wdecoy ) - ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versions.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versionss.ifEmpty(null)) // // SUBWORKFLOW: PSMReScoring // PSMRESCORING (ch_file_preparation_results, DATABASESEARCHENGINES.out.ch_id_files_idx, ch_expdesign) - ch_software_versions = ch_software_versions.mix(PSMRESCORING.out.versions.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PSMRESCORING.out.versionss.ifEmpty(null)) // // SUBWORKFLOW: PSMFDRCONTROL @@ -43,7 +43,7 @@ workflow ID { ch_consensus_results = Channel.empty() if (params.search_engines.split(",").size() > 1) { CONSENSUSID(PSMRESCORING.out.results.groupTuple(size: params.search_engines.split(",").size())) - ch_software_versions = ch_software_versions.mix(CONSENSUSID.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(CONSENSUSID.out.versions.ifEmpty(null)) ch_psmfdrcontrol = CONSENSUSID.out.consensusids ch_consensus_results = CONSENSUSID.out.consensusids } else { @@ -51,14 +51,14 @@ workflow ID { } PSMFDRCONTROL(ch_psmfdrcontrol) - ch_software_versions = ch_software_versions.mix(PSMFDRCONTROL.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PSMFDRCONTROL.out.versions.ifEmpty(null)) // // SUBWORKFLOW:PHOSPHOSCORING // if (params.enable_mod_localization) { PHOSPHOSCORING(ch_file_preparation_results, PSMFDRCONTROL.out.id_filtered) - ch_software_versions = ch_software_versions.mix(PHOSPHOSCORING.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PHOSPHOSCORING.out.versions.ifEmpty(null)) ch_id_results = PHOSPHOSCORING.out.id_luciphor } else { ch_id_results = PSMFDRCONTROL.out.id_filtered @@ -68,5 +68,5 @@ workflow ID { id_results = ch_id_results psmrescoring_results = PSMRESCORING.out.results ch_consensus_results = ch_consensus_results - version = ch_software_versions + versions = ch_software_versions } diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf index fc9c45436..a9046191c 100644 --- a/subworkflows/local/input_check.nf +++ b/subworkflows/local/input_check.nf @@ -7,6 +7,7 @@ include { SAMPLESHEET_CHECK } from '../../modules/local/samplesheet_check' workflow INPUT_CHECK { take: input_file // file: /path/to/input_file + ch_software_versions = Channel.empty() main: if (input_file.toString().toLowerCase().contains("sdrf")) { @@ -19,9 +20,10 @@ workflow INPUT_CHECK { } } SAMPLESHEET_CHECK ( input_file, is_sdrf, params.validate_ontologies ) + ch_software_versions = ch_software_versions.mix(SAMPLESHEET_CHECK.out.versions) emit: ch_input_file = SAMPLESHEET_CHECK.out.checked_file is_sdrf = is_sdrf - versions = SAMPLESHEET_CHECK.out.versions + versions = ch_software_versions } diff --git a/subworkflows/local/phosphoscoring.nf b/subworkflows/local/phosphoscoring.nf index c092d3cba..30a602871 100644 --- a/subworkflows/local/phosphoscoring.nf +++ b/subworkflows/local/phosphoscoring.nf @@ -14,13 +14,13 @@ workflow PHOSPHOSCORING { ch_version = Channel.empty() IDSCORESWITCHERFORLUCIPHOR(ch_id_files.combine(Channel.value("\"Posterior Error Probability_score\""))) - ch_version = ch_version.mix(IDSCORESWITCHERFORLUCIPHOR.out.version) + ch_version = ch_version.mix(IDSCORESWITCHERFORLUCIPHOR.out.versions) LUCIPHORADAPTER(ch_mzml_files.join(IDSCORESWITCHERFORLUCIPHOR.out.id_score_switcher)) - ch_version = ch_version.mix(LUCIPHORADAPTER.out.version) + ch_version = ch_version.mix(LUCIPHORADAPTER.out.versions) emit: id_luciphor = LUCIPHORADAPTER.out.ptm_in_id_luciphor - version = ch_version + versions = ch_version } diff --git a/subworkflows/local/proteininference.nf b/subworkflows/local/proteininference.nf index faa2b5e3e..e492caf26 100644 --- a/subworkflows/local/proteininference.nf +++ b/subworkflows/local/proteininference.nf @@ -15,16 +15,16 @@ workflow PROTEININFERENCE { if (params.protein_inference_method == "bayesian") { EPIFANY(ch_consus_file) - ch_version = ch_version.mix(EPIFANY.out.version) + ch_version = ch_version.mix(EPIFANY.out.versions) ch_inference = EPIFANY.out.epi_inference } else { PROTEININFERENCER(ch_consus_file) - ch_version = ch_version.mix(PROTEININFERENCER.out.version) + ch_version = ch_version.mix(PROTEININFERENCER.out.versions) ch_inference = PROTEININFERENCER.out.protein_inference } IDFILTER(ch_inference) - ch_version = ch_version.mix(IDFILTER.out.version) + ch_version = ch_version.mix(IDFILTER.out.versions) IDFILTER.out.id_filtered .multiMap{ it -> meta: it[0] @@ -35,6 +35,6 @@ workflow PROTEININFERENCE { emit: epi_idfilter = ch_epi_results.results - version = ch_version + versions = ch_version } diff --git a/subworkflows/local/proteinquant.nf b/subworkflows/local/proteinquant.nf index d4ef2d057..08fa573a9 100644 --- a/subworkflows/local/proteinquant.nf +++ b/subworkflows/local/proteinquant.nf @@ -15,17 +15,16 @@ workflow PROTEINQUANT { ch_version = Channel.empty() IDCONFLICTRESOLVER(ch_conflict_file) - ch_version = ch_version.mix(IDCONFLICTRESOLVER.out.version) + ch_version = ch_version.mix(IDCONFLICTRESOLVER.out.versions) PROTEINQUANTIFIER(IDCONFLICTRESOLVER.out.pro_resconf, ch_expdesign_file) - ch_version = ch_version.mix(PROTEINQUANTIFIER.out.version) + ch_version = ch_version.mix(PROTEINQUANTIFIER.out.versions) MSSTATSCONVERTER(IDCONFLICTRESOLVER.out.pro_resconf, ch_expdesign_file, "ISO") - ch_version = ch_version.mix(MSSTATSCONVERTER.out.version) + ch_version = ch_version.mix(MSSTATSCONVERTER.out.versions) emit: msstats_csv = MSSTATSCONVERTER.out.out_msstats out_mztab = PROTEINQUANTIFIER.out.out_mztab - - version = ch_version + versions = ch_version } diff --git a/subworkflows/local/psmfdrcontrol.nf b/subworkflows/local/psmfdrcontrol.nf index 01b5e1a88..26480f72e 100644 --- a/subworkflows/local/psmfdrcontrol.nf +++ b/subworkflows/local/psmfdrcontrol.nf @@ -7,6 +7,7 @@ include { FALSEDISCOVERYRATE as FDRCONSENSUSID } from '../../modules/local/openm include { IDFILTER } from '../../modules/local/openms/idfilter/main' workflow PSMFDRCONTROL { + take: ch_id_files @@ -16,18 +17,17 @@ workflow PSMFDRCONTROL { if (params.search_engines.split(",").size() == 1) { IDSCORESWITCHER(ch_id_files) - ch_version = ch_version.mix(IDSCORESWITCHER.out.version) + ch_version = ch_version.mix(IDSCORESWITCHER.out.versions) ch_idfilter = IDSCORESWITCHER.out.id_score_switcher } else { FDRCONSENSUSID(ch_id_files) - ch_version = ch_version.mix(FDRCONSENSUSID.out.version) + ch_version = ch_version.mix(FDRCONSENSUSID.out.versions) ch_idfilter = FDRCONSENSUSID.out.id_files_idx_ForIDPEP_FDR } IDFILTER(ch_idfilter) - ch_version = ch_version.mix(IDFILTER.out.version) + ch_version = ch_version.mix(IDFILTER.out.versions) emit: id_filtered =IDFILTER.out.id_filtered - - version = ch_version + versions = ch_version } diff --git a/subworkflows/local/psmrescoring.nf b/subworkflows/local/psmrescoring.nf index c6fce8553..156ce93fc 100644 --- a/subworkflows/local/psmrescoring.nf +++ b/subworkflows/local/psmrescoring.nf @@ -34,7 +34,7 @@ workflow PSMRESCORING { if (params.posterior_probabilities == 'percolator') { if (params.ms2rescore == true) { MS2RESCORE(ch_id_files.combine(ch_file_preparation_results, by: 0)) - ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versions) + ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versionss) MS2RESCORE.out.idxml.join(MS2RESCORE.out.feature_names).branch{ meta, idxml, feature_name -> sage: idxml.name.contains('sage') @@ -46,28 +46,29 @@ workflow PSMRESCORING { EXTRACTPSMFEATURES(ch_ms2rescore_branched.nosage) SAGEFEATURE(ch_ms2rescore_branched.sage) ch_id_files_feats = EXTRACTPSMFEATURES.out.id_files_feat.mix(SAGEFEATURE.out.id_files_feat) - ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.version) + ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.versions, SAGEFEATURE.out.versions) } else { EXTRACTPSMFEATURES(ch_id_files_branched.nosage) ch_id_files_feats = ch_id_files_branched.sage.mix(EXTRACTPSMFEATURES.out.id_files_feat) - ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.version) + ch_software_versions = ch_software_versions.mix(EXTRACTPSMFEATURES.out.versions) } // Add SNR features to percolator if (params.add_snr_feature_percolator) { SPECTRUM2FEATURES(ch_id_files_feats.combine(ch_file_preparation_results, by: 0)) ch_id_files_feats = SPECTRUM2FEATURES.out.id_files_snr - ch_software_versions = ch_software_versions.mix(SPECTRUM2FEATURES.out.version) + ch_software_versions = ch_software_versions.mix(SPECTRUM2FEATURES.out.versions) } // Rescoring for independent run, Sample or whole experiments if (params.rescore_range == "independent_run") { PERCOLATOR(ch_id_files_feats) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.version) + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) ch_consensus_input = PERCOLATOR.out.id_files_perc } else if (params.rescore_range == "by_sample") { // Sample map GETSAMPLE(ch_expdesign) + ch_software_versions = ch_software_versions.mix(GETSAMPLE.out.versions) ch_expdesign_sample = GETSAMPLE.out.ch_expdesign_sample ch_expdesign_sample.splitCsv(header: true, sep: '\t') .map { get_sample_map(it) }.set{ sample_map_idv } @@ -89,10 +90,10 @@ workflow PSMRESCORING { IDMERGER(ch_id_files_feat_branched.comet.groupTuple(by: 2) .mix(ch_id_files_feat_branched.msgf.groupTuple(by: 2)) .mix(ch_id_files_feat_branched.sage.groupTuple(by: 2))) - ch_software_versions = ch_software_versions.mix(IDMERGER.out.version) + ch_software_versions = ch_software_versions.mix(IDMERGER.out.versions) PERCOLATOR(IDMERGER.out.id_merged) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.version) + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) // Currently only ID runs on exactly one mzML file are supported in CONSENSUSID. Split idXML by runs IDRIPPER(PERCOLATOR.out.id_files_perc) @@ -101,7 +102,7 @@ workflow PSMRESCORING { meta.combine(id_rippers, by: 0) .map{ [it[1], it[2], "MS:1001491"]} .set{ ch_consensus_input } - ch_software_versions = ch_software_versions.mix(IDRIPPER.out.version) + ch_software_versions = ch_software_versions.mix(IDRIPPER.out.versions) } else if (params.rescore_range == "by_project"){ ch_id_files_feats.map {[it[0].experiment_id, it[0], it[1]]}.set { ch_id_files_feats} @@ -120,10 +121,10 @@ workflow PSMRESCORING { IDMERGER(ch_id_files_feat_branched.comet.groupTuple(by: 2) .mix(ch_id_files_feat_branched.msgf.groupTuple(by: 2)) .mix(ch_id_files_feat_branched.sage.groupTuple(by: 2))) - ch_software_versions = ch_software_versions.mix(IDMERGER.out.version) + ch_software_versions = ch_software_versions.mix(IDMERGER.out.versions) PERCOLATOR(IDMERGER.out.id_merged) - ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.version) + ch_software_versions = ch_software_versions.mix(PERCOLATOR.out.versions) // Currently only ID runs on exactly one mzML file are supported in CONSENSUSID. Split idXML by runs IDRIPPER(PERCOLATOR.out.id_files_perc) @@ -132,7 +133,7 @@ workflow PSMRESCORING { meta.combine(id_rippers, by: 0) .map{ [it[1], it[2], "MS:1001491"]} .set{ ch_consensus_input } - ch_software_versions = ch_software_versions.mix(IDRIPPER.out.version) + ch_software_versions = ch_software_versions.mix(IDRIPPER.out.versions) } ch_rescoring_results = ch_consensus_input @@ -140,26 +141,25 @@ workflow PSMRESCORING { MS2RESCORE(ch_id_files.combine(ch_file_preparation_results, by: 0)) ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versions) IDSCORESWITCHER(MS2RESCORE.out.idxml.combine(Channel.value("PEP"))) - ch_software_versions = ch_software_versions.mix(IDSCORESWITCHER.out.version) + ch_software_versions = ch_software_versions.mix(IDSCORESWITCHER.out.versions) ch_consensus_input = IDSCORESWITCHER.out.id_score_switcher.combine(Channel.value("MS:1001491")) ch_rescoring_results = IDSCORESWITCHER.out.id_score_switcher } else { ch_fdridpep = Channel.empty() if (params.search_engines.split(",").size() == 1) { FDRIDPEP(ch_id_files) - ch_software_versions = ch_software_versions.mix(FDRIDPEP.out.version) + ch_software_versions = ch_software_versions.mix(FDRIDPEP.out.versions) ch_id_files = Channel.empty() ch_fdridpep = FDRIDPEP.out.id_files_idx_ForIDPEP_FDR } IDPEP(ch_fdridpep.mix(ch_id_files)) - ch_software_versions = ch_software_versions.mix(IDPEP.out.version) + ch_software_versions = ch_software_versions.mix(IDPEP.out.versions) ch_consensus_input = IDPEP.out.id_files_ForIDPEP ch_rescoring_results = ch_consensus_input } emit: results = ch_rescoring_results - versions = ch_software_versions } diff --git a/workflows/dia.nf b/workflows/dia.nf index cced0edeb..d7a62dae8 100644 --- a/workflows/dia.nf +++ b/workflows/dia.nf @@ -51,7 +51,7 @@ workflow DIA { DIANNCFG(meta) ch_software_versions = ch_software_versions - .mix(DIANNCFG.out.version.ifEmpty(null)) + .mix(DIANNCFG.out.versions.ifEmpty(null)) // // MODULE: SILICOLIBRARYGENERATION @@ -91,7 +91,7 @@ workflow DIA { DIANN_PRELIMINARY_ANALYSIS(ch_file_preparation_results.combine(speclib)) } ch_software_versions = ch_software_versions - .mix(DIANN_PRELIMINARY_ANALYSIS.out.version.ifEmpty(null)) + .mix(DIANN_PRELIMINARY_ANALYSIS.out.versions.ifEmpty(null)) // // MODULE: ASSEMBLE_EMPIRICAL_LIBRARY @@ -104,7 +104,7 @@ workflow DIA { speclib ) ch_software_versions = ch_software_versions - .mix(ASSEMBLE_EMPIRICAL_LIBRARY.out.version.ifEmpty(null)) + .mix(ASSEMBLE_EMPIRICAL_LIBRARY.out.versions.ifEmpty(null)) indiv_fin_analysis_in = ch_file_preparation_results .combine(ch_searchdb) .combine(ASSEMBLE_EMPIRICAL_LIBRARY.out.log) @@ -118,7 +118,7 @@ workflow DIA { // INDIVIDUAL_FINAL_ANALYSIS(indiv_fin_analysis_in) ch_software_versions = ch_software_versions - .mix(INDIVIDUAL_FINAL_ANALYSIS.out.version.ifEmpty(null)) + .mix(INDIVIDUAL_FINAL_ANALYSIS.out.versions.ifEmpty(null)) // // MODULE: DIANNSUMMARY @@ -141,7 +141,7 @@ workflow DIA { ch_searchdb) ch_software_versions = ch_software_versions.mix( - DIANNSUMMARY.out.version.ifEmpty(null) + DIANNSUMMARY.out.versions.ifEmpty(null) ) // @@ -153,10 +153,10 @@ workflow DIA { DIANNSUMMARY.out.pr_matrix, ch_ms_info, meta, ch_searchdb, - DIANNSUMMARY.out.version + DIANNSUMMARY.out.versions ) ch_software_versions = ch_software_versions - .mix(DIANNCONVERT.out.version.ifEmpty(null)) + .mix(DIANNCONVERT.out.versions.ifEmpty(null)) // // MODULE: MSSTATS @@ -165,7 +165,7 @@ workflow DIA { MSSTATS(DIANNCONVERT.out.out_msstats) ch_msstats_out = MSSTATS.out.msstats_csv ch_software_versions = ch_software_versions.mix( - MSSTATS.out.version.ifEmpty(null) + MSSTATS.out.versions.ifEmpty(null) ) } diff --git a/workflows/lfq.nf b/workflows/lfq.nf index 256f3fdc7..16f2ff712 100644 --- a/workflows/lfq.nf +++ b/workflows/lfq.nf @@ -38,7 +38,7 @@ workflow LFQ { // SUBWORKFLOWS: ID // ID(ch_file_preparation_results, ch_database_wdecoy, ch_expdesign) - ch_software_versions = ch_software_versions.mix(ID.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(ID.out.versions.ifEmpty(null)) // // SUBWORKFLOW: PROTEOMICSLFQ @@ -54,7 +54,7 @@ workflow LFQ { ch_expdesign, ch_database_wdecoy ) - ch_software_versions = ch_software_versions.mix(PROTEOMICSLFQ.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PROTEOMICSLFQ.out.versions.ifEmpty(null)) // // MODULE: MSSTATS @@ -63,7 +63,7 @@ workflow LFQ { if(!params.skip_post_msstats && params.quantification_method == "feature_intensity"){ MSSTATS(PROTEOMICSLFQ.out.out_msstats) ch_msstats_out = MSSTATS.out.msstats_csv - ch_software_versions = ch_software_versions.mix(MSSTATS.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(MSSTATS.out.versions.ifEmpty(null)) } diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 72546f31e..b162a9232 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -56,7 +56,7 @@ workflow QUANTMS { INPUT_CHECK.out.ch_input_file, INPUT_CHECK.out.is_sdrf ) - ch_versions = ch_versions.mix(CREATE_INPUT_CHANNEL.out.version.ifEmpty(null)) + ch_versions = ch_versions.mix(CREATE_INPUT_CHANNEL.out.versions.ifEmpty(null)) // // SUBWORKFLOW: File preparation @@ -65,7 +65,7 @@ workflow QUANTMS { CREATE_INPUT_CHANNEL.out.ch_meta_config_iso.mix(CREATE_INPUT_CHANNEL.out.ch_meta_config_lfq).mix(CREATE_INPUT_CHANNEL.out.ch_meta_config_dia) ) - ch_versions = ch_versions.mix(FILE_PREPARATION.out.version.ifEmpty(null)) + ch_versions = ch_versions.mix(FILE_PREPARATION.out.versions.ifEmpty(null)) FILE_PREPARATION.out.results .branch { @@ -99,7 +99,7 @@ workflow QUANTMS { ch_db_for_decoy_creation_or_null ) ch_searchengine_in_db = DECOYDATABASE.out.db_decoy - ch_versions = ch_versions.mix(DECOYDATABASE.out.version.ifEmpty(null)) + ch_versions = ch_versions.mix(DECOYDATABASE.out.versions.ifEmpty(null)) } // This rescoring engine currently only is supported in id_only subworkflows via ms2rescore. @@ -111,7 +111,7 @@ workflow QUANTMS { log.warn "The rescoring engine is set to mokapot. This rescoring engine currently only supports psm-level-fdr via ms2rescore." } DDA_ID( FILE_PREPARATION.out.results, ch_searchengine_in_db, FILE_PREPARATION.out.spectrum_data, CREATE_INPUT_CHANNEL.out.ch_expdesign) - ch_versions = ch_versions.mix(DDA_ID.out.version.ifEmpty(null)) + ch_versions = ch_versions.mix(DDA_ID.out.versions.ifEmpty(null)) ch_ids_pmultiqc = ch_ids_pmultiqc.mix(DDA_ID.out.ch_pmultiqc_ids) ch_consensus_pmultiqc = ch_consensus_pmultiqc.mix(DDA_ID.out.ch_pmultiqc_consensus) } else { @@ -141,6 +141,7 @@ workflow QUANTMS { ch_versions.subscribe { version -> println "DEBUG: Version Info: ${version}" } + softwareVersionsToYAML(ch_versions) .collectFile( storeDir: "${params.outdir}/pipeline_info", diff --git a/workflows/tmt.nf b/workflows/tmt.nf index f46d2ed80..ddeb0b40b 100644 --- a/workflows/tmt.nf +++ b/workflows/tmt.nf @@ -38,31 +38,31 @@ workflow TMT { // SUBWORKFLOWS: ID // ID(ch_file_preparation_results, ch_database_wdecoy, ch_expdesign) - ch_software_versions = ch_software_versions.mix(ID.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(ID.out.versions.ifEmpty(null)) // // SUBWORKFLOW: FEATUREMAPPER // FEATUREMAPPER(ch_file_preparation_results, ID.out.id_results) - ch_software_versions = ch_software_versions.mix(FEATUREMAPPER.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(FEATUREMAPPER.out.versions.ifEmpty(null)) // // MODULE: FILEMERGE // FILEMERGE(FEATUREMAPPER.out.id_map.collect()) - ch_software_versions = ch_software_versions.mix(FILEMERGE.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(FILEMERGE.out.versions.ifEmpty(null)) // // SUBWORKFLOW: PROTEININFERENCE // PROTEININFERENCE(FILEMERGE.out.id_merge) - ch_software_versions = ch_software_versions.mix(PROTEININFERENCE.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PROTEININFERENCE.out.versions.ifEmpty(null)) // // SUBWORKFLOW: PROTEINQUANT // PROTEINQUANT(PROTEININFERENCE.out.epi_idfilter, ch_expdesign) - ch_software_versions = ch_software_versions.mix(PROTEINQUANT.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PROTEINQUANT.out.versions.ifEmpty(null)) // // MODULE: MSSTATSTMT @@ -71,7 +71,7 @@ workflow TMT { if(!params.skip_post_msstats){ MSSTATSTMT(PROTEINQUANT.out.msstats_csv) ch_msstats_out = MSSTATSTMT.out.msstats_csv - ch_software_versions = ch_software_versions.mix(MSSTATSTMT.out.version.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(MSSTATSTMT.out.versions.ifEmpty(null)) } ID.out.psmrescoring_results From 2a013509c1910e5d383603334fb1ae389c196319 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 20:04:34 +0100 Subject: [PATCH 16/34] update template 3.0.2 - versions issues --- subworkflows/local/input_check.nf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf index a9046191c..df7b455f1 100644 --- a/subworkflows/local/input_check.nf +++ b/subworkflows/local/input_check.nf @@ -7,9 +7,11 @@ include { SAMPLESHEET_CHECK } from '../../modules/local/samplesheet_check' workflow INPUT_CHECK { take: input_file // file: /path/to/input_file - ch_software_versions = Channel.empty() main: + + ch_software_versions = Channel.empty() + if (input_file.toString().toLowerCase().contains("sdrf")) { is_sdrf = true } else { From 1dfd40a23c2522c26da84ad66c76b6c91582a849 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Fri, 18 Oct 2024 20:13:11 +0100 Subject: [PATCH 17/34] update template 3.0.2 - versions issues --- subworkflows/local/dda_id.nf | 6 +++--- subworkflows/local/id.nf | 4 ++-- subworkflows/local/psmrescoring.nf | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/subworkflows/local/dda_id.nf b/subworkflows/local/dda_id.nf index 95915fe5b..16e8a3abc 100644 --- a/subworkflows/local/dda_id.nf +++ b/subworkflows/local/dda_id.nf @@ -39,7 +39,7 @@ workflow DDA_ID { ch_file_preparation_results, ch_database_wdecoy ) - ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versionss.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versions.ifEmpty(null)) ch_id_files = DATABASESEARCHENGINES.out.ch_id_files_idx ch_id_files.branch{ meta, filename -> @@ -59,7 +59,7 @@ workflow DDA_ID { if (params.posterior_probabilities == 'percolator') { if (params.ms2rescore == true) { MS2RESCORE(ch_id_files.combine(ch_file_preparation_results, by: 0)) - ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versionss) + ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versions) MS2RESCORE.out.idxml.join(MS2RESCORE.out.feature_names).branch{ meta, idxml, feature_name -> sage: idxml.name.contains('sage') @@ -170,7 +170,7 @@ workflow DDA_ID { } else if (params.posterior_probabilities == 'mokapot') { MS2RESCORE(ch_id_files.combine(ch_file_preparation_results, by: 0)) - ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versionss) + ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versions) IDSCORESWITCHER(MS2RESCORE.out.idxml.combine(Channel.value("PEP"))) ch_software_versions = ch_software_versions.mix(IDSCORESWITCHER.out.versions) ch_consensus_input = IDSCORESWITCHER.out.id_score_switcher.combine(Channel.value("MS:1001491")) diff --git a/subworkflows/local/id.nf b/subworkflows/local/id.nf index a51e4c723..38f6b9c99 100644 --- a/subworkflows/local/id.nf +++ b/subworkflows/local/id.nf @@ -28,13 +28,13 @@ workflow ID { ch_file_preparation_results, ch_database_wdecoy ) - ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versionss.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(DATABASESEARCHENGINES.out.versions.ifEmpty(null)) // // SUBWORKFLOW: PSMReScoring // PSMRESCORING (ch_file_preparation_results, DATABASESEARCHENGINES.out.ch_id_files_idx, ch_expdesign) - ch_software_versions = ch_software_versions.mix(PSMRESCORING.out.versionss.ifEmpty(null)) + ch_software_versions = ch_software_versions.mix(PSMRESCORING.out.versions.ifEmpty(null)) // // SUBWORKFLOW: PSMFDRCONTROL diff --git a/subworkflows/local/psmrescoring.nf b/subworkflows/local/psmrescoring.nf index 156ce93fc..e283aa773 100644 --- a/subworkflows/local/psmrescoring.nf +++ b/subworkflows/local/psmrescoring.nf @@ -34,7 +34,7 @@ workflow PSMRESCORING { if (params.posterior_probabilities == 'percolator') { if (params.ms2rescore == true) { MS2RESCORE(ch_id_files.combine(ch_file_preparation_results, by: 0)) - ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versionss) + ch_software_versions = ch_software_versions.mix(MS2RESCORE.out.versions) MS2RESCORE.out.idxml.join(MS2RESCORE.out.feature_names).branch{ meta, idxml, feature_name -> sage: idxml.name.contains('sage') From 7f288e99512ca0296cb8f74699999c2ba8bdbccd Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 07:40:31 +0100 Subject: [PATCH 18/34] update template 3.0.2 - versions issues --- .github/workflows/ci.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfac4ce34..e961c692e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,8 +63,15 @@ jobs: with: version: "${{ matrix.NXF_VER }}" - - name: Disk space cleanup - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + - name: Set up Apptainer + if: matrix.profile == 'singularity' + uses: eWaterCycle/setup-apptainer@main + + - name: Set up Singularity + if: matrix.profile == 'singularity' + run: | + mkdir -p $NXF_SINGULARITY_CACHEDIR + mkdir -p $NXF_SINGULARITY_LIBRARYDIR - name: Install micromamba env: @@ -81,6 +88,9 @@ jobs: if: matrix.exec_profile == 'singularity' uses: singularityhub/install-singularity@main + - name: Disk space cleanup + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + - name: Run pipeline with test data in docker/singularity profile if: matrix.exec_profile == 'docker' || matrix.exec_profile == 'singularity' # TODO nf-core: You can customise CI pipeline run tests as required From 6538c0e31323fe159a986851aae7858c558d59ef Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 08:44:27 +0100 Subject: [PATCH 19/34] update template 3.0.2 - versions issues --- modules/local/mzmlstatistics/main.nf | 2 +- workflows/quantms.nf | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/modules/local/mzmlstatistics/main.nf b/modules/local/mzmlstatistics/main.nf index 295cce780..da83cb40f 100644 --- a/modules/local/mzmlstatistics/main.nf +++ b/modules/local/mzmlstatistics/main.nf @@ -1,6 +1,6 @@ process MZMLSTATISTICS { tag "$meta.mzml_id" - label 'process_medium' + label 'process_very_low' label 'process_single' conda "bioconda::quantms-utils=0.0.11" diff --git a/workflows/quantms.nf b/workflows/quantms.nf index b162a9232..c7bec7ac6 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -135,13 +135,6 @@ workflow QUANTMS { ch_versions = ch_versions.mix(DIA.out.versions.ifEmpty(null)) } - // - // Collate and save software versions - // - ch_versions.subscribe { version -> - println "DEBUG: Version Info: ${version}" - } - softwareVersionsToYAML(ch_versions) .collectFile( storeDir: "${params.outdir}/pipeline_info", From cfebb68ee7566df16041bc8fd1b88150ba24189b Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 08:53:39 +0100 Subject: [PATCH 20/34] update template 3.0.2 - versions issues --- conf/base.config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/base.config b/conf/base.config index 716af6cf9..0e629e5b1 100644 --- a/conf/base.config +++ b/conf/base.config @@ -29,17 +29,17 @@ process { withLabel:process_single { cpus = { 1 } - memory = { 6.GB * task.attempt } + memory = { 4.GB * task.attempt } time = { 4.h * task.attempt } } withLabel:process_low { cpus = { 4 * task.attempt } - memory = { 12.GB * task.attempt } + memory = { 8.GB * task.attempt } time = { 6.h * task.attempt } } withLabel:process_very_low { cpus = { 2 * task.attempt} - memory = { 6.GB * task.attempt} + memory = { 4.GB * task.attempt} time = { 3.h * task.attempt} } withLabel:process_medium { From f42e31da6e30cf82593137b35825862fdc4e6a3a Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 08:53:42 +0100 Subject: [PATCH 21/34] update template 3.0.2 - versions issues --- conf/test.config | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 conf/test.config diff --git a/conf/test.config b/conf/test.config deleted file mode 100644 index e69de29bb..000000000 From b2875d28973b88857933599b1a05991c5fb12cbc Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 08:59:55 +0100 Subject: [PATCH 22/34] update template 3.0.2 - versions issues --- conf/base.config | 4 ++-- conf/test_lfq.config | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/conf/base.config b/conf/base.config index 0e629e5b1..fe7230d55 100644 --- a/conf/base.config +++ b/conf/base.config @@ -29,12 +29,12 @@ process { withLabel:process_single { cpus = { 1 } - memory = { 4.GB * task.attempt } + memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } } withLabel:process_low { cpus = { 4 * task.attempt } - memory = { 8.GB * task.attempt } + memory = { 12.GB * task.attempt } time = { 6.h * task.attempt } } withLabel:process_very_low { diff --git a/conf/test_lfq.config b/conf/test_lfq.config index cd2480ba7..1c03b809f 100644 --- a/conf/test_lfq.config +++ b/conf/test_lfq.config @@ -10,15 +10,18 @@ ------------------------------------------------------------------------------------------------ */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Test profile for DDA LFQ' config_profile_description = 'Minimal test dataset to check pipeline function of the label-free quantification branch of the pipeline' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - outdir = "./results_lfq" // Input data From 6c7a08634b98371564bdfbda4da011ef4666208d Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 10:06:08 +0100 Subject: [PATCH 23/34] update template 3.0.2 - versions issues --- conf/test_dda_id.config | 5 ----- conf/test_dia.config | 12 +++++++----- conf/test_full_dia.config | 13 ++++++++----- conf/test_full_lfq.config | 13 ++++++++----- conf/test_full_tmt.config | 12 ++++++++---- conf/test_latest_dia.config | 13 ++++++++----- conf/test_lfq_sage.config | 13 ++++++++----- conf/test_localize.config | 13 ++++++++----- conf/test_tmt.config | 12 ++++++++---- conf/test_tmt_corr.config | 12 ++++++++---- 10 files changed, 71 insertions(+), 47 deletions(-) diff --git a/conf/test_dda_id.config b/conf/test_dda_id.config index 0bbd9311c..e5b8da006 100644 --- a/conf/test_dda_id.config +++ b/conf/test_dda_id.config @@ -14,11 +14,6 @@ params { config_profile_name = 'Real full-size test profile for DDA ID' config_profile_description = 'Real full-size test dataset to check pipeline function of the DDA identification branch of the pipeline' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - outdir = "./results_lfq_dda_id" // Input data diff --git a/conf/test_dia.config b/conf/test_dia.config index deb1d03c9..ce041b928 100644 --- a/conf/test_dia.config +++ b/conf/test_dia.config @@ -10,15 +10,17 @@ ------------------------------------------------------------------------------------------------ */ +process { + resourceLimits = [ + cpus: 4, + memory: '6.GB', + time: '48.h' + ] +} params { config_profile_name = 'Test profile for DIA' config_profile_description = 'Minimal test dataset to check pipeline function for the data-independent acquisition pipeline branch.' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - outdir = './results_dia' // Input data diff --git a/conf/test_full_dia.config b/conf/test_full_dia.config index 1cfdd16d5..2bfb1142c 100644 --- a/conf/test_full_dia.config +++ b/conf/test_full_dia.config @@ -10,15 +10,18 @@ ------------------------------------------------------------------------------------------------ */ +process { + resourceLimits = [ + cpus: 4, + memory: '6.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Real full-size test profile for DIA' config_profile_description = 'Real full-size test dataset to check pipeline function for the data-independent acquisition pipeline branch.' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - outdir = './results_dia_full' // Input data diff --git a/conf/test_full_lfq.config b/conf/test_full_lfq.config index 4e4684f16..1b2ccc5d2 100644 --- a/conf/test_full_lfq.config +++ b/conf/test_full_lfq.config @@ -10,15 +10,18 @@ ------------------------------------------------------------------------------------------------ */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Real full-size test profile for DDA LFQ' config_profile_description = 'Real full-size test dataset to check pipeline function of the label-free quantification branch of the pipeline' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - outdir = "./results_lfq_full" // Input data diff --git a/conf/test_full_tmt.config b/conf/test_full_tmt.config index 11eea647f..32650ed58 100644 --- a/conf/test_full_tmt.config +++ b/conf/test_full_tmt.config @@ -10,16 +10,20 @@ ---------------------------------------------------------------------------------------- */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Real full test profile DDA ISO' config_profile_description = 'Real full test dataset in isotopic labelling mode to check pipeline function and sanity of results' outdir = "./results_iso_full" - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - // Input data for full size test input = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata-aws/tmt_full/PXD005486.sdrf.tsv' diff --git a/conf/test_latest_dia.config b/conf/test_latest_dia.config index 14eea22b7..ab99bf593 100644 --- a/conf/test_latest_dia.config +++ b/conf/test_latest_dia.config @@ -10,15 +10,18 @@ ------------------------------------------------------------------------------------------------ */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Test profile for latest DIA' config_profile_description = 'Minimal test dataset to check pipeline function for the data-independent acquisition pipeline branch for latest DIA-NN.' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - outdir = './results_latest_dia' // Input data diff --git a/conf/test_lfq_sage.config b/conf/test_lfq_sage.config index 8f7073b43..69234b6fb 100644 --- a/conf/test_lfq_sage.config +++ b/conf/test_lfq_sage.config @@ -10,15 +10,18 @@ ------------------------------------------------------------------------------------------------ */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Test profile for DDA LFQ with Sage' config_profile_description = 'Minimal test dataset to check pipeline function of the label-free quantification branch of the pipeline with the search engine Sage' - // Limit resources so that this can run on GitHub Actions - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - outdir = "./results_lfq" tracedir = "${params.outdir}/pipeline_info" diff --git a/conf/test_localize.config b/conf/test_localize.config index ef32bddda..32d6bb6fa 100644 --- a/conf/test_localize.config +++ b/conf/test_localize.config @@ -10,15 +10,18 @@ ---------------------------------------------------------------------------------------------------- */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Test PTM-localization profile' config_profile_description = 'Minimal test dataset to check pipeline function for PTM-localization, SDRF parsing and ConsensusID.' - // Limit resources so that this can run on Travis - max_cpus = 2 - max_memory = 6.GB - max_time = 1.h - outdir = "./results_localize" // Input data diff --git a/conf/test_tmt.config b/conf/test_tmt.config index 7184f1a49..c220c3f6e 100644 --- a/conf/test_tmt.config +++ b/conf/test_tmt.config @@ -10,16 +10,20 @@ ---------------------------------------------------------------------------------------- */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Full test profile DDA ISO' config_profile_description = 'Full test dataset in isotopic labelling mode to check pipeline function and sanity of results' outdir = "./results_iso" - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - // Input data for full size test input = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata/tmt_ci/PXD000001.sdrf.tsv' diff --git a/conf/test_tmt_corr.config b/conf/test_tmt_corr.config index 561d1f31b..276b675d1 100644 --- a/conf/test_tmt_corr.config +++ b/conf/test_tmt_corr.config @@ -10,16 +10,20 @@ ---------------------------------------------------------------------------------------- */ +process { + resourceLimits = [ + cpus: 4, + memory: '12.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Full test profile DDA ISO' config_profile_description = 'Full test dataset in isotopic labelling mode to check pipeline function and sanity of results' outdir = "./results_iso" - max_cpus = 2 - max_memory = 6.GB - max_time = 48.h - // Input data for full size test input = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata/tmt_ci/PXD000001.sdrf.tsv' From 5b7fc86a221633911855f729e39f2a2573604f73 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 10:44:36 +0100 Subject: [PATCH 24/34] remove empty versions --- workflows/quantms.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/quantms.nf b/workflows/quantms.nf index c7bec7ac6..66d2552e0 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -135,7 +135,7 @@ workflow QUANTMS { ch_versions = ch_versions.mix(DIA.out.versions.ifEmpty(null)) } - softwareVersionsToYAML(ch_versions) + softwareVersionsToYAML(ch_versions.filter { it != null }) .collectFile( storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_' + 'pipeline_software_' + 'mqc_' + 'versions.yml', From 0bcf6d38cb6759d5e7a15b431e5f3836493948c2 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 10:51:47 +0100 Subject: [PATCH 25/34] remove empty versions --- conf/test_dda_id.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/conf/test_dda_id.config b/conf/test_dda_id.config index e5b8da006..17ee2eff0 100644 --- a/conf/test_dda_id.config +++ b/conf/test_dda_id.config @@ -10,6 +10,14 @@ ------------------------------------------------------------------------------------------------ */ +process { + resourceLimits = [ + cpus: 4, + memory: '6.GB', + time: '48.h' + ] +} + params { config_profile_name = 'Real full-size test profile for DDA ID' config_profile_description = 'Real full-size test dataset to check pipeline function of the DDA identification branch of the pipeline' From f7e2d17facbcf343bdee0a9831fc2f87bcd2de9c Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 11:26:24 +0100 Subject: [PATCH 26/34] remove empty versions --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e961c692e..1a169c100 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,18 +42,18 @@ jobs: exec_profile: ["docker"] exclude: - test_profile: test_dia - exec_profile: conda + exec_profile: "conda" - test_profile: test_localize - exec_profile: conda + exec_profile: "conda" - NXF_VER: "latest-everything" exec_profile: "conda" include: - test_profile: test_latest_dia - exec_profile: singularity + exec_profile: "singularity" - test_profile: test_lfq - exec_profile: conda + exec_profile: "conda" - test_profile: test_dda_id - exec_profile: conda + exec_profile: "conda" steps: - name: Check out pipeline code uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4 From b7236acc597dec75aa1d92e14428485e51b25d98 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 11:39:44 +0100 Subject: [PATCH 27/34] remove empty versions --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a169c100..b46e6f26f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,11 +64,11 @@ jobs: version: "${{ matrix.NXF_VER }}" - name: Set up Apptainer - if: matrix.profile == 'singularity' + if: matrix.exec_profile == 'singularity' uses: eWaterCycle/setup-apptainer@main - name: Set up Singularity - if: matrix.profile == 'singularity' + if: matrix.exec_profile == 'singularity' run: | mkdir -p $NXF_SINGULARITY_CACHEDIR mkdir -p $NXF_SINGULARITY_LIBRARYDIR From 06a229df0757653cde49e06bbdea0fc77fba3fd0 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 16:12:38 +0100 Subject: [PATCH 28/34] remove empty versions --- workflows/quantms.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 66d2552e0..c7bec7ac6 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -135,7 +135,7 @@ workflow QUANTMS { ch_versions = ch_versions.mix(DIA.out.versions.ifEmpty(null)) } - softwareVersionsToYAML(ch_versions.filter { it != null }) + softwareVersionsToYAML(ch_versions) .collectFile( storeDir: "${params.outdir}/pipeline_info", name: 'nf_core_' + 'pipeline_software_' + 'mqc_' + 'versions.yml', From fc791680471e5cfe8322fa5881f524b317ddf782 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sat, 19 Oct 2024 18:59:30 +0100 Subject: [PATCH 29/34] remove empty versions --- conf/test_lfq.config | 2 +- nextflow.config | 3 +-- subworkflows/local/file_preparation.nf | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/conf/test_lfq.config b/conf/test_lfq.config index 1c03b809f..9dadd2963 100644 --- a/conf/test_lfq.config +++ b/conf/test_lfq.config @@ -29,7 +29,7 @@ params { input = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata/lfq_ci/BSA/BSA_design_urls.tsv' database = 'https://raw.githubusercontent.com/nf-core/test-datasets/quantms/testdata/lfq_ci/BSA/18Protein_SoCe_Tr_detergents_trace_target_decoy.fasta' posterior_probabilities = "fit_distributions" - search_engines = "msgf,comet" + search_engines = "comet" decoy_string= "rev" add_triqler_output = true protein_level_fdr_cutoff = 1.0 diff --git a/nextflow.config b/nextflow.config index d30b69461..ec761e09d 100644 --- a/nextflow.config +++ b/nextflow.config @@ -406,7 +406,6 @@ profiles { test_full { includeConfig 'conf/test_full_lfq.config' } test_dda_id { includeConfig 'conf/test_dda_id.config' } mambaci { includeConfig 'conf/mambaci.config' } - } // Load nf-core custom profiles from different Institutions @@ -470,7 +469,7 @@ dag { manifest { name = 'nf-core/quantms' author = """Yasset Perez-Riverol""" - homePage = 'https://github.com/nf-core/quantms' + homePage = 'https://github.com/bigbio/quantms' description = """Quantitative Mass Spectrometry nf-core workflow""" mainScript = 'main.nf' nextflowVersion = '!>=24.04.2' diff --git a/subworkflows/local/file_preparation.nf b/subworkflows/local/file_preparation.nf index 10b83effd..5217b9779 100644 --- a/subworkflows/local/file_preparation.nf +++ b/subworkflows/local/file_preparation.nf @@ -102,7 +102,7 @@ workflow FILE_PREPARATION { results = ch_results // channel: [val(mzml_id), indexedmzml|.d.tar] statistics = ch_statistics // channel: [ *_ms_info.parquet ] spectrum_data = ch_spectrum_df // channel: [val(mzml_id), *_spectrum_df.parquet] - versions = ch_versions // channel: [ *.version.txt ] + versions = ch_versions // channel: [ *.versions.yml ] } // From 94e4c9a5e673f18db942979f8bd50bdea97bf45b Mon Sep 17 00:00:00 2001 From: Chengxin Dai <37200167+daichengxin@users.noreply.github.com> Date: Sun, 20 Oct 2024 19:41:02 +0800 Subject: [PATCH 30/34] fixed version --- modules/local/openms/thirdparty/searchenginecomet/main.nf | 2 +- workflows/quantms.nf | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/local/openms/thirdparty/searchenginecomet/main.nf b/modules/local/openms/thirdparty/searchenginecomet/main.nf index fc5201002..41af36a78 100644 --- a/modules/local/openms/thirdparty/searchenginecomet/main.nf +++ b/modules/local/openms/thirdparty/searchenginecomet/main.nf @@ -113,7 +113,7 @@ process SEARCHENGINECOMET { cat <<-END_VERSIONS > versions.yml "${task.process}": CometAdapter: \$(CometAdapter 2>&1 | grep -E '^Version(.*)' | sed 's/Version: //g' | cut -d ' ' -f 1) - Comet: \$(comet 2>&1 | grep -E "Comet version.*" | sed 's/Comet version //g' | sed 's/"//g') + Comet: \$(comet 2>&1 | grep -E "Comet version.*" | sed 's/ Comet version //g' | sed 's/"//g') END_VERSIONS """ } diff --git a/workflows/quantms.nf b/workflows/quantms.nf index c7bec7ac6..44fe715da 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -133,6 +133,9 @@ workflow QUANTMS { ch_pipeline_results = ch_pipeline_results.mix(DIA.out.diann_report) ch_msstats_in = ch_msstats_in.mix(DIA.out.msstats_in) ch_versions = ch_versions.mix(DIA.out.versions.ifEmpty(null)) + + // Other subworkflow will return null when performing another subworkflow due to unknown reason. + ch_versions = ch_versions..filter( ~/versions/ ) } softwareVersionsToYAML(ch_versions) From 18353606abb96a92d8e80f96a0dc8e19b5b893e0 Mon Sep 17 00:00:00 2001 From: Chengxin Dai <37200167+daichengxin@users.noreply.github.com> Date: Sun, 20 Oct 2024 19:45:29 +0800 Subject: [PATCH 31/34] ignore nextflow config --- .nf-core.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.nf-core.yml b/.nf-core.yml index 14bda35d2..d17db7843 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -12,6 +12,7 @@ lint: - .github/PULL_REQUEST_TEMPLATE.md - .github/CONTRIBUTING.md - docs/README.md + - nextflow.config multiqc_config: false nf_core_version: 3.0.2 org_path: null From 63f1794f160b0fdb2472cf6ad173762a83c23359 Mon Sep 17 00:00:00 2001 From: Chengxin Dai <37200167+daichengxin@users.noreply.github.com> Date: Sun, 20 Oct 2024 20:00:59 +0800 Subject: [PATCH 32/34] Update .nf-core.yml --- .nf-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nf-core.yml b/.nf-core.yml index d17db7843..d86c822e7 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -12,7 +12,7 @@ lint: - .github/PULL_REQUEST_TEMPLATE.md - .github/CONTRIBUTING.md - docs/README.md - - nextflow.config + nextflow_config: false multiqc_config: false nf_core_version: 3.0.2 org_path: null From 4c3e8f081dc850797e821da792188dbd37b0e3c0 Mon Sep 17 00:00:00 2001 From: Yasset Perez-Riverol Date: Sun, 20 Oct 2024 14:36:32 +0200 Subject: [PATCH 33/34] remove empty versions --- workflows/quantms.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 44fe715da..ce19137a7 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -135,7 +135,7 @@ workflow QUANTMS { ch_versions = ch_versions.mix(DIA.out.versions.ifEmpty(null)) // Other subworkflow will return null when performing another subworkflow due to unknown reason. - ch_versions = ch_versions..filter( ~/versions/ ) + ch_versions = ch_versions.filter( ~/versions/ ) } softwareVersionsToYAML(ch_versions) From aab1541d7b41bc3a10731a190d9966df65b3afa0 Mon Sep 17 00:00:00 2001 From: Chengxin Dai <37200167+daichengxin@users.noreply.github.com> Date: Sun, 20 Oct 2024 22:56:30 +0800 Subject: [PATCH 34/34] Update quantms.nf --- workflows/quantms.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflows/quantms.nf b/workflows/quantms.nf index 44fe715da..092abd6b8 100644 --- a/workflows/quantms.nf +++ b/workflows/quantms.nf @@ -135,7 +135,7 @@ workflow QUANTMS { ch_versions = ch_versions.mix(DIA.out.versions.ifEmpty(null)) // Other subworkflow will return null when performing another subworkflow due to unknown reason. - ch_versions = ch_versions..filter( ~/versions/ ) + ch_versions = ch_versions.filter{ it != null } } softwareVersionsToYAML(ch_versions)