From a6a670ebe14006959279da95031eba4f5c82c6a9 Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Wed, 1 Dec 2021 09:32:13 +0000 Subject: [PATCH 01/26] Bump version to 1.6dev --- CHANGELOG.md | 4 ++++ nextflow.config | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edcf2fa5..a6bd63a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ 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). +## [Unpublished Version / DEV] + +### Enhancements & fixes + ## [[1.5](https://github.com/nf-core/fetchngs/releases/tag/1.5)] - 2021-12-01 * Finish porting the pipeline to the updated Nextflow DSL2 syntax adopted on nf-core/modules diff --git a/nextflow.config b/nextflow.config index f3284c52..2ad3e221 100644 --- a/nextflow.config +++ b/nextflow.config @@ -145,7 +145,7 @@ manifest { description = 'Pipeline to fetch metadata and raw FastQ files from public databases' mainScript = 'main.nf' nextflowVersion = '!>=21.10.3' - version = '1.5' + version = '1.6dev' } // Load modules.config for DSL2 module specific options From 3a402f20b71d8ceb04a18c18ef046c4b4b7926d9 Mon Sep 17 00:00:00 2001 From: "James A. Fellows Yates" Date: Mon, 13 Dec 2021 09:35:34 +0100 Subject: [PATCH 02/26] Fix typo in URL for usage to ENA API --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index 3cb17fcd..b21aa80d 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -24,7 +24,7 @@ If `SRR`/`ERR`/`DRR` run ids are provided then these will be resolved back to th The final sample information for all identifiers is obtained from the ENA which provides direct download links for FastQ files as well as their associated md5 sums. If download links exist, the files will be downloaded in parallel by FTP. Otherwise they are downloaded using sra-tools. -All of the sample metadata obtained from the ENA will be appended as additional columns to help you manually curate the generated samplesheet before you run the pipeline. You can customise the metadata fields that are appended to the samplesheet via the `--ena_metadata_fields` parameter. The default list of fields used by the pipeline can be found at the top of the [`bin/sra_ids_to_runinfo.py`](https://github.com/nf-core/fetchngs/blob/master/bin/sra_ids_to_runinfo.py) script within the pipeline repo. However, this pipeline requires a minimal set of fields to download FastQ files i.e. `'run_accession,experiment_accession,library_layout,fastq_ftp,fastq_md5'`. A comprehensive list of accepted metadata fields can be obtained from the [ENA API](https://www.ebi.ac.uk/ena/portal/api/returnFields?dataPortal=ena&format=tsv&result=read_run]). +All of the sample metadata obtained from the ENA will be appended as additional columns to help you manually curate the generated samplesheet before you run the pipeline. You can customise the metadata fields that are appended to the samplesheet via the `--ena_metadata_fields` parameter. The default list of fields used by the pipeline can be found at the top of the [`bin/sra_ids_to_runinfo.py`](https://github.com/nf-core/fetchngs/blob/master/bin/sra_ids_to_runinfo.py) script within the pipeline repo. However, this pipeline requires a minimal set of fields to download FastQ files i.e. `'run_accession,experiment_accession,library_layout,fastq_ftp,fastq_md5'`. A comprehensive list of accepted metadata fields can be obtained from the [ENA API](https://www.ebi.ac.uk/ena/portal/api/returnFields?dataPortal=ena&format=tsv&result=read_run). If you have a GEO accession (found in the data availability section of published papers) you can directly download a text file containing the appropriate SRA ids to pass to the pipeline: From 7ca1c7a57cad7b790acd34f7bc7119889266e545 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Tue, 14 Dec 2021 16:42:36 +0000 Subject: [PATCH 03/26] Template update for nf-core/tools version 2.2 --- .gitattributes | 2 + .github/CONTRIBUTING.md | 38 ++------ .github/ISSUE_TEMPLATE/bug_report.md | 63 ------------- .github/ISSUE_TEMPLATE/bug_report.yml | 52 ++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 - .github/ISSUE_TEMPLATE/feature_request.md | 32 ------- .github/ISSUE_TEMPLATE/feature_request.yml | 11 +++ .github/workflows/awsfulltest.yml | 8 +- .github/workflows/awstest.yml | 10 +- .github/workflows/ci.yml | 23 +++-- .github/workflows/linting_comment.yml | 1 + CHANGELOG.md | 2 +- CITATIONS.md | 2 +- README.md | 13 ++- assets/multiqc_config.yaml | 2 +- assets/nf-core-fetchngs_logo.png | Bin 18553 -> 0 bytes assets/nf-core-fetchngs_logo_light.png | Bin 0 -> 11380 bytes assets/sendmail_template.txt | 4 +- bin/scrape_software_versions.py | 36 ------- conf/base.config | 3 + conf/modules.config | 55 ++++++----- conf/test.config | 4 +- docs/images/nf-core-fetchngs_logo.png | Bin 35625 -> 0 bytes docs/images/nf-core-fetchngs_logo_dark.png | 9 ++ docs/images/nf-core-fetchngs_logo_light.png | Bin 0 -> 75527 bytes docs/output.md | 2 +- docs/usage.md | 36 ------- lib/NfcoreSchema.groovy | 26 +++-- lib/NfcoreTemplate.groovy | 30 ++---- lib/Utils.groovy | 7 -- lib/WorkflowMain.groovy | 6 +- modules.json | 9 +- modules/local/functions.nf | 68 ------------- modules/local/get_software_versions.nf | 33 ------- modules/local/samplesheet_check.nf | 24 ++--- .../custom/dumpsoftwareversions/main.nf | 21 +++++ .../custom/dumpsoftwareversions/meta.yml | 34 +++++++ .../templates/dumpsoftwareversions.py | 89 ++++++++++++++++++ modules/nf-core/modules/fastqc/functions.nf | 68 ------------- modules/nf-core/modules/fastqc/main.nf | 39 ++++---- modules/nf-core/modules/fastqc/meta.yml | 7 +- modules/nf-core/modules/multiqc/functions.nf | 68 ------------- modules/nf-core/modules/multiqc/main.nf | 31 +++--- modules/nf-core/modules/multiqc/meta.yml | 7 +- nextflow.config | 33 +++---- nextflow_schema.json | 29 ------ subworkflows/local/input_check.nf | 8 +- workflows/fetchngs.nf | 44 +++------ 48 files changed, 419 insertions(+), 671 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml delete mode 100644 assets/nf-core-fetchngs_logo.png create mode 100644 assets/nf-core-fetchngs_logo_light.png delete mode 100755 bin/scrape_software_versions.py delete mode 100644 docs/images/nf-core-fetchngs_logo.png create mode 100644 docs/images/nf-core-fetchngs_logo_dark.png create mode 100644 docs/images/nf-core-fetchngs_logo_light.png delete mode 100644 modules/local/functions.nf delete mode 100644 modules/local/get_software_versions.nf create mode 100644 modules/nf-core/modules/custom/dumpsoftwareversions/main.nf create mode 100644 modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml create mode 100644 modules/nf-core/modules/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py delete mode 100644 modules/nf-core/modules/fastqc/functions.nf delete mode 100644 modules/nf-core/modules/multiqc/functions.nf diff --git a/.gitattributes b/.gitattributes index 7fe55006..050bb120 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ *.config linguist-language=nextflow +modules/nf-core/** linguist-generated +subworkflows/nf-core/** linguist-generated diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1d7943a5..9aa27773 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -68,16 +68,13 @@ If you wish to contribute a new step, please use the following coding standards: 1. Define the corresponding input channel into your new process from the expected previous process channel 2. Write the process block (see below). 3. Define the output channel if needed (see below). -4. Add any new flags/options to `nextflow.config` with a default (see below). -5. Add any new flags/options to `nextflow_schema.json` with help text (with `nf-core schema build`). -6. Add any new flags/options to the help message (for integer/text parameters, print to help the corresponding `nextflow.config` parameter). -7. Add sanity checks for all relevant parameters. -8. Add any new software to the `scrape_software_versions.py` script in `bin/` and the version command to the `scrape_software_versions` process in `main.nf`. -9. Do local tests that the new code works properly and as expected. -10. Add a new test command in `.github/workflow/ci.yml`. -11. If applicable add a [MultiQC](https://https://multiqc.info/) module. -12. Update MultiQC config `assets/multiqc_config.yaml` so relevant suffixes, name clean up, General Statistics Table column order, and module figures are in the right order. -13. Optional: Add any descriptions of MultiQC report sections and output files to `docs/output.md`. +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). +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`. +9. Update MultiQC config `assets/multiqc_config.yaml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. +10. Add a description of the output files and if relevant any appropriate images from the MultiQC report to `docs/output.md`. ### Default values @@ -102,27 +99,6 @@ Please use the following naming schemes, to make it easy to understand what is g 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]` -### Software version reporting - -If you add a new tool to the pipeline, please ensure you add the information of the tool to the `get_software_version` process. - -Add to the script block of the process, something like the following: - -```bash - --version &> v_.txt 2>&1 || true -``` - -or - -```bash - --help | head -n 1 &> v_.txt 2>&1 || true -``` - -You then need to edit the script `bin/scrape_software_versions.py` to: - -1. Add a Python regex for your tool's `--version` output (as in stored in the `v_.txt` file), to ensure the version is reported as a `v` and the version number e.g. `v2.1.1` -2. Add a HTML entry to the `OrderedDict` for formatting in MultiQC. - ### Images and figures For overview images and other documents we follow the nf-core [style guidelines and examples](https://nf-co.re/developers/design_guidelines). diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 11bb35bf..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -name: Bug report -about: Report something that is broken or incorrect -labels: bug ---- - - - -## Check Documentation - -I have checked the following places for your error: - -- [ ] [nf-core website: troubleshooting](https://nf-co.re/usage/troubleshooting) -- [ ] [nf-core/fetchngs pipeline documentation](https://nf-co.re/fetchngs/usage) - -## Description of the bug - - - -## Steps to reproduce - -Steps to reproduce the behaviour: - -1. Command line: -2. See error: - -## Expected behaviour - - - -## Log files - -Have you provided the following extra information/files: - -- [ ] The command used to run the pipeline -- [ ] The `.nextflow.log` file - -## System - -- Hardware: -- Executor: -- OS: -- Version - -## Nextflow Installation - -- Version: - -## Container engine - -- Engine: -- version: - -## Additional context - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..975e8d0e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,52 @@ + +name: Bug report +description: Report something that is broken or incorrect +labels: bug +body: + + - type: markdown + attributes: + value: | + Before you post this issue, please check the documentation: + + - [nf-core website: troubleshooting](https://nf-co.re/usage/troubleshooting) + - [nf-core/fetchngs pipeline documentation](https://nf-co.re/fetchngs/usage) + + - type: textarea + id: description + attributes: + label: Description of the bug + description: A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + id: command_used + attributes: + label: Command used and terminal output + description: Steps to reproduce the behaviour. Please paste the command you used to launch the pipeline and the output from your terminal. + render: console + placeholder: | + $ nextflow run ... + + Some output where something broke + + - type: textarea + id: files + attributes: + label: Relevant files + description: | + Please drag and drop the relevant files here. Create a `.zip` archive if the extension is not allowed. + Your verbose log file `.nextflow.log` is often useful _(this is a hidden file in the directory where you launched the pipeline)_ as well as custom Nextflow configuration files. + + - type: textarea + id: system + attributes: + label: System information + description: | + * Nextflow version _(eg. 21.10.3)_ + * Hardware _(eg. HPC, Desktop, Cloud)_ + * Executor _(eg. slurm, local, awsbatch)_ + * Container engine: _(e.g. Docker, Singularity, Conda, Podman, Shifter or Charliecloud)_ + * OS _(eg. CentOS Linux, macOS, Linux Mint)_ + * Version of nf-core/fetchngs _(eg. 1.1, 1.5, 1.8.2)_ diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 7a59f73a..41a8beb7 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,3 @@ -blank_issues_enabled: false contact_links: - name: Join nf-core url: https://nf-co.re/join diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index c554f29b..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for the nf-core/fetchngs pipeline -labels: enhancement ---- - - - -## Is your feature request related to a problem? Please describe - - - - - -## Describe the solution you'd like - - - -## Describe alternatives you've considered - - - -## Additional context - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..f8ea51da --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,11 @@ +name: Feature request +description: Suggest an idea for the nf-core/fetchngs pipeline +labels: enhancement +body: + - type: textarea + id: description + attributes: + label: Description of feature + description: Please describe your suggestion for a new feature. It might help to describe a problem or use case, plus any alternatives that you have considered. + validations: + required: true diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 5b75ed9d..49a4e906 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,14 +14,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: nf-core/tower-action@master + uses: nf-core/tower-action@v2 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} - bearer_token: ${{ secrets.TOWER_BEARER_TOKEN }} + access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} pipeline: ${{ github.repository }} revision: ${{ github.sha }} @@ -30,5 +30,5 @@ jobs: { "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/fetchngs/results-${{ github.sha }}" } - profiles: '[ "test_full", "aws_tower" ]' - + profiles: test_full,aws_tower + pre_run_script: 'export NXF_VER=21.10.3' diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 47fd7072..1574928d 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -11,18 +11,18 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: nf-core/tower-action@master + uses: nf-core/tower-action@v2 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} - bearer_token: ${{ secrets.TOWER_BEARER_TOKEN }} + access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} pipeline: ${{ github.repository }} revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/fetchngs/work-${{ github.sha }} parameters: | { - "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/fetchngs/results-${{ github.sha }}" + "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/fetchngs/results-test-${{ github.sha }}" } - profiles: '[ "test", "aws_tower" ]' - + profiles: test,aws_tower + pre_run_script: 'export NXF_VER=21.10.3' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c01e1fce..7c485ed9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,9 @@ on: release: types: [published] -# Uncomment if we need an edge release of Nextflow again -# env: NXF_EDGE: 1 +env: + NXF_ANSI_LOG: false + CAPSULE_LOG: none jobs: test: @@ -17,20 +18,26 @@ jobs: # 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/fetchngs') }} runs-on: ubuntu-latest - env: - NXF_VER: ${{ matrix.nxf_ver }} - NXF_ANSI_LOG: false strategy: matrix: - # Nextflow versions: check pipeline minimum and current latest - nxf_ver: ['21.04.0', ''] + # Nextflow versions + include: + # Test pipeline minimum Nextflow version + - NXF_VER: '21.10.3' + NXF_EDGE: '' + # Test latest edge release of Nextflow + - NXF_VER: '' + NXF_EDGE: '1' steps: - name: Check out pipeline code uses: actions/checkout@v2 - name: Install Nextflow env: - CAPSULE_LOG: none + NXF_VER: ${{ matrix.NXF_VER }} + # Uncomment only if the edge release is more recent than the latest stable release + # See https://github.com/nextflow-io/nextflow/issues/2467 + # NXF_EDGE: ${{ matrix.NXF_EDGE }} run: | wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 90f03c6f..44d72994 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -15,6 +15,7 @@ jobs: uses: dawidd6/action-download-artifact@v2 with: workflow: linting.yml + workflow_conclusion: completed - name: Get PR number id: pr_number diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f94126e..c79ecb8d 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.2dev - [date] +## v1.6dev - [date] Initial release of nf-core/fetchngs, created with the [nf-core](https://nf-co.re/) template. diff --git a/CITATIONS.md b/CITATIONS.md index 523339ee..d23e6e10 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -12,7 +12,7 @@ * [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) -* [MultiQC](https://www.ncbi.nlm.nih.gov/pubmed/27312411/) +* [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. ## Software packaging/containerisation tools diff --git a/README.md b/README.md index d25c6ba6..4f9dce56 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# ![nf-core/fetchngs](docs/images/nf-core-fetchngs_logo.png) +# ![nf-core/fetchngs](docs/images/nf-core-fetchngs_logo_light.png#gh-light-mode-only) ![nf-core/fetchngs](docs/images/nf-core-fetchngs_logo_dark.png#gh-dark-mode-only) [![GitHub Actions CI Status](https://github.com/nf-core/fetchngs/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/fetchngs/actions?query=workflow%3A%22nf-core+CI%22) [![GitHub Actions Linting Status](https://github.com/nf-core/fetchngs/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/fetchngs/actions?query=workflow%3A%22nf-core+linting%22) [![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/fetchngs/results) [![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A521.04.0-23aa62.svg?labelColor=000000)](https://www.nextflow.io/) +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A521.10.3-23aa62.svg?labelColor=000000)](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/) @@ -33,18 +33,21 @@ On release, automated continuous integration tests run the pipeline on a full-si ## Quick Start -1. Install [`Nextflow`](https://www.nextflow.io/docs/latest/getstarted.html#installation) (`>=21.04.0`) +1. Install [`Nextflow`](https://www.nextflow.io/docs/latest/getstarted.html#installation) (`>=21.10.3`) 2. Install any of [`Docker`](https://docs.docker.com/engine/installation/), [`Singularity`](https://www.sylabs.io/guides/3.0/user-guide/), [`Podman`](https://podman.io/), [`Shifter`](https://nersc.gitlab.io/development/shifter/how-to-use/) or [`Charliecloud`](https://hpc.github.io/charliecloud/) for full pipeline reproducibility _(please only use [`Conda`](https://conda.io/miniconda.html) as a last resort; see [docs](https://nf-co.re/usage/configuration#basic-configuration-profiles))_ 3. Download the pipeline and test it on a minimal dataset with a single command: ```console - nextflow run nf-core/fetchngs -profile test, + nextflow run nf-core/fetchngs -profile test,YOURPROFILE ``` + Note that some form of configuration will be needed so that Nextflow knows how to fetch the required software. This is usually done in the form of a config profile (`YOURPROFILE` in the example command above). You can chain multiple config profiles in a comma-separated string. + + > * The pipeline comes with config profiles called `docker`, `singularity`, `podman`, `shifter`, `charliecloud` and `conda` which instruct the pipeline to use the named tool for software management. For example, `-profile test,docker`. > * Please check [nf-core/configs](https://github.com/nf-core/configs#documentation) to see if a custom config file to run nf-core pipelines already exists for your Institute. If so, you can simply use `-profile ` in your command. This will enable either `docker` or `singularity` and set the appropriate execution settings for your local compute environment. - > * If you are using `singularity` then the pipeline will auto-detect this and attempt to download the Singularity images directly as opposed to performing a conversion from Docker images. If you are persistently observing issues downloading Singularity images directly due to timeout or network issues then please use the `--singularity_pull_docker_container` parameter to pull and convert the Docker image instead. Alternatively, it is highly recommended to use the [`nf-core download`](https://nf-co.re/tools/#downloading-pipelines-for-offline-use) command to pre-download all of the required containers before running the pipeline and to set the [`NXF_SINGULARITY_CACHEDIR` or `singularity.cacheDir`](https://www.nextflow.io/docs/latest/singularity.html?#singularity-docker-hub) Nextflow options to be able to store and re-use the images from a central location for future pipeline runs. + > * If you are using `singularity` and are persistently observing issues downloading Singularity images directly due to timeout or network issues, then you can use the `--singularity_pull_docker_container` parameter to pull and convert the Docker image instead. Alternatively, you can use the [`nf-core download`](https://nf-co.re/tools/#downloading-pipelines-for-offline-use) command to download images first, before running the pipeline. Setting the [`NXF_SINGULARITY_CACHEDIR` or `singularity.cacheDir`](https://www.nextflow.io/docs/latest/singularity.html?#singularity-docker-hub) Nextflow options enables you to store and re-use the images from a central location for future pipeline runs. > * If you are using `conda`, it is highly recommended to use the [`NXF_CONDA_CACHEDIR` or `conda.cacheDir`](https://www.nextflow.io/docs/latest/conda.html) settings to store the environments in a central location for future pipeline runs. 4. Start running your own analysis! diff --git a/assets/multiqc_config.yaml b/assets/multiqc_config.yaml index 77679f83..4423f934 100644 --- a/assets/multiqc_config.yaml +++ b/assets/multiqc_config.yaml @@ -1,7 +1,7 @@ report_comment: > This report has been generated by the nf-core/fetchngs analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: software_versions: order: -1000 diff --git a/assets/nf-core-fetchngs_logo.png b/assets/nf-core-fetchngs_logo.png deleted file mode 100644 index 9c4e3e83836a2e15b4600dfd731e334406e07ad8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18553 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 -Content-Disposition: inline; filename="nf-core-fetchngs_logo.png" +Content-Disposition: inline; filename="nf-core-fetchngs_logo_light.png" -<% out << new File("$projectDir/assets/nf-core-fetchngs_logo.png"). +<% out << new File("$projectDir/assets/nf-core-fetchngs_logo_light.png"). bytes. encodeBase64(). toString(). diff --git a/bin/scrape_software_versions.py b/bin/scrape_software_versions.py deleted file mode 100755 index a4e45493..00000000 --- a/bin/scrape_software_versions.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import os - -results = {} -version_files = [x for x in os.listdir(".") if x.endswith(".version.txt")] -for version_file in version_files: - - software = version_file.replace(".version.txt", "") - if software == "pipeline": - software = "nf-core/fetchngs" - - with open(version_file) as fin: - version = fin.read().strip() - results[software] = version - -# Dump to YAML -print( - """ -id: 'software_versions' -section_name: 'nf-core/fetchngs Software Versions' -section_href: 'https://github.com/nf-core/fetchngs' -plot_type: 'html' -description: 'are collected at run time from the software output.' -data: | -
-""" -) -for k, v in sorted(results.items()): - print("
{}
{}
".format(k, v)) -print("
") - -# Write out as tsv file: -with open("software_versions.tsv", "w") as f: - for k, v in sorted(results.items()): - f.write("{}\t{}\n".format(k, v)) diff --git a/conf/base.config b/conf/base.config index a4d68207..f19f9f86 100644 --- a/conf/base.config +++ b/conf/base.config @@ -54,4 +54,7 @@ process { errorStrategy = 'retry' maxRetries = 2 } + withName:CUSTOM_DUMPSOFTWAREVERSIONS { + cache = false + } } diff --git a/conf/modules.config b/conf/modules.config index 0b1bfdec..a0506a4d 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -1,32 +1,41 @@ /* ======================================================================================== - Config file for defining DSL2 per module options + Config file for defining DSL2 per module options and publishing paths ======================================================================================== Available keys to override module options: - args = Additional arguments appended to command in module. - args2 = Second set of arguments appended to command in module (multi-tool modules). - args3 = Third set of arguments appended to command in module (multi-tool modules). - publish_dir = Directory to publish results. - publish_by_meta = Groovy list of keys available in meta map to append as directories to "publish_dir" path - If publish_by_meta = true - Value of ${meta['id']} is appended as a directory to "publish_dir" path - If publish_by_meta = ['id', 'custompath'] - If "id" is in meta map and "custompath" isn't then "${meta['id']}/custompath/" - is appended as a directory to "publish_dir" path - If publish_by_meta = false / null - No directories are appended to "publish_dir" path - publish_files = Groovy map where key = "file_ext" and value = "directory" to publish results for that file extension - The value of "directory" is appended to the standard "publish_dir" path as defined above. - If publish_files = null (unspecified) - All files are published. - If publish_files = false - No files are published. - suffix = File name suffix for output files. + ext.args = Additional arguments appended to command in module. + ext.args2 = Second set of arguments appended to command in module (multi-tool modules). + ext.args3 = Third set of arguments appended to command in module (multi-tool modules). + ext.prefix = File name prefix for output files. ---------------------------------------------------------------------------------------- */ -params { - modules { - 'fastqc' { - args = "--quiet" - } - 'multiqc' { - args = "" - } +process { + + publishDir = [ + path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" }, + mode: 'copy', + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + + withName: SAMPLESHEET_CHECK { + publishDir = [ + path: { "${params.outdir}/pipeline_info" }, + mode: 'copy', + saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + ] + } + + withName: FASTQC { + ext.args = '--quiet' } + + withName: CUSTOM_DUMPSOFTWAREVERSIONS { + publishDir = [ + path: { "${params.outdir}/pipeline_info" }, + mode: 'copy', + pattern: '*_versions.yml' + ] + } + } diff --git a/conf/test.config b/conf/test.config index 8fadc49c..0fcafcbf 100644 --- a/conf/test.config +++ b/conf/test.config @@ -16,8 +16,8 @@ params { // Limit resources so that this can run on GitHub Actions max_cpus = 2 - max_memory = 6.GB - max_time = 6.h + 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 diff --git a/docs/images/nf-core-fetchngs_logo.png b/docs/images/nf-core-fetchngs_logo.png deleted file mode 100644 index 737a0e6f645b564c95d33a6f34093ee389dc2857..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35625 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
    sG51%%n;Or{rl@(0x6J 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 Gy#F6Gql!uZ diff --git a/docs/images/nf-core-fetchngs_logo_dark.png b/docs/images/nf-core-fetchngs_logo_dark.png new file mode 100644 index 00000000..dee3db82 --- /dev/null +++ b/docs/images/nf-core-fetchngs_logo_dark.png @@ -0,0 +1,9 @@ + + + + 508 Resource Limit Is Reached + +

    Resource Limit Is Reached

    +The website is temporarily unable to service your request as it exceeded resource limit. +Please try again later. + diff --git a/docs/images/nf-core-fetchngs_logo_light.png b/docs/images/nf-core-fetchngs_logo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..c201c150b55cdf4278cedfc6c5b1c88a1f1ed3e7 GIT binary patch literal 75527 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�ev`Q}H7y#R1zKkC5n?0_OP7^FqWWeXhX0t0pNK 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

    )bNtXB<>| z?zw$VG?;}cA_WMLuWxkpU`bqq^-gI`l!vzyJIgmqm5DEFjm;@^zl*oW_s|8wm8e*b zz0XFbT9w}8+|d^`xK_6-vkAYgt=Keh)4pg{f8qatTnp1$c}kL8Q8Mn_uNQo(tIlKi zpX6ZQc^`-|an(4vp*vd)^SNh=Ro#iKRpvBh@*kGgjw6S?q%KHqoeH6(_1wIA`lV^z zAiRs`A3r0$<3C?@`aE7#*py0h!ZV&RT$9)V_a4o83@+F_%Eo_IXpu`p#0RmnkYKV6>PRTk%i$*vH0e2KA$-EIE^&JXaojXAE*53ZKr9x)`Qum z7UB9BUT@5(waVq@friz=*QwcTSIWnOG4BIs|6G-zA;m{oOAc}4!>le3X(;(rUNgef z(7*5!tt5aZn8P0!173!kFHC$!crh8;jTxMQSIE;}csC5F6Vx;H$&(nH3E%(&HAh^MAf}e0nfSMQPOniL_ z7j57+Bi!(wmiNfn2t9a|2C1x>?Ls7;Mf~#%uyxQ4XbR0iiZG~93)7HJPQ|COV0;>D z#;*;}%i>vM=bScHgBHF=!NCGns4A2;tr8_sKh_4a@ zt{B5ZWXgYDXOdJtuC%DBe?Lald9&;{9%iclNek+#CCvfe_-`5NJW@!FZA`&&O&=p9 zUwlVLYHm&ldOFGYwv^64tn!6!H32EqrT>2?b9bz=kKq{R5PdaZBW0#`LK1sQ18{uJjq4Q*}wb*uTa%(>{4%;VK01*KSq zh^qcE(^@tu>pk>REghc5E4ZPCWk%EaO%C z&%%0tbPv5YmqdT&R)}mL3i4XV6jvmR@TXK!7qX{ZJj;Gln!(~06Vc5%7Z>XGw*|CW z{3(&T7JDu_+<_&!Qbi0h)Zwm?Xj;_}Cbifn__LJbIWH-7#rR}P@spEbTfxO^XYW%M zhJEnJEAHE}H`p5>4E?|@|MY1)YOBU;fR@a2X-nTo)!{n3Xe8yyJAvAW=7UAr+^*hFU0;)||N9fTIy zB@~>=9fZueR+b%uo2$%=%7YAE@|9h4K3Gnr3xsLX&S#8Hmt95P4}F2SFI?k!cZE44 z^2&Ay?B%9a<(R{>NER!X`!cultn!S|gQPK!EeGM-a%y_zD!WSZ*gKbs4pw(8pY<-^ zZBJZw0{4iaQ9^ zT8kD}ql$!cJZi)g!$|5ll7vYeP!8VLd+Mk=2qkg8GX(MjA-$f&*W^R5TcrikeH_3g z2RzjTDrfB$SYPI)M3L--)_uH^7i!obxP{DPi zM5t48>!<|&hzBc#kyj=3dbup07F$XBsm!&;-|?ih7;FeG61KWhHgd-0#CxaI2<~64 zohOXU9U8pb+TZb2+zY+0l&eo_^T46u{q~Ue|CxIAMORWHakreaG}#%Q%Wu`*Og7GV zU(<`Cn@pWKnelXBd)xB7O*ED&nM^4DsVG+&`L>C}E7;)|eoNuO5us;xlLaK?UPnWL z9oIsOax`n6NWdBgeD0uZkVvFNYZ%?+(*c2XdpL?3?WayfRx`iGtCGnq$3sx;Vx(au zeMO66%Z|@fLcKSiZ}rdp!ka9fSR9_AmJ&!TPG)LeAcVXh*qv(ZH>Fx_p?Z7S7nWz) z)ey*k3!|#s(e?>@K9M-NqOo)0su5>}F+r^NmaMFtnvw_?(x_3SS5a+IXoVT<|7f5n z-$buLmMlGF3C@o%cq8VqPK?AJsprrN^WyKE4no3s8pPF}Mx72q;$0I|xYfakYG_Gc z357U>Rwm+~cQ?0o5ZVLAvyHORs^qFRX=&JXjNyp<-C>)ib3q~29*v;gHnL2YMhrPvbt=vSuYW4(cr@f z8=UnNlqNf&edfv)#HSxS=HRS5$s<37`H)w=WnJZkdw)=f6Q~4HzGpHu=cCi6ALdP1 zOCr9WAv56gk*@9&ED&R5pq8^O508?s7~M)Fejy@&lnCqs11Ju?5*TNoMVw8rVifFj zD0Up1el31t94lNCfFJZE_M$Bg$??f}Y%#sOy>j30VgauF7cy3Jc`~NLc@mm zb8?LBF*sBh>XCT{wRV0tuIBgEOClz^!hqnpS-}56WzSQ*Z%VqH3wb{?>5ydo4tnPU zxyUu-egF3R#hbM+cj|mFzLvWi^Qho&TOYdh=><&`I1208d#|_`Ht* zfRdAjL*2={gxY5jye5M9Fzx%{!{{ykj`IBreyhrM>4S#a(B$UT4niMF_`CmYdt<}! zv8TF&?0Y&h^K-)qPt6Bqvdv`30^U!{lAW*_lN~5#lp;HEsikw`{me=8=mP$JDi?Wt zpa#P;VlYn}B(4JBW&+~lL7B{A@a#9uw?wkCvgxV=oB4M7kt}3Vvit@|LV5W!K?I|L z;3>H|#C-&2vSf0SPNeU_A;)l4Y=bTzbFMEopMuqayJ>Lz%MeuS)id4_(^6#Vsx^#o zqJb}O-d?j;t$TRbuU`6g@^K<|lER|I)?xgC5t-FXN4tI4sFc_8?ck z_s6pNjh^u1IPD}Zwz6z0QHJgOnmH*Tb6H$7o)*DF6c6r@K!6SodT)WI{mhGGYJ}Iv z!G7g_coQcvliHBmNaKOzCs7eL*ZUIhBH6^Vh1?Ut9Hgq~`^Uy{HQT9hx&FUXSiT-x%ApC;r_aezH z5*`hvJZYm4$ztvx)wS-`9#1_?{hdO*b6x)e;_Sl70nEZD-K&s5e7azHJS6&nIr0Jy z?hX=4@T`nG|L}!jp#>f|MKlg4`HoU`vDo%oI}t>JFDa7b*?2-Xjg7j)tL_sR)!fA4 z23JD&1o4a40%LCb>_Aj+KL-dDo6-q&IyRM3Vtl zU6Y4%0zY5B3a3h_CFR^*rw14cAhz554#zc6UOiEcHj1tR-a)J!uynF>Gtjm(L5vac zkXVJ}Py~5D=3bgQMWH~wV;yehqYQ&q*5boqKlP*5;s z`X$CJ`Am|30f|^+vYK=ms{$_?=mVJC$3(L1Ny~P_IR~dzTaL2&%qKA?v&>rSREbn1 zkzOFc&M>~dF3>-o5p){uFYMDUgU?T*?8t2ujbV>sTsYHiSGuKX-cIu3QDPS6oVyA4EfZW2Xu4$^yXXbD|MOyt_HljBV9W z6`249m?4$_7Z3xlgJsFO8%4&}bYl3;ZyYtwQ0-PxX`kA^+oQ_p*x74by-6~1385-` za4&r=N%(~UHR7s(Dk}VPdPzeDZiiDz89;xt4p`a7Tg6>H)D3wmCj|!yibe7T{AVh; z*4=`{Lh%R{UP?R~u#_Hh;B9SUj(aupz6921>-B58q3%Q7{#bHcIb^a=%!{q|0`7%`CQcJU~7Riz({dUF&@K;~-%)}AK|MpP z6Vq)quNDoPAyEd~Zbr-yWc;Z)i+Ff@&0EFP-0rD^+#qCOLB+7J0{)#VaJAHF?AKT} z(v`Yr>SbyflDqkG5@ggM7A>wpIw7u#q*V7aSJ^-QJIP#+3%@TSRBw}~2Sq{JXiSHN zCvYnL$RPDV$sdq;5H!BCyKVExK{i3sTToWE`yQkVVmeuft0<@iSmwbkZ&W0`8Hq}1 z8pY?Q4kVmBAl-6C3703W%N+{L$2-ptYO!Xr_!s~_mYIKk#TD0f#l(r)50*1O zT~}6fshz-2@bN`%=&ax6Q3Rtco!>Xw+yDk&7V_`#v@)#s*R1XPkO;Kw|0ka~6a zdfJPaG8moV6TDf9k{=LetjpsNUZc}^*~h?omwZo}fmCQuOonx^b(n-}IZ3?t4W_#PZ236ID--qTq5GeclbvmU%r!C#T|19f7bM={LI z<$K@Ay!9H!DU!u7g?@d<%}CWobKJz-j;*zV=OZy49x4J6K894zlL`2^25M^|_z#AL zXRIxR;0&gwh`h+Me|Am;a4OM@*YSZ%LB0eoh2dUNAF~gb%BmMX2lz)ubQF>z&k;|v zXuXMHT#4$qC6F(|-5iTQ5?njvOXssIn6VZBhjT-nLXa_9J10)*#OMc(E~FW4_y!tr zpyow~JQ9{b<=G(42t7}_U*5Jis{Ng*(?eYKObubVVF;gk1;H1)`_hAs*i5FhyV1qL zn_mH!s86VWez=1m?V;$Vt0F!bK8UlrJ+X$$yoR+V$RpVdzGVrSVUrMb0r)I=BJkO% z_;ZL~1d55oZ&JGEJ7*n_=(lfD$}1Lk%(0H%06I0>{Em<8P@p2|9wmtwi94%en3joo zs5BV`Jf6IO|8BL{_3tX)rCp({-nhh}lkUihBo@j<`rW%CNRvD3+-zQN=HxCtvKuP| zNIYrR(!Tx^zCmRB+hK=BhiGvJBknGgf?KLqy8EO(XPvTw#;&~3B2aSu>7@gR1*ApI z0LrjP!rn1=%VhYywzo8Vfkez_K2wE(bANl+7!(j-Sw4~|2#VgPke%2TlsM#>2O zLM}42U(mDn^%}D32eRO)0Fs^#4_|RAO#u$wk7Qv?pvUbXdt{J;J3n6>YPP3zAc%2| zPvr-S$1_O%i!FnFDWk38P|nv@7)5NtM)P?EpeFjkip85!G?Z>Kt`3TKiU>k@Ntcr2 z#P?Bns)Ks){v6ddC*TseBo`@*_fg`m*AQz7*N~vkU=p*%bz-r|l&0E^;EHG2hogJ7 zCu*dN>lLXcfPHZSc%61JbC4yDBXEzmnAxoc&$#U`**7>xwezv8^?kb+LEiUk*vCQ< z7L||Hhfe6z;xo~-EvoBw=Vec1^%8ZRv&%|J+Be~9bP{&_y^J(7RzC_{lIY+z4=tj@ z<}I-`VGYH;h+>$^M(_cWr_3@9AZT<{dA$!Xh+&&#MKY6opZk-mKsA(SpLEx<$y^Cn z4gkx||C00p3n8eH*|2aioZK-IBa-L-fWcVn}SELDwx)Jllb2CHe3m@i&x>cGr9Ixs~!M zOG^|wxxkH`PTJTw$Vx6q7Ax79yy+6I=BgXb-)k6Y82cgezic&j=wqQLOON1tK{+=X zpWj+L2-Kss&cf)H4VjJEQG?~4_z1!Cfu8!z!_~*+8S%dTn}^P&d(*_}T)uaQKEDMB z0M~w`LHBpvNQK~#Louu+Jzk=+1pSQ(JmX9iy~{1i%Eh*0F-nab-tJ2*b{NC1GBZkm z<5WTuPy?R>lK%5c)Rw5S8C1f%69VqqvsTC+|9xOtHLX(Gm(+n1R|+kgDIR!cZe^SRw}7d z;1&em1-gDV6g*@e4JNquZCras|!I3mmu2_8wnNe^b(RX!YgJmR@kpN_+ke zN`AvRg&|j zlt6_`N3vKGh+P?G>H$^=Hk26yRz|@`CzS8?a?UqmvhMU)n#Q*q&hVAJM7=7`g@9pe z89^<=G(sm_Xlz7mRswoTyYz60oQcfIC5`WJn*c#XDC%LR1XncX@lk5zthKr8aWR6g z*hz(MArpKerN|aCl=H|}N;ULiw!VkJdB6UT&f3!vDrVG_N30uZJ*3FGavst7@RE(% zQ3-P_&_?8bq2tAqnG~n{@01>-qa3GMUVkVib@76t>i+aY#M?422j6bHc9ILyvS*B> zQQ;hTorEx+5%Ejntqj?MpK@L-A>*grn3}Xmf~eL9A<3fu@V^M${v%Mb`npo{-kWab zY$g4;waJ-CY5_)}&t6?C)$H8ON*&Z{gA*WkD2AnI$WqGr+dDx4Jha4IECI7ORlX%xLkM2S>PMcfQAoTHXiHgre$Ng``C+UO#Tf z%h)nwFM(vfd1`y)$+e<9#vF(0WB#2seWeOrC8+#Sznrt;aTFq+VHge(W zrLULV-9kwxSkZvb=A>{4q$?@Los{c>y!(<4Z}}x7H_1eA)Vm2%hAVvAq&Gr=X3qss z%ZI$*`HOR832P|h_`UCt@YeCB?vDk`1ijIFpj0~S;5t0+y?on^xUzWvD01NIzw-6X zg!GOMi0ue9#H92NEiey6Cu+B^icR#ZYNp@eiUFO?Nfr7Ruph>k>z8L==o+C44y|SzJlM0I*>xbKB8ipr}PC$Vq1>q1lcQUVmYSy6QkL>A*e-!H* zE^(h_rDTROBbAFN7eq_a_1wd0CwYNzI#a@`n-!AuwhhFxQXr+>8N&+;k^;lb@8IM0MP++-^ot&?qrdT% z@mt^g{?3Z;HrZm^T9}sx)ecIrLxK@CD-D*|m9|IDBSIvWPqVHyJ{kM@xVB3677f>}YM!uoen+4Oz@ixxU4lLhmdnA5_Cq zn!eQCP6VBdu#5-q++!n15F&4}luzs{UuR55zOLgFrsna*>NC!J?Cp@C$r2nxuAoQ6_@4>i!6BY@q3nq~DerN>eBtm6*u#Q`uY>m(|fJDWc zpd*|pqn5K+7*%^nTL*KYS_V1t6%vq`ecJ&{84B}oF zCzG?le%RKJAo5Za*j|fNy}S>y9=!0XA^r$uwZD_MT)i18>}k80A($6~-0{+6T>DhH z))3w`G*u{EYE@%Bnl`c);H`-I_l(mxT>~H9CT$R>H^+UeV*&En!Rqu z{b+UcK~w&8PUYTj?1*4Qo4e_xVehcV!aJ`ri#6`$VfW$Z)xp#{#z~hsQAf`=ZCNL{JQMT4Pss0(=nZcMfFg6F79R(b&tT1 zA~R(|O243sb%AyG9^}`bKkgKq*>=nPf)x~SUzz6ij(RZ7+V`Tx0@d|mcE1L^^tM(30<+-Ybq|(J5AS4>HfrK@Y`q@59{K__?e~yDbZ00uR4!EC zK}u!5t72Q@REmf9ef}1&kj+`|1rPau?0tDSl>Ha?jESj)=24Wj21$`>>}zF&EM+O8 zP|BJu$<9ohiBJ^H*b*sZ%N{XBX|Xd2VNhfr+4uL1o~3^Ozwck~bfmz60<-`UH0xR#w@qJc@Yfd_%Qh+H>r;$#Z1qbV zrbDJHdOvc^AMWnDGL8kjsrS%W2a9lta!`$y{I@cCQiV_DUaqD1l0l7rq3xZrgn4Q; zb1Ov|w{BJhjctMQG9DdwRQ895iFJ1u!(^ufX|3)uf_52N>3LlGgXa41v3o;U>5tz} zQ?3w0lPy~KS`pIY!cqX?eb+1jgybp03dMOF4w7UJ!9TNe%b~_Y!|!g{_meVEPTjju z6b99aFWsDOvAoD!g~kTx$tH=F#N-vnif-S9Ef%MO`V!8Md4V(TaHF5V+O`E)&~5kw zJzJ_>R<=re+xzxq2$ipz%-k)}=es{|L1!F4>o;~f$YbD}M_PEprG-R&sas!DYiMU!HhA>iwIu9mL)yPD&kZ`96?aOxR zH5kbH16m82C-TkrmOis2R;v4Q$0;vx0e*llBNk^ZT)p(~gdJaei(a-#oJmr`I-Xly z*+FkK={OhuC}?>W;>xRmRbGyX3BM2#^}xwJFh`5ETv{C~>N)qpRiNbJr)bHSPP`$B zs|#KH6>=r#R*yq?=Sq{)3}dl6B=UEd+1R3fzIWav8$i-5>H|Q4f1W)}d5%`QBg{(? zj5*;vGx30A6#A=M5Jw5WCOQos2Gj!`x3%-Yj^HY>!vSo8S1$wsYQ9tijZo=rN9*&G zoMT1H?nh<6^-XtoE4ads8oGazLupTJNnuj>tO&;H%3G0U;07@-q^i~#(mgm7@oa1jNZjh zINmdxO*uWzVmWZY(nuLhR7y_X8n5Utw->}v~%48?R&QC%cX(g z=Hs1{86xs}&WbLx6{(F&UFI8mxl=(hBmHlhKKd}gdBV4_{jKSuHtJL8&nB>lqn=A4 z$FDi=ieoR!RKFyV_GAGSG+^uS;;%V`OH@?huSlqc)=m#g6%w&hg(hQ zXJ-VR;lp)$wkkNaXt`0XqGaN3_n92mpLa`i3G;rFYM?UX`?LC)l%?rc!>-bSujYd* z+8+jHfAyvojlY_urb%Tg9r?`hZ-C%~0t`e9IyPN3O>R^*5(JT$*IXO_P+g}&&)g3MM6>U80+;-5j zns2RD`YqvqVnZ$1-Ue^a=w029 zec#SozG~OzV}(S$>_%DmhYK*yRT;oxwhb22woU~IIhI#QDGP&K(JKcSVieE&_hg#? zDS>zIaLB*{x8#NUr|6RIQm@ICwSSfzZLSzJXF^hF|9G-sZBxO%FpLT!?X`rF6le>@ zsHSE%N;%%AQMm>=Uydku{-&nd>oK5`pb5&V!YSU-fc{qhW193 z5ljvF!9)A#X<`wu4{-07nnoyau4#Lk79w#|-Mw2qSFBf=q>_8Q-(kwQ#w3xb8-i(7 z<}W~oPZWqzK89)$L&dj;ll@ZcL1COr2cT`@p}kQ@2F3AycZP*iVBw`dAN#8@WUTeC zM9A>JkU=Ua!wk)3_FlfoEFP^bB( zEv?-I&wY#wOWyVw%0%%2&G`k$Y?{^De8BXvkT zOxecNtenT%q~GxwWTAy>{Us#rD!26Ih{C;~X07jBU5G%Us0#H^v5)2tjXUAQ~b1(K=q3K#b}W|v&zy^LKPwC zCi}@G%b{Wr5p|(IKY)DqcrRWt⁢aNap>1nkqt+#?RWH3b^msFaUIg1xHIA4N&q% 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 literal 0 HcmV?d00001 diff --git a/docs/output.md b/docs/output.md index 1240ce0c..9ce80c16 100644 --- a/docs/output.md +++ b/docs/output.md @@ -60,7 +60,7 @@ Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQ * `pipeline_info/` * Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. - * Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.tsv`. + * Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. * Reformatted samplesheet files used as input to the pipeline: `samplesheet.valid.csv`. diff --git a/docs/usage.md b/docs/usage.md index 6e395601..9322b677 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -181,42 +181,6 @@ process { > **NB:** We specify just the process name i.e. `STAR_ALIGN` in the config file and not the full task name string that is printed to screen in the error message or on the terminal whilst the pipeline is running i.e. `RNASEQ:ALIGN_STAR:STAR_ALIGN`. You may get a warning suggesting that the process selector isn't recognised but you can ignore that if the process name has been specified correctly. This is something that needs to be fixed upstream in core Nextflow. -### Tool-specific options - -For the ultimate flexibility, we have implemented and are using Nextflow DSL2 modules in a way where it is possible for both developers and users to change tool-specific command-line arguments (e.g. providing an additional command-line argument to the `STAR_ALIGN` process) as well as publishing options (e.g. saving files produced by the `STAR_ALIGN` process that aren't saved by default by the pipeline). In the majority of instances, as a user you won't have to change the default options set by the pipeline developer(s), however, there may be edge cases where creating a simple custom config file can improve the behaviour of the pipeline if for example it is failing due to a weird error that requires setting a tool-specific parameter to deal with smaller / larger genomes. - -The command-line arguments passed to STAR in the `STAR_ALIGN` module are a combination of: - -* Mandatory arguments or those that need to be evaluated within the scope of the module, as supplied in the [`script`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/modules/nf-core/software/star/align/main.nf#L49-L55) section of the module file. - -* An [`options.args`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/modules/nf-core/software/star/align/main.nf#L56) string of non-mandatory parameters that is set to be empty by default in the module but can be overwritten when including the module in the sub-workflow / workflow context via the `addParams` Nextflow option. - -The nf-core/rnaseq pipeline has a sub-workflow (see [terminology](https://github.com/nf-core/modules#terminology)) specifically to align reads with STAR and to sort, index and generate some basic stats on the resulting BAM files using SAMtools. At the top of this file we import the `STAR_ALIGN` module via the Nextflow [`include`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/subworkflows/nf-core/align_star.nf#L10) keyword and by default the options passed to the module via the `addParams` option are set as an empty Groovy map [here](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/subworkflows/nf-core/align_star.nf#L5); this in turn means `options.args` will be set to empty by default in the module file too. This is an intentional design choice and allows us to implement well-written sub-workflows composed of a chain of tools that by default run with the bare minimum parameter set for any given tool in order to make it much easier to share across pipelines and to provide the flexibility for users and developers to customise any non-mandatory arguments. - -When including the sub-workflow above in the main pipeline workflow we use the same `include` statement, however, we now have the ability to overwrite options for each of the tools in the sub-workflow including the [`align_options`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/workflows/rnaseq.nf#L225) variable that will be used specifically to overwrite the optional arguments passed to the `STAR_ALIGN` module. In this case, the options to be provided to `STAR_ALIGN` have been assigned sensible defaults by the developer(s) in the pipeline's [`modules.config`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/modules.config#L70-L74) and can be accessed and customised in the [workflow context](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/workflows/rnaseq.nf#L201-L204) too before eventually passing them to the sub-workflow as a Groovy map called `star_align_options`. These options will then be propagated from `workflow -> sub-workflow -> module`. - -As mentioned at the beginning of this section it may also be necessary for users to overwrite the options passed to modules to be able to customise specific aspects of the way in which a particular tool is executed by the pipeline. Given that all of the default module options are stored in the pipeline's `modules.config` as a [`params` variable](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/modules.config#L24-L25) it is also possible to overwrite any of these options via a custom config file. - -Say for example we want to append an additional, non-mandatory parameter (i.e. `--outFilterMismatchNmax 16`) to the arguments passed to the `STAR_ALIGN` module. Firstly, we need to copy across the default `args` specified in the [`modules.config`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/modules.config#L71) and create a custom config file that is a composite of the default `args` as well as the additional options you would like to provide. This is very important because Nextflow will overwrite the default value of `args` that you provide via the custom config. - -As you will see in the example below, we have: - -* appended `--outFilterMismatchNmax 16` to the default `args` used by the module. -* changed the default `publish_dir` value to where the files will eventually be published in the main results directory. -* appended `'bam':''` to the default value of `publish_files` so that the BAM files generated by the process will also be saved in the top-level results directory for the module. Note: `'out':'log'` means any file/directory ending in `out` will now be saved in a separate directory called `my_star_directory/log/`. - -```nextflow -params { - modules { - 'star_align' { - args = "--quantMode TranscriptomeSAM --twopassMode Basic --outSAMtype BAM Unsorted --readFilesCommand zcat --runRNGseed 0 --outFilterMultimapNmax 20 --alignSJDBoverhangMin 1 --outSAMattributes NH HI AS NM MD --quantTranscriptomeBan Singleend --outFilterMismatchNmax 16" - publish_dir = "my_star_directory" - publish_files = ['out':'log', 'tab':'log', 'bam':''] - } - } -} -``` - ### Updating containers The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. If for some reason you need to use a different version of a particular tool with the pipeline then you just need to identify the `process` name and override the Nextflow `container` definition for that process using the `withName` declaration. For example, in the [nf-core/viralrecon](https://nf-co.re/viralrecon) pipeline a tool called [Pangolin](https://github.com/cov-lineages/pangolin) has been used during the COVID-19 pandemic to assign lineages to SARS-CoV-2 genome sequenced samples. Given that the lineage assignments change quite frequently it doesn't make sense to re-release the nf-core/viralrecon everytime a new version of Pangolin has been released. However, you can override the default container used by the pipeline by creating a custom config file and passing it as a command-line argument via `-c custom.config`. diff --git a/lib/NfcoreSchema.groovy b/lib/NfcoreSchema.groovy index 8d6920dd..40ab65f2 100755 --- a/lib/NfcoreSchema.groovy +++ b/lib/NfcoreSchema.groovy @@ -105,9 +105,13 @@ class NfcoreSchema { // Collect expected parameters from the schema def expectedParams = [] + def enums = [:] for (group in schemaParams) { for (p in group.value['properties']) { expectedParams.push(p.key) + if (group.value['properties'][p.key].containsKey('enum')) { + enums[p.key] = group.value['properties'][p.key]['enum'] + } } } @@ -155,7 +159,7 @@ class NfcoreSchema { println '' log.error 'ERROR: Validation of pipeline parameters failed!' JSONObject exceptionJSON = e.toJSON() - printExceptions(exceptionJSON, params_json, log) + printExceptions(exceptionJSON, params_json, log, enums) println '' has_error = true } @@ -202,7 +206,7 @@ class NfcoreSchema { } def type = '[' + group_params.get(param).type + ']' def description = group_params.get(param).description - def defaultValue = group_params.get(param).default ? " [default: " + group_params.get(param).default.toString() + "]" : '' + def defaultValue = group_params.get(param).default != null ? " [default: " + group_params.get(param).default.toString() + "]" : '' def description_default = description + colors.dim + defaultValue + colors.reset // Wrap long description texts // Loosely based on https://dzone.com/articles/groovy-plain-text-word-wrap @@ -260,13 +264,12 @@ class NfcoreSchema { // Get pipeline parameters defined in JSON Schema def Map params_summary = [:] - def blacklist = ['hostnames'] def params_map = paramsLoad(getSchemaPath(workflow, schema_filename=schema_filename)) for (group in params_map.keySet()) { def sub_params = new LinkedHashMap() def group_params = params_map.get(group) // This gets the parameters of that particular group for (param in group_params.keySet()) { - if (params.containsKey(param) && !blacklist.contains(param)) { + if (params.containsKey(param)) { def params_value = params.get(param) def schema_value = group_params.get(param).default def param_type = group_params.get(param).type @@ -330,7 +333,7 @@ class NfcoreSchema { // // Loop over nested exceptions and print the causingException // - private static void printExceptions(ex_json, params_json, log) { + private static void printExceptions(ex_json, params_json, log, enums, limit=5) { def causingExceptions = ex_json['causingExceptions'] if (causingExceptions.length() == 0) { def m = ex_json['message'] =~ /required key \[([^\]]+)\] not found/ @@ -346,11 +349,20 @@ class NfcoreSchema { else { def param = ex_json['pointerToViolation'] - ~/^#\// def param_val = params_json[param].toString() - log.error "* --${param}: ${ex_json['message']} (${param_val})" + if (enums.containsKey(param)) { + def error_msg = "* --${param}: '${param_val}' is not a valid choice (Available choices" + if (enums[param].size() > limit) { + log.error "${error_msg} (${limit} of ${enums[param].size()}): ${enums[param][0..limit-1].join(', ')}, ... )" + } else { + log.error "${error_msg}: ${enums[param].join(', ')})" + } + } else { + log.error "* --${param}: ${ex_json['message']} (${param_val})" + } } } for (ex in causingExceptions) { - printExceptions(ex, params_json, log) + printExceptions(ex, params_json, log, enums) } } diff --git a/lib/NfcoreTemplate.groovy b/lib/NfcoreTemplate.groovy index 44551e0a..2fc0a9b9 100755 --- a/lib/NfcoreTemplate.groovy +++ b/lib/NfcoreTemplate.groovy @@ -19,27 +19,16 @@ class NfcoreTemplate { } // - // Check params.hostnames + // Warn if a -profile or Nextflow config has not been provided to run the pipeline // - public static void hostName(workflow, params, log) { - Map colors = logColours(params.monochrome_logs) - if (params.hostnames) { - try { - def hostname = "hostname".execute().text.trim() - params.hostnames.each { prof, hnames -> - hnames.each { hname -> - if (hostname.contains(hname) && !workflow.profile.contains(prof)) { - log.info "=${colors.yellow}====================================================${colors.reset}=\n" + - "${colors.yellow}WARN: You are running with `-profile $workflow.profile`\n" + - " but your machine hostname is ${colors.white}'$hostname'${colors.reset}.\n" + - " ${colors.yellow_bold}Please use `-profile $prof${colors.reset}`\n" + - "=${colors.yellow}====================================================${colors.reset}=" - } - } - } - } catch (Exception e) { - log.warn "[$workflow.manifest.name] Could not determine 'hostname' - skipping check. Reason: ${e.message}." - } + public static void checkConfigProvided(workflow, log) { + 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 " } } @@ -168,7 +157,6 @@ class NfcoreTemplate { log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed successfully, but with errored process(es) ${colors.reset}-" } } else { - hostName(workflow, params, log) log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-" } } diff --git a/lib/Utils.groovy b/lib/Utils.groovy index 18173e98..1b88aec0 100755 --- a/lib/Utils.groovy +++ b/lib/Utils.groovy @@ -37,11 +37,4 @@ class Utils { "===================================================================================" } } - - // - // Join module args with appropriate spacing - // - public static String joinModuleArgs(args_list) { - return ' ' + args_list.join(' ') - } } diff --git a/lib/WorkflowMain.groovy b/lib/WorkflowMain.groovy index e8304ec2..d6a67b1f 100755 --- a/lib/WorkflowMain.groovy +++ b/lib/WorkflowMain.groovy @@ -61,6 +61,9 @@ class WorkflowMain { // Print parameter summary log to screen log.info paramsSummaryLog(workflow, params, log) + // Check that a -profile or Nextflow config has been provided to run the pipeline + NfcoreTemplate.checkConfigProvided(workflow, log) + // Check that conda channels are set-up correctly if (params.enable_conda) { Utils.checkCondaChannels(log) @@ -69,9 +72,6 @@ class WorkflowMain { // Check AWS batch settings NfcoreTemplate.awsBatch(workflow, params) - // Check the hostnames against configured profiles - NfcoreTemplate.hostName(workflow, params, log) - // Check input has been provided if (!params.input) { log.error "Please provide an input samplesheet to the pipeline e.g. '--input samplesheet.csv'" diff --git a/modules.json b/modules.json index e4a8a64f..d183e20a 100644 --- a/modules.json +++ b/modules.json @@ -3,12 +3,15 @@ "homePage": "https://github.com/nf-core/fetchngs", "repos": { "nf-core/modules": { + "custom/dumpsoftwareversions": { + "git_sha": "20d8250d9f39ddb05dfb437603aaf99b5c0b2b41" + }, "fastqc": { - "git_sha": "e937c7950af70930d1f34bb961403d9d2aa81c7d" + "git_sha": "9d0cad583b9a71a6509b754fdf589cbfbed08961" }, "multiqc": { - "git_sha": "e937c7950af70930d1f34bb961403d9d2aa81c7d" + "git_sha": "20d8250d9f39ddb05dfb437603aaf99b5c0b2b41" } } } -} +} \ No newline at end of file diff --git a/modules/local/functions.nf b/modules/local/functions.nf deleted file mode 100644 index da9da093..00000000 --- a/modules/local/functions.nf +++ /dev/null @@ -1,68 +0,0 @@ -// -// Utility functions used in nf-core DSL2 module files -// - -// -// Extract name of software tool from process name using $task.process -// -def getSoftwareName(task_process) { - return task_process.tokenize(':')[-1].tokenize('_')[0].toLowerCase() -} - -// -// Function to initialise default values and to generate a Groovy Map of available options for nf-core modules -// -def initOptions(Map args) { - def Map options = [:] - options.args = args.args ?: '' - options.args2 = args.args2 ?: '' - options.args3 = args.args3 ?: '' - options.publish_by_meta = args.publish_by_meta ?: [] - options.publish_dir = args.publish_dir ?: '' - options.publish_files = args.publish_files - options.suffix = args.suffix ?: '' - return options -} - -// -// Tidy up and join elements of a list to return a path string -// -def getPathFromList(path_list) { - def paths = path_list.findAll { item -> !item?.trim().isEmpty() } // Remove empty entries - paths = paths.collect { it.trim().replaceAll("^[/]+|[/]+\$", "") } // Trim whitespace and trailing slashes - return paths.join('/') -} - -// -// Function to save/publish module results -// -def saveFiles(Map args) { - if (!args.filename.endsWith('.version.txt')) { - def ioptions = initOptions(args.options) - def path_list = [ ioptions.publish_dir ?: args.publish_dir ] - if (ioptions.publish_by_meta) { - def key_list = ioptions.publish_by_meta instanceof List ? ioptions.publish_by_meta : args.publish_by_meta - for (key in key_list) { - if (args.meta && key instanceof String) { - def path = key - if (args.meta.containsKey(key)) { - path = args.meta[key] instanceof Boolean ? "${key}_${args.meta[key]}".toString() : args.meta[key] - } - path = path instanceof String ? path : '' - path_list.add(path) - } - } - } - if (ioptions.publish_files instanceof Map) { - for (ext in ioptions.publish_files) { - if (args.filename.endsWith(ext.key)) { - def ext_list = path_list.collect() - ext_list.add(ext.value) - return "${getPathFromList(ext_list)}/$args.filename" - } - } - } else if (ioptions.publish_files == null) { - return "${getPathFromList(path_list)}/$args.filename" - } - } -} diff --git a/modules/local/get_software_versions.nf b/modules/local/get_software_versions.nf deleted file mode 100644 index 4d37bd6a..00000000 --- a/modules/local/get_software_versions.nf +++ /dev/null @@ -1,33 +0,0 @@ -// Import generic module functions -include { saveFiles } from './functions' - -params.options = [:] - -process GET_SOFTWARE_VERSIONS { - publishDir "${params.outdir}", - mode: params.publish_dir_mode, - saveAs: { filename -> saveFiles(filename:filename, options:params.options, publish_dir:'pipeline_info', meta:[:], publish_by_meta:[]) } - - conda (params.enable_conda ? "conda-forge::python=3.8.3" : null) - if (workflow.containerEngine == 'singularity' && !params.singularity_pull_docker_container) { - container "https://depot.galaxyproject.org/singularity/python:3.8.3" - } else { - container "quay.io/biocontainers/python:3.8.3" - } - - cache false - - input: - path versions - - output: - path "software_versions.tsv" , emit: tsv - path 'software_versions_mqc.yaml', emit: yaml - - script: // This script is bundled with the pipeline, in nf-core/fetchngs/bin/ - """ - echo $workflow.manifest.version > pipeline.version.txt - echo $workflow.nextflow.version > nextflow.version.txt - scrape_software_versions.py &> software_versions_mqc.yaml - """ -} diff --git a/modules/local/samplesheet_check.nf b/modules/local/samplesheet_check.nf index 77f58557..3f114f13 100644 --- a/modules/local/samplesheet_check.nf +++ b/modules/local/samplesheet_check.nf @@ -1,31 +1,27 @@ -// Import generic module functions -include { saveFiles } from './functions' - -params.options = [:] - process SAMPLESHEET_CHECK { tag "$samplesheet" - publishDir "${params.outdir}", - mode: params.publish_dir_mode, - saveAs: { filename -> saveFiles(filename:filename, options:params.options, publish_dir:'pipeline_info', meta:[:], publish_by_meta:[]) } conda (params.enable_conda ? "conda-forge::python=3.8.3" : null) - if (workflow.containerEngine == 'singularity' && !params.singularity_pull_docker_container) { - container "https://depot.galaxyproject.org/singularity/python:3.8.3" - } else { - container "quay.io/biocontainers/python:3.8.3" - } + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/python:3.8.3' : + 'quay.io/biocontainers/python:3.8.3' }" input: path samplesheet output: - path '*.csv' + path '*.csv' , emit: csv + path "versions.yml", emit: versions script: // This script is bundled with the pipeline, in nf-core/fetchngs/bin/ """ check_samplesheet.py \\ $samplesheet \\ samplesheet.valid.csv + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + python: \$(python --version | sed 's/Python //g') + END_VERSIONS """ } diff --git a/modules/nf-core/modules/custom/dumpsoftwareversions/main.nf b/modules/nf-core/modules/custom/dumpsoftwareversions/main.nf new file mode 100644 index 00000000..934bb467 --- /dev/null +++ b/modules/nf-core/modules/custom/dumpsoftwareversions/main.nf @@ -0,0 +1,21 @@ +process CUSTOM_DUMPSOFTWAREVERSIONS { + label 'process_low' + + // Requires `pyyaml` which does not have a dedicated container but is in the MultiQC container + conda (params.enable_conda ? "bioconda::multiqc=1.11" : null) + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/multiqc:1.11--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.11--pyhdfd78af_0' }" + + input: + path versions + + output: + path "software_versions.yml" , emit: yml + path "software_versions_mqc.yml", emit: mqc_yml + path "versions.yml" , emit: versions + + script: + def args = task.ext.args ?: '' + template 'dumpsoftwareversions.py' +} diff --git a/modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml new file mode 100644 index 00000000..5b5b8a60 --- /dev/null +++ b/modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml @@ -0,0 +1,34 @@ +name: custom_dumpsoftwareversions +description: Custom module used to dump software versions within the nf-core pipeline template +keywords: + - custom + - version +tools: + - custom: + description: Custom module used to dump software versions within the nf-core pipeline template + homepage: https://github.com/nf-core/tools + documentation: https://github.com/nf-core/tools + licence: ['MIT'] +input: + - versions: + type: file + description: YML file containing software versions + pattern: "*.yml" + +output: + - yml: + type: file + description: Standard YML file containing software versions + pattern: "software_versions.yml" + - mqc_yml: + type: file + description: MultiQC custom content YML file containing software versions + pattern: "software_versions_mqc.yml" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + +authors: + - "@drpatelh" + - "@grst" diff --git a/modules/nf-core/modules/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py b/modules/nf-core/modules/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py new file mode 100644 index 00000000..d1390392 --- /dev/null +++ b/modules/nf-core/modules/custom/dumpsoftwareversions/templates/dumpsoftwareversions.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +import yaml +import platform +from textwrap import dedent + + +def _make_versions_html(versions): + html = [ + dedent( + """\\ + + + + + + + + + + """ + ) + ] + for process, tmp_versions in sorted(versions.items()): + html.append("") + for i, (tool, version) in enumerate(sorted(tmp_versions.items())): + html.append( + dedent( + f"""\\ + + + + + + """ + ) + ) + html.append("") + html.append("
    Process Name Software Version
    {process if (i == 0) else ''}{tool}{version}
    ") + return "\\n".join(html) + + +versions_this_module = {} +versions_this_module["${task.process}"] = { + "python": platform.python_version(), + "yaml": yaml.__version__, +} + +with open("$versions") as f: + versions_by_process = yaml.load(f, Loader=yaml.BaseLoader) | versions_this_module + +# aggregate versions by the module name (derived from fully-qualified process name) +versions_by_module = {} +for process, process_versions in versions_by_process.items(): + module = process.split(":")[-1] + try: + assert versions_by_module[module] == process_versions, ( + "We assume that software versions are the same between all modules. " + "If you see this error-message it means you discovered an edge-case " + "and should open an issue in nf-core/tools. " + ) + except KeyError: + versions_by_module[module] = process_versions + +versions_by_module["Workflow"] = { + "Nextflow": "$workflow.nextflow.version", + "$workflow.manifest.name": "$workflow.manifest.version", +} + +versions_mqc = { + "id": "software_versions", + "section_name": "${workflow.manifest.name} Software Versions", + "section_href": "https://github.com/${workflow.manifest.name}", + "plot_type": "html", + "description": "are collected at run time from the software output.", + "data": _make_versions_html(versions_by_module), +} + +with open("software_versions.yml", "w") as f: + yaml.dump(versions_by_module, f, default_flow_style=False) +with open("software_versions_mqc.yml", "w") as f: + yaml.dump(versions_mqc, f, default_flow_style=False) + +with open("versions.yml", "w") as f: + yaml.dump(versions_this_module, f, default_flow_style=False) diff --git a/modules/nf-core/modules/fastqc/functions.nf b/modules/nf-core/modules/fastqc/functions.nf deleted file mode 100644 index da9da093..00000000 --- a/modules/nf-core/modules/fastqc/functions.nf +++ /dev/null @@ -1,68 +0,0 @@ -// -// Utility functions used in nf-core DSL2 module files -// - -// -// Extract name of software tool from process name using $task.process -// -def getSoftwareName(task_process) { - return task_process.tokenize(':')[-1].tokenize('_')[0].toLowerCase() -} - -// -// Function to initialise default values and to generate a Groovy Map of available options for nf-core modules -// -def initOptions(Map args) { - def Map options = [:] - options.args = args.args ?: '' - options.args2 = args.args2 ?: '' - options.args3 = args.args3 ?: '' - options.publish_by_meta = args.publish_by_meta ?: [] - options.publish_dir = args.publish_dir ?: '' - options.publish_files = args.publish_files - options.suffix = args.suffix ?: '' - return options -} - -// -// Tidy up and join elements of a list to return a path string -// -def getPathFromList(path_list) { - def paths = path_list.findAll { item -> !item?.trim().isEmpty() } // Remove empty entries - paths = paths.collect { it.trim().replaceAll("^[/]+|[/]+\$", "") } // Trim whitespace and trailing slashes - return paths.join('/') -} - -// -// Function to save/publish module results -// -def saveFiles(Map args) { - if (!args.filename.endsWith('.version.txt')) { - def ioptions = initOptions(args.options) - def path_list = [ ioptions.publish_dir ?: args.publish_dir ] - if (ioptions.publish_by_meta) { - def key_list = ioptions.publish_by_meta instanceof List ? ioptions.publish_by_meta : args.publish_by_meta - for (key in key_list) { - if (args.meta && key instanceof String) { - def path = key - if (args.meta.containsKey(key)) { - path = args.meta[key] instanceof Boolean ? "${key}_${args.meta[key]}".toString() : args.meta[key] - } - path = path instanceof String ? path : '' - path_list.add(path) - } - } - } - if (ioptions.publish_files instanceof Map) { - for (ext in ioptions.publish_files) { - if (args.filename.endsWith(ext.key)) { - def ext_list = path_list.collect() - ext_list.add(ext.value) - return "${getPathFromList(ext_list)}/$args.filename" - } - } - } else if (ioptions.publish_files == null) { - return "${getPathFromList(path_list)}/$args.filename" - } - } -} diff --git a/modules/nf-core/modules/fastqc/main.nf b/modules/nf-core/modules/fastqc/main.nf index 39c327b2..d250eca0 100644 --- a/modules/nf-core/modules/fastqc/main.nf +++ b/modules/nf-core/modules/fastqc/main.nf @@ -1,22 +1,11 @@ -// Import generic module functions -include { initOptions; saveFiles; getSoftwareName } from './functions' - -params.options = [:] -options = initOptions(params.options) - process FASTQC { tag "$meta.id" label 'process_medium' - publishDir "${params.outdir}", - mode: params.publish_dir_mode, - saveAs: { filename -> saveFiles(filename:filename, options:params.options, publish_dir:getSoftwareName(task.process), meta:meta, publish_by_meta:['id']) } conda (params.enable_conda ? "bioconda::fastqc=0.11.9" : null) - if (workflow.containerEngine == 'singularity' && !params.singularity_pull_docker_container) { - container "https://depot.galaxyproject.org/singularity/fastqc:0.11.9--0" - } else { - container "quay.io/biocontainers/fastqc:0.11.9--0" - } + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/fastqc:0.11.9--0' : + 'quay.io/biocontainers/fastqc:0.11.9--0' }" input: tuple val(meta), path(reads) @@ -24,24 +13,32 @@ process FASTQC { output: tuple val(meta), path("*.html"), emit: html tuple val(meta), path("*.zip") , emit: zip - path "*.version.txt" , emit: version + path "versions.yml" , emit: versions script: + def args = task.ext.args ?: '' // Add soft-links to original FastQs for consistent naming in pipeline - def software = getSoftwareName(task.process) - def prefix = options.suffix ? "${meta.id}${options.suffix}" : "${meta.id}" + def prefix = task.ext.prefix ?: "${meta.id}" if (meta.single_end) { """ [ ! -f ${prefix}.fastq.gz ] && ln -s $reads ${prefix}.fastq.gz - fastqc $options.args --threads $task.cpus ${prefix}.fastq.gz - fastqc --version | sed -e "s/FastQC v//g" > ${software}.version.txt + fastqc $args --threads $task.cpus ${prefix}.fastq.gz + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + fastqc: \$( fastqc --version | sed -e "s/FastQC v//g" ) + END_VERSIONS """ } else { """ [ ! -f ${prefix}_1.fastq.gz ] && ln -s ${reads[0]} ${prefix}_1.fastq.gz [ ! -f ${prefix}_2.fastq.gz ] && ln -s ${reads[1]} ${prefix}_2.fastq.gz - fastqc $options.args --threads $task.cpus ${prefix}_1.fastq.gz ${prefix}_2.fastq.gz - fastqc --version | sed -e "s/FastQC v//g" > ${software}.version.txt + fastqc $args --threads $task.cpus ${prefix}_1.fastq.gz ${prefix}_2.fastq.gz + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + fastqc: \$( fastqc --version | sed -e "s/FastQC v//g" ) + END_VERSIONS """ } } diff --git a/modules/nf-core/modules/fastqc/meta.yml b/modules/nf-core/modules/fastqc/meta.yml index 8eb9953d..b09553a3 100644 --- a/modules/nf-core/modules/fastqc/meta.yml +++ b/modules/nf-core/modules/fastqc/meta.yml @@ -15,6 +15,7 @@ tools: overrepresented sequences. homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ + licence: ['GPL-2.0-only'] input: - meta: type: map @@ -40,10 +41,10 @@ output: type: file description: FastQC report archive pattern: "*_{fastqc.zip}" - - version: + - versions: type: file - description: File containing software version - pattern: "*.{version.txt}" + description: File containing software versions + pattern: "versions.yml" authors: - "@drpatelh" - "@grst" diff --git a/modules/nf-core/modules/multiqc/functions.nf b/modules/nf-core/modules/multiqc/functions.nf deleted file mode 100644 index da9da093..00000000 --- a/modules/nf-core/modules/multiqc/functions.nf +++ /dev/null @@ -1,68 +0,0 @@ -// -// Utility functions used in nf-core DSL2 module files -// - -// -// Extract name of software tool from process name using $task.process -// -def getSoftwareName(task_process) { - return task_process.tokenize(':')[-1].tokenize('_')[0].toLowerCase() -} - -// -// Function to initialise default values and to generate a Groovy Map of available options for nf-core modules -// -def initOptions(Map args) { - def Map options = [:] - options.args = args.args ?: '' - options.args2 = args.args2 ?: '' - options.args3 = args.args3 ?: '' - options.publish_by_meta = args.publish_by_meta ?: [] - options.publish_dir = args.publish_dir ?: '' - options.publish_files = args.publish_files - options.suffix = args.suffix ?: '' - return options -} - -// -// Tidy up and join elements of a list to return a path string -// -def getPathFromList(path_list) { - def paths = path_list.findAll { item -> !item?.trim().isEmpty() } // Remove empty entries - paths = paths.collect { it.trim().replaceAll("^[/]+|[/]+\$", "") } // Trim whitespace and trailing slashes - return paths.join('/') -} - -// -// Function to save/publish module results -// -def saveFiles(Map args) { - if (!args.filename.endsWith('.version.txt')) { - def ioptions = initOptions(args.options) - def path_list = [ ioptions.publish_dir ?: args.publish_dir ] - if (ioptions.publish_by_meta) { - def key_list = ioptions.publish_by_meta instanceof List ? ioptions.publish_by_meta : args.publish_by_meta - for (key in key_list) { - if (args.meta && key instanceof String) { - def path = key - if (args.meta.containsKey(key)) { - path = args.meta[key] instanceof Boolean ? "${key}_${args.meta[key]}".toString() : args.meta[key] - } - path = path instanceof String ? path : '' - path_list.add(path) - } - } - } - if (ioptions.publish_files instanceof Map) { - for (ext in ioptions.publish_files) { - if (args.filename.endsWith(ext.key)) { - def ext_list = path_list.collect() - ext_list.add(ext.value) - return "${getPathFromList(ext_list)}/$args.filename" - } - } - } else if (ioptions.publish_files == null) { - return "${getPathFromList(path_list)}/$args.filename" - } - } -} diff --git a/modules/nf-core/modules/multiqc/main.nf b/modules/nf-core/modules/multiqc/main.nf index da780800..3dceb162 100644 --- a/modules/nf-core/modules/multiqc/main.nf +++ b/modules/nf-core/modules/multiqc/main.nf @@ -1,21 +1,10 @@ -// Import generic module functions -include { initOptions; saveFiles; getSoftwareName } from './functions' - -params.options = [:] -options = initOptions(params.options) - process MULTIQC { label 'process_medium' - publishDir "${params.outdir}", - mode: params.publish_dir_mode, - saveAs: { filename -> saveFiles(filename:filename, options:params.options, publish_dir:getSoftwareName(task.process), meta:[:], publish_by_meta:[]) } - conda (params.enable_conda ? "bioconda::multiqc=1.10.1" : null) - if (workflow.containerEngine == 'singularity' && !params.singularity_pull_docker_container) { - container "https://depot.galaxyproject.org/singularity/multiqc:1.10.1--py_0" - } else { - container "quay.io/biocontainers/multiqc:1.10.1--py_0" - } + conda (params.enable_conda ? 'bioconda::multiqc=1.11' : null) + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/multiqc:1.11--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.11--pyhdfd78af_0' }" input: path multiqc_files @@ -24,12 +13,16 @@ process MULTIQC { path "*multiqc_report.html", emit: report path "*_data" , emit: data path "*_plots" , optional:true, emit: plots - path "*.version.txt" , emit: version + path "versions.yml" , emit: versions script: - def software = getSoftwareName(task.process) + def args = task.ext.args ?: '' """ - multiqc -f $options.args . - multiqc --version | sed -e "s/multiqc, version //g" > ${software}.version.txt + multiqc -f $args . + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) + END_VERSIONS """ } diff --git a/modules/nf-core/modules/multiqc/meta.yml b/modules/nf-core/modules/multiqc/meta.yml index 532a8bb1..63c75a45 100644 --- a/modules/nf-core/modules/multiqc/meta.yml +++ b/modules/nf-core/modules/multiqc/meta.yml @@ -11,6 +11,7 @@ tools: It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ + licence: ['GPL-3.0-or-later'] input: - multiqc_files: type: file @@ -29,10 +30,10 @@ output: type: file description: Plots created by MultiQC pattern: "*_data" - - version: + - versions: type: file - description: File containing software version - pattern: "*.{version.txt}" + description: File containing software versions + pattern: "versions.yml" authors: - "@abhi18av" - "@bunop" diff --git a/nextflow.config b/nextflow.config index 4b9fa9c3..ffb124e2 100644 --- a/nextflow.config +++ b/nextflow.config @@ -26,7 +26,6 @@ params { // Boilerplate options outdir = './results' tracedir = "${params.outdir}/pipeline_info" - publish_dir_mode = 'copy' email = null email_on_fail = null plaintext_email = false @@ -34,14 +33,12 @@ params { help = false validate_params = true show_hidden_params = false - schema_ignore_params = 'genomes,modules' + schema_ignore_params = 'genomes' enable_conda = false - singularity_pull_docker_container = false // Config options custom_config_version = 'master' custom_config_base = "https://raw.githubusercontent.com/nf-core/configs/${params.custom_config_version}" - hostnames = [:] config_profile_description = null config_profile_contact = null config_profile_url = null @@ -58,9 +55,6 @@ params { // Load base.config by default for all pipelines includeConfig 'conf/base.config' -// Load modules.config for DSL2 module specific options -includeConfig 'conf/modules.config' - // Load nf-core custom profiles from different Institutions try { includeConfig "${params.custom_config_base}/nfcore_custom.config" @@ -68,13 +62,6 @@ try { System.err.println("WARNING: Could not load nf-core/config profiles: ${params.custom_config_base}/nfcore_custom.config") } -// Load igenomes.config if required -if (!params.igenomes_ignore) { - includeConfig 'conf/igenomes.config' -} else { - params.genomes = [:] -} - profiles { debug { process.beforeScript = 'echo $HOSTNAME' } conda { @@ -126,11 +113,22 @@ profiles { test_full { includeConfig 'conf/test_full.config' } } +// Load igenomes.config if required +if (!params.igenomes_ignore) { + includeConfig 'conf/igenomes.config' +} else { + params.genomes = [:] +} + // Export these variables to prevent local Python/R libraries from conflicting with those in the container +// The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. +// See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. + env { PYTHONNOUSERSITE = 1 R_PROFILE_USER = "/.Rprofile" R_ENVIRON_USER = "/.Renviron" + JULIA_DEPOT_PATH = "/usr/local/share/julia" } // Capture exit codes from upstream processes when piping @@ -160,10 +158,13 @@ manifest { homePage = 'https://github.com/nf-core/fetchngs' description = 'Pipeline to fetch metadata and raw FastQ files from public databases' mainScript = 'main.nf' - nextflowVersion = '!>=21.04.0' - version = '1.2dev' + nextflowVersion = '!>=21.10.3' + version = '1.6dev' } +// Load modules.config for DSL2 module specific options +includeConfig 'conf/modules.config' + // Function to ensure that resource requirements don't go beyond // a maximum limit def check_max(obj, type) { diff --git a/nextflow_schema.json b/nextflow_schema.json index dc128f4f..ddfe8eb1 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -104,12 +104,6 @@ "help_text": "If you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter.", "fa_icon": "fas fa-users-cog" }, - "hostnames": { - "type": "string", - "description": "Institutional configs hostname.", - "hidden": true, - "fa_icon": "fas fa-users-cog" - }, "config_profile_name": { "type": "string", "description": "Institutional config name.", @@ -184,22 +178,6 @@ "fa_icon": "fas fa-question-circle", "hidden": true }, - "publish_dir_mode": { - "type": "string", - "default": "copy", - "description": "Method used to save pipeline results to output directory.", - "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", - "fa_icon": "fas fa-copy", - "enum": [ - "symlink", - "rellink", - "link", - "copy", - "copyNoFollow", - "move" - ], - "hidden": true - }, "email_on_fail": { "type": "string", "description": "Email address for completion summary, only when pipeline fails.", @@ -260,13 +238,6 @@ "description": "Run this workflow with Conda. You can also use '-profile conda' instead of providing this parameter.", "hidden": true, "fa_icon": "fas fa-bacon" - }, - "singularity_pull_docker_container": { - "type": "boolean", - "description": "Instead of directly downloading Singularity images for use with Singularity, force the workflow to pull and convert Docker containers instead.", - "hidden": true, - "fa_icon": "fas fa-toolbox", - "help_text": "This may be useful for example if you are unable to directly pull Singularity containers to run the pipeline due to http/https proxy issues." } } } diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf index b664bc8c..cddcbb3c 100644 --- a/subworkflows/local/input_check.nf +++ b/subworkflows/local/input_check.nf @@ -2,9 +2,7 @@ // Check input samplesheet and get read channels // -params.options = [:] - -include { SAMPLESHEET_CHECK } from '../../modules/local/samplesheet_check' addParams( options: params.options ) +include { SAMPLESHEET_CHECK } from '../../modules/local/samplesheet_check' workflow INPUT_CHECK { take: @@ -12,12 +10,14 @@ workflow INPUT_CHECK { main: SAMPLESHEET_CHECK ( samplesheet ) + .csv .splitCsv ( header:true, sep:',' ) .map { create_fastq_channels(it) } .set { reads } emit: - reads // channel: [ val(meta), [ reads ] ] + reads // channel: [ val(meta), [ reads ] ] + versions = SAMPLESHEET_CHECK.out.versions // channel: [ versions.yml ] } // Function to get list of [ meta, [ fastq_1, fastq_2 ] ] diff --git a/workflows/fetchngs.nf b/workflows/fetchngs.nf index 34aa8c1f..d85c5d75 100644 --- a/workflows/fetchngs.nf +++ b/workflows/fetchngs.nf @@ -32,18 +32,10 @@ ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multi ======================================================================================== */ -// Don't overwrite global params.modules, create a copy instead and use that within the main script. -def modules = params.modules.clone() - -// -// MODULE: Local to the pipeline -// -include { GET_SOFTWARE_VERSIONS } from '../modules/local/get_software_versions' addParams( options: [publish_files : ['tsv':'']] ) - // // SUBWORKFLOW: Consisting of a mix of local and nf-core/modules // -include { INPUT_CHECK } from '../subworkflows/local/input_check' addParams( options: [:] ) +include { INPUT_CHECK } from '../subworkflows/local/input_check' /* ======================================================================================== @@ -51,14 +43,12 @@ include { INPUT_CHECK } from '../subworkflows/local/input_check' addParams( opti ======================================================================================== */ -def multiqc_options = modules['multiqc'] -multiqc_options.args += params.multiqc_title ? Utils.joinModuleArgs(["--title \"$params.multiqc_title\""]) : '' - // // MODULE: Installed directly from nf-core/modules // -include { FASTQC } from '../modules/nf-core/modules/fastqc/main' addParams( options: modules['fastqc'] ) -include { MULTIQC } from '../modules/nf-core/modules/multiqc/main' addParams( options: multiqc_options ) +include { FASTQC } from '../modules/nf-core/modules/fastqc/main' +include { MULTIQC } from '../modules/nf-core/modules/multiqc/main' +include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/modules/custom/dumpsoftwareversions/main' /* ======================================================================================== @@ -71,7 +61,7 @@ def multiqc_report = [] workflow FETCHNGS { - ch_software_versions = Channel.empty() + ch_versions = Channel.empty() // // SUBWORKFLOW: Read in samplesheet, validate and stage input files @@ -79,6 +69,7 @@ workflow FETCHNGS { INPUT_CHECK ( ch_input ) + ch_versions = ch_versions.mix(INPUT_CHECK.out.versions) // // MODULE: Run FastQC @@ -86,21 +77,10 @@ workflow FETCHNGS { FASTQC ( INPUT_CHECK.out.reads ) - ch_software_versions = ch_software_versions.mix(FASTQC.out.version.first().ifEmpty(null)) + ch_versions = ch_versions.mix(FASTQC.out.versions.first()) - // - // MODULE: Pipeline reporting - // - ch_software_versions - .map { it -> if (it) [ it.baseName, it ] } - .groupTuple() - .map { it[1][0] } - .flatten() - .collect() - .set { ch_software_versions } - - GET_SOFTWARE_VERSIONS ( - ch_software_versions.map { it }.collect() + CUSTOM_DUMPSOFTWAREVERSIONS ( + ch_versions.unique().collectFile(name: 'collated_versions.yml') ) // @@ -113,14 +93,14 @@ workflow FETCHNGS { ch_multiqc_files = ch_multiqc_files.mix(Channel.from(ch_multiqc_config)) ch_multiqc_files = ch_multiqc_files.mix(ch_multiqc_custom_config.collect().ifEmpty([])) ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_files = ch_multiqc_files.mix(GET_SOFTWARE_VERSIONS.out.yaml.collect()) + ch_multiqc_files = ch_multiqc_files.mix(CUSTOM_DUMPSOFTWAREVERSIONS.out.mqc_yml.collect()) ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}.ifEmpty([])) MULTIQC ( ch_multiqc_files.collect() ) - multiqc_report = MULTIQC.out.report.toList() - ch_software_versions = ch_software_versions.mix(MULTIQC.out.version.ifEmpty(null)) + multiqc_report = MULTIQC.out.report.toList() + ch_versions = ch_versions.mix(MULTIQC.out.versions) } /* From 4a2e3c435eaf6cd4eb5cbc454f9fc6ddaa864f48 Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Mon, 27 Dec 2021 17:56:58 +0000 Subject: [PATCH 04/26] Replace dodgy logo --- docs/images/nf-core-fetchngs_logo_dark.png | Bin 288 -> 75668 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/nf-core-fetchngs_logo_dark.png b/docs/images/nf-core-fetchngs_logo_dark.png index dee3db82069b61e9a5380d940355f47ff565057c..e3452bf155e8506e48106bd0ac5f7056141c1511 100644 GIT binary patch literal 75668 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%0D6Aha9ZZvy3Owj0R@{kHIA1_W(q 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 BPEP;; literal 288 zcmaKn!EVAZ5Jd0(iYfQTPzk9AD^kHmL`q9kxd)CWS%D=(itV(`-**E&_qa1VJ8y-0 z(7UzWHwIh#TBG?`)zuoaM=2{~H&SY=@6J;(m(sk=N};CBQfXf{12_ Date: Tue, 15 Mar 2022 21:01:08 +0000 Subject: [PATCH 05/26] Remove igenomes.config remnants from last template sync --- nextflow.config | 7 ------- 1 file changed, 7 deletions(-) diff --git a/nextflow.config b/nextflow.config index bcc5e436..6501496b 100644 --- a/nextflow.config +++ b/nextflow.config @@ -110,13 +110,6 @@ profiles { test_full { includeConfig 'conf/test_full.config' } } -// Load igenomes.config if required -if (!params.igenomes_ignore) { - includeConfig 'conf/igenomes.config' -} else { - params.genomes = [:] -} - // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. From d6d7d70e2ba4eeada6c14b16c13e97aad5745f35 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Tue, 15 Mar 2022 22:20:00 +0000 Subject: [PATCH 06/26] Template update for nf-core/tools version 2.3 --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 - .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/awsfulltest.yml | 6 +- .github/workflows/awstest.yml | 6 +- .github/workflows/ci.yml | 4 +- .github/workflows/linting.yml | 28 +- .gitpod.yml | 14 + .nf-core.yml | 1 + .yamllint.yml | 6 + README.md | 6 +- bin/check_samplesheet.py | 346 ++++++++++++++------- conf/base.config | 4 +- conf/igenomes.config | 80 ++--- conf/modules.config | 18 +- conf/test.config | 6 +- conf/test_full.config | 6 +- docs/images/nf-core-fetchngs_logo_dark.png | Bin 288 -> 75668 bytes docs/usage.md | 21 +- lib/NfcoreSchema.groovy | 4 +- lib/Utils.groovy | 4 +- lib/WorkflowFetchngs.groovy | 4 +- main.nf | 24 +- nextflow.config | 18 +- nextflow_schema.json | 23 +- subworkflows/local/input_check.nf | 18 +- workflows/fetchngs.nf | 28 +- 26 files changed, 419 insertions(+), 259 deletions(-) create mode 100644 .gitpod.yml create mode 100644 .nf-core.yml create mode 100644 .yamllint.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 975e8d0e..2fde493e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,4 +1,3 @@ - name: Bug report description: Report something that is broken or incorrect labels: bug diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 107d79d0..494a0f4c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -19,7 +19,7 @@ Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/fetc - [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/fetchngs/tree/master/.github/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/fetchngs _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 (`nextflow run . -profile test,docker`). +- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker` --outdir `). - [ ] Usage Documentation in `docs/usage.md` is updated. - [ ] Output Documentation in `docs/output.md` is updated. - [ ] `CHANGELOG.md` is updated. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 49a4e906..2819cc09 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: nf-core/tower-action@v2 + uses: nf-core/tower-action@v3 # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters @@ -31,4 +31,6 @@ jobs: "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/fetchngs/results-${{ github.sha }}" } profiles: test_full,aws_tower - pre_run_script: 'export NXF_VER=21.10.3' + nextflow_config: | + process.errorStrategy = 'retry' + process.maxRetries = 3 diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 1574928d..94c7c4b7 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Launch workflow via tower - uses: nf-core/tower-action@v2 + uses: nf-core/tower-action@v3 with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} @@ -25,4 +25,6 @@ jobs: "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/fetchngs/results-test-${{ github.sha }}" } profiles: test,aws_tower - pre_run_script: 'export NXF_VER=21.10.3' + nextflow_config: | + process.errorStrategy = 'retry' + process.maxRetries = 3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c485ed9..e66d10a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ env: jobs: test: - name: Run workflow tests + name: Run pipeline with test data # 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/fetchngs') }} runs-on: ubuntu-latest @@ -47,4 +47,4 @@ jobs: # For example: adding multiple test runs with different parameters # Remember that you can parallelise this by using strategy.matrix run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,docker + nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 3b448773..fda934c0 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -12,9 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - with: - node-version: '10' + - uses: actions/setup-node@v2 - name: Install markdownlint run: npm install -g markdownlint-cli - name: Run Markdownlint @@ -51,9 +49,7 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - with: - node-version: '10' + - uses: actions/setup-node@v2 - name: Install editorconfig-checker run: npm install -g editorconfig-checker @@ -64,14 +60,13 @@ jobs: YAML: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 + - name: Checkout + uses: actions/checkout@master + - name: 'Yamllint' + uses: karancode/yamllint-github-action@master with: - node-version: '10' - - name: Install yaml-lint - run: npm install -g yaml-lint - - name: Run yaml-lint - run: yamllint $(find ${GITHUB_WORKSPACE} -type f -name "*.yml" -o -name "*.yaml") + yamllint_file_or_dir: '.' + yamllint_config_filepath: '.yamllint.yml' # If the above check failed, post a comment on the PR explaining the failure - name: Post PR comment @@ -84,10 +79,11 @@ jobs: To keep the code consistent with lots of contributors, we run automated code consistency checks. To fix this CI test, please run: - * Install `yaml-lint` - * [Install `npm`](https://www.npmjs.com/get-npm) then [install `yaml-lint`](https://www.npmjs.com/package/yaml-lint) (`npm install -g yaml-lint`) + * Install `yamllint` + * Install `yamllint` following [this](https://yamllint.readthedocs.io/en/stable/quickstart.html#installing-yamllint) + instructions or alternative install it in your [conda environment](https://anaconda.org/conda-forge/yamllint) * Fix the markdown errors - * Run the test locally: `yamllint $(find . -type f -name "*.yml" -o -name "*.yaml")` + * Run the test locally: `yamllint $(find . -type f -name "*.yml" -o -name "*.yaml") -c ./.yamllint.yml` * Fix any reported errors in your YAML files Once you push these changes the test should pass, and you can hide this comment :+1: diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..b7d4cee1 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,14 @@ +image: nfcore/gitpod:latest + +vscode: + extensions: # based on nf-core.nf-core-extensionpack + - codezombiech.gitignore # Language support for .gitignore files + # - cssho.vscode-svgviewer # SVG viewer + - davidanson.vscode-markdownlint # Markdown/CommonMark linting and style checking for Visual Studio Code + - eamodio.gitlens # Quickly glimpse into whom, why, and when a line or code block was changed + - 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 + - oderwat.indent-rainbow # Highlight indentation level + - streetsidesoftware.code-spell-checker # Spelling checker for source code diff --git a/.nf-core.yml b/.nf-core.yml new file mode 100644 index 00000000..3805dc81 --- /dev/null +++ b/.nf-core.yml @@ -0,0 +1 @@ +repository_type: pipeline diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 00000000..d466deec --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,6 @@ +extends: default + +rules: + document-start: disable + line-length: disable + truthy: disable diff --git a/README.md b/README.md index 4f9dce56..48675271 100644 --- a/README.md +++ b/README.md @@ -40,14 +40,14 @@ On release, automated continuous integration tests run the pipeline on a full-si 3. Download the pipeline and test it on a minimal dataset with a single command: ```console - nextflow run nf-core/fetchngs -profile test,YOURPROFILE + nextflow run nf-core/fetchngs -profile test,YOURPROFILE --outdir ``` Note that some form of configuration will be needed so that Nextflow knows how to fetch the required software. This is usually done in the form of a config profile (`YOURPROFILE` in the example command above). You can chain multiple config profiles in a comma-separated string. > * The pipeline comes with config profiles called `docker`, `singularity`, `podman`, `shifter`, `charliecloud` and `conda` which instruct the pipeline to use the named tool for software management. For example, `-profile test,docker`. > * Please check [nf-core/configs](https://github.com/nf-core/configs#documentation) to see if a custom config file to run nf-core pipelines already exists for your Institute. If so, you can simply use `-profile ` in your command. This will enable either `docker` or `singularity` and set the appropriate execution settings for your local compute environment. - > * If you are using `singularity` and are persistently observing issues downloading Singularity images directly due to timeout or network issues, then you can use the `--singularity_pull_docker_container` parameter to pull and convert the Docker image instead. Alternatively, you can use the [`nf-core download`](https://nf-co.re/tools/#downloading-pipelines-for-offline-use) command to download images first, before running the pipeline. Setting the [`NXF_SINGULARITY_CACHEDIR` or `singularity.cacheDir`](https://www.nextflow.io/docs/latest/singularity.html?#singularity-docker-hub) Nextflow options enables you to store and re-use the images from a central location for future pipeline runs. + > * If you are using `singularity`, please use the [`nf-core download`](https://nf-co.re/tools/#downloading-pipelines-for-offline-use) command to download images first, before running the pipeline. Setting the [`NXF_SINGULARITY_CACHEDIR` or `singularity.cacheDir`](https://www.nextflow.io/docs/latest/singularity.html?#singularity-docker-hub) Nextflow options enables you to store and re-use the images from a central location for future pipeline runs. > * If you are using `conda`, it is highly recommended to use the [`NXF_CONDA_CACHEDIR` or `conda.cacheDir`](https://www.nextflow.io/docs/latest/conda.html) settings to store the environments in a central location for future pipeline runs. 4. Start running your own analysis! @@ -55,7 +55,7 @@ On release, automated continuous integration tests run the pipeline on a full-si ```console - nextflow run nf-core/fetchngs -profile --input samplesheet.csv --genome GRCh37 + nextflow run nf-core/fetchngs --input samplesheet.csv --outdir --genome GRCh37 -profile ``` ## Documentation diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index b71b9855..5473b624 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -1,145 +1,249 @@ #!/usr/bin/env python -# TODO nf-core: Update the script to check the samplesheet -# This script is based on the example at: https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv -import os -import sys -import errno +"""Provide a command line tool to validate and transform tabular samplesheets.""" + + import argparse +import csv +import logging +import sys +from collections import Counter +from pathlib import Path -def parse_args(args=None): - Description = "Reformat nf-core/fetchngs samplesheet file and check its contents." - Epilog = "Example usage: python check_samplesheet.py " +logger = logging.getLogger() - parser = argparse.ArgumentParser(description=Description, epilog=Epilog) - parser.add_argument("FILE_IN", help="Input samplesheet file.") - parser.add_argument("FILE_OUT", help="Output file.") - return parser.parse_args(args) +class RowChecker: + """ + Define a service that can validate and transform each given row. -def make_dir(path): - if len(path) > 0: - try: - os.makedirs(path) - except OSError as exception: - if exception.errno != errno.EEXIST: - raise exception + Attributes: + modified (list): A list of dicts, where each dict corresponds to a previously + validated and transformed row. The order of rows is maintained. + """ -def print_error(error, context="Line", context_str=""): - error_str = "ERROR: Please check samplesheet -> {}".format(error) - if context != "" and context_str != "": - error_str = "ERROR: Please check samplesheet -> {}\n{}: '{}'".format( - error, context.strip(), context_str.strip() + VALID_FORMATS = ( + ".fq.gz", + ".fastq.gz", + ) + + def __init__( + self, + sample_col="sample", + first_col="fastq_1", + second_col="fastq_2", + single_col="single_end", + **kwargs, + ): + """ + Initialize the row checker with the expected column names. + + Args: + sample_col (str): The name of the column that contains the sample name + (default "sample"). + first_col (str): The name of the column that contains the first (or only) + FASTQ file path (default "fastq_1"). + second_col (str): The name of the column that contains the second (if any) + FASTQ file path (default "fastq_2"). + single_col (str): The name of the new column that will be inserted and + records whether the sample contains single- or paired-end sequencing + reads (default "single_end"). + + """ + super().__init__(**kwargs) + self._sample_col = sample_col + self._first_col = first_col + self._second_col = second_col + self._single_col = single_col + self._seen = set() + self.modified = [] + + def validate_and_transform(self, row): + """ + Perform all validations on the given row and insert the read pairing status. + + Args: + row (dict): A mapping from column headers (keys) to elements of that row + (values). + + """ + self._validate_sample(row) + self._validate_first(row) + self._validate_second(row) + self._validate_pair(row) + self._seen.add((row[self._sample_col], row[self._first_col])) + self.modified.append(row) + + def _validate_sample(self, row): + """Assert that the sample name exists and convert spaces to underscores.""" + assert len(row[self._sample_col]) > 0, "Sample input is required." + # Sanitize samples slightly. + row[self._sample_col] = row[self._sample_col].replace(" ", "_") + + def _validate_first(self, row): + """Assert that the first FASTQ entry is non-empty and has the right format.""" + assert len(row[self._first_col]) > 0, "At least the first FASTQ file is required." + self._validate_fastq_format(row[self._first_col]) + + def _validate_second(self, row): + """Assert that the second FASTQ entry has the right format if it exists.""" + if len(row[self._second_col]) > 0: + self._validate_fastq_format(row[self._second_col]) + + def _validate_pair(self, row): + """Assert that read pairs have the same file extension. Report pair status.""" + if row[self._first_col] and row[self._second_col]: + row[self._single_col] = False + assert ( + Path(row[self._first_col]).suffixes == Path(row[self._second_col]).suffixes + ), "FASTQ pairs must have the same file extensions." + else: + row[self._single_col] = True + + def _validate_fastq_format(self, filename): + """Assert that a given filename has one of the expected FASTQ extensions.""" + assert any(filename.endswith(extension) for extension in self.VALID_FORMATS), ( + f"The FASTQ file has an unrecognized extension: {filename}\n" + f"It should be one of: {', '.join(self.VALID_FORMATS)}" ) - print(error_str) - sys.exit(1) + def validate_unique_samples(self): + """ + Assert that the combination of sample name and FASTQ filename is unique. + + In addition to the validation, also rename the sample if more than one sample, + FASTQ file combination exists. + + """ + assert len(self._seen) == len(self.modified), "The pair of sample name and FASTQ must be unique." + if len({pair[0] for pair in self._seen}) < len(self._seen): + counts = Counter(pair[0] for pair in self._seen) + seen = Counter() + for row in self.modified: + sample = row[self._sample_col] + seen[sample] += 1 + if counts[sample] > 1: + row[self._sample_col] = f"{sample}_T{seen[sample]}" + + +def sniff_format(handle): + """ + Detect the tabular format. + + Args: + handle (text file): A handle to a `text file`_ object. The read position is + expected to be at the beginning (index 0). + + Returns: + csv.Dialect: The detected tabular format. + + .. _text file: + https://docs.python.org/3/glossary.html#term-text-file -# TODO nf-core: Update the check_samplesheet function -def check_samplesheet(file_in, file_out): """ - This function checks that the samplesheet follows the following structure: + peek = handle.read(2048) + sniffer = csv.Sniffer() + if not sniffer.has_header(peek): + logger.critical(f"The given sample sheet does not appear to contain a header.") + sys.exit(1) + dialect = sniffer.sniff(peek) + handle.seek(0) + return dialect - sample,fastq_1,fastq_2 - SAMPLE_PE,SAMPLE_PE_RUN1_1.fastq.gz,SAMPLE_PE_RUN1_2.fastq.gz - SAMPLE_PE,SAMPLE_PE_RUN2_1.fastq.gz,SAMPLE_PE_RUN2_2.fastq.gz - SAMPLE_SE,SAMPLE_SE_RUN1_1.fastq.gz, - For an example see: - https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv +def check_samplesheet(file_in, file_out): """ + Check that the tabular samplesheet has the structure expected by nf-core pipelines. - sample_mapping_dict = {} - with open(file_in, "r") as fin: + Validate the general shape of the table, expected columns, and each row. Also add + an additional column which records whether one or two FASTQ reads were found. - ## Check header - MIN_COLS = 2 - # TODO nf-core: Update the column names for the input samplesheet - HEADER = ["sample", "fastq_1", "fastq_2"] - header = [x.strip('"') for x in fin.readline().strip().split(",")] - if header[: len(HEADER)] != HEADER: - print("ERROR: Please check samplesheet header -> {} != {}".format(",".join(header), ",".join(HEADER))) - sys.exit(1) + Args: + file_in (pathlib.Path): The given tabular samplesheet. The format can be either + CSV, TSV, or any other format automatically recognized by ``csv.Sniffer``. + file_out (pathlib.Path): Where the validated and transformed samplesheet should + be created; always in CSV format. - ## Check sample entries - for line in fin: - lspl = [x.strip().strip('"') for x in line.strip().split(",")] - - # Check valid number of columns per row - if len(lspl) < len(HEADER): - print_error( - "Invalid number of columns (minimum = {})!".format(len(HEADER)), - "Line", - line, - ) - num_cols = len([x for x in lspl if x]) - if num_cols < MIN_COLS: - print_error( - "Invalid number of populated columns (minimum = {})!".format(MIN_COLS), - "Line", - line, - ) - - ## Check sample name entries - sample, fastq_1, fastq_2 = lspl[: len(HEADER)] - sample = sample.replace(" ", "_") - if not sample: - print_error("Sample entry has not been specified!", "Line", line) - - ## Check FastQ file extension - for fastq in [fastq_1, fastq_2]: - if fastq: - if fastq.find(" ") != -1: - print_error("FastQ file contains spaces!", "Line", line) - if not fastq.endswith(".fastq.gz") and not fastq.endswith(".fq.gz"): - print_error( - "FastQ file does not have extension '.fastq.gz' or '.fq.gz'!", - "Line", - line, - ) - - ## Auto-detect paired-end/single-end - sample_info = [] ## [single_end, fastq_1, fastq_2] - if sample and fastq_1 and fastq_2: ## Paired-end short reads - sample_info = ["0", fastq_1, fastq_2] - elif sample and fastq_1 and not fastq_2: ## Single-end short reads - sample_info = ["1", fastq_1, fastq_2] - else: - print_error("Invalid combination of columns provided!", "Line", line) - - ## Create sample mapping dictionary = { sample: [ single_end, fastq_1, fastq_2 ] } - if sample not in sample_mapping_dict: - sample_mapping_dict[sample] = [sample_info] - else: - if sample_info in sample_mapping_dict[sample]: - print_error("Samplesheet contains duplicate rows!", "Line", line) - else: - sample_mapping_dict[sample].append(sample_info) - - ## Write validated samplesheet with appropriate columns - if len(sample_mapping_dict) > 0: - out_dir = os.path.dirname(file_out) - make_dir(out_dir) - with open(file_out, "w") as fout: - fout.write(",".join(["sample", "single_end", "fastq_1", "fastq_2"]) + "\n") - for sample in sorted(sample_mapping_dict.keys()): - - ## Check that multiple runs of the same sample are of the same datatype - if not all(x[0] == sample_mapping_dict[sample][0][0] for x in sample_mapping_dict[sample]): - print_error("Multiple runs of a sample must be of the same datatype!", "Sample: {}".format(sample)) - - for idx, val in enumerate(sample_mapping_dict[sample]): - fout.write(",".join(["{}_T{}".format(sample, idx + 1)] + val) + "\n") - else: - print_error("No entries to process!", "Samplesheet: {}".format(file_in)) - - -def main(args=None): - args = parse_args(args) - check_samplesheet(args.FILE_IN, args.FILE_OUT) + Example: + This function checks that the samplesheet follows the following structure, + see also the `viral recon samplesheet`_:: + + sample,fastq_1,fastq_2 + SAMPLE_PE,SAMPLE_PE_RUN1_1.fastq.gz,SAMPLE_PE_RUN1_2.fastq.gz + SAMPLE_PE,SAMPLE_PE_RUN2_1.fastq.gz,SAMPLE_PE_RUN2_2.fastq.gz + SAMPLE_SE,SAMPLE_SE_RUN1_1.fastq.gz, + + .. _viral recon samplesheet: + https://raw.githubusercontent.com/nf-core/test-datasets/viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv + + """ + required_columns = {"sample", "fastq_1", "fastq_2"} + # See https://docs.python.org/3.9/library/csv.html#id3 to read up on `newline=""`. + with file_in.open(newline="") as in_handle: + reader = csv.DictReader(in_handle, dialect=sniff_format(in_handle)) + # Validate the existence of the expected header columns. + if not required_columns.issubset(reader.fieldnames): + logger.critical(f"The sample sheet **must** contain the column headers: {', '.join(required_columns)}.") + sys.exit(1) + # Validate each row. + checker = RowChecker() + for i, row in enumerate(reader): + try: + checker.validate_and_transform(row) + except AssertionError as error: + logger.critical(f"{str(error)} On line {i + 2}.") + sys.exit(1) + checker.validate_unique_samples() + header = list(reader.fieldnames) + header.insert(1, "single_end") + # See https://docs.python.org/3.9/library/csv.html#id3 to read up on `newline=""`. + with file_out.open(mode="w", newline="") as out_handle: + writer = csv.DictWriter(out_handle, header, delimiter=",") + writer.writeheader() + for row in checker.modified: + writer.writerow(row) + + +def parse_args(argv=None): + """Define and immediately parse command line arguments.""" + parser = argparse.ArgumentParser( + description="Validate and transform a tabular samplesheet.", + epilog="Example: python check_samplesheet.py samplesheet.csv samplesheet.valid.csv", + ) + parser.add_argument( + "file_in", + metavar="FILE_IN", + type=Path, + help="Tabular input samplesheet in CSV or TSV format.", + ) + parser.add_argument( + "file_out", + metavar="FILE_OUT", + type=Path, + help="Transformed output samplesheet in CSV format.", + ) + parser.add_argument( + "-l", + "--log-level", + help="The desired log level (default WARNING).", + choices=("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"), + default="WARNING", + ) + return parser.parse_args(argv) + + +def main(argv=None): + """Coordinate argument parsing and program execution.""" + args = parse_args(argv) + logging.basicConfig(level=args.log_level, format="[%(levelname)s] %(message)s") + if not args.file_in.is_file(): + logger.error(f"The given input file {args.file_in} was not found!") + sys.exit(2) + args.file_out.parent.mkdir(parents=True, exist_ok=True) + check_samplesheet(args.file_in, args.file_out) if __name__ == "__main__": diff --git a/conf/base.config b/conf/base.config index f19f9f86..211eb24a 100644 --- a/conf/base.config +++ b/conf/base.config @@ -1,7 +1,7 @@ /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nf-core/fetchngs Nextflow base config file -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A 'blank slate' config file, appropriate for general use on most high performance compute environments. Assumes that all software is installed and available on the PATH. Runs in `local` mode - all jobs will be run on the logged in environment. diff --git a/conf/igenomes.config b/conf/igenomes.config index 855948de..7a1b3ac6 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -1,7 +1,7 @@ /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Nextflow config file for iGenomes paths -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Defines reference genomes using iGenome paths. Can be used by any config that customises the base path using: $params.igenomes_base / --igenomes_base @@ -13,7 +13,7 @@ params { genomes { 'GRCh37' { fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BismarkIndex/" @@ -26,7 +26,7 @@ params { } 'GRCh38' { fasta = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BismarkIndex/" @@ -38,7 +38,7 @@ params { } 'GRCm38' { fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BismarkIndex/" @@ -51,7 +51,7 @@ params { } 'TAIR10' { fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BismarkIndex/" @@ -62,7 +62,7 @@ params { } 'EB2' { fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BismarkIndex/" @@ -72,7 +72,7 @@ params { } 'UMD3.1' { fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BismarkIndex/" @@ -83,7 +83,7 @@ params { } 'WBcel235' { fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BismarkIndex/" @@ -94,7 +94,7 @@ params { } 'CanFam3.1' { fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BismarkIndex/" @@ -105,7 +105,7 @@ params { } 'GRCz10' { fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BismarkIndex/" @@ -115,7 +115,7 @@ params { } 'BDGP6' { fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BismarkIndex/" @@ -126,7 +126,7 @@ params { } 'EquCab2' { fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BismarkIndex/" @@ -137,7 +137,7 @@ params { } 'EB1' { fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BismarkIndex/" @@ -147,7 +147,7 @@ params { } 'Galgal4' { fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BismarkIndex/" @@ -157,7 +157,7 @@ params { } 'Gm01' { fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BismarkIndex/" @@ -167,7 +167,7 @@ params { } 'Mmul_1' { fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BismarkIndex/" @@ -178,7 +178,7 @@ params { } 'IRGSP-1.0' { fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BismarkIndex/" @@ -188,7 +188,7 @@ params { } 'CHIMP2.1.4' { fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BismarkIndex/" @@ -199,7 +199,7 @@ params { } 'Rnor_5.0' { fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BismarkIndex/" @@ -209,7 +209,7 @@ params { } 'Rnor_6.0' { fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BismarkIndex/" @@ -219,7 +219,7 @@ params { } 'R64-1-1' { fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BismarkIndex/" @@ -230,7 +230,7 @@ params { } 'EF2' { fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BismarkIndex/" @@ -242,7 +242,7 @@ params { } 'Sbi1' { fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BismarkIndex/" @@ -252,7 +252,7 @@ params { } 'Sscrofa10.2' { fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BismarkIndex/" @@ -263,7 +263,7 @@ params { } 'AGPv3' { fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BismarkIndex/" @@ -273,7 +273,7 @@ params { } 'hg38' { fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BismarkIndex/" @@ -285,7 +285,7 @@ params { } 'hg19' { fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BismarkIndex/" @@ -298,7 +298,7 @@ params { } 'mm10' { fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BismarkIndex/" @@ -311,7 +311,7 @@ params { } 'bosTau8' { fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BismarkIndex/" @@ -321,7 +321,7 @@ params { } 'ce10' { fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BismarkIndex/" @@ -333,7 +333,7 @@ params { } 'canFam3' { fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BismarkIndex/" @@ -344,7 +344,7 @@ params { } 'danRer10' { fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BismarkIndex/" @@ -355,7 +355,7 @@ params { } 'dm6' { fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BismarkIndex/" @@ -366,7 +366,7 @@ params { } 'equCab2' { fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BismarkIndex/" @@ -377,7 +377,7 @@ params { } 'galGal4' { fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BismarkIndex/" @@ -388,7 +388,7 @@ params { } 'panTro4' { fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BismarkIndex/" @@ -399,7 +399,7 @@ params { } 'rn6' { fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BismarkIndex/" @@ -409,7 +409,7 @@ params { } 'sacCer3' { fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BismarkIndex/" @@ -419,7 +419,7 @@ params { } 'susScr3' { fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/genome.fa" + bwa = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/version0.6.0/" bowtie2 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/Bowtie2Index/" star = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/STARIndex/" bismark = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BismarkIndex/" diff --git a/conf/modules.config b/conf/modules.config index a0506a4d..da58a5d8 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -1,12 +1,12 @@ /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Config file for defining DSL2 per module options and publishing paths -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Available keys to override module options: - ext.args = Additional arguments appended to command in module. - ext.args2 = Second set of arguments appended to command in module (multi-tool modules). - ext.args3 = Third set of arguments appended to command in module (multi-tool modules). - ext.prefix = File name prefix for output files. + ext.args = Additional arguments appended to command in module. + ext.args2 = Second set of arguments appended to command in module (multi-tool modules). + ext.args3 = Third set of arguments appended to command in module (multi-tool modules). + ext.prefix = File name prefix for output files. ---------------------------------------------------------------------------------------- */ @@ -14,14 +14,14 @@ process { publishDir = [ path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] withName: SAMPLESHEET_CHECK { publishDir = [ path: { "${params.outdir}/pipeline_info" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] } @@ -33,7 +33,7 @@ process { withName: CUSTOM_DUMPSOFTWAREVERSIONS { publishDir = [ path: { "${params.outdir}/pipeline_info" }, - mode: 'copy', + mode: params.publish_dir_mode, pattern: '*_versions.yml' ] } diff --git a/conf/test.config b/conf/test.config index 0fcafcbf..19140958 100644 --- a/conf/test.config +++ b/conf/test.config @@ -1,11 +1,11 @@ /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Nextflow config file for running minimal tests -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Defines input files and everything required to run a fast and simple pipeline test. Use as follows: - nextflow run nf-core/fetchngs -profile test, + nextflow run nf-core/fetchngs -profile test, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/conf/test_full.config b/conf/test_full.config index 759deae1..460f61d4 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -1,11 +1,11 @@ /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Nextflow config file for running full-size tests -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Defines input files and everything required to run a full size pipeline test. Use as follows: - nextflow run nf-core/fetchngs -profile test_full, + nextflow run nf-core/fetchngs -profile test_full, --outdir ---------------------------------------------------------------------------------------- */ diff --git a/docs/images/nf-core-fetchngs_logo_dark.png b/docs/images/nf-core-fetchngs_logo_dark.png index dee3db82069b61e9a5380d940355f47ff565057c..e3452bf155e8506e48106bd0ac5f7056141c1511 100644 GIT binary patch literal 75668 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%0D6Aha9ZZvy3Owj0R@{kHIA1_W(q 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 BPEP;; literal 288 zcmaKn!EVAZ5Jd0(iYfQTPzk9AD^kHmL`q9kxd)CWS%D=(itV(`-**E&_qa1VJ8y-0 z(7UzWHwIh#TBG?`)zuoaM=2{~H&SY=@6J;(m(sk=N};CBQfXf{12_ --genome GRCh37 -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -141,11 +141,11 @@ Whilst the default requirements set within the pipeline will hopefully work for For example, if the nf-core/rnaseq pipeline is failing after multiple re-submissions of the `STAR_ALIGN` process due to an exit code of `137` this would indicate that there is an out of memory issue: ```console -[62/149eb0] NOTE: Process `RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) -- Execution is retried (1) -Error executing process > 'RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)' +[62/149eb0] NOTE: Process `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) -- Execution is retried (1) +Error executing process > 'NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)' Caused by: - Process `RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) + Process `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN (WT_REP1)` terminated with an error exit status (137) Command executed: STAR \ @@ -169,17 +169,24 @@ Work dir: Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` ``` -To bypass this error you would need to find exactly which resources are set by the `STAR_ALIGN` process. The quickest way is to search for `process STAR_ALIGN` in the [nf-core/rnaseq Github repo](https://github.com/nf-core/rnaseq/search?q=process+STAR_ALIGN). We have standardised the structure of Nextflow DSL2 pipelines such that all module files will be present in the `modules/` directory and so based on the search results the file we want is `modules/nf-core/software/star/align/main.nf`. If you click on the link to that file you will notice that there is a `label` directive at the top of the module that is set to [`label process_high`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/modules/nf-core/software/star/align/main.nf#L9). The [Nextflow `label`](https://www.nextflow.io/docs/latest/process.html#label) directive allows us to organise workflow processes in separate groups which can be referenced in a configuration file to select and configure subset of processes having similar computing requirements. The default values for the `process_high` label are set in the pipeline's [`base.config`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L33-L37) which in this case is defined as 72GB. Providing you haven't set any other standard nf-core parameters to __cap__ the [maximum resources](https://nf-co.re/usage/configuration#max-resources) used by the pipeline then we can try and bypass the `STAR_ALIGN` process failure by creating a custom config file that sets at least 72GB of memory, in this case increased to 100GB. The custom config below can then be provided to the pipeline via the [`-c`](#-c) parameter as highlighted in previous sections. +To bypass this error you would need to find exactly which resources are set by the `STAR_ALIGN` process. The quickest way is to search for `process STAR_ALIGN` in the [nf-core/rnaseq Github repo](https://github.com/nf-core/rnaseq/search?q=process+STAR_ALIGN). +We have standardised the structure of Nextflow DSL2 pipelines such that all module files will be present in the `modules/` directory and so, based on the search results, the file we want is `modules/nf-core/software/star/align/main.nf`. +If you click on the link to that file you will notice that there is a `label` directive at the top of the module that is set to [`label process_high`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/modules/nf-core/software/star/align/main.nf#L9). +The [Nextflow `label`](https://www.nextflow.io/docs/latest/process.html#label) directive allows us to organise workflow processes in separate groups which can be referenced in a configuration file to select and configure subset of processes having similar computing requirements. +The default values for the `process_high` label are set in the pipeline's [`base.config`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L33-L37) which in this case is defined as 72GB. +Providing you haven't set any other standard nf-core parameters to **cap** the [maximum resources](https://nf-co.re/usage/configuration#max-resources) used by the pipeline then we can try and bypass the `STAR_ALIGN` process failure by creating a custom config file that sets at least 72GB of memory, in this case increased to 100GB. +The custom config below can then be provided to the pipeline via the [`-c`](#-c) parameter as highlighted in previous sections. ```nextflow process { - withName: STAR_ALIGN { + withName: 'NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN' { memory = 100.GB } } ``` -> **NB:** We specify just the process name i.e. `STAR_ALIGN` in the config file and not the full task name string that is printed to screen in the error message or on the terminal whilst the pipeline is running i.e. `RNASEQ:ALIGN_STAR:STAR_ALIGN`. You may get a warning suggesting that the process selector isn't recognised but you can ignore that if the process name has been specified correctly. This is something that needs to be fixed upstream in core Nextflow. +> **NB:** We specify the full process name i.e. `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN` in the config file because this takes priority over the short name (`STAR_ALIGN`) and allows existing configuration using the full process name to be correctly overridden. +> If you get a warning suggesting that the process selector isn't recognised check that the process name has been specified correctly. ### Updating containers diff --git a/lib/NfcoreSchema.groovy b/lib/NfcoreSchema.groovy index 40ab65f2..b3d092f8 100755 --- a/lib/NfcoreSchema.groovy +++ b/lib/NfcoreSchema.groovy @@ -27,7 +27,7 @@ class NfcoreSchema { /* groovylint-disable-next-line UnusedPrivateMethodParameter */ public static void validateParameters(workflow, params, log, schema_filename='nextflow_schema.json') { def has_error = false - //=====================================================================// + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Check for nextflow core params and unexpected params def json = new File(getSchemaPath(workflow, schema_filename=schema_filename)).text def Map schemaParams = (Map) new JsonSlurper().parseText(json).get('definitions') @@ -135,7 +135,7 @@ class NfcoreSchema { } } - //=====================================================================// + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Validate parameters against the schema InputStream input_stream = new File(getSchemaPath(workflow, schema_filename=schema_filename)).newInputStream() JSONObject raw_schema = new JSONObject(new JSONTokener(input_stream)) diff --git a/lib/Utils.groovy b/lib/Utils.groovy index 1b88aec0..28567bd7 100755 --- a/lib/Utils.groovy +++ b/lib/Utils.groovy @@ -29,12 +29,12 @@ class Utils { conda_check_failed |= !(channels.indexOf('bioconda') < channels.indexOf('defaults')) if (conda_check_failed) { - log.warn "=============================================================================\n" + + 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/user/install.html#set-up-channels\n" + " NB: The order of the channels matters!\n" + - "===================================================================================" + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" } } } diff --git a/lib/WorkflowFetchngs.groovy b/lib/WorkflowFetchngs.groovy index bd9b9ebe..a9c0bccf 100755 --- a/lib/WorkflowFetchngs.groovy +++ b/lib/WorkflowFetchngs.groovy @@ -48,11 +48,11 @@ class WorkflowFetchngs { // private static void genomeExistsError(params, log) { if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - log.error "=============================================================================\n" + + log.error "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + " Currently, the available genome keys are:\n" + " ${params.genomes.keySet().join(", ")}\n" + - "===================================================================================" + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" System.exit(1) } } diff --git a/main.nf b/main.nf index ec7491ff..4da08510 100644 --- a/main.nf +++ b/main.nf @@ -1,8 +1,8 @@ #!/usr/bin/env nextflow /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nf-core/fetchngs -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Github : https://github.com/nf-core/fetchngs Website: https://nf-co.re/fetchngs Slack : https://nfcore.slack.com/channels/fetchngs @@ -12,25 +12,25 @@ nextflow.enable.dsl = 2 /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GENOME PARAMETER VALUES -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ params.fasta = WorkflowMain.getGenomeAttribute(params, 'fasta') /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VALIDATE & PRINT PARAMETER SUMMARY -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ WorkflowMain.initialise(workflow, params, log) /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NAMED WORKFLOW FOR PIPELINE -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ include { FETCHNGS } from './workflows/fetchngs' @@ -43,9 +43,9 @@ workflow NFCORE_FETCHNGS { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RUN ALL WORKFLOWS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // @@ -57,7 +57,7 @@ workflow { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ THE END -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/nextflow.config b/nextflow.config index ffb124e2..e004d928 100644 --- a/nextflow.config +++ b/nextflow.config @@ -1,7 +1,7 @@ /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nf-core/fetchngs Nextflow config file -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Default config options for all compute environments ---------------------------------------------------------------------------------------- */ @@ -24,8 +24,9 @@ params { max_multiqc_email_size = '25.MB' // Boilerplate options - outdir = './results' + outdir = null tracedir = "${params.outdir}/pipeline_info" + publish_dir_mode = 'copy' email = null email_on_fail = null plaintext_email = false @@ -62,6 +63,15 @@ try { System.err.println("WARNING: Could not load nf-core/config profiles: ${params.custom_config_base}/nfcore_custom.config") } +// Load nf-core/fetchngs custom profiles from different institutions. +// Warning: Uncomment only if a pipeline-specific instititutional config already exists on nf-core/configs! +// try { +// includeConfig "${params.custom_config_base}/pipeline/fetchngs.config" +// } catch (Exception e) { +// System.err.println("WARNING: Could not load nf-core/config/fetchngs profiles: ${params.custom_config_base}/pipeline/fetchngs.config") +// } + + profiles { debug { process.beforeScript = 'echo $HOSTNAME' } conda { @@ -121,7 +131,7 @@ if (!params.igenomes_ignore) { } // 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. +// 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. env { diff --git a/nextflow_schema.json b/nextflow_schema.json index ddfe8eb1..5d1e5fb6 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -11,7 +11,8 @@ "fa_icon": "fas fa-terminal", "description": "Define where the pipeline should find input data and save output data.", "required": [ - "input" + "input", + "outdir" ], "properties": { "input": { @@ -26,8 +27,8 @@ }, "outdir": { "type": "string", - "description": "Path to the output directory where the results will be saved.", - "default": "./results", + "format": "directory-path", + "description": "The output directory where the results will be saved. You have to use absolute paths to storage on Cloud infrastructure.", "fa_icon": "fas fa-folder-open" }, "email": { @@ -178,6 +179,22 @@ "fa_icon": "fas fa-question-circle", "hidden": true }, + "publish_dir_mode": { + "type": "string", + "default": "copy", + "description": "Method used to save pipeline results to output directory.", + "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", + "fa_icon": "fas fa-copy", + "enum": [ + "symlink", + "rellink", + "link", + "copy", + "copyNoFollow", + "move" + ], + "hidden": true + }, "email_on_fail": { "type": "string", "description": "Email address for completion summary, only when pipeline fails.", diff --git a/subworkflows/local/input_check.nf b/subworkflows/local/input_check.nf index cddcbb3c..0aecf87f 100644 --- a/subworkflows/local/input_check.nf +++ b/subworkflows/local/input_check.nf @@ -12,7 +12,7 @@ workflow INPUT_CHECK { SAMPLESHEET_CHECK ( samplesheet ) .csv .splitCsv ( header:true, sep:',' ) - .map { create_fastq_channels(it) } + .map { create_fastq_channel(it) } .set { reads } emit: @@ -21,22 +21,24 @@ workflow INPUT_CHECK { } // Function to get list of [ meta, [ fastq_1, fastq_2 ] ] -def create_fastq_channels(LinkedHashMap row) { +def create_fastq_channel(LinkedHashMap row) { + // create meta map def meta = [:] - meta.id = row.sample - meta.single_end = row.single_end.toBoolean() + meta.id = row.sample + meta.single_end = row.single_end.toBoolean() - def array = [] + // add path(s) of the fastq file(s) to the meta map + def fastq_meta = [] if (!file(row.fastq_1).exists()) { exit 1, "ERROR: Please check input samplesheet -> Read 1 FastQ file does not exist!\n${row.fastq_1}" } if (meta.single_end) { - array = [ meta, [ file(row.fastq_1) ] ] + fastq_meta = [ meta, [ file(row.fastq_1) ] ] } else { if (!file(row.fastq_2).exists()) { exit 1, "ERROR: Please check input samplesheet -> Read 2 FastQ file does not exist!\n${row.fastq_2}" } - array = [ meta, [ file(row.fastq_1), file(row.fastq_2) ] ] + fastq_meta = [ meta, [ file(row.fastq_1), file(row.fastq_2) ] ] } - return array + return fastq_meta } diff --git a/workflows/fetchngs.nf b/workflows/fetchngs.nf index d85c5d75..af57a592 100644 --- a/workflows/fetchngs.nf +++ b/workflows/fetchngs.nf @@ -1,7 +1,7 @@ /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VALIDATE INPUTS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ def summary_params = NfcoreSchema.paramsSummaryMap(workflow, params) @@ -18,18 +18,18 @@ for (param in checkPathParamList) { if (param) { file(param, checkIfExists: true if (params.input) { ch_input = file(params.input) } else { exit 1, 'Input samplesheet not specified!' } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CONFIG FILES -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ ch_multiqc_config = file("$projectDir/assets/multiqc_config.yaml", checkIfExists: true) ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config) : Channel.empty() /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT LOCAL MODULES/SUBWORKFLOWS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // @@ -38,9 +38,9 @@ ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multi include { INPUT_CHECK } from '../subworkflows/local/input_check' /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT NF-CORE MODULES/SUBWORKFLOWS -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // @@ -51,9 +51,9 @@ include { MULTIQC } from '../modules/nf-core/modules/multiqc include { CUSTOM_DUMPSOFTWAREVERSIONS } from '../modules/nf-core/modules/custom/dumpsoftwareversions/main' /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RUN MAIN WORKFLOW -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ // Info required for completion email and summary @@ -104,9 +104,9 @@ workflow FETCHNGS { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ COMPLETION EMAIL AND SUMMARY -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ workflow.onComplete { @@ -117,7 +117,7 @@ workflow.onComplete { } /* -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ THE END -======================================================================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ From c1b2abc018291e8eca2d1a8415e77a41a1cc8641 Mon Sep 17 00:00:00 2001 From: maxibor Date: Thu, 17 Mar 2022 10:30:09 +0100 Subject: [PATCH 07/26] Add troubleshooting section and FTP alternative docs --- docs/usage.md | 6 ++++++ nextflow_schema.json | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index b21aa80d..6e09c9a7 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -251,3 +251,9 @@ We recommend adding the following line to your environment to limit this (typica ```console NXF_OPTS='-Xms1g -Xmx4g' ``` + +## Troubleshooting + +### `FTP` download is blocked at my workplace/institution, how can I still use *nf-core/fetchngs* ? + +If downloading data with FTP is blocked on your network connection, you may want to use the [`--force_sratools_download`](https://nf-co.re/fetchngs/1.5/parameters#force_sratools_download) flag to force fetchngs download using [sra-tools](https://github.com/ncbi/sra-tools) instead of the ENA FTP. diff --git a/nextflow_schema.json b/nextflow_schema.json index ae439a7b..550b91c8 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -53,7 +53,8 @@ "force_sratools_download": { "type": "boolean", "fa_icon": "fas fa-tools", - "description": "Force download FastQ files via sra-tools instead of via the ENA FTP." + "description": "Force download FastQ files via sra-tools instead of via the ENA FTP.", + "help_text": "If downloading data through FTP is blocked on your network connection, you may want to use this flag to force fetchngs to download using sra-tools instead of the ENA FTP. " }, "skip_fastq_download": { "type": "boolean", From dca46e6ece994b0af66f27a792dce7477cd76178 Mon Sep 17 00:00:00 2001 From: maxibor Date: Thu, 17 Mar 2022 11:52:20 +0100 Subject: [PATCH 08/26] fix linting --- docs/usage.md | 6 +++--- nextflow_schema.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 6e09c9a7..7b59a707 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -174,7 +174,7 @@ Work dir: Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run` ``` -To bypass this error you would need to find exactly which resources are set by the `STAR_ALIGN` process. The quickest way is to search for `process STAR_ALIGN` in the [nf-core/rnaseq Github repo](https://github.com/nf-core/rnaseq/search?q=process+STAR_ALIGN). We have standardised the structure of Nextflow DSL2 pipelines such that all module files will be present in the `modules/` directory and so based on the search results the file we want is `modules/nf-core/software/star/align/main.nf`. If you click on the link to that file you will notice that there is a `label` directive at the top of the module that is set to [`label process_high`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/modules/nf-core/software/star/align/main.nf#L9). The [Nextflow `label`](https://www.nextflow.io/docs/latest/process.html#label) directive allows us to organise workflow processes in separate groups which can be referenced in a configuration file to select and configure subset of processes having similar computing requirements. The default values for the `process_high` label are set in the pipeline's [`base.config`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L33-L37) which in this case is defined as 72GB. Providing you haven't set any other standard nf-core parameters to __cap__ the [maximum resources](https://nf-co.re/usage/configuration#max-resources) used by the pipeline then we can try and bypass the `STAR_ALIGN` process failure by creating a custom config file that sets at least 72GB of memory, in this case increased to 100GB. The custom config below can then be provided to the pipeline via the [`-c`](#-c) parameter as highlighted in previous sections. +To bypass this error you would need to find exactly which resources are set by the `STAR_ALIGN` process. The quickest way is to search for `process STAR_ALIGN` in the [nf-core/rnaseq Github repo](https://github.com/nf-core/rnaseq/search?q=process+STAR_ALIGN). We have standardised the structure of Nextflow DSL2 pipelines such that all module files will be present in the `modules/` directory and so based on the search results the file we want is `modules/nf-core/software/star/align/main.nf`. If you click on the link to that file you will notice that there is a `label` directive at the top of the module that is set to [`label process_high`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/modules/nf-core/software/star/align/main.nf#L9). The [Nextflow `label`](https://www.nextflow.io/docs/latest/process.html#label) directive allows us to organise workflow processes in separate groups which can be referenced in a configuration file to select and configure subset of processes having similar computing requirements. The default values for the `process_high` label are set in the pipeline's [`base.config`](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L33-L37) which in this case is defined as 72GB. Providing you haven't set any other standard nf-core parameters to **cap** the [maximum resources](https://nf-co.re/usage/configuration#max-resources) used by the pipeline then we can try and bypass the `STAR_ALIGN` process failure by creating a custom config file that sets at least 72GB of memory, in this case increased to 100GB. The custom config below can then be provided to the pipeline via the [`-c`](#-c) parameter as highlighted in previous sections. ```nextflow process { @@ -254,6 +254,6 @@ NXF_OPTS='-Xms1g -Xmx4g' ## Troubleshooting -### `FTP` download is blocked at my workplace/institution, how can I still use *nf-core/fetchngs* ? +### `FTP` download is blocked at my workplace/institution, how can I still use _nf-core/fetchngs_ ? -If downloading data with FTP is blocked on your network connection, you may want to use the [`--force_sratools_download`](https://nf-co.re/fetchngs/1.5/parameters#force_sratools_download) flag to force fetchngs download using [sra-tools](https://github.com/ncbi/sra-tools) instead of the ENA FTP. +If downloading data with FTP is blocked on your network connection, you may want to use the [`--force_sratools_download`](https://nf-co.re/fetchngs/1.5/parameters#force_sratools_download) flag to force fetchngs download using [sra-tools](https://github.com/ncbi/sra-tools) instead of the ENA FTP. diff --git a/nextflow_schema.json b/nextflow_schema.json index 550b91c8..57676091 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -53,7 +53,7 @@ "force_sratools_download": { "type": "boolean", "fa_icon": "fas fa-tools", - "description": "Force download FastQ files via sra-tools instead of via the ENA FTP.", + "description": "Force download FASTQ files via sra-tools instead of via the ENA FTP.", "help_text": "If downloading data through FTP is blocked on your network connection, you may want to use this flag to force fetchngs to download using sra-tools instead of the ENA FTP. " }, "skip_fastq_download": { From 17261e3c89d27a55a61d091f4251f79c166130dc Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Wed, 23 Mar 2022 13:48:06 +0000 Subject: [PATCH 09/26] Template update for nf-core/tools version 2.3.1 --- .editorconfig | 5 +- .github/CONTRIBUTING.md | 15 +- .github/ISSUE_TEMPLATE/bug_report.yml | 1 - .github/PULL_REQUEST_TEMPLATE.md | 6 +- .github/workflows/awsfulltest.yml | 1 - .github/workflows/awstest.yml | 2 +- .github/workflows/branch.yml | 5 +- .github/workflows/ci.yml | 12 +- .github/workflows/linting.yml | 85 ++--------- .github/workflows/linting_comment.yml | 3 +- .gitpod.yml | 16 +- .markdownlint.yml | 14 -- .prettierrc.yml | 1 + .yamllint.yml | 6 - CHANGELOG.md | 2 + CITATIONS.md | 27 ++-- README.md | 31 ++-- assets/email_template.html | 142 ++++++++++++------ assets/multiqc_config.yaml | 11 -- assets/multiqc_config.yml | 11 ++ assets/schema_input.json | 5 +- docs/README.md | 8 +- docs/output.md | 28 ++-- docs/usage.md | 109 +++++++------- modules.json | 8 +- .../custom/dumpsoftwareversions/main.nf | 3 + .../custom/dumpsoftwareversions/meta.yml | 2 +- modules/nf-core/modules/fastqc/main.nf | 3 + modules/nf-core/modules/fastqc/meta.yml | 90 +++++------ modules/nf-core/modules/multiqc/main.nf | 9 +- modules/nf-core/modules/multiqc/meta.yml | 66 ++++---- nextflow_schema.json | 14 +- workflows/fetchngs.nf | 2 +- 33 files changed, 361 insertions(+), 382 deletions(-) delete mode 100644 .markdownlint.yml create mode 100644 .prettierrc.yml delete mode 100644 .yamllint.yml delete mode 100644 assets/multiqc_config.yaml create mode 100644 assets/multiqc_config.yml diff --git a/.editorconfig b/.editorconfig index 95549501..b6b31907 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,12 +8,9 @@ trim_trailing_whitespace = true indent_size = 4 indent_style = space -[*.{yml,yaml}] +[*.{md,yml,yaml,html,css,scss,js}] indent_size = 2 -[*.json] -insert_final_newline = unset - # These files are edited and tested upstream in nf-core/modules [/modules/nf-core/**] charset = unset diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9aa27773..1f2a7938 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -15,8 +15,7 @@ Contributions to the code are even more welcome ;) If you'd like to write some code for nf-core/fetchngs, the standard workflow is as follows: -1. Check that there isn't already an issue about your idea in the [nf-core/fetchngs issues](https://github.com/nf-core/fetchngs/issues) to avoid duplicating work - * If there isn't one already, please create one so that others know you're working on this +1. Check that there isn't already an issue about your idea in the [nf-core/fetchngs issues](https://github.com/nf-core/fetchngs/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/fetchngs repository](https://github.com/nf-core/fetchngs) 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). @@ -49,9 +48,9 @@ These tests are run both with the latest available version of `Nextflow` and als :warning: Only in the unlikely and regretful event of a release happening with a bug. -* On your own fork, make a new branch `patch` based on `upstream/master`. -* Fix the bug, and bump version (X.Y.Z+1). -* A PR should be made on `master` from patch to directly this particular bug. +- On your own fork, make a new branch `patch` based on `upstream/master`. +- Fix the bug, and bump version (X.Y.Z+1). +- A PR should be made on `master` from patch to directly this particular bug. ## Getting help @@ -73,7 +72,7 @@ If you wish to contribute a new step, please use the following coding standards: 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`. -9. Update MultiQC config `assets/multiqc_config.yaml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. +9. Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. 10. Add a description of the output files and if relevant any appropriate images from the MultiQC report to `docs/output.md`. ### Default values @@ -92,8 +91,8 @@ The process resources can be passed on to the tool dynamically within the proces Please use the following naming schemes, to make it easy to understand what is going where. -* initial process channel: `ch_output_from_` -* intermediate and terminal channels: `ch__for_` +- initial process channel: `ch_output_from_` +- intermediate and terminal channels: `ch__for_` ### Nextflow version bumping diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 2fde493e..8c2c9513 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -2,7 +2,6 @@ name: Bug report description: Report something that is broken or incorrect labels: bug body: - - type: markdown attributes: value: | diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 494a0f4c..cc4fa909 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -16,10 +16,10 @@ Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/fetc - [ ] This comment contains a description of changes (with reason). - [ ] 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/fetchngs/tree/master/.github/CONTRIBUTING.md) - - [ ] If necessary, also make a PR on the nf-core/fetchngs _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. + - [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/fetchngs/tree/master/.github/CONTRIBUTING.md) + - [ ] If necessary, also make a PR on the nf-core/fetchngs _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 (`nextflow run . -profile test,docker` --outdir `). +- [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). - [ ] Usage Documentation in `docs/usage.md` is updated. - [ ] Output Documentation in `docs/output.md` is updated. - [ ] `CHANGELOG.md` is updated. diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 2819cc09..92f6bca7 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -18,7 +18,6 @@ jobs: # TODO nf-core: You can customise AWS full pipeline tests as required # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters - with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 94c7c4b7..b47b5cc9 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -10,9 +10,9 @@ jobs: if: github.repository == 'nf-core/fetchngs' runs-on: ubuntu-latest steps: + # Launch workflow using Tower CLI tool action - name: Launch workflow via tower uses: nf-core/tower-action@v3 - with: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 5b8e5919..957452c4 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,8 +13,7 @@ jobs: - name: Check PRs if: github.repository == 'nf-core/fetchngs' run: | - { [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/fetchngs ]] && [[ $GITHUB_HEAD_REF = "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] - + "{ [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/fetchngs ]] && [[ $GITHUB_HEAD_REF = "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]]" # If the above check failed, post a comment on the PR explaining the failure # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets @@ -43,4 +42,4 @@ jobs: Thanks again for your contribution! repo-token: ${{ secrets.GITHUB_TOKEN }} allow-repeats: false - +# diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e66d10a4..71d37bd5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,18 +16,18 @@ jobs: test: name: Run pipeline with test data # 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/fetchngs') }} + if: "${{ github.event_name != 'push' || (github.event_name == 'push' && github.repository == 'nf-core/fetchngs') }}" runs-on: ubuntu-latest strategy: matrix: # Nextflow versions include: # Test pipeline minimum Nextflow version - - NXF_VER: '21.10.3' - NXF_EDGE: '' + - NXF_VER: "21.10.3" + NXF_EDGE: "" # Test latest edge release of Nextflow - - NXF_VER: '' - NXF_EDGE: '1' + - NXF_VER: "" + NXF_EDGE: "1" steps: - name: Check out pipeline code uses: actions/checkout@v2 @@ -48,3 +48,5 @@ jobs: # Remember that you can parallelise this by using strategy.matrix run: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results + +# diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index fda934c0..e9cf5de3 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,6 +1,7 @@ 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 that the code meets the nf-core guidelines +# It runs the `nf-core lint` and markdown lint tests to ensure +# that the code meets the nf-core guidelines. on: push: pull_request: @@ -8,42 +9,6 @@ on: types: [published] jobs: - Markdown: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - - name: Install markdownlint - run: npm install -g markdownlint-cli - - name: Run Markdownlint - run: markdownlint . - - # If the above check failed, post a comment on the PR explaining the failure - - name: Post PR comment - if: failure() - uses: mshick/add-pr-comment@v1 - with: - message: | - ## Markdown linting is failing - - To keep the code consistent with lots of contributors, we run automated code consistency checks. - To fix this CI test, please run: - - * Install `markdownlint-cli` - * On Mac: `brew install markdownlint-cli` - * Everything else: [Install `npm`](https://www.npmjs.com/get-npm) then [install `markdownlint-cli`](https://www.npmjs.com/package/markdownlint-cli) (`npm install -g markdownlint-cli`) - * Fix the markdown errors - * Automatically: `markdownlint . --fix` - * Manually resolve anything left from `markdownlint .` - - Once you push these changes the test should pass, and you can hide this comment :+1: - - We highly recommend setting up markdownlint in your code editor so that this formatting is done automatically on save. Ask about it on Slack for help! - - Thanks again for your contribution! - repo-token: ${{ secrets.GITHUB_TOKEN }} - allow-repeats: false - EditorConfig: runs-on: ubuntu-latest steps: @@ -55,49 +20,24 @@ jobs: run: npm install -g editorconfig-checker - name: Run ECLint check - run: editorconfig-checker -exclude README.md $(git ls-files | grep -v test) + run: editorconfig-checker -exclude README.md $(find .* -type f | grep -v '.git\|.py\|.md\|json\|yml\|yaml\|html\|css\|work\|.nextflow\|build\|nf_core.egg-info\|log.txt\|Makefile') - YAML: + Prettier: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@master - - name: 'Yamllint' - uses: karancode/yamllint-github-action@master - with: - yamllint_file_or_dir: '.' - yamllint_config_filepath: '.yamllint.yml' - - # If the above check failed, post a comment on the PR explaining the failure - - name: Post PR comment - if: failure() - uses: mshick/add-pr-comment@v1 - with: - message: | - ## YAML linting is failing - - To keep the code consistent with lots of contributors, we run automated code consistency checks. - To fix this CI test, please run: - - * Install `yamllint` - * Install `yamllint` following [this](https://yamllint.readthedocs.io/en/stable/quickstart.html#installing-yamllint) - instructions or alternative install it in your [conda environment](https://anaconda.org/conda-forge/yamllint) - * Fix the markdown errors - * Run the test locally: `yamllint $(find . -type f -name "*.yml" -o -name "*.yaml") -c ./.yamllint.yml` - * Fix any reported errors in your YAML files + - uses: actions/checkout@v2 - Once you push these changes the test should pass, and you can hide this comment :+1: + - uses: actions/setup-node@v2 - We highly recommend setting up yaml-lint in your code editor so that this formatting is done automatically on save. Ask about it on Slack for help! + - name: Install Prettier + run: npm install -g prettier - Thanks again for your contribution! - repo-token: ${{ secrets.GITHUB_TOKEN }} - allow-repeats: false + - name: Run Prettier --check + run: prettier --check ${GITHUB_WORKSPACE} nf-core: runs-on: ubuntu-latest steps: - - name: Check out pipeline code uses: actions/checkout@v2 @@ -110,8 +50,8 @@ jobs: - uses: actions/setup-python@v1 with: - python-version: '3.6' - architecture: 'x64' + python-version: "3.6" + architecture: "x64" - name: Install dependencies run: | @@ -139,3 +79,4 @@ jobs: lint_results.md PR_number.txt +# diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 44d72994..91c487a1 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -1,4 +1,3 @@ - name: nf-core linting comment # This workflow is triggered after the linting action is complete # It posts an automated comment to the PR, even if the PR is coming from a fork @@ -27,4 +26,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.pr_number.outputs.pr_number }} path: linting-logs/lint_results.md - +# diff --git a/.gitpod.yml b/.gitpod.yml index b7d4cee1..c452ee93 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -2,13 +2,13 @@ image: nfcore/gitpod:latest vscode: extensions: # based on nf-core.nf-core-extensionpack - - codezombiech.gitignore # Language support for .gitignore files + - codezombiech.gitignore # Language support for .gitignore files # - cssho.vscode-svgviewer # SVG viewer - - davidanson.vscode-markdownlint # Markdown/CommonMark linting and style checking for Visual Studio Code - - eamodio.gitlens # Quickly glimpse into whom, why, and when a line or code block was changed - - 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 + - davidanson.vscode-markdownlint # Markdown/CommonMark linting and style checking for Visual Studio Code + - eamodio.gitlens # Quickly glimpse into whom, why, and when a line or code block was changed + - 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 - - oderwat.indent-rainbow # Highlight indentation level - - streetsidesoftware.code-spell-checker # Spelling checker for source code + - oderwat.indent-rainbow # Highlight indentation level + - streetsidesoftware.code-spell-checker # Spelling checker for source code diff --git a/.markdownlint.yml b/.markdownlint.yml deleted file mode 100644 index 9e605fcf..00000000 --- a/.markdownlint.yml +++ /dev/null @@ -1,14 +0,0 @@ -# Markdownlint configuration file -default: true -line-length: false -ul-indent: - indent: 4 -no-duplicate-header: - siblings_only: true -no-inline-html: - allowed_elements: - - img - - p - - kbd - - details - - summary diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 00000000..c81f9a76 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1 @@ +printWidth: 120 diff --git a/.yamllint.yml b/.yamllint.yml deleted file mode 100644 index d466deec..00000000 --- a/.yamllint.yml +++ /dev/null @@ -1,6 +0,0 @@ -extends: default - -rules: - document-start: disable - line-length: disable - truthy: disable diff --git a/CHANGELOG.md b/CHANGELOG.md index c79ecb8d..8f705e21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ Initial release of nf-core/fetchngs, created with the [nf-core](https://nf-co.re ### `Fixed` +- Clarified conda usage and added an installation tutorial for Singularity since the one on Syllabs' website uses an outdate version of GO Compiler + ### `Dependencies` ### `Deprecated` diff --git a/CITATIONS.md b/CITATIONS.md index d23e6e10..1854d6e6 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -10,23 +10,26 @@ ## Pipeline tools -* [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) +- [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) -* [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) - > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. +- [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) + > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. ## Software packaging/containerisation tools -* [Anaconda](https://anaconda.com) - > Anaconda Software Distribution. Computer software. Vers. 2-2.4.0. Anaconda, Nov. 2016. Web. +- [Anaconda](https://anaconda.com) -* [Bioconda](https://pubmed.ncbi.nlm.nih.gov/29967506/) - > Grüning B, Dale R, Sjödin A, Chapman BA, Rowe J, Tomkins-Tinch CH, Valieris R, Köster J; Bioconda Team. Bioconda: sustainable and comprehensive software distribution for the life sciences. Nat Methods. 2018 Jul;15(7):475-476. doi: 10.1038/s41592-018-0046-7. PubMed PMID: 29967506. + > Anaconda Software Distribution. Computer software. Vers. 2-2.4.0. Anaconda, Nov. 2016. Web. -* [BioContainers](https://pubmed.ncbi.nlm.nih.gov/28379341/) - > da Veiga Leprevost F, Grüning B, Aflitos SA, Röst HL, Uszkoreit J, Barsnes H, Vaudel M, Moreno P, Gatto L, Weber J, Bai M, Jimenez RC, Sachsenberg T, Pfeuffer J, Alvarez RV, Griss J, Nesvizhskii AI, Perez-Riverol Y. BioContainers: an open-source and community-driven framework for software standardization. Bioinformatics. 2017 Aug 15;33(16):2580-2582. doi: 10.1093/bioinformatics/btx192. PubMed PMID: 28379341; PubMed Central PMCID: PMC5870671. +- [Bioconda](https://pubmed.ncbi.nlm.nih.gov/29967506/) -* [Docker](https://dl.acm.org/doi/10.5555/2600239.2600241) + > Grüning B, Dale R, Sjödin A, Chapman BA, Rowe J, Tomkins-Tinch CH, Valieris R, Köster J; Bioconda Team. Bioconda: sustainable and comprehensive software distribution for the life sciences. Nat Methods. 2018 Jul;15(7):475-476. doi: 10.1038/s41592-018-0046-7. PubMed PMID: 29967506. -* [Singularity](https://pubmed.ncbi.nlm.nih.gov/28494014/) - > Kurtzer GM, Sochat V, Bauer MW. Singularity: Scientific containers for mobility of compute. PLoS One. 2017 May 11;12(5):e0177459. doi: 10.1371/journal.pone.0177459. eCollection 2017. PubMed PMID: 28494014; PubMed Central PMCID: PMC5426675. +- [BioContainers](https://pubmed.ncbi.nlm.nih.gov/28379341/) + + > da Veiga Leprevost F, Grüning B, Aflitos SA, Röst HL, Uszkoreit J, Barsnes H, Vaudel M, Moreno P, Gatto L, Weber J, Bai M, Jimenez RC, Sachsenberg T, Pfeuffer J, Alvarez RV, Griss J, Nesvizhskii AI, Perez-Riverol Y. BioContainers: an open-source and community-driven framework for software standardization. Bioinformatics. 2017 Aug 15;33(16):2580-2582. doi: 10.1093/bioinformatics/btx192. PubMed PMID: 28379341; PubMed Central PMCID: PMC5870671. + +- [Docker](https://dl.acm.org/doi/10.5555/2600239.2600241) + +- [Singularity](https://pubmed.ncbi.nlm.nih.gov/28494014/) + > Kurtzer GM, Sochat V, Bauer MW. Singularity: Scientific containers for mobility of compute. PLoS One. 2017 May 11;12(5):e0177459. doi: 10.1371/journal.pone.0177459. eCollection 2017. PubMed PMID: 28494014; PubMed Central PMCID: PMC5426675. diff --git a/README.md b/README.md index 48675271..2b4c0965 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ![nf-core/fetchngs](docs/images/nf-core-fetchngs_logo_light.png#gh-light-mode-only) ![nf-core/fetchngs](docs/images/nf-core-fetchngs_logo_dark.png#gh-dark-mode-only) +# ![nf-core/fetchngs](docs/images/nf-core/fetchngs_logo_light.png#gh-light-mode-only) ![nf-core/fetchngs](docs/images/nf-core/fetchngs_logo_dark.png#gh-dark-mode-only) [![GitHub Actions CI Status](https://github.com/nf-core/fetchngs/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/fetchngs/actions?query=workflow%3A%22nf-core+CI%22) [![GitHub Actions Linting Status](https://github.com/nf-core/fetchngs/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/fetchngs/actions?query=workflow%3A%22nf-core+linting%22) @@ -17,11 +17,13 @@ ## Introduction + **nf-core/fetchngs** is a bioinformatics best-practice analysis pipeline for Pipeline to fetch metadata and raw FastQ files from public databases. The pipeline is built using [Nextflow](https://www.nextflow.io), a workflow tool to run tasks across multiple compute infrastructures in a very portable manner. It uses Docker/Singularity containers making installation trivial and results highly reproducible. The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementation of this pipeline uses one container per process which makes it much easier to maintain and update software dependencies. Where possible, these processes have been submitted to and installed from [nf-core/modules](https://github.com/nf-core/modules) in order to make them available to all nf-core pipelines, and to everyone within the Nextflow community! + On release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/fetchngs/results). ## Pipeline summary @@ -35,28 +37,28 @@ On release, automated continuous integration tests run the pipeline on a full-si 1. Install [`Nextflow`](https://www.nextflow.io/docs/latest/getstarted.html#installation) (`>=21.10.3`) -2. Install any of [`Docker`](https://docs.docker.com/engine/installation/), [`Singularity`](https://www.sylabs.io/guides/3.0/user-guide/), [`Podman`](https://podman.io/), [`Shifter`](https://nersc.gitlab.io/development/shifter/how-to-use/) or [`Charliecloud`](https://hpc.github.io/charliecloud/) for full pipeline reproducibility _(please only use [`Conda`](https://conda.io/miniconda.html) as a last resort; see [docs](https://nf-co.re/usage/configuration#basic-configuration-profiles))_ +2. Install any of [`Docker`](https://docs.docker.com/engine/installation/), [`Singularity`](https://www.sylabs.io/guides/3.0/user-guide/) (you can follow [this tutorial](https://singularity-tutorial.github.io/01-installation/)), [`Podman`](https://podman.io/), [`Shifter`](https://nersc.gitlab.io/development/shifter/how-to-use/) or [`Charliecloud`](https://hpc.github.io/charliecloud/) for full pipeline reproducibility _(you can use [`Conda`](https://conda.io/miniconda.html) both to install Nextflow itself and also to manage software within pipelines. Please only use it within pipelines as a last resort; see [docs](https://nf-co.re/usage/configuration#basic-configuration-profiles))_. 3. Download the pipeline and test it on a minimal dataset with a single command: - ```console - nextflow run nf-core/fetchngs -profile test,YOURPROFILE --outdir - ``` + ```console + nextflow run nf-core/fetchngs -profile test,YOURPROFILE --outdir + ``` - Note that some form of configuration will be needed so that Nextflow knows how to fetch the required software. This is usually done in the form of a config profile (`YOURPROFILE` in the example command above). You can chain multiple config profiles in a comma-separated string. + Note that some form of configuration will be needed so that Nextflow knows how to fetch the required software. This is usually done in the form of a config profile (`YOURPROFILE` in the example command above). You can chain multiple config profiles in a comma-separated string. - > * The pipeline comes with config profiles called `docker`, `singularity`, `podman`, `shifter`, `charliecloud` and `conda` which instruct the pipeline to use the named tool for software management. For example, `-profile test,docker`. - > * Please check [nf-core/configs](https://github.com/nf-core/configs#documentation) to see if a custom config file to run nf-core pipelines already exists for your Institute. If so, you can simply use `-profile ` in your command. This will enable either `docker` or `singularity` and set the appropriate execution settings for your local compute environment. - > * If you are using `singularity`, please use the [`nf-core download`](https://nf-co.re/tools/#downloading-pipelines-for-offline-use) command to download images first, before running the pipeline. Setting the [`NXF_SINGULARITY_CACHEDIR` or `singularity.cacheDir`](https://www.nextflow.io/docs/latest/singularity.html?#singularity-docker-hub) Nextflow options enables you to store and re-use the images from a central location for future pipeline runs. - > * If you are using `conda`, it is highly recommended to use the [`NXF_CONDA_CACHEDIR` or `conda.cacheDir`](https://www.nextflow.io/docs/latest/conda.html) settings to store the environments in a central location for future pipeline runs. + > - The pipeline comes with config profiles called `docker`, `singularity`, `podman`, `shifter`, `charliecloud` and `conda` which instruct the pipeline to use the named tool for software management. For example, `-profile test,docker`. + > - Please check [nf-core/configs](https://github.com/nf-core/configs#documentation) to see if a custom config file to run nf-core pipelines already exists for your Institute. If so, you can simply use `-profile ` in your command. This will enable either `docker` or `singularity` and set the appropriate execution settings for your local compute environment. + > - If you are using `singularity`, please use the [`nf-core download`](https://nf-co.re/tools/#downloading-pipelines-for-offline-use) command to download images first, before running the pipeline. Setting the [`NXF_SINGULARITY_CACHEDIR` or `singularity.cacheDir`](https://www.nextflow.io/docs/latest/singularity.html?#singularity-docker-hub) Nextflow options enables you to store and re-use the images from a central location for future pipeline runs. + > - If you are using `conda`, it is highly recommended to use the [`NXF_CONDA_CACHEDIR` or `conda.cacheDir`](https://www.nextflow.io/docs/latest/conda.html) settings to store the environments in a central location for future pipeline runs. 4. Start running your own analysis! - + - ```console - nextflow run nf-core/fetchngs --input samplesheet.csv --outdir --genome GRCh37 -profile - ``` + ```console + nextflow run nf-core/fetchngs --input samplesheet.csv --outdir --genome GRCh37 -profile + ``` ## Documentation @@ -82,6 +84,7 @@ For further information or help, don't hesitate to get in touch on the [Slack `# + An extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file. You can cite the `nf-core` publication as follows: diff --git a/assets/email_template.html b/assets/email_template.html index 1848021d..5ebb0f0a 100644 --- a/assets/email_template.html +++ b/assets/email_template.html @@ -1,53 +1,111 @@ - - - - + + + + - - nf-core/fetchngs Pipeline Report - - -

    + + + nf-core/fetchngs Pipeline Report + + +
    + - +

    nf-core/fetchngs v${version}

    +

    Run Name: $runName

    -

    nf-core/fetchngs v${version}

    -

    Run Name: $runName

    - -<% if (!success){ - out << """ -
    -

    nf-core/fetchngs execution completed unsuccessfully!

    + <% if (!success){ out << """ +
    +

    nf-core/fetchngs execution completed unsuccessfully!

    The exit status of the task that caused the workflow execution to fail was: $exitStatus.

    The full error message was:

    -
    ${errorReport}
    -
    - """ -} else { - out << """ -
    +
    ${errorReport}
    +
    + """ } else { out << """ +
    nf-core/fetchngs execution completed successfully! -
    - """ -} -%> +
    + """ } %> -

    The workflow was completed at $dateComplete (duration: $duration)

    -

    The command used to launch the workflow was as follows:

    -
    $commandLine
    +

    The workflow was completed at $dateComplete (duration: $duration)

    +

    The command used to launch the workflow was as follows:

    +
    +$commandLine
    -

    Pipeline Configuration:

    - - - <% out << summary.collect{ k,v -> "" }.join("\n") %> - -
    $k
    $v
    +

    Pipeline Configuration:

    + + + <% out << summary.collect{ k,v -> " + + + + + " }.join("\n") %> + +
    + $k + +
    $v
    +
    -

    nf-core/fetchngs

    -

    https://github.com/nf-core/fetchngs

    - -
    - - +

    nf-core/fetchngs

    +

    https://github.com/nf-core/fetchngs

    +
    + diff --git a/assets/multiqc_config.yaml b/assets/multiqc_config.yaml deleted file mode 100644 index 4423f934..00000000 --- a/assets/multiqc_config.yaml +++ /dev/null @@ -1,11 +0,0 @@ -report_comment: > - This report has been generated by the nf-core/fetchngs - analysis pipeline. For information about how to interpret these results, please see the - documentation. -report_section_order: - software_versions: - order: -1000 - nf-core-fetchngs-summary: - order: -1001 - -export_plots: true diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml new file mode 100644 index 00000000..a1144be1 --- /dev/null +++ b/assets/multiqc_config.yml @@ -0,0 +1,11 @@ +report_comment: > + This report has been generated by the nf-core/fetchngs + analysis pipeline. For information about how to interpret these results, please see the + documentation. +report_section_order: + software_versions: + order: -1000 + "nf-core-fetchngs-summary": + order: -1001 + +export_plots: true diff --git a/assets/schema_input.json b/assets/schema_input.json index a3eb1209..38b915cc 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -31,9 +31,6 @@ ] } }, - "required": [ - "sample", - "fastq_1" - ] + "required": ["sample", "fastq_1"] } } diff --git a/docs/README.md b/docs/README.md index 46da73c8..64975d0a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,9 +2,9 @@ The nf-core/fetchngs documentation is split into the following pages: -* [Usage](usage.md) - * An overview of how the pipeline works, how to run it and a description of all of the different command-line flags. -* [Output](output.md) - * An overview of the different results produced by the pipeline and how to interpret them. +- [Usage](usage.md) + - An overview of how the pipeline works, how to run it and a description of all of the different command-line flags. +- [Output](output.md) + - An overview of the different results produced by the pipeline and how to interpret them. You can find a lot more documentation about installing, configuring and running nf-core pipelines on the website: [https://nf-co.re](https://nf-co.re) diff --git a/docs/output.md b/docs/output.md index 9ce80c16..d7a9c039 100644 --- a/docs/output.md +++ b/docs/output.md @@ -12,18 +12,18 @@ The directories listed below will be created in the results directory after the The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: -* [FastQC](#fastqc) - Raw read QC -* [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline -* [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution +- [FastQC](#fastqc) - Raw read QC +- [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline +- [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution ### FastQC
    Output files -* `fastqc/` - * `*_fastqc.html`: FastQC report containing quality metrics. - * `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. +- `fastqc/` + - `*_fastqc.html`: FastQC report containing quality metrics. + - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images.
    @@ -42,10 +42,10 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d
    Output files -* `multiqc/` - * `multiqc_report.html`: a standalone HTML file that can be viewed in your web browser. - * `multiqc_data/`: directory containing parsed statistics from the different tools used in the pipeline. - * `multiqc_plots/`: directory containing static images from the report in various formats. +- `multiqc/` + - `multiqc_report.html`: a standalone HTML file that can be viewed in your web browser. + - `multiqc_data/`: directory containing parsed statistics from the different tools used in the pipeline. + - `multiqc_plots/`: directory containing static images from the report in various formats.
    @@ -58,10 +58,10 @@ Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQ
    Output files -* `pipeline_info/` - * Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. - * Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. - * Reformatted samplesheet files used as input to the pipeline: `samplesheet.valid.csv`. +- `pipeline_info/` + - Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. + - Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. + - Reformatted samplesheet files used as input to the pipeline: `samplesheet.valid.csv`.
    diff --git a/docs/usage.md b/docs/usage.md index 73e623d4..9ac1f8fc 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -44,11 +44,11 @@ TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz, TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz, ``` -| Column | Description | -|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | -| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | -| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| Column | Description | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | +| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. @@ -57,7 +57,7 @@ An [example samplesheet](../assets/samplesheet.csv) has been provided with the p The typical command for running the pipeline is as follows: ```console -nextflow run nf-core/fetchngs --input samplesheet.csv --outdir --genome GRCh37 -profile docker +nextflow run nf-core/fetchngs --input samplesheet.csv --outdir --genome GRCh37 -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -65,9 +65,9 @@ This will launch the pipeline with the `docker` configuration profile. See below Note that the pipeline will create the following files in your working directory: ```console -work # Directory containing the nextflow working files -results # Finished results (configurable, see below) -.nextflow_log # Log file from Nextflow +work # Directory containing the nextflow working files + # Finished results in specified location (defined with --outdir) +.nextflow_log # Log file from Nextflow # Other nextflow hidden files, eg. history of pipeline runs and old logs. ``` @@ -106,25 +106,25 @@ They are loaded in sequence, so later profiles can overwrite earlier profiles. If `-profile` is not specified, the pipeline will run locally and expect all software to be installed and available on the `PATH`. This is _not_ recommended. -* `docker` - * A generic configuration profile to be used with [Docker](https://docker.com/) -* `singularity` - * A generic configuration profile to be used with [Singularity](https://sylabs.io/docs/) -* `podman` - * A generic configuration profile to be used with [Podman](https://podman.io/) -* `shifter` - * A generic configuration profile to be used with [Shifter](https://nersc.gitlab.io/development/shifter/how-to-use/) -* `charliecloud` - * A generic configuration profile to be used with [Charliecloud](https://hpc.github.io/charliecloud/) -* `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 or Charliecloud. -* `test` - * A profile with a complete configuration for automated testing - * Includes links to test data so needs no other parameters +- `docker` + - A generic configuration profile to be used with [Docker](https://docker.com/) +- `singularity` + - A generic configuration profile to be used with [Singularity](https://sylabs.io/docs/) +- `podman` + - A generic configuration profile to be used with [Podman](https://podman.io/) +- `shifter` + - A generic configuration profile to be used with [Shifter](https://nersc.gitlab.io/development/shifter/how-to-use/) +- `charliecloud` + - A generic configuration profile to be used with [Charliecloud](https://hpc.github.io/charliecloud/) +- `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 or Charliecloud. +- `test` + - A profile with a complete configuration for automated testing + - Includes links to test data so needs no other parameters ### `-resume` -Specify this when restarting a pipeline. Nextflow will used cached results from any pipeline steps where the inputs are the same, continuing from where it got to previously. +Specify this when restarting a pipeline. Nextflow will use cached results from any pipeline steps where the inputs are the same, continuing from where it got to previously. For input to be considered the same, not only the names must be identical but the files' contents as well. For more info about this parameter, see [this blog post](https://www.nextflow.io/blog/2019/demystifying-nextflow-resume.html). You can also supply a run name to resume a specific run: `-resume [run-name]`. Use the `nextflow log` command to show previous run names. @@ -186,6 +186,7 @@ process { ``` > **NB:** We specify the full process name i.e. `NFCORE_RNASEQ:RNASEQ:ALIGN_STAR:STAR_ALIGN` in the config file because this takes priority over the short name (`STAR_ALIGN`) and allows existing configuration using the full process name to be correctly overridden. +> > If you get a warning suggesting that the process selector isn't recognised check that the process name has been specified correctly. ### Updating containers @@ -196,35 +197,35 @@ The [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) implementatio 2. Find the latest version of the Biocontainer available on [Quay.io](https://quay.io/repository/biocontainers/pangolin?tag=latest&tab=tags) 3. Create the custom config accordingly: - * For Docker: - - ```nextflow - process { - withName: PANGOLIN { - container = 'quay.io/biocontainers/pangolin:3.0.5--pyhdfd78af_0' - } - } - ``` - - * For Singularity: - - ```nextflow - process { - withName: PANGOLIN { - container = 'https://depot.galaxyproject.org/singularity/pangolin:3.0.5--pyhdfd78af_0' - } - } - ``` - - * For Conda: - - ```nextflow - process { - withName: PANGOLIN { - conda = 'bioconda::pangolin=3.0.5' - } - } - ``` + - For Docker: + + ```nextflow + process { + withName: PANGOLIN { + container = 'quay.io/biocontainers/pangolin:3.0.5--pyhdfd78af_0' + } + } + ``` + + - For Singularity: + + ```nextflow + process { + withName: PANGOLIN { + container = 'https://depot.galaxyproject.org/singularity/pangolin:3.0.5--pyhdfd78af_0' + } + } + ``` + + - For Conda: + + ```nextflow + process { + withName: PANGOLIN { + conda = 'bioconda::pangolin=3.0.5' + } + } + ``` > **NB:** If you wish to periodically update individual tool-specific results (e.g. Pangolin) generated by the pipeline then you must ensure to keep the `work/` directory otherwise the `-resume` ability of the pipeline will be compromised and it will restart from scratch. diff --git a/modules.json b/modules.json index d183e20a..b599fa52 100644 --- a/modules.json +++ b/modules.json @@ -4,14 +4,14 @@ "repos": { "nf-core/modules": { "custom/dumpsoftwareversions": { - "git_sha": "20d8250d9f39ddb05dfb437603aaf99b5c0b2b41" + "git_sha": "e745e167c1020928ef20ea1397b6b4d230681b4d" }, "fastqc": { - "git_sha": "9d0cad583b9a71a6509b754fdf589cbfbed08961" + "git_sha": "e745e167c1020928ef20ea1397b6b4d230681b4d" }, "multiqc": { - "git_sha": "20d8250d9f39ddb05dfb437603aaf99b5c0b2b41" + "git_sha": "e745e167c1020928ef20ea1397b6b4d230681b4d" } } } -} \ No newline at end of file +} diff --git a/modules/nf-core/modules/custom/dumpsoftwareversions/main.nf b/modules/nf-core/modules/custom/dumpsoftwareversions/main.nf index 934bb467..327d5100 100644 --- a/modules/nf-core/modules/custom/dumpsoftwareversions/main.nf +++ b/modules/nf-core/modules/custom/dumpsoftwareversions/main.nf @@ -15,6 +15,9 @@ process CUSTOM_DUMPSOFTWAREVERSIONS { path "software_versions_mqc.yml", emit: mqc_yml path "versions.yml" , emit: versions + when: + task.ext.when == null || task.ext.when + script: def args = task.ext.args ?: '' template 'dumpsoftwareversions.py' diff --git a/modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml b/modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml index 5b5b8a60..60b546a0 100644 --- a/modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml +++ b/modules/nf-core/modules/custom/dumpsoftwareversions/meta.yml @@ -8,7 +8,7 @@ tools: description: Custom module used to dump software versions within the nf-core pipeline template homepage: https://github.com/nf-core/tools documentation: https://github.com/nf-core/tools - licence: ['MIT'] + licence: ["MIT"] input: - versions: type: file diff --git a/modules/nf-core/modules/fastqc/main.nf b/modules/nf-core/modules/fastqc/main.nf index d250eca0..ed6b8c50 100644 --- a/modules/nf-core/modules/fastqc/main.nf +++ b/modules/nf-core/modules/fastqc/main.nf @@ -15,6 +15,9 @@ process FASTQC { tuple val(meta), path("*.zip") , emit: zip path "versions.yml" , emit: versions + when: + task.ext.when == null || task.ext.when + script: def args = task.ext.args ?: '' // Add soft-links to original FastQs for consistent naming in pipeline diff --git a/modules/nf-core/modules/fastqc/meta.yml b/modules/nf-core/modules/fastqc/meta.yml index b09553a3..4da5bb5a 100644 --- a/modules/nf-core/modules/fastqc/meta.yml +++ b/modules/nf-core/modules/fastqc/meta.yml @@ -1,52 +1,52 @@ name: fastqc description: Run FastQC on sequenced reads keywords: - - quality control - - qc - - adapters - - fastq + - quality control + - qc + - adapters + - fastq tools: - - fastqc: - description: | - FastQC gives general quality metrics about your reads. - It provides information about the quality score distribution - across your reads, the per base sequence content (%A/C/G/T). - You get information about adapter contamination and other - overrepresented sequences. - homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ - documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ - licence: ['GPL-2.0-only'] + - fastqc: + description: | + FastQC gives general quality metrics about your reads. + It provides information about the quality score distribution + across your reads, the per base sequence content (%A/C/G/T). + You get information about adapter contamination and other + overrepresented sequences. + homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ + documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ + licence: ["GPL-2.0-only"] 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}" - - zip: - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + - 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}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - - "@drpatelh" - - "@grst" - - "@ewels" - - "@FelixKrueger" + - "@drpatelh" + - "@grst" + - "@ewels" + - "@FelixKrueger" diff --git a/modules/nf-core/modules/multiqc/main.nf b/modules/nf-core/modules/multiqc/main.nf index 3dceb162..1264aac1 100644 --- a/modules/nf-core/modules/multiqc/main.nf +++ b/modules/nf-core/modules/multiqc/main.nf @@ -1,10 +1,10 @@ process MULTIQC { label 'process_medium' - conda (params.enable_conda ? 'bioconda::multiqc=1.11' : null) + conda (params.enable_conda ? 'bioconda::multiqc=1.12' : null) container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.11--pyhdfd78af_0' : - 'quay.io/biocontainers/multiqc:1.11--pyhdfd78af_0' }" + 'https://depot.galaxyproject.org/singularity/multiqc:1.12--pyhdfd78af_0' : + 'quay.io/biocontainers/multiqc:1.12--pyhdfd78af_0' }" input: path multiqc_files @@ -15,6 +15,9 @@ process MULTIQC { path "*_plots" , optional:true, emit: plots path "versions.yml" , emit: versions + when: + task.ext.when == null || task.ext.when + script: def args = task.ext.args ?: '' """ diff --git a/modules/nf-core/modules/multiqc/meta.yml b/modules/nf-core/modules/multiqc/meta.yml index 63c75a45..6fa891ef 100644 --- a/modules/nf-core/modules/multiqc/meta.yml +++ b/modules/nf-core/modules/multiqc/meta.yml @@ -1,40 +1,40 @@ name: MultiQC description: Aggregate results from bioinformatics analyses across many samples into a single report keywords: - - QC - - bioinformatics tools - - Beautiful stand-alone HTML report + - QC + - bioinformatics tools + - Beautiful stand-alone HTML report tools: - - multiqc: - description: | - MultiQC searches a given directory for analysis logs and compiles a HTML report. - It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. - homepage: https://multiqc.info/ - documentation: https://multiqc.info/docs/ - licence: ['GPL-3.0-or-later'] + - multiqc: + description: | + MultiQC searches a given directory for analysis logs and compiles a HTML report. + It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. + homepage: https://multiqc.info/ + documentation: https://multiqc.info/docs/ + licence: ["GPL-3.0-or-later"] input: - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC + - multiqc_files: + type: file + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC output: - - report: - type: file - description: MultiQC report file - pattern: "multiqc_report.html" - - data: - type: dir - description: MultiQC data dir - pattern: "multiqc_data" - - plots: - type: file - description: Plots created by MultiQC - pattern: "*_data" - - versions: - type: file - description: File containing software versions - pattern: "versions.yml" + - report: + type: file + description: MultiQC report file + pattern: "multiqc_report.html" + - data: + type: dir + description: MultiQC data dir + pattern: "multiqc_data" + - plots: + type: file + description: Plots created by MultiQC + pattern: "*_data" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" authors: - - "@abhi18av" - - "@bunop" - - "@drpatelh" + - "@abhi18av" + - "@bunop" + - "@drpatelh" diff --git a/nextflow_schema.json b/nextflow_schema.json index 5d1e5fb6..6976f507 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -10,10 +10,7 @@ "type": "object", "fa_icon": "fas fa-terminal", "description": "Define where the pipeline should find input data and save output data.", - "required": [ - "input", - "outdir" - ], + "required": ["input", "outdir"], "properties": { "input": { "type": "string", @@ -185,14 +182,7 @@ "description": "Method used to save pipeline results to output directory.", "help_text": "The Nextflow `publishDir` option specifies which intermediate files should be saved to the output directory. This option tells the pipeline what method should be used to move these files. See [Nextflow docs](https://www.nextflow.io/docs/latest/process.html#publishdir) for details.", "fa_icon": "fas fa-copy", - "enum": [ - "symlink", - "rellink", - "link", - "copy", - "copyNoFollow", - "move" - ], + "enum": ["symlink", "rellink", "link", "copy", "copyNoFollow", "move"], "hidden": true }, "email_on_fail": { diff --git a/workflows/fetchngs.nf b/workflows/fetchngs.nf index af57a592..3f2eb0ff 100644 --- a/workflows/fetchngs.nf +++ b/workflows/fetchngs.nf @@ -23,7 +23,7 @@ if (params.input) { ch_input = file(params.input) } else { exit 1, 'Input sample ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -ch_multiqc_config = file("$projectDir/assets/multiqc_config.yaml", checkIfExists: true) +ch_multiqc_config = file("$projectDir/assets/multiqc_config.yml", checkIfExists: true) ch_multiqc_custom_config = params.multiqc_config ? Channel.fromPath(params.multiqc_config) : Channel.empty() /* From 2e62a0482c802d89212f106716c2a273dc1715a3 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Thu, 24 Mar 2022 11:38:03 +0000 Subject: [PATCH 10/26] Template update for nf-core/tools version 2.3.2 --- .github/PULL_REQUEST_TEMPLATE.md | 1 - .github/workflows/awsfulltest.yml | 2 -- .github/workflows/awstest.yml | 2 -- .gitpod.yml | 2 +- CHANGELOG.md | 2 -- 5 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cc4fa909..1f17f774 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,7 +10,6 @@ Remember that PRs should be made against the dev branch, unless you're preparing Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/fetchngs/tree/master/.github/CONTRIBUTING.md) --> - ## PR checklist diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 92f6bca7..28a35b95 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -22,8 +22,6 @@ jobs: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} - pipeline: ${{ github.repository }} - revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/fetchngs/work-${{ github.sha }} parameters: | { diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index b47b5cc9..330cf712 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -17,8 +17,6 @@ jobs: workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} - pipeline: ${{ github.repository }} - revision: ${{ github.sha }} workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/fetchngs/work-${{ github.sha }} parameters: | { diff --git a/.gitpod.yml b/.gitpod.yml index c452ee93..85d95ecc 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -4,7 +4,7 @@ vscode: extensions: # based on nf-core.nf-core-extensionpack - codezombiech.gitignore # Language support for .gitignore files # - cssho.vscode-svgviewer # SVG viewer - - davidanson.vscode-markdownlint # Markdown/CommonMark linting and style checking for Visual Studio Code + - esbenp.prettier-vscode # Markdown/CommonMark linting and style checking for Visual Studio Code - eamodio.gitlens # Quickly glimpse into whom, why, and when a line or code block was changed - 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f705e21..c79ecb8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,6 @@ Initial release of nf-core/fetchngs, created with the [nf-core](https://nf-co.re ### `Fixed` -- Clarified conda usage and added an installation tutorial for Singularity since the one on Syllabs' website uses an outdate version of GO Compiler - ### `Dependencies` ### `Deprecated` From ce7bb867348d37878826796ed40658df0862cbb2 Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Thu, 31 Mar 2022 22:34:50 +0100 Subject: [PATCH 11/26] Fix prettier --- CHANGELOG.md | 64 ++++++++++++++++++++-------------------- CITATIONS.md | 35 ++++++++++++---------- README.md | 12 ++++---- assets/schema_input.json | 2 +- docs/output.md | 54 ++++++++++++++++----------------- docs/usage.md | 14 ++++----- modules.json | 2 +- nextflow_schema.json | 7 ++--- 8 files changed, 96 insertions(+), 94 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7d9d75a..7bbf0e90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Enhancements & fixes -* Updated pipeline template to [nf-core/tools 2.2](https://github.com/nf-core/tools/releases/tag/2.2) +- Updated pipeline template to [nf-core/tools 2.2](https://github.com/nf-core/tools/releases/tag/2.2) ## [[1.5](https://github.com/nf-core/fetchngs/releases/tag/1.5)] - 2021-12-01 -* Finish porting the pipeline to the updated Nextflow DSL2 syntax adopted on nf-core/modules - * Bump minimum Nextflow version from `21.04.0` -> `21.10.3` - * Removed `--publish_dir_mode` as it is no longer required for the new syntax +- Finish porting the pipeline to the updated Nextflow DSL2 syntax adopted on nf-core/modules + - Bump minimum Nextflow version from `21.04.0` -> `21.10.3` + - Removed `--publish_dir_mode` as it is no longer required for the new syntax ### Enhancements & fixes @@ -21,51 +21,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Enhancements & fixes -* Convert pipeline to updated Nextflow DSL2 syntax for future adoption across nf-core -* Added a workflow to download FastQ files and to create samplesheets for ids from the [Synapse platform](https://www.synapse.org/) hosted by [Sage Bionetworks](https://sagebionetworks.org/). -* SRA identifiers not available for direct download via the ENA FTP will now be downloaded via [`sra-tools`](https://github.com/ncbi/sra-tools). -* Added `--force_sratools_download` parameter to preferentially download all FastQ files via `sra-tools` instead of ENA FTP. -* Correctly handle errors from SRA identifiers that do **not** return metadata, for example, due to being private. -* Retry an error in prefetch via bash script in order to allow it to resume interrupted downloads. -* Name output FastQ files by `{EXP_ACC}_{RUN_ACC}*fastq.gz` instead of `{EXP_ACC}_{T*}*fastq.gz` for run id provenance -* [[#46](https://github.com/nf-core/fetchngs/issues/46)] - Bug in sra_ids_to_runinfo.py -* Added support for [DDBJ ids](https://www.ddbj.nig.ac.jp/index-e.html). See examples below: - -| `DDBJ` | -|---------------| -| PRJDB4176 | -| SAMD00114846 | -| DRA008156 | -| DRP004793 | -| DRR171822 | -| DRS090921 | -| DRX162434 | +- Convert pipeline to updated Nextflow DSL2 syntax for future adoption across nf-core +- Added a workflow to download FastQ files and to create samplesheets for ids from the [Synapse platform](https://www.synapse.org/) hosted by [Sage Bionetworks](https://sagebionetworks.org/). +- SRA identifiers not available for direct download via the ENA FTP will now be downloaded via [`sra-tools`](https://github.com/ncbi/sra-tools). +- Added `--force_sratools_download` parameter to preferentially download all FastQ files via `sra-tools` instead of ENA FTP. +- Correctly handle errors from SRA identifiers that do **not** return metadata, for example, due to being private. +- Retry an error in prefetch via bash script in order to allow it to resume interrupted downloads. +- Name output FastQ files by `{EXP_ACC}_{RUN_ACC}*fastq.gz` instead of `{EXP_ACC}_{T*}*fastq.gz` for run id provenance +- [[#46](https://github.com/nf-core/fetchngs/issues/46)] - Bug in sra_ids_to_runinfo.py +- Added support for [DDBJ ids](https://www.ddbj.nig.ac.jp/index-e.html). See examples below: + +| `DDBJ` | +| ------------ | +| PRJDB4176 | +| SAMD00114846 | +| DRA008156 | +| DRP004793 | +| DRR171822 | +| DRS090921 | +| DRX162434 | ## [[1.3](https://github.com/nf-core/fetchngs/releases/tag/1.3)] - 2021-09-15 ### Enhancements & fixes -* Replaced Python `requests` with `urllib` to fetch ENA metadata +- Replaced Python `requests` with `urllib` to fetch ENA metadata ### Software dependencies -| Dependency | Old version | New version | -|-------------|-------------|-------------| -| `python` | 3.8.3 | 3.9.5 | +| Dependency | Old version | New version | +| ---------- | ----------- | ----------- | +| `python` | 3.8.3 | 3.9.5 | ## [[1.2](https://github.com/nf-core/fetchngs/releases/tag/1.2)] - 2021-07-28 ### Enhancements & fixes -* Updated pipeline template to [nf-core/tools 2.1](https://github.com/nf-core/tools/releases/tag/2.1) -* [[#26](https://github.com/nf-core/fetchngs/pull/26)] - Update broken EBI API URL +- Updated pipeline template to [nf-core/tools 2.1](https://github.com/nf-core/tools/releases/tag/2.1) +- [[#26](https://github.com/nf-core/fetchngs/pull/26)] - Update broken EBI API URL ## [[1.1](https://github.com/nf-core/fetchngs/releases/tag/1.1)] - 2021-06-22 ### Enhancements & fixes -* [[#12](https://github.com/nf-core/fetchngs/issues/12)] - Error when using singularity - /etc/resolv.conf doesn't exist in container -* Added `--sample_mapping_fields` parameter to create a separate `id_mappings.csv` and `multiqc_config.yml` with selected fields that can be used to rename samples in general and in [MultiQC](https://multiqc.info/docs/#bulk-sample-renaming) +- [[#12](https://github.com/nf-core/fetchngs/issues/12)] - Error when using singularity - /etc/resolv.conf doesn't exist in container +- Added `--sample_mapping_fields` parameter to create a separate `id_mappings.csv` and `multiqc_config.yml` with selected fields that can be used to rename samples in general and in [MultiQC](https://multiqc.info/docs/#bulk-sample-renaming) ## [[1.0](https://github.com/nf-core/fetchngs/releases/tag/1.0)] - 2021-06-08 @@ -85,7 +85,7 @@ Via a single file of ids, provided one-per-line the pipeline performs the follow Currently, the following types of example identifiers are supported: | `SRA` | `ENA` | `GEO` | -|--------------|--------------|------------| +| ------------ | ------------ | ---------- | | SRR11605097 | ERR4007730 | GSM4432381 | | SRX8171613 | ERX4009132 | GSE147507 | | SRS6531847 | ERS4399630 | | diff --git a/CITATIONS.md b/CITATIONS.md index 2590785c..3826bfe7 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -10,31 +10,36 @@ ## Pipeline tools -* [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. +- [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) -* [Python](http://www.python.org) + > 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. -* [Requests](https://docs.python-requests.org/) +- [Python](http://www.python.org) -* [sra-tools](https://github.com/ncbi/sra-tools) +- [Requests](https://docs.python-requests.org/) + +- [sra-tools](https://github.com/ncbi/sra-tools) ## Pipeline resources -* [ENA](https://pubmed.ncbi.nlm.nih.gov/33175160/) - > Harrison PW, Ahamed A, Aslam R, Alako BTF, Burgin J, Buso N, Courtot M, Fan J, Gupta D, Haseeb M, Holt S, Ibrahim T, Ivanov E, Jayathilaka S, Kadhirvelu VB, Kumar M, Lopez R, Kay S, Leinonen R, Liu X, O'Cathail C, Pakseresht A, Park Y, Pesant S, Rahman N, Rajan J, Sokolov A, Vijayaraja S, Waheed Z, Zyoud A, Burdett T, Cochrane G. The European Nucleotide Archive in 2020. Nucleic Acids Res. 2021 Jan 8;49(D1):D82-D85. doi: 10.1093/nar/gkaa1028. PubMed PMID: 33175160; PubMed Central PMCID: PMC7778925. +- [ENA](https://pubmed.ncbi.nlm.nih.gov/33175160/) + + > Harrison PW, Ahamed A, Aslam R, Alako BTF, Burgin J, Buso N, Courtot M, Fan J, Gupta D, Haseeb M, Holt S, Ibrahim T, Ivanov E, Jayathilaka S, Kadhirvelu VB, Kumar M, Lopez R, Kay S, Leinonen R, Liu X, O'Cathail C, Pakseresht A, Park Y, Pesant S, Rahman N, Rajan J, Sokolov A, Vijayaraja S, Waheed Z, Zyoud A, Burdett T, Cochrane G. The European Nucleotide Archive in 2020. Nucleic Acids Res. 2021 Jan 8;49(D1):D82-D85. doi: 10.1093/nar/gkaa1028. PubMed PMID: 33175160; PubMed Central PMCID: PMC7778925. + +- [SRA](https://pubmed.ncbi.nlm.nih.gov/21062823/) + + > Leinonen R, Sugawara H, Shumway M, International Nucleotide Sequence Database Collaboration. The sequence read archive. Nucleic Acids Res. 2011 Jan;39 (Database issue):D19-21. doi: 10.1093/nar/gkq1019. Epub 2010 Nov 9. PubMed PMID: 21062823; PubMed Central PMCID: PMC3013647. + +- [DDBJ](https://pubmed.ncbi.nlm.nih.gov/33156332/) -* [SRA](https://pubmed.ncbi.nlm.nih.gov/21062823/) - > Leinonen R, Sugawara H, Shumway M, International Nucleotide Sequence Database Collaboration. The sequence read archive. Nucleic Acids Res. 2011 Jan;39 (Database issue):D19-21. doi: 10.1093/nar/gkq1019. Epub 2010 Nov 9. PubMed PMID: 21062823; PubMed Central PMCID: PMC3013647. + > Fukuda A, Kodama Y, Mashima J, Fujisawa T, Ogasawara O. DDBJ update: streamlining submission and access of human data. Nucleic Acids Res. 2021 Jan 8;49(D1):D71-D75. doi: 10.1093/nar/gkaa982. PubMed PMID: 33156332; PubMed Central PMCID: PMC7779041. -* [DDBJ](https://pubmed.ncbi.nlm.nih.gov/33156332/) - > Fukuda A, Kodama Y, Mashima J, Fujisawa T, Ogasawara O. DDBJ update: streamlining submission and access of human data. Nucleic Acids Res. 2021 Jan 8;49(D1):D71-D75. doi: 10.1093/nar/gkaa982. PubMed PMID: 33156332; PubMed Central PMCID: PMC7779041. +- [GEO](https://pubmed.ncbi.nlm.nih.gov/23193258/) -* [GEO](https://pubmed.ncbi.nlm.nih.gov/23193258/) - > Barrett T, Wilhite SE, Ledoux P, Evangelista C, Kim IF, Tomashevsky M, Marshall KA, Phillippy KH, Sherman PM, Holko M, Yefanov A, Lee H, Zhang N, Robertson CL, Serova N, Davis S, Soboleva A. NCBI GEO: archive for functional genomics data sets--update. Nucleic Acids Res. 2013 Jan;41(Database issue):D991-5. doi: 10.1093/nar/gks1193. Epub 2012 Nov 27. PubMed PMID: 23193258; PubMed Central PMCID: PMC3531084. + > Barrett T, Wilhite SE, Ledoux P, Evangelista C, Kim IF, Tomashevsky M, Marshall KA, Phillippy KH, Sherman PM, Holko M, Yefanov A, Lee H, Zhang N, Robertson CL, Serova N, Davis S, Soboleva A. NCBI GEO: archive for functional genomics data sets--update. Nucleic Acids Res. 2013 Jan;41(Database issue):D991-5. doi: 10.1093/nar/gks1193. Epub 2012 Nov 27. PubMed PMID: 23193258; PubMed Central PMCID: PMC3531084. -* [Synapse](https://pubmed.ncbi.nlm.nih.gov/24071850/) - > Omberg L, Ellrott K, Yuan Y, Kandoth C, Wong C, Kellen MR, Friend SH, Stuart J, Liang H, Margolin AA. Enabling transparent and collaborative computational analysis of 12 tumor types within The Cancer Genome Atlas. Nat Genet. 2013 Oct;45(10):1121-6. doi: 10.1038/ng.2761. PMID: 24071850; PMCID: PMC3950337. +- [Synapse](https://pubmed.ncbi.nlm.nih.gov/24071850/) + > Omberg L, Ellrott K, Yuan Y, Kandoth C, Wong C, Kellen MR, Friend SH, Stuart J, Liang H, Margolin AA. Enabling transparent and collaborative computational analysis of 12 tumor types within The Cancer Genome Atlas. Nat Genet. 2013 Oct;45(10):1121-6. doi: 10.1038/ng.2761. PMID: 24071850; PMCID: PMC3950337. ## Software packaging/containerisation tools diff --git a/README.md b/README.md index 7839c848..d1f7d596 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ Via a single file of ids, provided one-per-line (see [example input file](https: 1. Resolve database ids back to appropriate experiment-level ids and to be compatible with the [ENA API](https://ena-docs.readthedocs.io/en/latest/retrieval/programmatic-access.html) 2. Fetch extensive id metadata via ENA API 3. Download FastQ files: - - If direct download links are available from the ENA API, fetch in parallel via `curl` and perform `md5sum` check - - Otherwise use [`sra-tools`](https://github.com/ncbi/sra-tools) to download `.sra` files and convert them to FastQ + - If direct download links are available from the ENA API, fetch in parallel via `curl` and perform `md5sum` check + - Otherwise use [`sra-tools`](https://github.com/ncbi/sra-tools) to download `.sra` files and convert them to FastQ 4. Collate id metadata and paths to FastQ files in a single samplesheet ### Synapse ids @@ -67,9 +67,9 @@ The columns in the auto-created samplesheet can be tailored to be accepted out-o 4. Start running your own analysis! - ```bash - nextflow run nf-core/fetchngs --input ids.txt --outdir -profile - ``` + ```bash + nextflow run nf-core/fetchngs --input ids.txt --outdir -profile + ``` ## Documentation @@ -87,7 +87,7 @@ For further information or help, don't hesitate to get in touch on the [Slack `# ## Citations -If you use nf-core/fetchngs for your analysis, please cite it using the following doi: [10.5281/zenodo.5070524](https://doi.org/10.5281/zenodo.5070524) +If you use nf-core/fetchngs for your analysis, please cite it using the following doi: [10.5281/zenodo.5070524](https://doi.org/10.5281/zenodo.5070524) An extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file. diff --git a/assets/schema_input.json b/assets/schema_input.json index 25006d9b..9a800216 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -8,7 +8,7 @@ "type": "array", "items": { "type": "string", - "pattern":"^(((SR|ER|DR)[APRSX])|(SAM(N|EA|D))|(PRJ(NA|EB|DB))|(GS[EM])|(syn))(\\d+)$", + "pattern": "^(((SR|ER|DR)[APRSX])|(SAM(N|EA|D))|(PRJ(NA|EB|DB))|(GS[EM])|(syn))(\\d+)$", "errorMessage": "Please provide a valid SRA, ENA, DDBJ or GEO identifier" } } diff --git a/docs/output.md b/docs/output.md index 897d5cd1..7402976c 100644 --- a/docs/output.md +++ b/docs/output.md @@ -8,10 +8,10 @@ This document describes the output produced by the pipeline. The directories lis The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data depending on the type of ids provided: -* Download FastQ files and create samplesheet from: - 1. [SRA / ENA / DDBJ / GEO ids](#sra--ena--ddbj--geo-ids) - 2. [Synapse ids](#synapse-ids) -* [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution +- Download FastQ files and create samplesheet from: + 1. [SRA / ENA / DDBJ / GEO ids](#sra--ena--ddbj--geo-ids) + 2. [Synapse ids](#synapse-ids) +- [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution Please see the [usage documentation](https://nf-co.re/fetchngs/usage#introduction) for a list of supported public repository identifiers and how to provide them to the pipeline. @@ -20,17 +20,17 @@ Please see the [usage documentation](https://nf-co.re/fetchngs/usage#introductio
    Output files -* `fastq/` - * `*.fastq.gz`: Paired-end/single-end reads downloaded from the SRA / ENA / DDBJ / GEO. -* `fastq/md5/` - * `*.md5`: Files containing `md5` sum for FastQ files downloaded from the ENA. -* `samplesheet/` - * `samplesheet.csv`: Auto-created samplesheet with collated metadata and paths to downloaded FastQ files. - * `id_mappings.csv`: File with selected fields that can be used to rename samples to more informative names; see [`--sample_mapping_fields`](https://nf-co.re/fetchngs/parameters#sample_mapping_fields) parameter to customise this behaviour. - * `multiqc_config.yml`: [MultiQC](https://multiqc.info/docs/#bulk-sample-renaming) config file that can be passed to most nf-core pipelines via the `--multiqc_config` parameter for bulk renaming of sample names from database ids; [`--sample_mapping_fields`](https://nf-co.re/fetchngs/parameters#sample_mapping_fields) parameter to customise this behaviour. -* `metadata/` - * `*.runinfo_ftp.tsv`: Re-formatted metadata file downloaded from the ENA. - * `*.runinfo.tsv`: Original metadata file downloaded from the ENA. +- `fastq/` + - `*.fastq.gz`: Paired-end/single-end reads downloaded from the SRA / ENA / DDBJ / GEO. +- `fastq/md5/` + - `*.md5`: Files containing `md5` sum for FastQ files downloaded from the ENA. +- `samplesheet/` + - `samplesheet.csv`: Auto-created samplesheet with collated metadata and paths to downloaded FastQ files. + - `id_mappings.csv`: File with selected fields that can be used to rename samples to more informative names; see [`--sample_mapping_fields`](https://nf-co.re/fetchngs/parameters#sample_mapping_fields) parameter to customise this behaviour. + - `multiqc_config.yml`: [MultiQC](https://multiqc.info/docs/#bulk-sample-renaming) config file that can be passed to most nf-core pipelines via the `--multiqc_config` parameter for bulk renaming of sample names from database ids; [`--sample_mapping_fields`](https://nf-co.re/fetchngs/parameters#sample_mapping_fields) parameter to customise this behaviour. +- `metadata/` + - `*.runinfo_ftp.tsv`: Re-formatted metadata file downloaded from the ENA. + - `*.runinfo.tsv`: Original metadata file downloaded from the ENA.
    @@ -41,15 +41,15 @@ The final sample information for all identifiers is obtained from the ENA which
    Output files -* `fastq/` - * `*.fastq.gz`: Paired-end/single-end reads downloaded from Synapse. -* `fastq/md5/` - * `*.md5`: Files containing `md5` sum for FastQ files downloaded from the Synapse platform. -* `samplesheet/` - * `samplesheet.csv`: Auto-created samplesheet with collated metadata and paths to downloaded FastQ files. -* `metadata/` - * `*.metadata.txt`: Original metadata file generated using the `synapse show` command. - * `*.list.txt`: Original output of the `synapse list` command, containing the Synapse ids, file version numbers, file names, and other file-specific data for the Synapse directory ID provided. +- `fastq/` + - `*.fastq.gz`: Paired-end/single-end reads downloaded from Synapse. +- `fastq/md5/` + - `*.md5`: Files containing `md5` sum for FastQ files downloaded from the Synapse platform. +- `samplesheet/` + - `samplesheet.csv`: Auto-created samplesheet with collated metadata and paths to downloaded FastQ files. +- `metadata/` + - `*.metadata.txt`: Original metadata file generated using the `synapse show` command. + - `*.list.txt`: Original output of the `synapse list` command, containing the Synapse ids, file version numbers, file names, and other file-specific data for the Synapse directory ID provided.
    @@ -62,9 +62,9 @@ The final sample information for the FastQ files downloaded from `Synapse` is ob
    Output files -* `pipeline_info/` - * Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. - * Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline. +- `pipeline_info/` + - Reports generated by Nextflow: `execution_report.html`, `execution_timeline.html`, `execution_trace.txt` and `pipeline_dag.dot`/`pipeline_dag.svg`. + - Reports generated by the pipeline: `pipeline_report.html`, `pipeline_report.txt` and `software_versions.yml`. The `pipeline_report*` files will only be present if the `--email` / `--email_on_fail` parameter's are used when running the pipeline.
    diff --git a/docs/usage.md b/docs/usage.md index 8c827443..2eb38745 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -9,7 +9,7 @@ The pipeline has been set-up to automatically download and process the raw FastQ files from both public and private repositories. Identifiers can be provided in a file, one-per-line via the `--input` parameter. Currently, the following types of example identifiers are supported: | `SRA` | `ENA` | `DDBJ` | `GEO` | `Synapse` | -|--------------|--------------|--------------|------------|-------------| +| ------------ | ------------ | ------------ | ---------- | ----------- | | SRR11605097 | ERR4007730 | DRR171822 | GSM4432381 | syn26240435 | | SRX8171613 | ERX4009132 | DRX162434 | GSE147507 | | | SRS6531847 | ERS4399630 | DRS090921 | | | @@ -28,9 +28,9 @@ All of the sample metadata obtained from the ENA will be appended as additional If you have a GEO accession (found in the data availability section of published papers) you can directly download a text file containing the appropriate SRA ids to pass to the pipeline: -* Search for your GEO accession on [GEO](https://www.ncbi.nlm.nih.gov/geo) -* Click `SRA Run Selector` at the bottom of the GEO accession page -* Select the desired samples in the `SRA Run Selector` and then download the `Accession List` +- Search for your GEO accession on [GEO](https://www.ncbi.nlm.nih.gov/geo) +- Click `SRA Run Selector` at the bottom of the GEO accession page +- Select the desired samples in the `SRA Run Selector` and then download the `Accession List` This downloads a text file called `SRR_Acc_List.txt` that can be directly provided to the pipeline e.g. `--input SRR_Acc_List.txt`. @@ -47,9 +47,9 @@ The final sample information for the FastQ files used for samplesheet generation
    Supported File Names -* Files named `SRR493366_1.fastq` and `SRR493366_2.fastq` will have a sample name of `SRR493366` -* Files named `SRR_493_367_1.fastq` and `SRR_493_367_2.fastq` will have a sample name of `SRR_493_367` -* Files named `filename12_1.fastq` and `filename12_2.fastq` will have a sample name of `filename12` +- Files named `SRR493366_1.fastq` and `SRR493366_2.fastq` will have a sample name of `SRR493366` +- Files named `SRR_493_367_1.fastq` and `SRR_493_367_2.fastq` will have a sample name of `SRR_493_367` +- Files named `filename12_1.fastq` and `filename12_2.fastq` will have a sample name of `filename12`
    diff --git a/modules.json b/modules.json index 2baafc4f..f39d24ab 100644 --- a/modules.json +++ b/modules.json @@ -8,4 +8,4 @@ } } } -} \ No newline at end of file +} diff --git a/nextflow_schema.json b/nextflow_schema.json index 872360c3..6bb52772 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -26,10 +26,7 @@ "default": "sra", "description": "Specifies the type of identifier provided via `--input` - available options are 'sra' and 'synapse'.", "fa_icon": "fas fa-keyboard", - "enum": [ - "sra", - "synapse" - ] + "enum": ["sra", "synapse"] }, "ena_metadata_fields": { "type": "string", @@ -248,4 +245,4 @@ "$ref": "#/definitions/generic_options" } ] -} \ No newline at end of file +} From 82213da7d16e19c9418dd0cc3bf4e47e9e53a54b Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Thu, 31 Mar 2022 22:36:17 +0100 Subject: [PATCH 12/26] Update CHANGELOG after merging template updates --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bbf0e90..a6b1be4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Enhancements & fixes -- Updated pipeline template to [nf-core/tools 2.2](https://github.com/nf-core/tools/releases/tag/2.2) +- Updated pipeline template to [nf-core/tools 2.3.2](https://github.com/nf-core/tools/releases/tag/2.3.2) ## [[1.5](https://github.com/nf-core/fetchngs/releases/tag/1.5)] - 2021-12-01 From 56f37b2f395391a616e0ac930e42b51d6f69f37e Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Thu, 31 Mar 2022 22:39:32 +0100 Subject: [PATCH 13/26] Add --outdir to CI tests --- .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 f80ae073..7b5cfdbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: - name: Run pipeline with test data run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,docker + nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results parameters: name: Test workflow parameters @@ -67,6 +67,6 @@ jobs: sudo mv nextflow /usr/local/bin/ - name: Run pipeline with various parameters run: | - nextflow run ${GITHUB_WORKSPACE} -profile test,docker ${{ matrix.parameters }} + nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results ${{ matrix.parameters }} # From 456584a6ca9ba18d6f8b73b5977582084d05e2be Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Mon, 25 Apr 2022 13:15:58 +0100 Subject: [PATCH 14/26] Replace vanilla Linux Biocontainer with Ubuntu --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6b1be4a..66753fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Enhancements & fixes +- [[nf-core/rnaseq#764](https://github.com/nf-core/rnaseq/issues/764)] - Test fails when using GCP due to missing tools in the basic biocontainer - Updated pipeline template to [nf-core/tools 2.3.2](https://github.com/nf-core/tools/releases/tag/2.3.2) ## [[1.5](https://github.com/nf-core/fetchngs/releases/tag/1.5)] - 2021-12-01 From 4bf86f22570c3612e9a69996bbdaea80f2aaad42 Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Mon, 25 Apr 2022 13:57:43 +0100 Subject: [PATCH 15/26] Actually push updated modules --- modules/local/sra_fastq_ftp.nf | 4 ++-- modules/local/sra_merge_samplesheet.nf | 5 ++--- modules/local/synapse_merge_samplesheet.nf | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/local/sra_fastq_ftp.nf b/modules/local/sra_fastq_ftp.nf index edb5241a..c09f66e0 100644 --- a/modules/local/sra_fastq_ftp.nf +++ b/modules/local/sra_fastq_ftp.nf @@ -6,8 +6,8 @@ process SRA_FASTQ_FTP { conda (params.enable_conda ? "conda-forge::sed=4.7" : null) container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/biocontainers/v1.2.0_cv1/biocontainers_v1.2.0_cv1.img' : - 'biocontainers/biocontainers:v1.2.0_cv1' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: tuple val(meta), val(fastq) diff --git a/modules/local/sra_merge_samplesheet.nf b/modules/local/sra_merge_samplesheet.nf index 863dfaa7..ca9c0068 100644 --- a/modules/local/sra_merge_samplesheet.nf +++ b/modules/local/sra_merge_samplesheet.nf @@ -1,10 +1,9 @@ - process SRA_MERGE_SAMPLESHEET { conda (params.enable_conda ? "conda-forge::sed=4.7" : null) container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/biocontainers/v1.2.0_cv1/biocontainers_v1.2.0_cv1.img' : - 'biocontainers/biocontainers:v1.2.0_cv1' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: path ('samplesheets/*') diff --git a/modules/local/synapse_merge_samplesheet.nf b/modules/local/synapse_merge_samplesheet.nf index 01461e14..68bfd68b 100644 --- a/modules/local/synapse_merge_samplesheet.nf +++ b/modules/local/synapse_merge_samplesheet.nf @@ -3,8 +3,8 @@ process SYNAPSE_MERGE_SAMPLESHEET { conda (params.enable_conda ? "conda-forge::sed=4.7" : null) container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://containers.biocontainers.pro/s3/SingImgsRepo/biocontainers/v1.2.0_cv1/biocontainers_v1.2.0_cv1.img' : - 'biocontainers/biocontainers:v1.2.0_cv1' }" + 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : + 'ubuntu:20.04' }" input: path ('samplesheets/*') From b635257ae753765b7c98f54d2cbc4eaacbad3fbb Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Mon, 25 Apr 2022 14:27:03 +0100 Subject: [PATCH 16/26] Use sra-tools container with curl --- modules/local/sra_fastq_ftp.nf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/local/sra_fastq_ftp.nf b/modules/local/sra_fastq_ftp.nf index c09f66e0..4e8a34aa 100644 --- a/modules/local/sra_fastq_ftp.nf +++ b/modules/local/sra_fastq_ftp.nf @@ -4,10 +4,10 @@ process SRA_FASTQ_FTP { label 'process_low' label 'error_retry' - conda (params.enable_conda ? "conda-forge::sed=4.7" : null) + conda (params.enable_conda ? 'bioconda::sra-tools=2.11.0' : null) container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/ubuntu:20.04' : - 'ubuntu:20.04' }" + 'https://depot.galaxyproject.org/singularity/sra-tools:2.11.0--pl5262h314213e_0' : + 'quay.io/biocontainers/sra-tools:2.11.0--pl5262h314213e_0' }" input: tuple val(meta), val(fastq) From c7351884f0664c59876f2f055380025ec12c00a1 Mon Sep 17 00:00:00 2001 From: "Moritz E. Beber" Date: Thu, 12 May 2022 17:32:28 +0200 Subject: [PATCH 17/26] refactor: remove local modules/subworkflows --- bin/retry_with_backoff.sh | 100 ----------------------- modules/local/sratools_fasterqdump.nf | 68 --------------- modules/local/sratools_prefetch.nf | 41 ---------- subworkflows/local/sra_fastq_sratools.nf | 31 ------- 4 files changed, 240 deletions(-) delete mode 100755 bin/retry_with_backoff.sh delete mode 100644 modules/local/sratools_fasterqdump.nf delete mode 100644 modules/local/sratools_prefetch.nf delete mode 100644 subworkflows/local/sra_fastq_sratools.nf diff --git a/bin/retry_with_backoff.sh b/bin/retry_with_backoff.sh deleted file mode 100755 index 4bdbf1e0..00000000 --- a/bin/retry_with_backoff.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env bash - -set -u - -retry_with_backoff() { - local max_attempts=${1} - local delay=${2} - local max_time=${3} - local attempt=1 - local output= - local status= - - shift 3 - - while [ ${attempt} -le ${max_attempts} ]; do - output=$("${@}") - status=${?} - - if [ ${status} -eq 0 ]; then - break - fi - - if [ ${attempt} -lt ${max_attempts} ]; then - echo "Failed attempt ${attempt} of ${max_attempts}. Retrying in ${delay} s." >&2 - sleep ${delay} - elif [ ${attempt} -eq ${max_attempts} ]; then - echo "Failed after ${attempt} attempts." >&2 - return ${status} - fi - - attempt=$(( ${attempt} + 1 )) - delay=$(( ${delay} * 2 )) - if [ ${delay} -ge ${max_time} ]; then - delay=${max_time} - fi - done - - echo "${output}" -} - -RETRY=5 -DELAY=1 -MAX_TIME=60 - -usage() { - echo "Usage:" >&2 - echo "$(basename ${0}) [-h] [-r NUM] [-d NUM] [-m NUM] COMMAND" >&2 - echo "Call the given command with retries and exponential backoff." >&2 - echo "" >&2 - echo " -r NUM Set the number of retry attempts (default ${RETRY})." >&2 - echo " -d NUM Set the base number of seconds to delay (default ${DELAY})." >&2 - echo " -m NUM Set the maximum delay in seconds (default ${MAX_TIME})." >&2 - echo "" >&2 -} - -check_numeric() { - local arg=${1} - if [[ ! ${arg} =~ ^[0-9]+$ ]]; then - echo "Illegal argument: ${arg}" >&2 - echo "Expected a number." >&2 - echo "" >&2 - usage - exit 2 - fi -} - -while getopts ":hr:d:m:" arg; do - case ${arg} in - h) - usage - exit 0 - ;; - r) - check_numeric ${OPTARG} - RETRY=${OPTARG} - ;; - d) - check_numeric ${OPTARG} - DELAY=${OPTARG} - ;; - m) - check_numeric ${OPTARG} - MAX_TIME=${OPTARG} - ;; - ?) - echo "Invalid option: -${OPTARG}" >&2 - echo "" >&2 - usage - exit 2 - ;; - :) - echo "Missing argument for: -${OPTARG}" >&2 - echo "" >&2 - usage - exit 2 - ;; - esac -done - -retry_with_backoff ${RETRY} ${DELAY} ${MAX_TIME} ${@:OPTIND} diff --git a/modules/local/sratools_fasterqdump.nf b/modules/local/sratools_fasterqdump.nf deleted file mode 100644 index 7a75e551..00000000 --- a/modules/local/sratools_fasterqdump.nf +++ /dev/null @@ -1,68 +0,0 @@ - -process SRATOOLS_FASTERQDUMP { - tag "$meta.id" - label 'process_medium' - - conda (params.enable_conda ? 'bioconda::sra-tools=2.11.0 conda-forge::pigz=2.6' : null) - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/mulled-v2-5f89fe0cd045cb1d615630b9261a1d17943a9b6a:6a9ff0e76ec016c3d0d27e0c0d362339f2d787e6-0' : - 'quay.io/biocontainers/mulled-v2-5f89fe0cd045cb1d615630b9261a1d17943a9b6a:6a9ff0e76ec016c3d0d27e0c0d362339f2d787e6-0' }" - - input: - tuple val(meta), path(sra) - - output: - tuple val(meta), path(fastq_output), emit: reads - tuple val(meta), path(md5_output) , emit: md5 - path "versions.yml" , emit: versions - - script: - def args = task.ext.args ?: '' - def args2 = task.ext.args2 ?: '' - def config = "/LIBS/GUID = \"${UUID.randomUUID().toString()}\"\\n/libs/cloud/report_instance_identity = \"true\"\\n" - // Paired-end data extracted by fasterq-dump (--split-3 the default) always creates - // *_1.fastq *_2.fastq files but sometimes also an additional *.fastq file - // for unpaired reads which we ignore here. - fastq_output = meta.single_end ? '*.fastq.gz' : '*_{1,2}.fastq.gz' - md5_output = meta.single_end ? '*.fastq.gz.md5' : '*_{1,2}.fastq.gz.md5' - """ - eval "\$(vdb-config -o n NCBI_SETTINGS | sed 's/[" ]//g')" - if [[ ! -f "\${NCBI_SETTINGS}" ]]; then - mkdir -p "\$(dirname "\${NCBI_SETTINGS}")" - printf '${config}' > "\${NCBI_SETTINGS}" - fi - - fasterq-dump \\ - $args \\ - --threads $task.cpus \\ - ${sra.name} - - pigz \\ - $args2 \\ - --no-name \\ - --processes $task.cpus \\ - *.fastq - - ## Rename FastQ files by meta.id - if [ -f ${sra.name}.fastq.gz ]; then - mv ${sra.name}.fastq.gz ${meta.id}.fastq.gz - md5sum ${meta.id}.fastq.gz > ${meta.id}.fastq.gz.md5 - fi - - if [ -f ${sra.name}_1.fastq.gz ]; then - mv ${sra.name}_1.fastq.gz ${meta.id}_1.fastq.gz - md5sum ${meta.id}_1.fastq.gz > ${meta.id}_1.fastq.gz.md5 - fi - - if [ -f ${sra.name}_2.fastq.gz ]; then - mv ${sra.name}_2.fastq.gz ${meta.id}_2.fastq.gz - md5sum ${meta.id}_2.fastq.gz > ${meta.id}_2.fastq.gz.md5 - fi - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - sratools: \$(fasterq-dump --version 2>&1 | grep -Eo '[0-9.]+') - pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) - END_VERSIONS - """ -} diff --git a/modules/local/sratools_prefetch.nf b/modules/local/sratools_prefetch.nf deleted file mode 100644 index 76679a93..00000000 --- a/modules/local/sratools_prefetch.nf +++ /dev/null @@ -1,41 +0,0 @@ - -process SRATOOLS_PREFETCH { - tag "$id" - label 'process_low' - label 'error_retry' - - conda (params.enable_conda ? 'bioconda::sra-tools=2.11.0' : null) - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/sra-tools:2.11.0--pl5262h314213e_0' : - 'quay.io/biocontainers/sra-tools:2.11.0--pl5262h314213e_0' }" - - input: - tuple val(meta), val(id) - - output: - tuple val(meta), path("$id"), emit: sra - path "versions.yml" , emit: versions - - script: - def args = task.ext.args ?: '' - def config = "/LIBS/GUID = \"${UUID.randomUUID().toString()}\"\\n/libs/cloud/report_instance_identity = \"true\"\\n" - """ - eval "\$(vdb-config -o n NCBI_SETTINGS | sed 's/[" ]//g')" - if [[ ! -f "\${NCBI_SETTINGS}" ]]; then - mkdir -p "\$(dirname "\${NCBI_SETTINGS}")" - printf '${config}' > "\${NCBI_SETTINGS}" - fi - - retry_with_backoff.sh prefetch \\ - $args \\ - --progress \\ - $id - - vdb-validate $id - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - sratools: \$(prefetch --version 2>&1 | grep -Eo '[0-9.]+') - END_VERSIONS - """ -} diff --git a/subworkflows/local/sra_fastq_sratools.nf b/subworkflows/local/sra_fastq_sratools.nf deleted file mode 100644 index 1d59eb61..00000000 --- a/subworkflows/local/sra_fastq_sratools.nf +++ /dev/null @@ -1,31 +0,0 @@ -// -// Download FASTQ sequencing reads from the NCBI's Sequence Read Archive (SRA). -// - -include { SRATOOLS_PREFETCH } from '../../modules/local/sratools_prefetch' -include { SRATOOLS_FASTERQDUMP } from '../../modules/local/sratools_fasterqdump' - -workflow SRA_FASTQ_SRATOOLS { - take: - sra_ids // channel: [ val(meta), val(id) ] - - main: - - ch_versions = Channel.empty() - - // - // Prefetch sequencing reads in SRA format. - // - SRATOOLS_PREFETCH ( sra_ids ) - ch_versions = ch_versions.mix( SRATOOLS_PREFETCH.out.versions.first() ) - - // - // Convert the SRA format into one or more compressed FASTQ files. - // - SRATOOLS_FASTERQDUMP ( SRATOOLS_PREFETCH.out.sra ) - ch_versions = ch_versions.mix( SRATOOLS_FASTERQDUMP.out.versions.first() ) - - emit: - reads = SRATOOLS_FASTERQDUMP.out.reads // channel: [ val(meta), [ reads ] ] - versions = ch_versions // channel: [ versions.yml ] -} From 3de66f289f4186d523a62defc448d5ecfb625fc2 Mon Sep 17 00:00:00 2001 From: "Moritz E. Beber" Date: Thu, 12 May 2022 17:35:44 +0200 Subject: [PATCH 18/26] chore: install nf-core modules for sratools --- modules.json | 9 +++ .../custom/sratoolsncbisettings/main.nf | 20 +++++++ .../custom/sratoolsncbisettings/meta.yml | 28 ++++++++++ .../templates/detect_ncbi_settings.sh | 45 +++++++++++++++ .../modules/sratools/fasterqdump/main.nf | 48 ++++++++++++++++ .../modules/sratools/fasterqdump/meta.yml | 47 ++++++++++++++++ .../nf-core/modules/sratools/prefetch/main.nf | 25 +++++++++ .../modules/sratools/prefetch/meta.yml | 48 ++++++++++++++++ .../prefetch/templates/retry_with_backoff.sh | 55 +++++++++++++++++++ 9 files changed, 325 insertions(+) create mode 100644 modules/nf-core/modules/custom/sratoolsncbisettings/main.nf create mode 100644 modules/nf-core/modules/custom/sratoolsncbisettings/meta.yml create mode 100644 modules/nf-core/modules/custom/sratoolsncbisettings/templates/detect_ncbi_settings.sh create mode 100644 modules/nf-core/modules/sratools/fasterqdump/main.nf create mode 100644 modules/nf-core/modules/sratools/fasterqdump/meta.yml create mode 100644 modules/nf-core/modules/sratools/prefetch/main.nf create mode 100644 modules/nf-core/modules/sratools/prefetch/meta.yml create mode 100644 modules/nf-core/modules/sratools/prefetch/templates/retry_with_backoff.sh diff --git a/modules.json b/modules.json index f39d24ab..fefca2b7 100644 --- a/modules.json +++ b/modules.json @@ -5,6 +5,15 @@ "nf-core/modules": { "custom/dumpsoftwareversions": { "git_sha": "e745e167c1020928ef20ea1397b6b4d230681b4d" + }, + "custom/sratoolsncbisettings": { + "git_sha": "b2dbaa99309a2057efc32ef9d029ed91140068df" + }, + "sratools/fasterqdump": { + "git_sha": "0cdf7767a79faf424645beeff83ecfa5528b6a7c" + }, + "sratools/prefetch": { + "git_sha": "1b228835e9525990db99243cb4f0d07aa6e01bc3" } } } diff --git a/modules/nf-core/modules/custom/sratoolsncbisettings/main.nf b/modules/nf-core/modules/custom/sratoolsncbisettings/main.nf new file mode 100644 index 00000000..21bf3005 --- /dev/null +++ b/modules/nf-core/modules/custom/sratoolsncbisettings/main.nf @@ -0,0 +1,20 @@ +process CUSTOM_SRATOOLSNCBISETTINGS { + tag 'ncbi-settings' + label 'process_low' + + conda (params.enable_conda ? 'bioconda::sra-tools=2.11.0' : null) + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/sra-tools:2.11.0--pl5321ha49a11a_3' : + 'quay.io/biocontainers/sra-tools:2.11.0--pl5321ha49a11a_3' }" + + output: + path('*.mkfg') , emit: ncbi_settings + path 'versions.yml', emit: versions + + when: + task.ext.when == null || task.ext.when + + shell: + config = "/LIBS/GUID = \"${UUID.randomUUID().toString()}\"\\n/libs/cloud/report_instance_identity = \"true\"\\n" + template 'detect_ncbi_settings.sh' +} diff --git a/modules/nf-core/modules/custom/sratoolsncbisettings/meta.yml b/modules/nf-core/modules/custom/sratoolsncbisettings/meta.yml new file mode 100644 index 00000000..01e98856 --- /dev/null +++ b/modules/nf-core/modules/custom/sratoolsncbisettings/meta.yml @@ -0,0 +1,28 @@ +name: "sratoolsncbisettings" +description: Test for the presence of suitable NCBI settings or create them on the fly. +keywords: + - NCBI + - settings + - sra-tools + - prefetch + - fasterq-dump +tools: + - "sratools": + description: "SRA Toolkit and SDK from NCBI" + homepage: https://github.com/ncbi/sra-tools + documentation: https://github.com/ncbi/sra-tools/wiki + tool_dev_url: https://github.com/ncbi/sra-tools + licence: "['Public Domain']" + +output: + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + - ncbi_settings: + type: file + description: An NCBI user settings file. + pattern: "*.mkfg" + +authors: + - "@Midnighter" diff --git a/modules/nf-core/modules/custom/sratoolsncbisettings/templates/detect_ncbi_settings.sh b/modules/nf-core/modules/custom/sratoolsncbisettings/templates/detect_ncbi_settings.sh new file mode 100644 index 00000000..cfe3a324 --- /dev/null +++ b/modules/nf-core/modules/custom/sratoolsncbisettings/templates/detect_ncbi_settings.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +set -u + + +# Get the expected NCBI settings path and define the environment variable +# `NCBI_SETTINGS`. +eval "$(vdb-config -o n NCBI_SETTINGS | sed 's/[" ]//g')" + +# If the user settings do not exist yet, create a file suitable for `prefetch` +# and `fasterq-dump`. If an existing settings file does not contain the required +# values, error out with a helpful message. +if [[ ! -f "${NCBI_SETTINGS}" ]]; then + printf '!{config}' > 'user-settings.mkfg' +else + prefetch --help &> /dev/null + if [[ $? = 78 ]]; then + echo "You have an existing vdb-config at '${NCBI_SETTINGS}' but it is"\ + "missing the required entries for /LIBS/GUID and"\ + "/libs/cloud/report_instance_identity."\ + "Feel free to add the following to your settings file:" >&2 + echo "$(printf '!{config}')" >&2 + exit 1 + fi + fasterq-dump --help &> /dev/null + if [[ $? = 78 ]]; then + echo "You have an existing vdb-config at '${NCBI_SETTINGS}' but it is"\ + "missing the required entries for /LIBS/GUID and"\ + "/libs/cloud/report_instance_identity."\ + "Feel free to add the following to your settings file:" >&2 + echo "$(printf '!{config}')" >&2 + exit 1 + fi + if [[ "${NCBI_SETTINGS}" != *.mkfg ]]; then + echo "The detected settings '${NCBI_SETTINGS}' do not have the required"\ + "file extension '.mkfg'." >&2 + exit 1 + fi + cp "${NCBI_SETTINGS}" ./ +fi + +cat <<-END_VERSIONS > versions.yml +"!{task.process}": + sratools: $(vdb-config --version 2>&1 | grep -Eo '[0-9.]+') +END_VERSIONS diff --git a/modules/nf-core/modules/sratools/fasterqdump/main.nf b/modules/nf-core/modules/sratools/fasterqdump/main.nf new file mode 100644 index 00000000..18f46e51 --- /dev/null +++ b/modules/nf-core/modules/sratools/fasterqdump/main.nf @@ -0,0 +1,48 @@ +process SRATOOLS_FASTERQDUMP { + tag "$meta.id" + label 'process_medium' + + conda (params.enable_conda ? 'bioconda::sra-tools=2.11.0 conda-forge::pigz=2.6' : null) + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-5f89fe0cd045cb1d615630b9261a1d17943a9b6a:6a9ff0e76ec016c3d0d27e0c0d362339f2d787e6-0' : + 'quay.io/biocontainers/mulled-v2-5f89fe0cd045cb1d615630b9261a1d17943a9b6a:6a9ff0e76ec016c3d0d27e0c0d362339f2d787e6-0' }" + + input: + tuple val(meta), path(sra) + path ncbi_settings + + output: + tuple val(meta), path(output), emit: reads + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def args2 = task.ext.args2 ?: '' + // Paired-end data extracted by fasterq-dump (--split-3 the default) always creates + // *_1.fastq *_2.fastq files but sometimes also an additional *.fastq file + // for unpaired reads which we ignore here. + output = meta.single_end ? '*.fastq.gz' : '*_{1,2}.fastq.gz' + """ + export NCBI_SETTINGS="\$PWD/${ncbi_settings}" + + fasterq-dump \\ + $args \\ + --threads $task.cpus \\ + ${sra.name} + + pigz \\ + $args2 \\ + --no-name \\ + --processes $task.cpus \\ + *.fastq + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + sratools: \$(fasterq-dump --version 2>&1 | grep -Eo '[0-9.]+') + pigz: \$( pigz --version 2>&1 | sed 's/pigz //g' ) + END_VERSIONS + """ +} diff --git a/modules/nf-core/modules/sratools/fasterqdump/meta.yml b/modules/nf-core/modules/sratools/fasterqdump/meta.yml new file mode 100644 index 00000000..d6fbd444 --- /dev/null +++ b/modules/nf-core/modules/sratools/fasterqdump/meta.yml @@ -0,0 +1,47 @@ +name: sratools_fasterqdump +description: Extract sequencing reads in FASTQ format from a given NCBI Sequence Read Archive (SRA). +keywords: + - sequencing + - FASTQ + - dump +tools: + - sratools: + description: SRA Toolkit and SDK from NCBI + homepage: https://github.com/ncbi/sra-tools + documentation: https://github.com/ncbi/sra-tools/wiki + tool_dev_url: https://github.com/ncbi/sra-tools + licence: ["Public Domain"] + +input: + - meta: + type: map + description: > + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - sra: + type: directory + description: Directory containing ETL data for the given SRA. + pattern: "*/*.sra" + - ncbi_settings: + type: file + description: > + An NCBI user settings file. + pattern: "*.mkfg" + +output: + - meta: + type: map + description: > + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + - reads: + type: file + description: Extracted FASTQ file or files if the sequencing reads are paired-end. + pattern: "*.fastq.gz" + +authors: + - "@Midnighter" diff --git a/modules/nf-core/modules/sratools/prefetch/main.nf b/modules/nf-core/modules/sratools/prefetch/main.nf new file mode 100644 index 00000000..3426ae12 --- /dev/null +++ b/modules/nf-core/modules/sratools/prefetch/main.nf @@ -0,0 +1,25 @@ +process SRATOOLS_PREFETCH { + tag "$id" + label 'process_low' + + conda (params.enable_conda ? 'bioconda::sra-tools=2.11.0' : null) + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/sra-tools:2.11.0--pl5321ha49a11a_3' : + 'quay.io/biocontainers/sra-tools:2.11.0--pl5321ha49a11a_3' }" + + input: + tuple val(meta), val(id) + path ncbi_settings + + output: + tuple val(meta), path(id), emit: sra + path 'versions.yml' , emit: versions + + when: + task.ext.when == null || task.ext.when + + shell: + args = task.ext.args ?: '' + args2 = task.ext.args2 ?: '5 1 100' // + template 'retry_with_backoff.sh' +} diff --git a/modules/nf-core/modules/sratools/prefetch/meta.yml b/modules/nf-core/modules/sratools/prefetch/meta.yml new file mode 100644 index 00000000..a3a26522 --- /dev/null +++ b/modules/nf-core/modules/sratools/prefetch/meta.yml @@ -0,0 +1,48 @@ +name: sratools_prefetch +description: Download sequencing data from the NCBI Sequence Read Archive (SRA). +keywords: + - sequencing + - fastq + - prefetch +tools: + - sratools: + description: SRA Toolkit and SDK from NCBI + homepage: https://github.com/ncbi/sra-tools + documentation: https://github.com/ncbi/sra-tools/wiki + tool_dev_url: https://github.com/ncbi/sra-tools + licence: ["Public Domain"] + +input: + - meta: + type: map + description: > + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - id: + type: val + description: > + A string denoting an SRA id. + - ncbi_settings: + type: file + description: > + An NCBI user settings file. + pattern: "*.mkfg" + +output: + - meta: + type: map + description: > + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - sra: + type: directory + description: > + Directory containing the ETL data for the given SRA id. + pattern: "*/*.sra" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + +authors: + - "@Midnighter" diff --git a/modules/nf-core/modules/sratools/prefetch/templates/retry_with_backoff.sh b/modules/nf-core/modules/sratools/prefetch/templates/retry_with_backoff.sh new file mode 100644 index 00000000..cec0ab43 --- /dev/null +++ b/modules/nf-core/modules/sratools/prefetch/templates/retry_with_backoff.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +set -u + +retry_with_backoff() { + local max_attempts=${1} + local delay=${2} + local max_time=${3} + local attempt=1 + local output= + local status= + + # Remove the first three arguments to this function in order to access + # the 'real' command with `${@}`. + shift 3 + + while [ ${attempt} -le ${max_attempts} ]; do + output=$("${@}") + status=${?} + + if [ ${status} -eq 0 ]; then + break + fi + + if [ ${attempt} -lt ${max_attempts} ]; then + echo "Failed attempt ${attempt} of ${max_attempts}. Retrying in ${delay} s." >&2 + sleep ${delay} + elif [ ${attempt} -eq ${max_attempts} ]; then + echo "Failed after ${attempt} attempts." >&2 + return ${status} + fi + + attempt=$(( ${attempt} + 1 )) + delay=$(( ${delay} * 2 )) + if [ ${delay} -ge ${max_time} ]; then + delay=${max_time} + fi + done + + echo "${output}" +} + +export NCBI_SETTINGS="$PWD/!{ncbi_settings}" + +retry_with_backoff !{args2} \ + prefetch \ + !{args} \ + !{id} + +vdb-validate !{id} + +cat <<-END_VERSIONS > versions.yml +"!{task.process}": + sratools: $(prefetch --version 2>&1 | grep -Eo '[0-9.]+') +END_VERSIONS From ad15361b924709cc078fb04b69d0ffa61719d920 Mon Sep 17 00:00:00 2001 From: "Moritz E. Beber" Date: Thu, 12 May 2022 17:53:57 +0200 Subject: [PATCH 19/26] refactor: implement new subworkflow --- subworkflows/nf-core/srafastq/main.nf | 38 ++++++++++++++++++++++++ subworkflows/nf-core/srafastq/meta.yml | 40 ++++++++++++++++++++++++++ workflows/sra.nf | 8 +++--- 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 subworkflows/nf-core/srafastq/main.nf create mode 100644 subworkflows/nf-core/srafastq/meta.yml diff --git a/subworkflows/nf-core/srafastq/main.nf b/subworkflows/nf-core/srafastq/main.nf new file mode 100644 index 00000000..f57b6fac --- /dev/null +++ b/subworkflows/nf-core/srafastq/main.nf @@ -0,0 +1,38 @@ +include { CUSTOM_SRATOOLSNCBISETTINGS } from '../../../modules/nf-core/modules/custom/sratoolsncbisettings/main' +include { SRATOOLS_PREFETCH } from '../../../modules/nf-core/modules/sratools/prefetch/main' +include { SRATOOLS_FASTERQDUMP } from '../../../modules/nf-core/modules/sratools/fasterqdump/main' + +/** + * Download FASTQ sequencing reads from the NCBI's Sequence Read Archive (SRA). + */ +workflow SRAFASTQ { + take: + sra_ids // channel: [ val(meta), val(id) ] + + main: + + ch_versions = Channel.empty() + + // + // Detect existing NCBI user settings or create new ones. + // + CUSTOM_SRATOOLSNCBISETTINGS() + def settings = CUSTOM_SRATOOLSNCBISETTINGS.out.ncbi_settings // value channel: path(settings) + ch_versions = ch_versions.mix( CUSTOM_SRATOOLSNCBISETTINGS.out.versions ) + + // + // Prefetch sequencing reads in SRA format. + // + SRATOOLS_PREFETCH ( sra_ids, settings ) + ch_versions = ch_versions.mix( SRATOOLS_PREFETCH.out.versions.first() ) + + // + // Convert the SRA format into one or more compressed FASTQ files. + // + SRATOOLS_FASTERQDUMP ( SRATOOLS_PREFETCH.out.sra, settings ) + ch_versions = ch_versions.mix( SRATOOLS_FASTERQDUMP.out.versions.first() ) + + emit: + reads = SRATOOLS_FASTERQDUMP.out.reads // channel: [ val(meta), [ reads ] ] + versions = ch_versions // channel: [ versions.yml ] +} diff --git a/subworkflows/nf-core/srafastq/meta.yml b/subworkflows/nf-core/srafastq/meta.yml new file mode 100644 index 00000000..873ccaca --- /dev/null +++ b/subworkflows/nf-core/srafastq/meta.yml @@ -0,0 +1,40 @@ +name: sra_fastq +description: Download FASTQ sequencing reads from the NCBI's Sequence Read Archive (SRA). +keywords: + - SRA + - NCBI + - sequencing + - FASTQ + - prefetch + - fasterq-dump +modules: + - custom/sratoolsncbisettings + - sratools/prefetch + - sratools/fasterqdump +input: + - meta: + type: map + description: > + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - id: + type: string + description: > + SRA run identifier. +# TODO Update when we decide on a standard for subworkflow docs +output: + - meta: + type: map + description: > + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: Extracted FASTQ file or files if the sequencing reads are paired-end. + pattern: "*.fastq.gz" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@Midnighter" diff --git a/workflows/sra.nf b/workflows/sra.nf index 9336fcc1..2b3cb498 100644 --- a/workflows/sra.nf +++ b/workflows/sra.nf @@ -26,7 +26,7 @@ include { SRA_TO_SAMPLESHEET } from '../modules/local/sra_to_samplesheet' include { SRA_MERGE_SAMPLESHEET } from '../modules/local/sra_merge_samplesheet' include { MULTIQC_MAPPINGS_CONFIG } from '../modules/local/multiqc_mappings_config' -include { SRA_FASTQ_SRATOOLS } from '../subworkflows/local/sra_fastq_sratools' +include { SRAFASTQ } from '../subworkflows/nf-core/srafastq/main' /* ======================================================================================== @@ -97,16 +97,16 @@ workflow SRA { // // SUBWORKFLOW: Download sequencing reads without FTP links using sra-tools. // - SRA_FASTQ_SRATOOLS ( + SRAFASTQ ( ch_sra_reads.sra.map { meta, reads -> [ meta, meta.run_accession ] } ) - ch_versions = ch_versions.mix(SRA_FASTQ_SRATOOLS.out.versions.first()) + ch_versions = ch_versions.mix(SRAFASTQ.out.versions.first()) // // MODULE: Stage FastQ files downloaded by SRA together and auto-create a samplesheet // SRA_TO_SAMPLESHEET ( - SRA_FASTQ_FTP.out.fastq.mix(SRA_FASTQ_SRATOOLS.out.reads), + SRA_FASTQ_FTP.out.fastq.mix(SRAFASTQ.out.reads), params.nf_core_pipeline ?: '', params.sample_mapping_fields ) From 3630eb63148c1b40801c288f66f8452343b6f251 Mon Sep 17 00:00:00 2001 From: "Moritz E. Beber" Date: Mon, 16 May 2022 10:46:02 +0200 Subject: [PATCH 20/26] chore: add entry to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66753fad..4c614eec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Enhancements & fixes +- [#89](https://github.com/nf-core/fetchngs/pull/89) - Improve detection and usage of the NCBI user settings by using the standardized sra-tools modules from nf-core. + - [[nf-core/rnaseq#764](https://github.com/nf-core/rnaseq/issues/764)] - Test fails when using GCP due to missing tools in the basic biocontainer - Updated pipeline template to [nf-core/tools 2.3.2](https://github.com/nf-core/tools/releases/tag/2.3.2) From 7676eace1a46be6b0a7cc69955064ee9edcbfc33 Mon Sep 17 00:00:00 2001 From: nf-core-bot Date: Mon, 16 May 2022 10:16:14 +0000 Subject: [PATCH 21/26] Template update for nf-core/tools version 2.4 --- .github/workflows/awsfulltest.yml | 3 - .github/workflows/awstest.yml | 3 - .github/workflows/branch.yml | 3 +- .github/workflows/ci.yml | 2 - .github/workflows/fix-linting.yml | 55 ++++++++++ .github/workflows/linting.yml | 4 +- .github/workflows/linting_comment.yml | 1 - .prettierignore | 9 ++ README.md | 25 ++--- assets/email_template.html | 142 ++++++++------------------ bin/check_samplesheet.py | 16 ++- nextflow.config | 2 +- 12 files changed, 135 insertions(+), 130 deletions(-) create mode 100644 .github/workflows/fix-linting.yml create mode 100644 .prettierignore diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 28a35b95..0067883d 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -28,6 +28,3 @@ jobs: "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/fetchngs/results-${{ github.sha }}" } profiles: test_full,aws_tower - nextflow_config: | - process.errorStrategy = 'retry' - process.maxRetries = 3 diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 330cf712..d6cd3108 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -23,6 +23,3 @@ jobs: "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/fetchngs/results-test-${{ github.sha }}" } profiles: test,aws_tower - nextflow_config: | - process.errorStrategy = 'retry' - process.maxRetries = 3 diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 957452c4..708158fa 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -13,7 +13,7 @@ jobs: - name: Check PRs if: github.repository == 'nf-core/fetchngs' run: | - "{ [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/fetchngs ]] && [[ $GITHUB_HEAD_REF = "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]]" + { [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/fetchngs ]] && [[ $GITHUB_HEAD_REF = "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] # If the above check failed, post a comment on the PR explaining the failure # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets @@ -42,4 +42,3 @@ jobs: Thanks again for your contribution! repo-token: ${{ secrets.GITHUB_TOKEN }} allow-repeats: false -# diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71d37bd5..3787d962 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,5 +48,3 @@ jobs: # Remember that you can parallelise this by using strategy.matrix run: | nextflow run ${GITHUB_WORKSPACE} -profile test,docker --outdir ./results - -# diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml new file mode 100644 index 00000000..27e4431c --- /dev/null +++ b/.github/workflows/fix-linting.yml @@ -0,0 +1,55 @@ +name: Fix linting from a comment +on: + issue_comment: + types: [created] + +jobs: + deploy: + # Only run if comment is on a PR with the main repo, and if it contains the magic keywords + if: > + contains(github.event.comment.html_url, '/pull/') && + contains(github.event.comment.body, '@nf-core-bot fix linting') && + github.repository == 'nf-core/fetchngs' + runs-on: ubuntu-latest + steps: + # Use the @nf-core-bot token to check out so we can push later + - uses: actions/checkout@v3 + with: + token: ${{ secrets.nf_core_bot_auth_token }} + + # Action runs on the issue comment, so we don't get the PR by default + # Use the gh cli to check out the PR + - name: Checkout Pull Request + run: gh pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} + + - uses: actions/setup-node@v2 + + - name: Install Prettier + run: npm install -g prettier @prettier/plugin-php + + # Check that we actually need to fix something + - name: Run 'prettier --check' + id: prettier_status + run: | + if prettier --check ${GITHUB_WORKSPACE}; then + echo "::set-output name=result::pass" + else + echo "::set-output name=result::fail" + fi + + - name: Run 'prettier --write' + if: steps.prettier_status.outputs.result == 'fail' + run: prettier --write ${GITHUB_WORKSPACE} + + - name: Commit & push changes + if: steps.prettier_status.outputs.result == 'fail' + run: | + git config user.email "core@nf-co.re" + git config user.name "nf-core-bot" + git config push.default upstream + git add . + git status + git commit -m "[automated] Fix linting with Prettier" + git push diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index e9cf5de3..77358dee 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -48,7 +48,7 @@ jobs: wget -qO- get.nextflow.io | bash sudo mv nextflow /usr/local/bin/ - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v3 with: python-version: "3.6" architecture: "x64" @@ -78,5 +78,3 @@ jobs: lint_log.txt lint_results.md PR_number.txt - -# diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 91c487a1..04758f61 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -26,4 +26,3 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.pr_number.outputs.pr_number }} path: linting-logs/lint_results.md -# diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..d0e7ae58 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +email_template.html +.nextflow* +work/ +data/ +results/ +.DS_Store +testing/ +testing* +*.pyc diff --git a/README.md b/README.md index 2b4c0965..a3d4c2f1 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,19 @@ -# ![nf-core/fetchngs](docs/images/nf-core/fetchngs_logo_light.png#gh-light-mode-only) ![nf-core/fetchngs](docs/images/nf-core/fetchngs_logo_dark.png#gh-dark-mode-only) +# ![nf-core/fetchngs](docs/images/nf-core-fetchngs_logo_light.png#gh-light-mode-only) ![nf-core/fetchngs](docs/images/nf-core-fetchngs_logo_dark.png#gh-dark-mode-only) [![GitHub Actions CI Status](https://github.com/nf-core/fetchngs/workflows/nf-core%20CI/badge.svg)](https://github.com/nf-core/fetchngs/actions?query=workflow%3A%22nf-core+CI%22) [![GitHub Actions Linting Status](https://github.com/nf-core/fetchngs/workflows/nf-core%20linting/badge.svg)](https://github.com/nf-core/fetchngs/actions?query=workflow%3A%22nf-core+linting%22) -[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/fetchngs/results) -[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) - -[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A521.10.3-23aa62.svg?labelColor=000000)](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/) - -[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23fetchngs-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/fetchngs) -[![Follow on Twitter](http://img.shields.io/badge/twitter-%40nf__core-1DA1F2?labelColor=000000&logo=twitter)](https://twitter.com/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) +[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?logo=Amazon%20AWS)](https://nf-co.re/fetchngs/results) +[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8)](https://doi.org/10.5281/zenodo.XXXXXXX) + +[![Nextflow](https://img.shields.io/badge/nextflow%20DSL2-%E2%89%A521.10.3-23aa62.svg)](https://www.nextflow.io/) +[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?logo=anaconda)](https://docs.conda.io/en/latest/) +[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?logo=docker)](https://www.docker.com/) +[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg)](https://sylabs.io/docs/) +[![Launch on Nextflow Tower](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Nextflow%20Tower-%234256e7)](https://tower.nf/launch?pipeline=https://github.com/nf-core/fetchngs) + +[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23fetchngs-4A154B?logo=slack)](https://nfcore.slack.com/channels/fetchngs) +[![Follow on Twitter](http://img.shields.io/badge/twitter-%40nf__core-1DA1F2?logo=twitter)](https://twitter.com/nf_core) +[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?logo=youtube)](https://www.youtube.com/c/nf-core) ## Introduction diff --git a/assets/email_template.html b/assets/email_template.html index 5ebb0f0a..1848021d 100644 --- a/assets/email_template.html +++ b/assets/email_template.html @@ -1,111 +1,53 @@ - - - - + + + + - - - nf-core/fetchngs Pipeline Report - - -
    - + + nf-core/fetchngs Pipeline Report + + +
    -

    nf-core/fetchngs v${version}

    -

    Run Name: $runName

    + - <% if (!success){ out << """ -
    -

    nf-core/fetchngs execution completed unsuccessfully!

    +

    nf-core/fetchngs v${version}

    +

    Run Name: $runName

    + +<% if (!success){ + out << """ +
    +

    nf-core/fetchngs execution completed unsuccessfully!

    The exit status of the task that caused the workflow execution to fail was: $exitStatus.

    The full error message was:

    -
    ${errorReport}
    -
    - """ } else { out << """ -
    +
    ${errorReport}
    +
    + """ +} else { + out << """ +
    nf-core/fetchngs execution completed successfully! -
    - """ } %> +
    + """ +} +%> -

    The workflow was completed at $dateComplete (duration: $duration)

    -

    The command used to launch the workflow was as follows:

    -
    -$commandLine
    +

    The workflow was completed at $dateComplete (duration: $duration)

    +

    The command used to launch the workflow was as follows:

    +
    $commandLine
    -

    Pipeline Configuration:

    - - - <% out << summary.collect{ k,v -> " - - - - - " }.join("\n") %> - -
    - $k - -
    $v
    -
    +

    Pipeline Configuration:

    + + + <% out << summary.collect{ k,v -> "" }.join("\n") %> + +
    $k
    $v
    -

    nf-core/fetchngs

    -

    https://github.com/nf-core/fetchngs

    -
    - +

    nf-core/fetchngs

    +

    https://github.com/nf-core/fetchngs

    + +
    + + diff --git a/bin/check_samplesheet.py b/bin/check_samplesheet.py index 5473b624..3652c63c 100755 --- a/bin/check_samplesheet.py +++ b/bin/check_samplesheet.py @@ -98,7 +98,7 @@ def _validate_pair(self, row): if row[self._first_col] and row[self._second_col]: row[self._single_col] = False assert ( - Path(row[self._first_col]).suffixes == Path(row[self._second_col]).suffixes + Path(row[self._first_col]).suffixes[-2:] == Path(row[self._second_col]).suffixes[-2:] ), "FASTQ pairs must have the same file extensions." else: row[self._single_col] = True @@ -129,6 +129,16 @@ def validate_unique_samples(self): row[self._sample_col] = f"{sample}_T{seen[sample]}" +def read_head(handle, num_lines=10): + """Read the specified number of lines from the current position in the file.""" + lines = [] + for idx, line in enumerate(handle): + if idx == num_lines: + break + lines.append(line) + return "".join(lines) + + def sniff_format(handle): """ Detect the tabular format. @@ -144,13 +154,13 @@ def sniff_format(handle): https://docs.python.org/3/glossary.html#term-text-file """ - peek = handle.read(2048) + peek = read_head(handle) + handle.seek(0) sniffer = csv.Sniffer() if not sniffer.has_header(peek): logger.critical(f"The given sample sheet does not appear to contain a header.") sys.exit(1) dialect = sniffer.sniff(peek) - handle.seek(0) return dialect diff --git a/nextflow.config b/nextflow.config index e004d928..c8a3c7f1 100644 --- a/nextflow.config +++ b/nextflow.config @@ -159,7 +159,7 @@ trace { } dag { enabled = true - file = "${params.tracedir}/pipeline_dag_${trace_timestamp}.svg" + file = "${params.tracedir}/pipeline_dag_${trace_timestamp}.html" } manifest { From 2f260ba4d6d7eb21a8e6bc42e8549c7fe017daca Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Mon, 16 May 2022 21:17:47 +0100 Subject: [PATCH 22/26] Follow up fixes to #57 --- CHANGELOG.md | 7 +++++++ docs/usage.md | 10 ++++------ nextflow_schema.json | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 987d753a..5f2477fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [[1.6](https://github.com/nf-core/fetchngs/releases/tag/1.6)] - 2022-05-17 +- [#57](https://github.com/nf-core/fetchngs/pull/57) - fetchngs fails if FTP is blocked - [#89](https://github.com/nf-core/fetchngs/pull/89) - Improve detection and usage of the NCBI user settings by using the standardized sra-tools modules from nf-core. - [[nf-core/rnaseq#764](https://github.com/nf-core/rnaseq/issues/764)] - Test fails when using GCP due to missing tools in the basic biocontainer - Updated pipeline template to [nf-core/tools 2.4.1](https://github.com/nf-core/tools/releases/tag/2.4.1) +### Software dependencies + +| Dependency | Old version | New version | +| --------------- | ----------- | ----------- | +| `synapseclient` | 2.4.0 | 2.6.0 | + ## [[1.5](https://github.com/nf-core/fetchngs/releases/tag/1.5)] - 2021-12-01 - Finish porting the pipeline to the updated Nextflow DSL2 syntax adopted on nf-core/modules diff --git a/docs/usage.md b/docs/usage.md index f9f20346..b6c97e33 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -57,6 +57,10 @@ The final sample information for the FastQ files used for samplesheet generation As a bonus, the columns in the auto-created samplesheet can be tailored to be accepted out-of-the-box by selected nf-core pipelines, these currently include [nf-core/rnaseq](https://nf-co.re/rnaseq/usage#samplesheet-input) and the Illumina processing mode of [nf-core/viralrecon](https://nf-co.re/viralrecon/usage#illumina-samplesheet-format). You can use the `--nf_core_pipeline` parameter to customise this behaviour e.g. `--nf_core_pipeline rnaseq`. More pipelines will be supported in due course as we adopt and standardise samplesheet input across nf-core. It is highly recommended that you double-check that all of the identifiers you defined using `--input` are represented in the samplesheet. Also, public databases don't reliably hold information such as strandedness information so you may need to amend these entries too if for example your samplesheet was created by providing `--nf_core_pipeline rnaseq`. +### Bypass `FTP` data download + +If FTP connections are blocked on your network use the [`--force_sratools_download`](https://nf-co.re/fetchngs/parameters#force_sratools_download) parameter to force the pipeline to download data using sra-tools instead of the ENA FTP. + ## Running the pipeline The typical command for running the pipeline is as follows: @@ -259,9 +263,3 @@ We recommend adding the following line to your environment to limit this (typica ```console NXF_OPTS='-Xms1g -Xmx4g' ``` - -## Troubleshooting - -### `FTP` download is blocked at my workplace/institution, how can I still use _nf-core/fetchngs_ ? - -If downloading data with FTP is blocked on your network connection, you may want to use the [`--force_sratools_download`](https://nf-co.re/fetchngs/1.5/parameters#force_sratools_download) flag to force fetchngs download using [sra-tools](https://github.com/ncbi/sra-tools) instead of the ENA FTP. diff --git a/nextflow_schema.json b/nextflow_schema.json index b476e227..2bc7c52e 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -49,7 +49,7 @@ "type": "boolean", "fa_icon": "fas fa-tools", "description": "Force download FASTQ files via sra-tools instead of via the ENA FTP.", - "help_text": "If downloading data through FTP is blocked on your network connection, you may want to use this flag to force fetchngs to download using sra-tools instead of the ENA FTP. " + "help_text": "If FTP connections are blocked on your network use this flag to force the pipeline to download data using sra-tools instead of the ENA FTP." }, "skip_fastq_download": { "type": "boolean", From 7086977dc2296d648c00b2b26561aa6936d3caf6 Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Mon, 16 May 2022 21:24:53 +0100 Subject: [PATCH 23/26] Fix nf-core linting --- LICENSE | 2 +- nextflow.config | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 515e402d..7a9b6d5a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) Harshil Patel +Copyright (c) Harshil Patel, Moritz E. Beber and Jose Espinosa-Carrasco Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/nextflow.config b/nextflow.config index 40293d3b..237190ec 100644 --- a/nextflow.config +++ b/nextflow.config @@ -67,7 +67,6 @@ try { // System.err.println("WARNING: Could not load nf-core/config/fetchngs profiles: ${params.custom_config_base}/pipeline/fetchngs.config") // } - profiles { debug { process.beforeScript = 'echo $HOSTNAME' } conda { From d023066e2f7af9fd80e745c058aab49efd97b962 Mon Sep 17 00:00:00 2001 From: "Moritz E. Beber" Date: Tue, 17 May 2022 11:28:31 +0200 Subject: [PATCH 24/26] fix: use parameter for publishing mode refactor: adjust FASTQ pattern --- conf/modules.config | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/conf/modules.config b/conf/modules.config index 1ff70172..82a5f75c 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -24,7 +24,7 @@ process { withName: CUSTOM_DUMPSOFTWAREVERSIONS { publishDir = [ path: { "${params.outdir}/pipeline_info" }, - mode: 'copy', + mode: params.publish_dir_mode, pattern: '*_versions.yml' ] } @@ -48,7 +48,7 @@ if (params.input_type == 'sra') { withName: SRA_RUNINFO_TO_FTP { publishDir = [ path: { "${params.outdir}/metadata" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] } @@ -58,12 +58,12 @@ if (params.input_type == 'sra') { publishDir = [ [ path: { "${params.outdir}/fastq" }, - mode: 'copy', - pattern: "*gz" + mode: params.publish_dir_mode, + pattern: "*.fastq.gz" ], [ path: { "${params.outdir}/fastq/md5" }, - mode: 'copy', + mode: params.publish_dir_mode, pattern: "*.md5" ] ] @@ -80,12 +80,12 @@ if (params.input_type == 'sra') { publishDir = [ [ path: { "${params.outdir}/fastq" }, - mode: 'copy', - pattern: "*gz" + mode: params.publish_dir_mode, + pattern: "*.fastq.gz" ], [ path: { "${params.outdir}/fastq/md5" }, - mode: 'copy', + mode: params.publish_dir_mode, pattern: "*.md5" ] ] @@ -101,7 +101,7 @@ if (params.input_type == 'sra') { withName: SRA_MERGE_SAMPLESHEET { publishDir = [ path: { "${params.outdir}/samplesheet" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] } @@ -109,7 +109,7 @@ if (params.input_type == 'sra') { withName: MULTIQC_MAPPINGS_CONFIG { publishDir = [ path: { "${params.outdir}/samplesheet" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] } @@ -129,7 +129,7 @@ if (params.input_type == 'synapse') { ext.args = '--long' publishDir = [ path: { "${params.outdir}/metadata" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] } @@ -138,12 +138,12 @@ if (params.input_type == 'synapse') { publishDir = [ [ path: { "${params.outdir}/fastq" }, - mode: 'copy', - pattern: "*gz" + mode: params.publish_dir_mode, + pattern: "*.fastq.gz" ], [ path: { "${params.outdir}/fastq/md5" }, - mode: 'copy', + mode: params.publish_dir_mode, pattern: "*.md5" ] ] @@ -152,7 +152,7 @@ if (params.input_type == 'synapse') { withName: SYNAPSE_SHOW { publishDir = [ path: { "${params.outdir}/metadata" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] } @@ -167,7 +167,7 @@ if (params.input_type == 'synapse') { withName: SYNAPSE_MERGE_SAMPLESHEET { publishDir = [ path: { "${params.outdir}/samplesheet" }, - mode: 'copy', + mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] } From 7f6e4928613fb5e0f03f9f70e52ad3431c87e9b1 Mon Sep 17 00:00:00 2001 From: "Moritz E. Beber" Date: Tue, 17 May 2022 11:36:17 +0200 Subject: [PATCH 25/26] chore: describe change --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2477fd..8d5d7efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [[1.6](https://github.com/nf-core/fetchngs/releases/tag/1.6)] - 2022-05-17 +- [#93](https://github.com/nf-core/fetchngs/pull/93) - Adjust modules configuration to respect the `publish_dir_mode` parameter. - [#57](https://github.com/nf-core/fetchngs/pull/57) - fetchngs fails if FTP is blocked - [#89](https://github.com/nf-core/fetchngs/pull/89) - Improve detection and usage of the NCBI user settings by using the standardized sra-tools modules from nf-core. - [[nf-core/rnaseq#764](https://github.com/nf-core/rnaseq/issues/764)] - Test fails when using GCP due to missing tools in the basic biocontainer From e697f22fbd5696060fee11505027fa0ed8051b7c Mon Sep 17 00:00:00 2001 From: Harshil Patel Date: Tue, 17 May 2022 11:54:01 +0100 Subject: [PATCH 26/26] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d5d7efc..9cdb7a0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [[1.6](https://github.com/nf-core/fetchngs/releases/tag/1.6)] - 2022-05-17 -- [#93](https://github.com/nf-core/fetchngs/pull/93) - Adjust modules configuration to respect the `publish_dir_mode` parameter. - [#57](https://github.com/nf-core/fetchngs/pull/57) - fetchngs fails if FTP is blocked - [#89](https://github.com/nf-core/fetchngs/pull/89) - Improve detection and usage of the NCBI user settings by using the standardized sra-tools modules from nf-core. +- [#93](https://github.com/nf-core/fetchngs/pull/93) - Adjust modules configuration to respect the `publish_dir_mode` parameter. - [[nf-core/rnaseq#764](https://github.com/nf-core/rnaseq/issues/764)] - Test fails when using GCP due to missing tools in the basic biocontainer - Updated pipeline template to [nf-core/tools 2.4.1](https://github.com/nf-core/tools/releases/tag/2.4.1)