diff --git a/.github/workflows/fix-linting.yml b/.github/workflows/fix-linting.yml new file mode 100644 index 0000000..20c91c6 --- /dev/null +++ b/.github/workflows/fix-linting.yml @@ -0,0 +1,71 @@ +name: fix-linting +run-name: fix linting (automated) +on: + issue_comment: + types: [created] + +jobs: + fix-linting: + # 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/modules' + runs-on: ubuntu-latest + steps: + # Use the @nf-core-bot token to check out so we can push later + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + with: + token: ${{ secrets.nf_core_bot_auth_token }} + + # indication that the linting is being fixed + - name: React on comment + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + comment-id: ${{ github.event.comment.id }} + reactions: eyes + + # 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@60edb5dd545a775178f52524783378180af0d1f8 # v4 + + - 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: Post nothing-to-do comment + if: steps.prettier_status.outputs.result == 'pass' + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Nothing for me to do here! :shrug: + This is probably because the linting errors come from `nf-core lint` and have to be fixed manually (or with `nf-core lint --fix`). + + - 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/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b366a48 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,286 @@ +name: Run tests +on: + pull_request: + branches: [main] + workflow_dispatch: + +# Cancel if a newer run is started +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 + # FIXME Flip this off once we get to less than a couple hundred. Adding + # this so it will only run against changed files. It'll make it much + # easier to fix these as they come up rather than everything at once. + with: + extra_args: "" + + prettier: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + + - name: Install NodeJS + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4 + with: + node-version: "20" + + - name: Install Prettier + run: npm install -g prettier@3.1.0 + + - name: Run Prettier --check + run: prettier --check . + + editorconfig: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + + - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4 + with: + node-version: "20" + + - name: Install editorconfig-checker + run: npm install -g editorconfig-checker + + - name: Run ECLint check + run: editorconfig-checker -exclude README.md $(git ls-files | grep -v test) + + nf-test-changes: + name: nf-test-changes + runs-on: ubuntu-latest + outputs: + # Expose detected tags as 'modules' and 'workflows' output variables + paths: ${{ steps.list.outputs.components }} + modules: ${{ steps.outputs.outputs.modules }} + subworkflows: ${{ steps.outputs.outputs.subworkflows}} + # Prod for version bumping + + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + with: + fetch-depth: 0 + + - name: List nf-test files + id: list + uses: adamrtalbot/detect-nf-test-changes@6e67b7a6bd3caf8571b99cab3ab764c0e758f55c # v0.0.3 + with: + head: ${{ github.sha }} + base: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} + n_parents: 2 + + - name: Separate modules and subworkflows + id: outputs + run: | + echo modules=$(echo '${{ steps.list.outputs.components }}' | jq -c '. | map(select(contains("modules"))) | map(gsub("modules/class-modules/"; ""))') >> $GITHUB_OUTPUT + echo subworkflows=$(echo '${{ steps.list.outputs.components }}' | jq '. | map(select(contains("subworkflows"))) | map(gsub("subworkflows/class-modules/"; ""))') >> $GITHUB_OUTPUT + + - name: debug + run: | + echo ${{ steps.outputs.outputs.modules }} + echo ${{ steps.outputs.outputs.subworkflows }} + + nf-core-lint-modules: + runs-on: ubuntu-latest + name: nf-core-lint-modules + needs: nf-test-changes + if: ( needs.nf-test-changes.outputs.modules != '[]') + strategy: + fail-fast: false + matrix: + tags: ["${{ fromJson(needs.nf-test-changes.outputs.modules) }}"] + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + + - name: Set up Python + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + with: + python-version: "3.11" + + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4 + id: cache-pip + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip + restore-keys: | + ${{ runner.os }}-pip + + - name: Install pip + run: python -m pip install --upgrade pip + + - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4 + with: + distribution: "temurin" + java-version: "17" + + - name: Setup Nextflow + uses: nf-core/setup-nextflow@v2 + + - name: Install nf-core tools development version + run: python -m pip install --upgrade --force-reinstall git+https://github.com/nf-core/tools.git@dev + + - name: Lint module ${{ matrix.tags }} + run: nf-core modules --git-remote https://github.com/mirpedrol/class-modules lint ${{ matrix.tags }} + + nf-core-lint-subworkflows: + runs-on: ubuntu-latest + name: nf-core-lint-modules + needs: nf-test-changes + if: ( needs.nf-test-changes.outputs.subworkflows != '[]') + strategy: + fail-fast: false + matrix: + tags: + [ + "${{ fromJson(needs.nf-test-changes.outputs.subworkflows) }}", + ] + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + + - name: Set up Python + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + with: + python-version: "3.11" + + - name: Install pip + run: python -m pip install --upgrade pip + + - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4 + with: + distribution: "temurin" + java-version: "17" + + - name: Setup Nextflow + uses: nf-core/setup-nextflow@561fcfc7146dcb12e3871909b635ab092a781f34 # v2 + + - name: Install nf-core tools development version + run: python -m pip install --upgrade --force-reinstall git+https://github.com/nf-core/tools.git@dev + + - name: Lint module ${{ matrix.tags }} + run: nf-core subworkflows --git-remote https://github.com/mirpedrol/class-modules lint ${{ matrix.tags }} + + nf-test: + runs-on: ubuntu-latest + name: nf-test + needs: nf-test-changes + if: ( needs.nf-test-changes.outputs.paths != '[]' ) + strategy: + fail-fast: false + matrix: + path: ["${{ fromJson(needs.nf-test-changes.outputs.paths) }}"] + profile: [conda, docker, singularity] + env: + NXF_ANSI_LOG: false + NFTEST_VER: "0.8.4" + + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + + - uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4 + with: + distribution: "temurin" + java-version: "17" + - name: Setup Nextflow + uses: nf-core/setup-nextflow@v2 + + - name: Install nf-test + uses: nf-core/setup-nf-test@v1 + + - name: Setup apptainer + if: matrix.profile == 'singularity' + uses: eWaterCycle/setup-apptainer@main + + - name: Set up Singularity + if: matrix.profile == 'singularity' + uses: eWaterCycle/setup-singularity@v7 + with: + singularity-version: 3.8.3 + + - name: Set up Python + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5 + with: + python-version: "3.11" + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4 + id: cache-pip-pdiff + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-pdiff + restore-keys: | + ${{ runner.os }}-pip-pdiff + + - name: Install Python dependencies + run: python -m pip install --upgrade pip pdiff cryptography + + - name: Set up miniconda + uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3 + with: + miniconda-version: "latest" + auto-update-conda: true + channels: conda-forge,bioconda,defaults + + - name: Conda setup + run: | + conda clean -a + conda install -n base conda-libmamba-solver + conda config --set solver libmamba + echo $(realpath $CONDA)/condabin >> $GITHUB_PATH + echo $(realpath python) >> $GITHUB_PATH + + # Test the module + - name: Run nf-test + env: + NFT_DIFF: "pdiff" + NFT_DIFF_ARGS: "--line-numbers --width 120 --expand-tabs=2" + run: | + PROFILE=${{ matrix.profile }} + + NFT_WORKDIR=~ \ + nf-test test \ + --profile=${{ matrix.profile }} \ + --tap=test.tap \ + --verbose \ + ${{ matrix.path }} + + - uses: pcolby/tap-summary@0959cbe1d4422e62afc65778cdaea6716c41d936 # v1 + with: + path: >- + test.tap + + - name: Clean up + if: always() + run: | + sudo rm -rf /home/ubuntu/tests/ + + confirm-pass: + runs-on: ubuntu-latest + needs: + [ + prettier, + editorconfig, + nf-core-lint-modules, + nf-core-lint-subworkflows, + nf-test-changes, + nf-test, + ] + if: always() + steps: + - name: All tests ok + if: ${{ success() || !contains(needs.*.result, 'failure') }} + run: exit 0 + - name: One or more tests failed + if: ${{ contains(needs.*.result, 'failure') }} + run: exit 1 + + - name: debug-print + if: always() + run: | + echo "toJSON(needs) = ${{ toJSON(needs) }}" + echo "toJSON(needs.*.result) = ${{ toJSON(needs.*.result) }}" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5b85a5d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,31 @@ +repos: + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v3.1.0" + hooks: + - id: prettier + additional_dependencies: + - prettier@3.2.5 + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.28.5 + hooks: + - id: check-jsonschema + # match meta.ymls in one of the subdirectories of modules/nf-core + files: ^modules/nf-core/.*/meta\.yml$ + args: ["--schemafile", "modules/yaml-schema.json"] + - id: check-jsonschema + # match meta.ymls in one of the subdirectories of subworkflows/nf-core + files: ^subworkflows/nf-core/.*/meta\.yml$ + args: ["--schemafile", "subworkflows/yaml-schema.json"] + - id: check-github-workflows + - repo: https://github.com/renovatebot/pre-commit-hooks + rev: 37.408.2 + hooks: + - id: renovate-config-validator + # use ruff for python files + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.10 + hooks: + - id: ruff + files: \.py$ + args: [--fix, --exit-non-zero-on-fix, "--select", "I,E1,E4,E7,E9,F,UP,N"] # sort imports and fix (rules taken from nf-core/tools) + - id: ruff-format # formatter diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..41fc347 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,17 @@ +includes/Maven_Pro/ + +# gitignore +.nextflow* +work/ +results/ +test_output/ +output/ +.DS_Store +*.code-workspace +tests/data/ +.screenrc +.*.sw? +__pycache__ +*.pyo +*.pyc +.github/renovate.json5 diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..c81f9a7 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1 @@ +printWidth: 120 diff --git a/README.md b/README.md index 55c3400..0ef2868 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,30 @@ -# class-modules -A subset of curated nf-core/module and module templates +# class modules + +[![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/) + +![GitHub Actions Coda Linting](https://github.com/nf-core/modules/workflows/Code%20Linting/badge.svg) + +> [!NOTE] +> THIS REPOSITORY IS A SUBSET OF THE [nf-core/modules](https://github.com/nf-core/modules) REPOSITORY + +> [!WARNING] +> UNDER DEVELOPEMENT + +A repository for hosting curated [Nextflow DSL2](https://www.nextflow.io/docs/latest/dsl2.html) module files containing tool-specific process definitions and their associated documentation. + +These modules are part of classes of modules depending on their usage. Alternative tools belong to the same class. + +## Table of contents + +- [Using nf-core/tools](#using-nf-coretools) + +### Using nf-core/tools + +The usual nf-core/tools can be used by specifying the appropriate repository. + +```bash +nf-core modules --git-remote https://github.com/mirpedrol/class-modules +``` diff --git a/modules/class-modules/clustalo/align/environment.yml b/modules/class-modules/clustalo/align/environment.yml new file mode 100644 index 0000000..be1eef9 --- /dev/null +++ b/modules/class-modules/clustalo/align/environment.yml @@ -0,0 +1,8 @@ +name: clustalo_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::clustalo=1.2.4 + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/clustalo/align/main.nf b/modules/class-modules/clustalo/align/main.nf new file mode 100644 index 0000000..eb230ca --- /dev/null +++ b/modules/class-modules/clustalo/align/main.nf @@ -0,0 +1,57 @@ +process CLUSTALO_ALIGN { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-4cefc38542f86c17596c29b35a059de10387c6a7:adbe4fbad680f9beb083956d79128039a727e7b3-0': + 'biocontainers/mulled-v2-4cefc38542f86c17596c29b35a059de10387c6a7:adbe4fbad680f9beb083956d79128039a727e7b3-0' }" + + input: + tuple val(meta) , path(fasta) + tuple val(meta2), path(tree) + val(compress) + + output: + tuple val(meta), path("*.aln{.gz,}"), emit: alignment + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def write_output = compress ? "--force -o >(pigz -cp ${task.cpus} > ${prefix}.aln.gz)" : "> ${prefix}.aln" + // using >() is necessary to preserve the return value, + // so nextflow knows to display an error when it failed + // the --force -o is necessary, as clustalo expands the commandline input, + // causing it to treat the pipe as a parameter and fail + // this way, the command expands to /dev/fd/, and --force allows writing output to an already existing file + """ + clustalo \ + -i ${fasta} \ + --threads=${task.cpus} \ + $args \ + $write_output + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + clustalo: \$( clustalo --version ) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.aln${compress ? '.gz' : ''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + clustalo: \$( clustalo --version ) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/clustalo/align/meta.yml b/modules/class-modules/clustalo/align/meta.yml new file mode 100644 index 0000000..469b3a3 --- /dev/null +++ b/modules/class-modules/clustalo/align/meta.yml @@ -0,0 +1,61 @@ +name: "clustalo_align" +description: Align sequences using Clustal Omega +keywords: + - alignment + - MSA + - genomics +tools: + - "clustalo": + description: "Latest version of Clustal: a multiple sequence alignment program for DNA or proteins" + homepage: "http://www.clustal.org/omega/" + documentation: "http://www.clustal.org/omega/" + tool_dev_url: "http://www.clustal.org/omega/" + doi: "10.1038/msb.2011.75" + licence: ["GPL v2"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - fasta: + type: file + description: Input sequences in FASTA format + pattern: "*.{fa,fasta}" + - meta2: + type: map + description: | + Groovy Map containing tree information + e.g. `[ id:'test_tree']` + - tree: + type: file + description: Input guide tree in Newick format + pattern: "*.{dnd}" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - alignment: + type: file + description: Alignment file, in gzipped fasta format + pattern: "*.aln{.gz,}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@luisas" + - "@joseespinosa" +maintainers: + - "@luisas" + - "@joseespinosa" + - "@lrauschning" diff --git a/modules/class-modules/clustalo/align/tests/main.nf.test b/modules/class-modules/clustalo/align/tests/main.nf.test new file mode 100644 index 0000000..3edd36a --- /dev/null +++ b/modules/class-modules/clustalo/align/tests/main.nf.test @@ -0,0 +1,98 @@ +nextflow_process { + + name "Test Process CLUSTALO_ALIGN" + script "../main.nf" + process "CLUSTALO_ALIGN" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "clustalo" + tag "clustalo/align" + tag "clustalo/guidetree" + + test("sarscov2 - contigs-fasta - uncompressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment - uncompressed")}, + { assert snapshot(process.out.versions).match("versions0") } + ) + } + + } + + test("sarscov2 - contigs-fasta - compressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment - compressed")}, + { assert snapshot(process.out.versions).match("versions1") } + ) + } + + } + + test("sarscov2 - contigs-fasta - guide_tree") { + + setup { + + run("CLUSTALO_GUIDETREE") { + script "../../guidetree/main.nf" + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = CLUSTALO_GUIDETREE.out.tree.collect{ meta, tree -> tree }.map{ tree -> [[ id: 'test_summary'], tree]} + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("with_guide_tree_alignment")}, + { assert snapshot(process.out.versions).match("with_guide_tree_versions") } + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/clustalo/align/tests/main.nf.test.snap b/modules/class-modules/clustalo/align/tests/main.nf.test.snap new file mode 100644 index 0000000..d7d6987 --- /dev/null +++ b/modules/class-modules/clustalo/align/tests/main.nf.test.snap @@ -0,0 +1,57 @@ +{ + "alignment - compressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,74bb9a2820a91cf68db94dbd46787722" + ] + ] + ], + "timestamp": "2024-02-09T19:39:46.647351958" + }, + "versions": { + "content": [ + [ + "versions.yml:md5,327da6a4250a6b7c4e45cddaa1f56280" + ] + ], + "timestamp": "2024-02-09T19:39:14.826528498" + }, + "alignment - uncompressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln:md5,74bb9a2820a91cf68db94dbd46787722" + ] + ] + ], + "timestamp": "2024-02-09T19:39:14.786480272" + }, + "with_guide_tree_alignment": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,74bb9a2820a91cf68db94dbd46787722" + ] + ] + ], + "timestamp": "2024-02-09T19:40:45.057777867" + }, + "with_guide_tree_versions": { + "content": [ + [ + "versions.yml:md5,327da6a4250a6b7c4e45cddaa1f56280" + ] + ], + "timestamp": "2024-02-09T19:40:45.122824595" + } +} \ No newline at end of file diff --git a/modules/class-modules/clustalo/align/tests/nextflow.config b/modules/class-modules/clustalo/align/tests/nextflow.config new file mode 100644 index 0000000..71db4c7 --- /dev/null +++ b/modules/class-modules/clustalo/align/tests/nextflow.config @@ -0,0 +1,3 @@ +process { + ext.args = { tree ? "--guidetree-in=$tree" : "" } +} \ No newline at end of file diff --git a/modules/class-modules/clustalo/align/tests/tags.yml b/modules/class-modules/clustalo/align/tests/tags.yml new file mode 100644 index 0000000..58bd277 --- /dev/null +++ b/modules/class-modules/clustalo/align/tests/tags.yml @@ -0,0 +1,2 @@ +clustalo/align: + - "modules/nf-core/clustalo/align/**" diff --git a/modules/class-modules/clustalo/guidetree/environment.yml b/modules/class-modules/clustalo/guidetree/environment.yml new file mode 100644 index 0000000..38b2f5b --- /dev/null +++ b/modules/class-modules/clustalo/guidetree/environment.yml @@ -0,0 +1,7 @@ +name: clustalo_guidetree +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::clustalo=1.2.4 diff --git a/modules/class-modules/clustalo/guidetree/main.nf b/modules/class-modules/clustalo/guidetree/main.nf new file mode 100644 index 0000000..b94f2aa --- /dev/null +++ b/modules/class-modules/clustalo/guidetree/main.nf @@ -0,0 +1,47 @@ +process CLUSTALO_GUIDETREE { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/clustalo:1.2.4--h87f3376_5': + 'biocontainers/clustalo:1.2.4--h87f3376_5' }" + + input: + tuple val(meta), path(fasta) + + output: + tuple val(meta), path("*.dnd"), emit: tree + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + clustalo \\ + -i ${fasta} \\ + --guidetree-out ${prefix}.dnd \\ + --threads=${task.cpus} \\ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + clustalo: \$( clustalo --version ) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.dnd + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + clustalo: \$( clustalo --version ) + END_VERSIONS + """ +} diff --git a/modules/class-modules/clustalo/guidetree/meta.yml b/modules/class-modules/clustalo/guidetree/meta.yml new file mode 100644 index 0000000..b8e0235 --- /dev/null +++ b/modules/class-modules/clustalo/guidetree/meta.yml @@ -0,0 +1,46 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +name: "clustalo_guidetree" +description: Renders a guidetree in clustalo +keywords: + - guide tree + - msa + - newick +tools: + - "clustalo": + description: "Latest version of Clustal: a multiple sequence alignment program for DNA or proteins" + homepage: "http://www.clustal.org/omega/" + documentation: "http://www.clustal.org/omega/" + tool_dev_url: "http://www.clustal.org/omega/" + doi: "10.1038/msb.2011.75" + licence: ["GPL v2"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - fasta: + type: file + description: Input sequences in FASTA format + pattern: "*.{fa,fasta}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - tree: + type: file + description: Guide tree file in Newick format + pattern: "*.{dnd}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@luisas" + - "@JoseEspinosa" +maintainers: + - "@luisas" + - "@JoseEspinosa" diff --git a/modules/class-modules/clustalo/guidetree/tests/main.nf.test b/modules/class-modules/clustalo/guidetree/tests/main.nf.test new file mode 100644 index 0000000..d670ae0 --- /dev/null +++ b/modules/class-modules/clustalo/guidetree/tests/main.nf.test @@ -0,0 +1,33 @@ +nextflow_process { + + name "Test Process CLUSTALO_GUIDETREE" + script "../main.nf" + process "CLUSTALO_GUIDETREE" + + tag "modules" + tag "modules_nfcore" + tag "clustalo" + tag "clustalo/guidetree" + + test("sarscov2 - contigs-fasta") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.tree).match("tree")}, + { assert snapshot(process.out.versions).match("versions") } + ) + } + } + +} diff --git a/modules/class-modules/clustalo/guidetree/tests/main.nf.test.snap b/modules/class-modules/clustalo/guidetree/tests/main.nf.test.snap new file mode 100644 index 0000000..6e3fdfc --- /dev/null +++ b/modules/class-modules/clustalo/guidetree/tests/main.nf.test.snap @@ -0,0 +1,23 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,64796b9beb7201a42b2c78cbdad51049" + ] + ], + "timestamp": "2023-11-27T22:49:13.44908228" + }, + "tree": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.dnd:md5,5428bad500a0a0bd985744bec1a12a70" + ] + ] + ], + "timestamp": "2023-11-27T22:49:13.43743393" + } +} \ No newline at end of file diff --git a/modules/class-modules/clustalo/guidetree/tests/tags.yml b/modules/class-modules/clustalo/guidetree/tests/tags.yml new file mode 100644 index 0000000..9b07c86 --- /dev/null +++ b/modules/class-modules/clustalo/guidetree/tests/tags.yml @@ -0,0 +1,2 @@ +clustalo/guidetree: + - "modules/nf-core/clustalo/guidetree/**" diff --git a/modules/class-modules/famsa/align/environment.yml b/modules/class-modules/famsa/align/environment.yml new file mode 100644 index 0000000..c41cda2 --- /dev/null +++ b/modules/class-modules/famsa/align/environment.yml @@ -0,0 +1,7 @@ +name: famsa_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::famsa=2.2.2 diff --git a/modules/class-modules/famsa/align/main.nf b/modules/class-modules/famsa/align/main.nf new file mode 100644 index 0000000..096d8ff --- /dev/null +++ b/modules/class-modules/famsa/align/main.nf @@ -0,0 +1,53 @@ + + +process FAMSA_ALIGN { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/famsa:2.2.2--h9f5acd7_0': + 'biocontainers/famsa:2.2.2--h9f5acd7_0' }" + + input: + tuple val(meta) , path(fasta) + tuple val(meta2), path(tree) + val(compress) + + output: + tuple val(meta), path("*.aln{.gz,}"), emit: alignment + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def compress_args = compress ? '-gz' : '' + def prefix = task.ext.prefix ?: "${meta.id}" + def options_tree = tree ? "-gt import $tree" : "" + """ + famsa $options_tree \\ + $compress_args \\ + $args \\ + -t ${task.cpus} \\ + ${fasta} \\ + ${prefix}.aln${compress ? '.gz':''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + famsa: \$( famsa -help 2>&1 | head -n 2 | tail -n 1 | sed 's/ version //g' ) + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.aln${compress ? '.gz' : ''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + famsa: \$( famsa -help 2>&1 | head -n 2 | tail -n 1 | sed 's/ version //g' ) + END_VERSIONS + """ +} diff --git a/modules/class-modules/famsa/align/meta.yml b/modules/class-modules/famsa/align/meta.yml new file mode 100644 index 0000000..6acf3c2 --- /dev/null +++ b/modules/class-modules/famsa/align/meta.yml @@ -0,0 +1,58 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +name: "famsa_align" +description: Aligns sequences using FAMSA +keywords: + - alignment + - MSA + - genomics +tools: + - "famsa": + description: "Algorithm for large-scale multiple sequence alignments" + homepage: "https://github.com/refresh-bio/FAMSA" + documentation: "https://github.com/refresh-bio/FAMSA" + tool_dev_url: "https://github.com/refresh-bio/FAMSA" + doi: "10.1038/srep33964" + licence: ["GPL v3"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - fasta: + type: file + description: Input sequences in FASTA format + pattern: "*.{fa,fasta}" + - meta2: + type: map + description: | + Groovy Map containing tree information + e.g. `[ id:'test_tree']` + - tree: + type: file + description: Input guide tree in Newick format + pattern: "*.{dnd}" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is handled by passing '-gz' to FAMSA along with any other options specified in task.ext.args. +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - alignment: + type: file + description: Alignment file, in FASTA format. May be gzipped or uncompressed, depending on if compress is set to true or false + pattern: "*.aln{.gz,}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@luisas" + - "@JoseEspinosa" +maintainers: + - "@luisas" + - "@JoseEspinosa" diff --git a/modules/class-modules/famsa/align/tests/main.nf.test b/modules/class-modules/famsa/align/tests/main.nf.test new file mode 100644 index 0000000..2d7cac3 --- /dev/null +++ b/modules/class-modules/famsa/align/tests/main.nf.test @@ -0,0 +1,96 @@ +nextflow_process { + + name "Test Process FAMSA_ALIGN" + script "../main.nf" + process "FAMSA_ALIGN" + + tag "modules" + tag "modules_nfcore" + tag "famsa" + tag "famsa/align" + tag "famsa/guidetree" + + test("sarscov2 - fasta - uncompressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment_uncompressed")}, + { assert snapshot(process.out.versions).match("versions0") } + ) + } + + } + + test("sarscov2 - fasta - compressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment_compressed")}, + { assert snapshot(process.out.versions).match("versions1") } + ) + } + + } + + test("sarscov2 - fasta - guide_tree") { + + setup { + run("FAMSA_GUIDETREE") { + script "../../guidetree/main.nf" + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = FAMSA_GUIDETREE.out.tree.collect{ meta, tree -> tree }.map{ tree -> [[ id: 'test_summary'], tree]} + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("with_guide_tree_alignment")}, + { assert snapshot(process.out.versions).match("with_guide_tree_versions") } + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/famsa/align/tests/main.nf.test.snap b/modules/class-modules/famsa/align/tests/main.nf.test.snap new file mode 100644 index 0000000..95bbbf1 --- /dev/null +++ b/modules/class-modules/famsa/align/tests/main.nf.test.snap @@ -0,0 +1,57 @@ +{ + "alignment_uncompressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln:md5,7cf7375f2ba360814ea978731838b972" + ] + ] + ], + "timestamp": "2024-02-09T19:08:43.577982822" + }, + "versions": { + "content": [ + [ + "versions.yml:md5,7d9e0a8c263fa6d9017075fe88c9e9dc" + ] + ], + "timestamp": "2024-02-09T19:08:43.670136799" + }, + "with_guide_tree_alignment": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,7cf7375f2ba360814ea978731838b972" + ] + ] + ], + "timestamp": "2024-02-09T19:10:05.167368314" + }, + "alignment_compressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,7cf7375f2ba360814ea978731838b972" + ] + ] + ], + "timestamp": "2024-02-09T19:09:25.819156831" + }, + "with_guide_tree_versions": { + "content": [ + [ + "versions.yml:md5,7d9e0a8c263fa6d9017075fe88c9e9dc" + ] + ], + "timestamp": "2024-02-09T19:10:05.231995851" + } +} \ No newline at end of file diff --git a/modules/class-modules/famsa/align/tests/tags.yml b/modules/class-modules/famsa/align/tests/tags.yml new file mode 100644 index 0000000..d010f3b --- /dev/null +++ b/modules/class-modules/famsa/align/tests/tags.yml @@ -0,0 +1,2 @@ +famsa/align: + - "modules/nf-core/famsa/align/**" diff --git a/modules/class-modules/famsa/guidetree/environment.yml b/modules/class-modules/famsa/guidetree/environment.yml new file mode 100644 index 0000000..28be1c7 --- /dev/null +++ b/modules/class-modules/famsa/guidetree/environment.yml @@ -0,0 +1,7 @@ +name: famsa_guidetree +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::famsa=2.2.2 diff --git a/modules/class-modules/famsa/guidetree/main.nf b/modules/class-modules/famsa/guidetree/main.nf new file mode 100644 index 0000000..7d8f46c --- /dev/null +++ b/modules/class-modules/famsa/guidetree/main.nf @@ -0,0 +1,49 @@ + +process FAMSA_GUIDETREE { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/famsa:2.2.2--h9f5acd7_0': + 'biocontainers/famsa:2.2.2--h9f5acd7_0' }" + + input: + tuple val(meta), path(fasta) + + output: + tuple val(meta), path("*.dnd"), emit: tree + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + famsa -gt_export \\ + $args \\ + -t ${task.cpus} \\ + ${fasta} \\ + ${prefix}.dnd + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + famsa: \$( famsa -help 2>&1 | head -n 2 | tail -n 1 | sed 's/ version //g' ) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.dnd + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + famsa: \$( famsa -help 2>&1 | head -n 2 | tail -n 1 | sed 's/ version //g' ) + END_VERSIONS + """ +} + diff --git a/modules/class-modules/famsa/guidetree/meta.yml b/modules/class-modules/famsa/guidetree/meta.yml new file mode 100644 index 0000000..2bd4e79 --- /dev/null +++ b/modules/class-modules/famsa/guidetree/meta.yml @@ -0,0 +1,46 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +name: "famsa_guidetree" +description: Renders a guidetree in famsa +keywords: + - guide tree + - msa + - newick +tools: + - "famsa": + description: "Algorithm for large-scale multiple sequence alignments" + homepage: "https://github.com/refresh-bio/FAMSA" + documentation: "https://github.com/refresh-bio/FAMSA" + tool_dev_url: "https://github.com/refresh-bio/FAMSA" + doi: "10.1038/srep33964" + licence: ["GPL v3"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - fasta: + type: file + description: Input sequences in FASTA format + pattern: "*.{fa,fasta}" +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - tree: + type: file + description: Guide tree file in Newick format + pattern: "*.{dnd}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@luisas" + - "@JoseEspinosa" +maintainers: + - "@luisas" + - "@JoseEspinosa" diff --git a/modules/class-modules/famsa/guidetree/tests/main.nf.test b/modules/class-modules/famsa/guidetree/tests/main.nf.test new file mode 100644 index 0000000..867e781 --- /dev/null +++ b/modules/class-modules/famsa/guidetree/tests/main.nf.test @@ -0,0 +1,32 @@ +nextflow_process { + + name "Test Process FAMSA_GUIDETREE" + script "../main.nf" + process "FAMSA_GUIDETREE" + + tag "modules" + tag "modules_nfcore" + tag "famsa" + tag "famsa/guidetree" + + test("sarscov2 - fasta") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.tree).match("tree")}, + { assert snapshot(process.out.versions).match("versions") } + ) + } + } +} diff --git a/modules/class-modules/famsa/guidetree/tests/main.nf.test.snap b/modules/class-modules/famsa/guidetree/tests/main.nf.test.snap new file mode 100644 index 0000000..00a049d --- /dev/null +++ b/modules/class-modules/famsa/guidetree/tests/main.nf.test.snap @@ -0,0 +1,23 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,320ce01bcb255b03ef5125755bf95195" + ] + ], + "timestamp": "2023-11-29T12:12:38.870544616" + }, + "tree": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.dnd:md5,f3ef8b16a7a16cb4548942ebf2e7bad6" + ] + ] + ], + "timestamp": "2023-11-29T12:12:38.855536268" + } +} \ No newline at end of file diff --git a/modules/class-modules/famsa/guidetree/tests/tags.yml b/modules/class-modules/famsa/guidetree/tests/tags.yml new file mode 100644 index 0000000..a81a270 --- /dev/null +++ b/modules/class-modules/famsa/guidetree/tests/tags.yml @@ -0,0 +1,2 @@ +famsa/guidetree: + - "modules/nf-core/famsa/guidetree/**" diff --git a/modules/class-modules/kalign/align/environment.yml b/modules/class-modules/kalign/align/environment.yml new file mode 100644 index 0000000..93563ea --- /dev/null +++ b/modules/class-modules/kalign/align/environment.yml @@ -0,0 +1,8 @@ +name: kalign_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::kalign3=3.4.0 + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/kalign/align/main.nf b/modules/class-modules/kalign/align/main.nf new file mode 100644 index 0000000..e1601e1 --- /dev/null +++ b/modules/class-modules/kalign/align/main.nf @@ -0,0 +1,50 @@ +process KALIGN_ALIGN { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-5cd0277547c6b33133225c8ce14c0cf2a4396ea2:0a70b6d89a3e06fbdc4a735461e8b98ff32ee5de-0': + 'biocontainers/mulled-v2-5cd0277547c6b33133225c8ce14c0cf2a4396ea2:0a70b6d89a3e06fbdc4a735461e8b98ff32ee5de-0' }" + + input: + tuple val(meta), path(fasta) + val(compress) + + output: + tuple val(meta), path("*.aln{.gz,}"), emit: alignment + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def write_output = compress ? ">(pigz -cp ${task.cpus} > ${prefix}.aln.gz)" : "${prefix}.aln" + """ + unpigz -cdf $fasta | \\ + kalign \\ + $args \\ + -o ${write_output} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + kalign: \$(echo \$(kalign -v) | sed 's/kalign //g' ) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.aln${compress ? '.gz' : ''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + kalign : \$(echo \$(kalign -v) | sed 's/kalign //g' ) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/kalign/align/meta.yml b/modules/class-modules/kalign/align/meta.yml new file mode 100644 index 0000000..187f6bc --- /dev/null +++ b/modules/class-modules/kalign/align/meta.yml @@ -0,0 +1,47 @@ +name: "kalign_align" +description: "Aligns sequences using kalign" +keywords: + - alignment + - MSA + - genomics +tools: + - "kalign": + description: "Kalign is a fast and accurate multiple sequence alignment algorithm." + homepage: "https://msa.sbc.su.se/cgi-bin/msa.cgi" + documentation: "https://github.com/TimoLassmann/kalign" + tool_dev_url: "https://github.com/TimoLassmann/kalign" + doi: "10.1093/bioinformatics/btz795" + licence: ["GPL v3"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - fasta: + type: file + description: Input sequences in FASTA format. May be gzipped or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - alignment: + type: file + description: Alignment file. May be gzipped or uncompressed, depending on if `compress` is set to `true` or `false`. + pattern: "*.{aln}{.gz,}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@luisas" + - "@JoseEspinosa" +maintainers: + - "@luisas" + - "@JoseEspinosa" diff --git a/modules/class-modules/kalign/align/tests/main.nf.test b/modules/class-modules/kalign/align/tests/main.nf.test new file mode 100644 index 0000000..d90ad9b --- /dev/null +++ b/modules/class-modules/kalign/align/tests/main.nf.test @@ -0,0 +1,54 @@ +// nf-core modules test kalign/align +nextflow_process { + + name "Test Process KALIGN_ALIGN" + script "../main.nf" + process "KALIGN_ALIGN" + + tag "modules" + tag "modules_nfcore" + tag "kalign" + tag "kalign/align" + + test("sarscov2 - fasta - uncompressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - uncompressed")}, + ) + } + } + + test("sarscov2 - fasta - compressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['illumina']['contigs_fasta'], checkIfExists: true) + ] + input[1] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - compressed")}, + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/kalign/align/tests/main.nf.test.snap b/modules/class-modules/kalign/align/tests/main.nf.test.snap new file mode 100644 index 0000000..da6fc94 --- /dev/null +++ b/modules/class-modules/kalign/align/tests/main.nf.test.snap @@ -0,0 +1,60 @@ +{ + "SARS-CoV-2 scaffolds fasta - uncompressed": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.aln:md5,c165ecf48fb89862cc2a991cc3cadb2d" + ] + ], + "1": [ + "versions.yml:md5,0764ff5c30fd8befd86baa9026493ffe" + ], + "alignment": [ + [ + { + "id": "test" + }, + "test.aln:md5,c165ecf48fb89862cc2a991cc3cadb2d" + ] + ], + "versions": [ + "versions.yml:md5,0764ff5c30fd8befd86baa9026493ffe" + ] + } + ], + "timestamp": "2024-03-22T16:42:01.934768" + }, + "SARS-CoV-2 scaffolds fasta - compressed": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,c165ecf48fb89862cc2a991cc3cadb2d" + ] + ], + "1": [ + "versions.yml:md5,0764ff5c30fd8befd86baa9026493ffe" + ], + "alignment": [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,c165ecf48fb89862cc2a991cc3cadb2d" + ] + ], + "versions": [ + "versions.yml:md5,0764ff5c30fd8befd86baa9026493ffe" + ] + } + ], + "timestamp": "2024-03-22T16:42:07.734293" + } +} \ No newline at end of file diff --git a/modules/class-modules/kalign/align/tests/tags.yml b/modules/class-modules/kalign/align/tests/tags.yml new file mode 100644 index 0000000..fa93d17 --- /dev/null +++ b/modules/class-modules/kalign/align/tests/tags.yml @@ -0,0 +1,2 @@ +kalign/align: + - "modules/nf-core/kalign/align/**" diff --git a/modules/class-modules/learnmsa/align/environment.yml b/modules/class-modules/learnmsa/align/environment.yml new file mode 100644 index 0000000..124b8d8 --- /dev/null +++ b/modules/class-modules/learnmsa/align/environment.yml @@ -0,0 +1,8 @@ +name: learnmsa_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::learnmsa=2.0.1 + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/learnmsa/align/main.nf b/modules/class-modules/learnmsa/align/main.nf new file mode 100644 index 0000000..304fb07 --- /dev/null +++ b/modules/class-modules/learnmsa/align/main.nf @@ -0,0 +1,50 @@ +process LEARNMSA_ALIGN { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-741e0da5cf2d6d964f559672e2908c2111cbb46b:4930edd009376542543bfd2e20008bb1ae58f841-0' : + 'biocontainers/mulled-v2-741e0da5cf2d6d964f559672e2908c2111cbb46b:4930edd009376542543bfd2e20008bb1ae58f841-0' }" + + input: + tuple val(meta), path(fasta) + val(compress) + + output: + tuple val(meta), path("*.aln{.gz,}"), emit: alignment + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def write_output = compress ? ">(pigz -cp ${task.cpus} > ${prefix}.aln.gz)" : "${prefix}.aln" + """ + learnMSA \\ + $args \\ + -i <(unpigz -cdf $fasta) \\ + -o $write_output + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + learnmsa: \$(learnMSA -h | grep 'version' | awk -F 'version ' '{print \$2}' | awk '{print \$1}' | sed 's/)//g') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.aln${compress ? '.gz' : ''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + learnmsa: \$(learnMSA -h | grep 'version' | awk -F 'version ' '{print \$2}' | awk '{print \$1}' | sed 's/)//g') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/learnmsa/align/meta.yml b/modules/class-modules/learnmsa/align/meta.yml new file mode 100644 index 0000000..66a9f7d --- /dev/null +++ b/modules/class-modules/learnmsa/align/meta.yml @@ -0,0 +1,47 @@ +name: "learnmsa_align" +description: Align sequences using learnMSA +keywords: + - alignment + - MSA + - genomics +tools: + - "learnmsa": + description: "learnMSA: Learning and Aligning large Protein Families" + homepage: "https://github.com/Gaius-Augustus/learnMSA" + documentation: "https://github.com/Gaius-Augustus/learnMSA" + tool_dev_url: "https://github.com/Gaius-Augustus/learnMSA" + doi: "10.1093/gigascience/giac104" + licence: ["MIT"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - fasta: + type: file + description: Input sequences in FASTA format. May be gz-compressed or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - alignment: + type: file + description: Alignment file, in FASTA format. May be gzipped or uncompressed. + pattern: "*.aln{.gz,}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@luisas" + - "@JoseEspinosa" +maintainers: + - "@luisas" + - "@JoseEspinosa" diff --git a/modules/class-modules/learnmsa/align/tests/main.nf.test b/modules/class-modules/learnmsa/align/tests/main.nf.test new file mode 100644 index 0000000..8459ead --- /dev/null +++ b/modules/class-modules/learnmsa/align/tests/main.nf.test @@ -0,0 +1,59 @@ +// nf-core modules test learnmsa/align +nextflow_process { + + name "Test Process LEARNMSA_ALIGN" + script "../main.nf" + process "LEARNMSA_ALIGN" + + tag "modules" + tag "modules_nfcore" + tag "learnmsa" + tag "learnmsa/align" + + test("sarscov2 - fasta - uncompressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[1] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.alignment.get(0).get(1)).getText().contains(">sample1") }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + + } + + test("sarscov2 - fasta - compressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[1] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.alignment.get(0).get(1)).getTextGzip().contains(">sample1") }, + { assert snapshot(process.out.versions).match("versions1") } + ) + } + + } + +} \ No newline at end of file diff --git a/modules/class-modules/learnmsa/align/tests/main.nf.test.snap b/modules/class-modules/learnmsa/align/tests/main.nf.test.snap new file mode 100644 index 0000000..981738a --- /dev/null +++ b/modules/class-modules/learnmsa/align/tests/main.nf.test.snap @@ -0,0 +1,26 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,85322b0f038aa768f202fd0d748d6c7c" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-20T16:06:48.867020809" + }, + "versions1": { + "content": [ + [ + "versions.yml:md5,85322b0f038aa768f202fd0d748d6c7c" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-20T16:12:13.921813607" + } +} \ No newline at end of file diff --git a/modules/class-modules/learnmsa/align/tests/tags.yml b/modules/class-modules/learnmsa/align/tests/tags.yml new file mode 100644 index 0000000..127b628 --- /dev/null +++ b/modules/class-modules/learnmsa/align/tests/tags.yml @@ -0,0 +1,2 @@ +learnmsa/align: + - "modules/nf-core/learnmsa/align/**" diff --git a/modules/class-modules/mafft/environment.yml b/modules/class-modules/mafft/environment.yml new file mode 100644 index 0000000..595252e --- /dev/null +++ b/modules/class-modules/mafft/environment.yml @@ -0,0 +1,8 @@ +name: mafft +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::mafft=7.520 + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/mafft/main.nf b/modules/class-modules/mafft/main.nf new file mode 100644 index 0000000..f09a0c9 --- /dev/null +++ b/modules/class-modules/mafft/main.nf @@ -0,0 +1,75 @@ +process MAFFT { + tag "$meta.id" + label 'process_high' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-12eba4a074f913c639117640936668f5a6a01da6:425707898cf4f85051b77848be253b88f1d2298a-0': + 'biocontainers/mulled-v2-12eba4a074f913c639117640936668f5a6a01da6:425707898cf4f85051b77848be253b88f1d2298a-0' }" + + input: + tuple val(meta) , path(fasta) + tuple val(meta2), path(add) + tuple val(meta3), path(addfragments) + tuple val(meta4), path(addfull) + tuple val(meta5), path(addprofile) + tuple val(meta6), path(addlong) + val(compress) + + output: + tuple val(meta), path("*.fas{.gz,}"), emit: fas + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def add = add ? "--add <(unpigz -cdf ${add})" : '' + def addfragments = addfragments ? "--addfragments <(unpigz -cdf ${addfragments})" : '' + def addfull = addfull ? "--addfull <(unpigz -cdf ${addfull})" : '' + def addprofile = addprofile ? "--addprofile <(unpigz -cdf ${addprofile})" : '' + def addlong = addlong ? "--addlong <(unpigz -cdf ${addlong})" : '' + def write_output = compress ? " | pigz -cp ${task.cpus} > ${prefix}.fas.gz" : "> ${prefix}.fas" + // this will not preserve MAFFTs return value, but mafft crashes when it receives a process substitution + if ("$fasta" == "${prefix}.fas" ) error "Input and output names are the same, set prefix in module configuration to disambiguate!" + """ + mafft \\ + --thread ${task.cpus} \\ + ${add} \\ + ${addfragments} \\ + ${addfull} \\ + ${addprofile} \\ + ${addlong} \\ + ${args} \\ + ${fasta} \\ + ${write_output} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + mafft: \$(mafft --version 2>&1 | sed 's/^v//' | sed 's/ (.*)//') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def add = add ? "--add ${add}" : '' + def addfragments = addfragments ? "--addfragments ${addfragments}" : '' + def addfull = addfull ? "--addfull ${addfull}" : '' + def addprofile = addprofile ? "--addprofile ${addprofile}" : '' + def addlong = addlong ? "--addlong ${addlong}" : '' + if ("$fasta" == "${prefix}.fas" ) error "Input and output names are the same, set prefix in module configuration to disambiguate!" + """ + touch ${prefix}.fas${compress ? '.gz' : ''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + mafft: \$(mafft --version 2>&1 | sed 's/^v//' | sed 's/ (.*)//') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + +} diff --git a/modules/class-modules/mafft/meta.yml b/modules/class-modules/mafft/meta.yml new file mode 100644 index 0000000..90b9ed3 --- /dev/null +++ b/modules/class-modules/mafft/meta.yml @@ -0,0 +1,95 @@ +name: mafft +description: Multiple sequence alignment using MAFFT +keywords: + - fasta + - msa + - multiple sequence alignment +tools: + - "mafft": + description: Multiple alignment program for amino acid or nucleotide sequences based on fast Fourier transform + homepage: https://mafft.cbrc.jp/alignment/software/ + documentation: https://mafft.cbrc.jp/alignment/software/manual/manual.html + tool_dev_url: https://mafft.cbrc.jp/alignment/software/source.html + doi: "10.1093/nar/gkf436" + licence: ["BSD"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: FASTA file containing the sequences to align. May be gzipped or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - meta2: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - add: + type: file + description: FASTA file containing sequences to align to the sequences in `fasta` using `--add`. May be gzipped or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - meta3: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - addfragments: + type: file + description: FASTA file containing sequences to align to the sequences in `fasta` using `--addfragments`. May be gzipped or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - meta4: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - addfull: + type: file + description: FASTA file containing sequences to align to the sequences in `fasta` using `--addfull`. May be gzipped or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - meta5: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - addprofile: + type: file + description: FASTA file containing sequences to align to the sequences in `fasta` using `--addprofile`. May be gzipped or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - meta6: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - addlong: + type: file + description: FASTA file containing sequences to align to the sequences in `fasta` using `--addlong`. May be gzipped or uncompressed. + pattern: "*.{fa,fasta}{.gz,}" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. +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" + - fas: + type: file + description: Aligned sequences in FASTA format. May be gzipped or uncompressed. + pattern: "*.fas{.gz,}" +authors: + - "@MillironX" +maintainers: + - "@MillironX" + - "@Joon-Klaps" diff --git a/modules/class-modules/mafft/tests/main.nf.test b/modules/class-modules/mafft/tests/main.nf.test new file mode 100644 index 0000000..f57ab49 --- /dev/null +++ b/modules/class-modules/mafft/tests/main.nf.test @@ -0,0 +1,248 @@ +nextflow_process { + + name "Test Process MAFFT" + script "../main.nf" + process "MAFFT" + tag "modules" + tag "modules_nfcore" + tag "mafft" + + test("SARS-CoV-2 scaffolds fasta - uncompressed") { + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['illumina']['scaffolds_fasta'], checkIfExists: true) + ] + input[1] = [[:], []] + input[2] = [[:], []] + input[3] = [[:], []] + input[4] = [[:], []] + input[5] = [[:], []] + input[6] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - uncompressed")} + ) + } + + } + + test("SARS-CoV-2 scaffolds fasta - compressed") { + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['illumina']['scaffolds_fasta'], checkIfExists: true) + ] + input[1] = [[:], []] + input[2] = [[:], []] + input[3] = [[:], []] + input[4] = [[:], []] + input[5] = [[:], []] + input[6] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - compressed")} + ) + } + + } + + test("SARS-CoV-2 scaffolds fasta - add informative sites fasta normal") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + input[1] = [[ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[2] = [[:], []] + input[3] = [[:], []] + input[4] = [[:], []] + input[5] = [[:], []] + input[6] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - add informative sites fasta normal") } + ) + } + } + + test("SARS-CoV-2 scaffolds fasta - add informative sites fasta fragments") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + input[1] = [[:], []] + input[2] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[3] = [[:], []] + input[4] = [[:], []] + input[5] = [[:], []] + input[6] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - add informative sites fasta fragments") } + ) + } + } + + test("SARS-CoV-2 scaffolds fasta - add informative sites fasta full") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + input[1] = [[:], []] + input[2] = [[:], []] + input[3] = [[ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[4] = [[:], []] + input[5] = [[:], []] + input[6] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - add informative sites fasta full") } + ) + } + + } + + test("SARS-CoV-2 scaffolds fasta - add informative sites fasta profile") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + input[1] = [[:], []] + input[2] = [[:], []] + input[3] = [[:], []] + input[4] = [[ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[5] = [[:], []] + input[6] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - add informative sites fasta profile") } + ) + } + + } + + test("SARS-CoV-2 scaffolds fasta - add informative sites fasta long") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + input[1] = [[:], []] + input[2] = [[:], []] + input[3] = [[:], []] + input[4] = [[:], []] + input[5] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[6] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - add informative sites fasta long") } + ) + } + + } + + test("SARS-CoV-2 scaffolds fasta - add informative sites all sites fasta multiple") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['genome_fasta'], checkIfExists: true) + ] + input[1] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['all_sites_fas'], checkIfExists: true) + ] + input[2] = [ + [ id:'test', single_end:false ], // meta map + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[3] = [[:], []] + input[4] = [[:], []] + input[5] = [[:], []] + input[6] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match("SARS-CoV-2 scaffolds fasta - add informative sites fasta multiple") } + ) + } + + } + +} \ No newline at end of file diff --git a/modules/class-modules/mafft/tests/main.nf.test.snap b/modules/class-modules/mafft/tests/main.nf.test.snap new file mode 100644 index 0000000..c14ad08 --- /dev/null +++ b/modules/class-modules/mafft/tests/main.nf.test.snap @@ -0,0 +1,250 @@ +{ + "SARS-CoV-2 scaffolds fasta - uncompressed": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas:md5,23426611f4a0df532b6708f072bd445b" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas:md5,23426611f4a0df532b6708f072bd445b" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:08:41.735774847" + }, + "SARS-CoV-2 scaffolds fasta - add informative sites fasta multiple": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,aed7f866c3a20dc9d2f2b4ad73515961" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,aed7f866c3a20dc9d2f2b4ad73515961" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:10:38.940555785" + }, + "SARS-CoV-2 scaffolds fasta - add informative sites fasta normal": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,a57a34f1c566dea114dc1b13416536d4" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,a57a34f1c566dea114dc1b13416536d4" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:09:35.656248409" + }, + "SARS-CoV-2 scaffolds fasta - add informative sites fasta long": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,e8868da70d1f3050a8daaee0e53b2fd9" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,e8868da70d1f3050a8daaee0e53b2fd9" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:10:26.372655394" + }, + "SARS-CoV-2 scaffolds fasta - add informative sites fasta profile": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,c2b5caf39beff4473878e6aa4036ad43" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,c2b5caf39beff4473878e6aa4036ad43" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:10:14.039053212" + }, + "SARS-CoV-2 scaffolds fasta - add informative sites fasta fragments": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,aed7f866c3a20dc9d2f2b4ad73515961" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,aed7f866c3a20dc9d2f2b4ad73515961" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:09:49.737364197" + }, + "SARS-CoV-2 scaffolds fasta - add informative sites fasta full": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,611cb0a65195a282f110f7f56e310c66" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,611cb0a65195a282f110f7f56e310c66" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:10:02.952480822" + }, + "SARS-CoV-2 scaffolds fasta - compressed": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,23426611f4a0df532b6708f072bd445b" + ] + ], + "1": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ], + "fas": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fas.gz:md5,23426611f4a0df532b6708f072bd445b" + ] + ], + "versions": [ + "versions.yml:md5,6e930f6a5acc19ff3a7849536a9fd0ee" + ] + } + ], + "timestamp": "2024-02-09T19:09:21.096197597" + } +} \ No newline at end of file diff --git a/modules/class-modules/mafft/tests/tags.yml b/modules/class-modules/mafft/tests/tags.yml new file mode 100644 index 0000000..caddc3c --- /dev/null +++ b/modules/class-modules/mafft/tests/tags.yml @@ -0,0 +1,2 @@ +mafft: + - modules/nf-core/mafft/** diff --git a/modules/class-modules/magus/align/environment.yml b/modules/class-modules/magus/align/environment.yml new file mode 100644 index 0000000..685f5a8 --- /dev/null +++ b/modules/class-modules/magus/align/environment.yml @@ -0,0 +1,8 @@ +name: magus_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::magus-msa=0.2.0 + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/magus/align/main.nf b/modules/class-modules/magus/align/main.nf new file mode 100644 index 0000000..8c077e2 --- /dev/null +++ b/modules/class-modules/magus/align/main.nf @@ -0,0 +1,58 @@ +process MAGUS_ALIGN { + tag "$meta.id" + label 'process_high' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-ae4ea1182e75371808710b6c081bef8b228c4815:10b41722a6b9471a0945fe6baeb9aff444d8eb1d-0': + 'biocontainers/mulled-v2-ae4ea1182e75371808710b6c081bef8b228c4815:10b41722a6b9471a0945fe6baeb9aff444d8eb1d-0' }" + + input: + tuple val(meta) , path(fasta) + tuple val(meta2), path(tree) + val(compress) + + output: + tuple val(meta), path("*.aln{.gz,}"), emit: alignment + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def loadtree = tree ? "-t $tree" : '' + def write_output = compress ? "--overwrite -o >(pigz -cp ${task.cpus} > ${prefix}.aln.gz)" : "-o ${prefix}.aln" + // using >() is necessary to preserve the return value, + // so nextflow knows to display an error when it failed + // using --overwrite is necessary, as the file descriptor generated by the named file will already exist + """ + magus \\ + -np $task.cpus \\ + -i $fasta \\ + -d ./ \\ + $write_output \\ + $loadtree \\ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + MAGUS: \$(magus --version) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "" | gzip > ${prefix}.aln${compress ? '.gz' : ''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + MAGUS: \$(magus --version) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/magus/align/meta.yml b/modules/class-modules/magus/align/meta.yml new file mode 100644 index 0000000..f9ada96 --- /dev/null +++ b/modules/class-modules/magus/align/meta.yml @@ -0,0 +1,67 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +name: "magus_align" +description: Multiple Sequence Alignment using Graph Clustering +keywords: + - MSA + - alignment + - genomics + - graph +tools: + - "magus": + description: "Multiple Sequence Alignment using Graph Clustering" + homepage: "https://github.com/vlasmirnov/MAGUS" + documentation: "https://github.com/vlasmirnov/MAGUS" + tool_dev_url: "https://github.com/vlasmirnov/MAGUS" + doi: "10.1093/bioinformatics/btaa992" + licence: ["MIT"] + +input: + - meta: + type: map + description: | + Groovy Map containing the fasta meta information + e.g. `[ id:'test', single_end:false ]` + + - meta2: + type: map + description: | + Groovy Map containing sample information for the specified guide tree (if supplied) + e.g. `[ id:'test', single_end:false ]` + + - fasta: + type: file + description: Input sequences in FASTA format. + pattern: "*.{fa,fna,fasta}" + + - tree: + type: file + description: Optional path to a file containing a guide tree in newick format to use as input. + If empty, or overwritten by passing `-t [fasttree|fasttree-noml|clustal|parttree]`, MAGUS will construct its own guide tree. If empty, `fasttree` is used as a default. + pattern: "*.{dnd,tree}" + + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. + +output: + - meta: + type: map + description: | + Groovy Map containing sample meta information. + e.g. `[ id:'test', single_end:false ]` + + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + + - alignment: + type: file + description: File containing the output alignment, in FASTA format containing gaps. + The sequences may be in a different order than in the input FASTA. + The output file may or may not be gzipped, depending on the value supplied to `compress`. + pattern: "*.aln{.gz,}" + +authors: + - "@lrauschning" diff --git a/modules/class-modules/magus/align/tests/main.nf.test b/modules/class-modules/magus/align/tests/main.nf.test new file mode 100644 index 0000000..6b603f2 --- /dev/null +++ b/modules/class-modules/magus/align/tests/main.nf.test @@ -0,0 +1,113 @@ +nextflow_process { + + name "Test Process MAGUS_ALIGN" + script "../main.nf" + process "MAGUS_ALIGN" + + tag "modules" + tag "modules_nfcore" + tag "magus" + tag "magus/align" + tag "magus/guidetree" + + test("setoxin - fasta - uncompressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + // tests seem to be reproducible on a single machine, but not across different machines + // test the correct samples are in there + { assert path(process.out.alignment[0][1]).getText().contains(">1apf") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1ahl") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1atx") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1sh1") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1bds") }, + { assert snapshot(process.out.versions).match("versions0") } + ) + } + + } + + test("setoxin - fasta - compressed") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + // tests seem to be reproducible on a single machine, but not across different machines + // test the correct samples are in there + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1apf") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1ahl") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1atx") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1sh1") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1bds") }, + { assert snapshot(process.out.versions).match("versions1") } + ) + } + + } + test("setoxin - fasta - guide_tree") { + + setup { + run("MAGUS_GUIDETREE") { + script "../../guidetree/main.nf" + process { + """ + input[0] = [ [ id:'test' ], // meta map + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + """ + } + } + } + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = MAGUS_GUIDETREE.out.tree.collect{ meta, tree -> tree }.map{ tree -> [[ id: 'test_summary'], tree]} + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + // tests seem to be reproducible on a single machine, but not across different machines + // test the correct samples are in there + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1apf") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1ahl") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1atx") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1sh1") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1bds") }, + { assert snapshot(process.out.versions).match("with_guide_tree_versions") } + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/magus/align/tests/main.nf.test.snap b/modules/class-modules/magus/align/tests/main.nf.test.snap new file mode 100644 index 0000000..9b4f5f6 --- /dev/null +++ b/modules/class-modules/magus/align/tests/main.nf.test.snap @@ -0,0 +1,65 @@ +{ + "alignment_uncompressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln:md5,36feabc3daa2e02bade367fbbb25998b" + ] + ] + ], + "timestamp": "2024-03-28T18:20:59.519188125" + }, + "versions0": { + "content": [ + [ + "versions.yml:md5,ef9456e058ce51bce10dbc3703da29c7" + ] + ], + "timestamp": "2024-03-28T18:16:37.893176542" + }, + "versions1": { + "content": [ + [ + "versions.yml:md5,ef9456e058ce51bce10dbc3703da29c7" + ] + ], + "timestamp": "2024-03-28T18:17:23.679862847" + }, + "with_guide_tree_alignment": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,f3c292f0d5594cdafa9a3a270be706d7" + ] + ] + ], + "timestamp": "2024-03-28T18:24:31.933699545" + }, + "alignment_compressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,0be13ed7dc73a21accf406b7355c360e" + ] + ] + ], + "timestamp": "2024-03-04T18:07:34.889870533" + }, + "with_guide_tree_versions": { + "content": [ + [ + "versions.yml:md5,ef9456e058ce51bce10dbc3703da29c7" + ] + ], + "timestamp": "2024-03-28T18:24:32.0238804" + } +} \ No newline at end of file diff --git a/modules/class-modules/magus/align/tests/tags.yml b/modules/class-modules/magus/align/tests/tags.yml new file mode 100644 index 0000000..f2dfd3a --- /dev/null +++ b/modules/class-modules/magus/align/tests/tags.yml @@ -0,0 +1,2 @@ +magus/align: + - "modules/nf-core/magus/align/**" diff --git a/modules/class-modules/magus/guidetree/environment.yml b/modules/class-modules/magus/guidetree/environment.yml new file mode 100644 index 0000000..8e75033 --- /dev/null +++ b/modules/class-modules/magus/guidetree/environment.yml @@ -0,0 +1,7 @@ +name: magus_guidetree +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::magus-msa=0.2.0 diff --git a/modules/class-modules/magus/guidetree/main.nf b/modules/class-modules/magus/guidetree/main.nf new file mode 100644 index 0000000..eb37fb9 --- /dev/null +++ b/modules/class-modules/magus/guidetree/main.nf @@ -0,0 +1,48 @@ +process MAGUS_GUIDETREE { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/magus-msa:0.2.0--pyhdfd78af_0': + 'biocontainers/magus-msa:0.2.0--pyhdfd78af_0' }" + + input: + tuple val(meta), path(fasta) + + output: + tuple val(meta), path("*.tree"), emit: tree + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + magus \\ + -np $task.cpus \\ + -i $fasta \\ + -o ${prefix}.tree \\ + --onlyguidetree TRUE \\ + $args + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + MAGUS: \$(magus --version) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.tree + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + MAGUS: \$(magus --version) + END_VERSIONS + """ +} diff --git a/modules/class-modules/magus/guidetree/meta.yml b/modules/class-modules/magus/guidetree/meta.yml new file mode 100644 index 0000000..7d21391 --- /dev/null +++ b/modules/class-modules/magus/guidetree/meta.yml @@ -0,0 +1,49 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +name: "magus_guidetree" +description: Multiple Sequence Alignment using Graph Clustering +keywords: + - MSA + - guidetree + - genomics + - graph +tools: + - "magus": + description: "Multiple Sequence Alignment using Graph Clustering" + homepage: "https://github.com/vlasmirnov/MAGUS" + documentation: "https://github.com/vlasmirnov/MAGUS" + tool_dev_url: "https://github.com/vlasmirnov/MAGUS" + doi: "10.1093/bioinformatics/btaa992" + licence: ["MIT"] + +input: + - meta: + type: map + description: | + Groovy Map containing fasta meta information + e.g. `[ id:'test', single_end:false ]` + + - fasta: + type: file + description: Input sequences in FASTA format. + pattern: "*.{fa,fna,fasta}" + +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" + + - tree: + type: file + description: File containing the output guidetree, in newick format. + pattern: "*.tree" + +authors: + - "@lrauschning" diff --git a/modules/class-modules/magus/guidetree/tests/main.nf.test b/modules/class-modules/magus/guidetree/tests/main.nf.test new file mode 100644 index 0000000..953e37e --- /dev/null +++ b/modules/class-modules/magus/guidetree/tests/main.nf.test @@ -0,0 +1,39 @@ +nextflow_process { + + name "Test Process MAGUS_GUIDETREE" + script "../main.nf" + process "MAGUS_GUIDETREE" + + tag "modules" + tag "modules_nfcore" + tag "magus" + tag "magus/guidetree" + + test("setoxin - fasta") { + + when { + process { + """ + input[0] = [ [ id:'test' ], // meta map + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + //{ assert snapshot(process.out.tree).match("tree")}, + // tests seem to be reproducible on a single machine, but not across different machines + // test the correct samples are in there + { assert path(process.out.tree[0][1]).getText().contains("1apf") }, + { assert path(process.out.tree[0][1]).getText().contains("1ahl") }, + { assert path(process.out.tree[0][1]).getText().contains("1atx") }, + { assert path(process.out.tree[0][1]).getText().contains("1sh1") }, + { assert path(process.out.tree[0][1]).getText().contains("1bds") }, + { assert snapshot(process.out.versions).match("versions") } + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/magus/guidetree/tests/main.nf.test.snap b/modules/class-modules/magus/guidetree/tests/main.nf.test.snap new file mode 100644 index 0000000..d564be3 --- /dev/null +++ b/modules/class-modules/magus/guidetree/tests/main.nf.test.snap @@ -0,0 +1,23 @@ +{ + "versions": { + "content": [ + [ + "versions.yml:md5,5a2ad92c9ea945c4bf4890f02ca2562f" + ] + ], + "timestamp": "2024-03-28T18:25:41.292337485" + }, + "tree": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.tree:md5,c742636229d166322a2824d409595738" + ] + ] + ], + "timestamp": "2024-03-28T18:25:41.226027114" + } +} \ No newline at end of file diff --git a/modules/class-modules/magus/guidetree/tests/tags.yml b/modules/class-modules/magus/guidetree/tests/tags.yml new file mode 100644 index 0000000..12b89af --- /dev/null +++ b/modules/class-modules/magus/guidetree/tests/tags.yml @@ -0,0 +1,2 @@ +magus/guidetree: + - "modules/nf-core/magus/guidetree/**" diff --git a/modules/class-modules/mtmalign/align/environment.yml b/modules/class-modules/mtmalign/align/environment.yml new file mode 100644 index 0000000..59d426b --- /dev/null +++ b/modules/class-modules/mtmalign/align/environment.yml @@ -0,0 +1,8 @@ +name: mtmalign_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::mtm-align=20220104 + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/mtmalign/align/main.nf b/modules/class-modules/mtmalign/align/main.nf new file mode 100644 index 0000000..933d2c7 --- /dev/null +++ b/modules/class-modules/mtmalign/align/main.nf @@ -0,0 +1,73 @@ + + +process MTMALIGN_ALIGN { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-5bcf71dc66dac33d8e003c5e78043b80f5c7f269:8f0e486d46f7ab38892c1a8f78d2894a549d03b5-0': + 'biocontainers/mulled-v2-5bcf71dc66dac33d8e003c5e78043b80f5c7f269:8f0e486d46f7ab38892c1a8f78d2894a549d03b5-0' }" + + input: + tuple val(meta), path(pdbs) + val(compress) + + output: + tuple val(meta), path("${prefix}.aln${compress ? '.gz' : ''}"), emit: alignment + tuple val(meta), path("${prefix}.pdb${compress ? '.gz' : ''}"), emit: structure + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + // mTMalign is not capable of writing to stdout + // if -o /dev/stdout is specified, the output file will be polluted with debug messages emitted by mTMalign + """ + # decompress input files if required + if ls ./*.pdb.gz 2&> /dev/null; then # check if any files are compressed; calling unpigz with an empty arg will cause it to panic + unpigz -d ./*.pdb.gz + fi + + # construct input file for mtmalign + ls *.pdb | sed s/\\ /\\n/ > input_list.txt + + mtm-align -i input_list.txt -o ${prefix}.pdb + # -o does not affect the fasta naming, so move it to the new name + mv ./mTM_result/result.fasta ./mTM_result/${prefix}.aln + # Remove ".pdb" from the ids in the alignment file + sed -i 's/\\.pdb//g' ./mTM_result/${prefix}.aln + + # compress both output files + if ${compress}; then + pigz -p ${task.cpus} ./mTM_result/${prefix}.aln ./mTM_result/${prefix}.pdb + fi + + # move everything in mTM_result to the working directory + mv ./mTM_result/* . + + # mtm-align -v prints the wrong version 20180725, so extract it from the cosmetic output in the help message + cat <<-END_VERSIONS > versions.yml + "${task.process}": + mTM-align: \$( mtm-align -h | grep -e "\\(Version [[:digit:]]*\\)" | grep -oe "[[:digit:]]*" ) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.aln${compress ? '.gz' : ''} + touch ${prefix}.pdb${compress ? '.gz' : ''} + + # mtm-align -v prints the wrong version 20180725, so extract it from the cosmetic output in the help message + cat <<-END_VERSIONS > versions.yml + "${task.process}": + mTM-align: \$( mtm-align -h | grep -e "\\(Version [[:digit:]]*\\)" | grep -oe "[[:digit:]]*" ) + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/mtmalign/align/meta.yml b/modules/class-modules/mtmalign/align/meta.yml new file mode 100644 index 0000000..1e444e1 --- /dev/null +++ b/modules/class-modules/mtmalign/align/meta.yml @@ -0,0 +1,57 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/yaml-schema.json +name: "mtmalign_align" +description: Aligns protein structures using mTM-align +keywords: + - alignment + - MSA + - genomics + - structure +tools: + - "mTM-align": + description: "Algorithm for structural multiple sequence alignments" + homepage: "http://yanglab.nankai.edu.cn/mTM-align/" + documentation: "http://yanglab.nankai.edu.cn/mTM-align/help/" + tool_dev_url: "http://yanglab.nankai.edu.cn/mTM-align/" + doi: "10.1093/bioinformatics/btx828" + licence: ["None"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - pdbs: + type: file + description: Input protein structures in PDB format. Files may be gzipped or uncompressed. + They should contain exactly one chain! + pattern: "*.{pdb}" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - alignment: + type: file + description: Alignment in FASTA format. May be gzipped or uncompressed. + pattern: "*.aln{.gz,}" + - structure: + type: file + description: Overlaid structures in PDB format. May be gzipped or uncompressed. + pattern: "${prefix}.pdb{.gz,}" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@lrauschning" +maintainers: + - "@lrauschning" diff --git a/modules/class-modules/mtmalign/align/tests/main.nf.test b/modules/class-modules/mtmalign/align/tests/main.nf.test new file mode 100644 index 0000000..ada32c3 --- /dev/null +++ b/modules/class-modules/mtmalign/align/tests/main.nf.test @@ -0,0 +1,90 @@ +nextflow_process { + + name "Test Process MTMALIGN_ALIGN" + script "../main.nf" + process "MTMALIGN_ALIGN" + tag "modules" + tag "modules_nfcore" + tag "mtmalign" + tag "mtmalign/align" + tag "untar" + + test("Test on seatoxin dataset - uncompressed") { + setup { + + run("UNTAR") { + script "../../../../../modules/nf-core/untar/main.nf" + process { + """ + archive = file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/structures/seatoxin-ref.tar.gz", checkIfExists: true) + input[0] = Channel.of(tuple([id:'test'], archive)) + """ + } + } + } + + when { + params { + } + process { + """ + input[0] = UNTAR.out.untar.map { meta,dir -> [[ id:'test' ], file(dir).listFiles().collect()]} + input[1] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + // mTMalign may be nondeterministic, just check if the pdbs are all in there + //{ assert snapshot(process.out).match() } + { assert path(process.out.alignment[0][1]).getText().contains(">1ahl") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1apf") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1atx") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1bds") }, + { assert path(process.out.alignment[0][1]).getText().contains(">1sh1") }, + { assert snapshot(process.out.versions).match("versions0") } + ) + } + } + + test("Test on seatoxin dataset - compressed") { + setup { + + run("UNTAR") { + script "../../../../../modules/nf-core/untar/main.nf" + process { + """ + archive = file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/structures/seatoxin-ref.tar.gz", checkIfExists: true) + input[0] = Channel.of(tuple([id:'test'], archive)) + """ + } + } + } + + when { + params { + } + process { + """ + input[0] = UNTAR.out.untar.map { meta,dir -> [[ id:'test' ], file(dir).listFiles().collect()]} + input[1] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + // mTMalign may be nondeterministic, just check if the pdbs are all in there + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1ahl") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1apf") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1atx") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1bds") }, + { assert path(process.out.alignment[0][1]).getTextGzip().contains(">1sh1") }, + { assert snapshot(process.out.versions).match("versions1") } + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/mtmalign/align/tests/main.nf.test.snap b/modules/class-modules/mtmalign/align/tests/main.nf.test.snap new file mode 100644 index 0000000..0eefb19 --- /dev/null +++ b/modules/class-modules/mtmalign/align/tests/main.nf.test.snap @@ -0,0 +1,26 @@ +{ + "versions0": { + "content": [ + [ + "versions.yml:md5,7cbacec15bb9e0c8cbb27610bde74c10" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-03T11:01:13.729263689" + }, + "versions1": { + "content": [ + [ + "versions.yml:md5,7cbacec15bb9e0c8cbb27610bde74c10" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.04.2" + }, + "timestamp": "2024-06-03T11:01:37.28539854" + } +} \ No newline at end of file diff --git a/modules/class-modules/mtmalign/align/tests/tags.yml b/modules/class-modules/mtmalign/align/tests/tags.yml new file mode 100644 index 0000000..87a2e3b --- /dev/null +++ b/modules/class-modules/mtmalign/align/tests/tags.yml @@ -0,0 +1,2 @@ +mtmalign/align: + - modules/nf-core/mtmalign/align/** diff --git a/modules/class-modules/muscle5/super5/environment.yml b/modules/class-modules/muscle5/super5/environment.yml new file mode 100644 index 0000000..fbaf4a2 --- /dev/null +++ b/modules/class-modules/muscle5/super5/environment.yml @@ -0,0 +1,8 @@ +name: muscle5_super5 +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::muscle=5.1 + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/muscle5/super5/main.nf b/modules/class-modules/muscle5/super5/main.nf new file mode 100644 index 0000000..87af149 --- /dev/null +++ b/modules/class-modules/muscle5/super5/main.nf @@ -0,0 +1,63 @@ +process MUSCLE5_SUPER5 { + tag "$meta.id" + label 'process_medium' + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-8eb01a3c2755c935d070dd03ff2dee698eeb4466:ceb6e65e00346ed20d0d8078dddf9858a7af0fe2-0': + 'biocontainers/mulled-v2-8eb01a3c2755c935d070dd03ff2dee698eeb4466:ceb6e65e00346ed20d0d8078dddf9858a7af0fe2-0' }" + + input: + tuple val(meta), path(fasta) + val(compress) + + output: + tuple val(meta), path("*.aln{.gz,}"), emit: alignment + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + prefix = args.contains('-perm all') ? "${prefix}@" : "${prefix}" + def write_output = (compress && !args.contains('-perm all')) ? " -output >(pigz -cp ${task.cpus} > ${prefix}.aln.gz)" : "-output ${prefix}.aln" + // muscle internally expands the shell pipe to a file descriptor of the form /dev/fd/ + // this causes it to fail, unless -output is left at the end of the call + // see also clustalo/align + // using >() is necessary to preserve the return value, + // so nextflow knows to display an error when it failed + """ + muscle \\ + -super5 ${fasta} \\ + ${args} \\ + -threads ${task.cpus} \\ + $write_output + + + # output may be multiple files if -perm all is set + # compress these individually if set to compress output + if ${args.contains('-perm all') && compress}; then + pigz -p ${task.cpus} *.aln + fi + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + muscle: \$(muscle -version | head -n 1 | cut -d ' ' -f 2 | sed 's/.linux64//') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.aln${compress ? '.gz' : ''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + muscle: \$(muscle -version | head -n 1 | cut -d ' ' -f 2 | sed 's/.linux64//') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/muscle5/super5/meta.yml b/modules/class-modules/muscle5/super5/meta.yml new file mode 100644 index 0000000..057128d --- /dev/null +++ b/modules/class-modules/muscle5/super5/meta.yml @@ -0,0 +1,51 @@ +name: "muscle5_super5" +description: Muscle is a program for creating multiple alignments of amino acid or nucleotide sequences. This particular module uses the super5 algorithm for very big alignments. It can permutate the guide tree according to a set of flags. +keywords: + - align + - msa + - multiple sequence alignment +tools: + - muscle -super5: + description: "Muscle v5 is a major re-write of MUSCLE based on new algorithms." + homepage: "https://drive5.com/muscle5/" + documentation: "https://drive5.com/muscle5/manual/" + doi: "10.1101/2021.06.20.449169" + licence: ["Public Domain"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Input sequences for alignment must be in FASTA format + pattern: "*.{fasta,fa,fna}" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. +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" + - alignment: + type: file + description: Multiple sequence alignment produced in gzipped FASTA format. If '-perm all' is passed in ext.args, this will be multiple files per input! + pattern: "*.{aln.gz}" +authors: + - "@alessiovignoli" + - "@JoseEspinosa" +maintainers: + - "@alessiovignoli" + - "@JoseEspinosa" + - "@lrauschning" diff --git a/modules/class-modules/muscle5/super5/tests/main.nf.test b/modules/class-modules/muscle5/super5/tests/main.nf.test new file mode 100644 index 0000000..c154120 --- /dev/null +++ b/modules/class-modules/muscle5/super5/tests/main.nf.test @@ -0,0 +1,72 @@ +nextflow_process { + + name "Test Process MUSCLE5_SUPER5" + script "../main.nf" + process "MUSCLE5_SUPER5" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "muscle5" + tag "muscle5/super5" + + test("fasta - align_sequence - uncompressed") { + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment - uncompressed")}, + ) + } + } + + test("fasta - align_sequence - compressed") { + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment - compressed")}, + ) + } + } + test("fasta - align_sequence - compressed - perm_all") { + config "./perm_all.config" + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("perm-all")}, + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/muscle5/super5/tests/main.nf.test.snap b/modules/class-modules/muscle5/super5/tests/main.nf.test.snap new file mode 100644 index 0000000..ce7aadf --- /dev/null +++ b/modules/class-modules/muscle5/super5/tests/main.nf.test.snap @@ -0,0 +1,46 @@ +{ + "alignment - compressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,46ba556df08f7aabbe5e1ba31d226b6a" + ] + ] + ], + "timestamp": "2024-02-09T19:08:23.498404397" + }, + "perm-all": { + "content": [ + [ + [ + { + "id": "test" + }, + [ + "testabc.0.aln.gz:md5,46ba556df08f7aabbe5e1ba31d226b6a", + "testacb.0.aln.gz:md5,46ba556df08f7aabbe5e1ba31d226b6a", + "testbca.0.aln.gz:md5,46ba556df08f7aabbe5e1ba31d226b6a", + "testnone.0.aln.gz:md5,46ba556df08f7aabbe5e1ba31d226b6a" + ] + ] + ] + ], + "timestamp": "2024-02-09T19:08:37.386512953" + }, + "alignment - uncompressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln:md5,46ba556df08f7aabbe5e1ba31d226b6a" + ] + ] + ], + "timestamp": "2024-02-09T19:16:25.330353817" + } +} \ No newline at end of file diff --git a/modules/class-modules/muscle5/super5/tests/nextflow.config b/modules/class-modules/muscle5/super5/tests/nextflow.config new file mode 100644 index 0000000..e69de29 diff --git a/modules/class-modules/muscle5/super5/tests/perm_all.config b/modules/class-modules/muscle5/super5/tests/perm_all.config new file mode 100644 index 0000000..d350271 --- /dev/null +++ b/modules/class-modules/muscle5/super5/tests/perm_all.config @@ -0,0 +1,3 @@ +process { + ext.args = { "-perm all" } +} diff --git a/modules/class-modules/muscle5/super5/tests/tags.yml b/modules/class-modules/muscle5/super5/tests/tags.yml new file mode 100644 index 0000000..c915c6a --- /dev/null +++ b/modules/class-modules/muscle5/super5/tests/tags.yml @@ -0,0 +1,2 @@ +muscle5/super5: + - "modules/nf-core/muscle5/super5/**" diff --git a/modules/class-modules/tcoffee/align/environment.yml b/modules/class-modules/tcoffee/align/environment.yml new file mode 100644 index 0000000..28f159f --- /dev/null +++ b/modules/class-modules/tcoffee/align/environment.yml @@ -0,0 +1,8 @@ +name: tcoffee_align +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::t-coffee=13.46.0.919e8c6b + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/tcoffee/align/main.nf b/modules/class-modules/tcoffee/align/main.nf new file mode 100644 index 0000000..a14964c --- /dev/null +++ b/modules/class-modules/tcoffee/align/main.nf @@ -0,0 +1,68 @@ +process TCOFFEE_ALIGN { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0': + 'biocontainers/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0' }" + + input: + tuple val(meta) , path(fasta) + tuple val(meta2), path(tree) + tuple val(meta3), path(template), path(accessory_informations) + val(compress) + + output: + tuple val(meta), path("*.aln{.gz,}"), emit: alignment + // in the args there might be the request to generate a lib file, so the following is an optional output + tuple val(meta), path("*.*lib") , emit: lib, optional : true + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def tree_args = tree ? "-usetree $tree" : "" + def template_args = template ? "-template_file $template" : "" + def outfile = compress ? "stdout" : "${prefix}.aln" + def write_output = compress ? " | pigz -cp ${task.cpus} > ${prefix}.aln.gz" : "" + """ + export TEMP='./' + t_coffee -seq ${fasta} \ + $tree_args \ + $template_args \ + $args \ + -thread ${task.cpus} \ + -outfile $outfile \ + $write_output + + # If stdout file exist and compress is true, then compress the file + # This is a patch for the current behaviour of the regressive algorithm + # that does not support the stdout redirection + if [ -f stdout ] && [ "$compress" = true ]; then + pigz -cp ${task.cpus} < stdout > ${prefix}.aln.gz + rm stdout + fi + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.aln${compress ? '.gz':''} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/tcoffee/align/meta.yml b/modules/class-modules/tcoffee/align/meta.yml new file mode 100644 index 0000000..4125d1e --- /dev/null +++ b/modules/class-modules/tcoffee/align/meta.yml @@ -0,0 +1,80 @@ +name: "tcoffee_align" +description: Aligns sequences using T_COFFEE +keywords: + - alignment + - MSA + - genomics +tools: + - "tcoffee": + description: "A collection of tools for Computing, Evaluating and Manipulating Multiple Alignments of DNA, RNA, Protein Sequences and Structures." + homepage: "http://www.tcoffee.org/Projects/tcoffee/" + documentation: "https://tcoffee.readthedocs.io/en/latest/tcoffee_main_documentation.html" + tool_dev_url: "https://github.com/cbcrg/tcoffee" + doi: "10.1006/jmbi.2000.4042" + licence: ["GPL v3"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - fasta: + type: file + description: Input sequences in FASTA format + pattern: "*.{fa,fasta}" + - meta2: + type: map + description: | + Groovy Map containing tree information + e.g. `[ id:'test_tree']` + - tree: + type: file + description: Input guide tree in Newick format + pattern: "*.{dnd}" + - meta3: + type: map + description: | + Groovy Map containing tree information + e.g. `[ id:'test_infos']` + - template: + type: file + description: T_coffee template file that maps sequences to the accessory information files to be used. + pattern: "*" + - accessory_informations: + type: file + description: Accessory files to be used in the alignment. For example, it could be protein structures or secondary structures. + pattern: "*" + - compress: + type: boolean + description: Flag representing whether the output MSA should be compressed. Set to true to enable/false to disable compression. Compression is done using pigz, and is multithreaded. +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test']` + - alignment: + type: file + description: Alignment file in FASTA format. May be gzipped. + pattern: "*.aln{.gz,}" + - lib: + type: file + description: optional output, the library generated from the MSA file. + pattern: "*.*lib" + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" +authors: + - "@luisas" + - "@JoseEspinosa" + - "@alessiovignoli" +maintainers: + - "@luisas" + - "@JoseEspinosa" + - "@lrauschning" + - "@alessiovignoli" diff --git a/modules/class-modules/tcoffee/align/tests/lib.config b/modules/class-modules/tcoffee/align/tests/lib.config new file mode 100644 index 0000000..2fc113e --- /dev/null +++ b/modules/class-modules/tcoffee/align/tests/lib.config @@ -0,0 +1,3 @@ +process { + ext.args = { "-output fasta_aln -out_lib=sample_lib1.tc_lib" } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/align/tests/main.nf.test b/modules/class-modules/tcoffee/align/tests/main.nf.test new file mode 100644 index 0000000..307534f --- /dev/null +++ b/modules/class-modules/tcoffee/align/tests/main.nf.test @@ -0,0 +1,177 @@ +nextflow_process { + + name "Test Process TCOFFEE_ALIGN" + script "../main.nf" + process "TCOFFEE_ALIGN" + + tag "modules" + tag "modules_nfcore" + tag "tcoffee" + tag "tcoffee/align" + tag "famsa/guidetree" + tag "untar" + + test("fasta - align_sequence") { + + config "./sequence.config" + + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = [[:],[],[]] + input[3] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment")}, + { assert snapshot(process.out.versions).match("versions_uncomp") } + ) + } + } + + test("fasta - align_sequence - uncompressed") { + + config "./sequence.config" + + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = [[:],[],[]] + input[3] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment - uncompressed")}, + { assert snapshot(process.out.versions).match("versions_comp") } + ) + } + } + + test("sarscov2 - fasta - align_with_guide_tree") { + + config "./tree.config" + + setup { + + run("FAMSA_GUIDETREE") { + script "../../../famsa/guidetree//main.nf" + process { + """ + input[0] = [ [ id:'test' ], + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + + """ + } + } + } + + when { + process { + """ + input[0] = [ [ id:'test' ], + file(params.test_data['sarscov2']['genome']['informative_sites_fas'], checkIfExists: true) + ] + input[1] = FAMSA_GUIDETREE.out.tree.collect{ meta, tree -> tree }.map{ tree -> [[ id: 'test'], tree]} + input[2] = [ [:], [], [] ] + input[3] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment_guidetree")}, + { assert snapshot(process.out.versions).match("versions_guidetree") } + ) + } + + } + + test("fasta - align_with_structure") { + + config "./structure.config" + + setup { + + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/structures/seatoxin-ref.tar.gz", checkIfExists: true) + ] + + """ + } + } + } + + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = [ [:], [] ] + input[2] = UNTAR.out.untar.map { meta,dir -> [[ id:'test' ], [] ,file(dir).listFiles().collect()]} + input[3] = true + """ + + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.alignment.get(0).get(1)).getTextGzip().contains("1ahl") }, + { assert snapshot(process.out.versions).match("versions_structure") } + ) + } + + } + + test("fasta - align_with_lib") { + + config "./lib.config" + + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = [[:],[],[]] + input[3] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.alignment).match("alignment - lib") }, + { assert path(process.out.lib.get(0).get(1)).getText().contains("1ahl") }, + { assert snapshot(process.out.versions).match("versions_lib") } + ) + } + } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/align/tests/main.nf.test.snap b/modules/class-modules/tcoffee/align/tests/main.nf.test.snap new file mode 100644 index 0000000..dfef40a --- /dev/null +++ b/modules/class-modules/tcoffee/align/tests/main.nf.test.snap @@ -0,0 +1,130 @@ +{ + "versions_structure": { + "content": [ + [ + "versions.yml:md5,fb187c9186b50a8076d08cd3be3c1b70" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-28T19:00:28.712838" + }, + "versions_lib": { + "content": [ + [ + "versions.yml:md5,fb187c9186b50a8076d08cd3be3c1b70" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-19T14:04:06.031557" + }, + "alignment - uncompressed": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln:md5,bd1db08ad04514cc6d1334598c1a6ef0" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-28T18:59:54.582504" + }, + "versions_comp": { + "content": [ + [ + "versions.yml:md5,fb187c9186b50a8076d08cd3be3c1b70" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-28T18:59:54.593312" + }, + "versions_guidetree": { + "content": [ + [ + "versions.yml:md5,fb187c9186b50a8076d08cd3be3c1b70" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-28T19:00:10.618213" + }, + "alignment - lib": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,bd1db08ad04514cc6d1334598c1a6ef0" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-19T13:57:39.653762" + }, + "alignment": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,bd1db08ad04514cc6d1334598c1a6ef0" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-28T18:59:35.169119" + }, + "versions_uncomp": { + "content": [ + [ + "versions.yml:md5,fb187c9186b50a8076d08cd3be3c1b70" + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-28T18:59:35.2062" + }, + "alignment_guidetree": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.aln.gz:md5,93bc8adfcd88f7913718eacc13da8e4a" + ] + ] + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "24.01.0" + }, + "timestamp": "2024-02-28T19:00:10.611489" + } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/align/tests/sequence.config b/modules/class-modules/tcoffee/align/tests/sequence.config new file mode 100644 index 0000000..69c6fc1 --- /dev/null +++ b/modules/class-modules/tcoffee/align/tests/sequence.config @@ -0,0 +1,3 @@ +process { + ext.args = { "-output fasta_aln" } +} diff --git a/modules/class-modules/tcoffee/align/tests/structure.config b/modules/class-modules/tcoffee/align/tests/structure.config new file mode 100644 index 0000000..1cbd9c9 --- /dev/null +++ b/modules/class-modules/tcoffee/align/tests/structure.config @@ -0,0 +1,5 @@ +process { + withName: "TCOFFEE_ALIGN" { + ext.args = { "-method TMalign_pair -output fasta_aln" } + } +} diff --git a/modules/class-modules/tcoffee/align/tests/tags.yml b/modules/class-modules/tcoffee/align/tests/tags.yml new file mode 100644 index 0000000..b367ce0 --- /dev/null +++ b/modules/class-modules/tcoffee/align/tests/tags.yml @@ -0,0 +1,2 @@ +tcoffee/align: + - "modules/nf-core/tcoffee/align/**" diff --git a/modules/class-modules/tcoffee/align/tests/tree.config b/modules/class-modules/tcoffee/align/tests/tree.config new file mode 100644 index 0000000..d426ed4 --- /dev/null +++ b/modules/class-modules/tcoffee/align/tests/tree.config @@ -0,0 +1,5 @@ +process { + withName: "TCOFFEE_ALIGN"{ + ext.args = { "-output fasta_aln" } + } +} diff --git a/modules/class-modules/tcoffee/alncompare/environment.yml b/modules/class-modules/tcoffee/alncompare/environment.yml new file mode 100644 index 0000000..dfa1414 --- /dev/null +++ b/modules/class-modules/tcoffee/alncompare/environment.yml @@ -0,0 +1,8 @@ +name: "tcoffee_alncompare" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::t-coffee=13.46.0.919e8c6b + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/tcoffee/alncompare/main.nf b/modules/class-modules/tcoffee/alncompare/main.nf new file mode 100644 index 0000000..043158a --- /dev/null +++ b/modules/class-modules/tcoffee/alncompare/main.nf @@ -0,0 +1,64 @@ +process TCOFFEE_ALNCOMPARE { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0': + 'biocontainers/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0' }" + + input: + tuple val(meta), path(msa), path(ref_msa) + + output: + tuple val(meta), path("*.scores"), emit: scores + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def prefix = task.ext.prefix ? task.ext.prefix : "${msa.baseName}" + def args = task.ext.args ? task.ext.args.contains('compare_mode') ? task.ext.args : (task.ext.args +'-compare_mode tc ' ) : '-compare_mode tc ' + def metric_name = args.split('compare_mode ')[1].split(' ')[0] + def header = meta.keySet().join(",") + def values = meta.values().join(",") + def read_msa = msa.getName().endsWith(".gz") ? "<(unpigz -cdf ${msa})" : msa + def read_ref = ref_msa.getName().endsWith(".gz") ? "<(unpigz -cdf ${ref_msa})" : ref_msa + + """ + export TEMP='./' + t_coffee -other_pg aln_compare \ + -al1 ${read_ref} \ + -al2 ${read_msa} \ + ${args} \ + | grep -v "seq1" | grep -v '*' | \ + awk '{ print \$4}' ORS="\t" \ + >> "scores.txt" + + # Add metadata info to output file + echo "${header},${metric_name}" > "${prefix}.scores" + + # Add values + scores=\$(awk '{sub(/[[:space:]]+\$/, "")} 1' scores.txt | tr -s '[:blank:]' ',') + echo "${values},\$scores" >> "${prefix}.scores" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + stub: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + """ + touch "${prefix}.scores" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/tcoffee/alncompare/meta.yml b/modules/class-modules/tcoffee/alncompare/meta.yml new file mode 100644 index 0000000..3150255 --- /dev/null +++ b/modules/class-modules/tcoffee/alncompare/meta.yml @@ -0,0 +1,52 @@ +name: "tcoffee_alncompare" +description: Compares 2 alternative MSAs to evaluate them. +keywords: + - alignment + - MSA + - evaluation +tools: + - "tcoffee": + description: "A collection of tools for Multiple Alignments of DNA, RNA, Protein Sequence" + homepage: "http://www.tcoffee.org/Projects/tcoffee/" + documentation: "https://tcoffee.readthedocs.io/en/latest/tcoffee_main_documentation.html" + tool_dev_url: "https://github.com/cbcrg/tcoffee" + doi: "10.1006/jmbi.2000.4042" + licence: ["GPL v3"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', ... ] + - msa: + type: file + description: fasta file containing the alignment to be evaluated. Can be gzipped or uncompressed + pattern: "*.{aln,fa,fasta,fas}{.gz,}" + - ref_msa: + type: file + description: fasta file containing the reference alignment used for the evaluation. Can be gzipped or uncompressed + pattern: "*.{aln,fa,fasta,fas}{.gz,}" + +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" + - scores: + type: file + description: a file containing the score of the alignment + pattern: "*.scores" + +authors: + - "@l-mansouri" + - "@luisas" diff --git a/modules/class-modules/tcoffee/alncompare/tests/main.nf.test b/modules/class-modules/tcoffee/alncompare/tests/main.nf.test new file mode 100644 index 0000000..225a4f1 --- /dev/null +++ b/modules/class-modules/tcoffee/alncompare/tests/main.nf.test @@ -0,0 +1,33 @@ +nextflow_process { + + name "Test Process TCOFFEE_ALNCOMPARE" + script "../main.nf" + process "TCOFFEE_ALNCOMPARE" + tag "modules" + tag "modules_nfcore" + tag "tcoffee" + tag "tcoffee/alncompare" + + test("seatoxin") { + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true), + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin.ref", checkIfExists: true) + ] + """ + } + + } + + then { + assert process.success + assert snapshot(process.out).match() + } + + } + +} diff --git a/modules/class-modules/tcoffee/alncompare/tests/main.nf.test.snap b/modules/class-modules/tcoffee/alncompare/tests/main.nf.test.snap new file mode 100644 index 0000000..d1fd92e --- /dev/null +++ b/modules/class-modules/tcoffee/alncompare/tests/main.nf.test.snap @@ -0,0 +1,31 @@ +{ + "seatoxin": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "setoxin-ref.scores:md5,c77aceec520beb56f08c342e01c56a14" + ] + ], + "1": [ + "versions.yml:md5,438507517a1a831c7b7a1571b1fdd98d" + ], + "scores": [ + [ + { + "id": "test" + }, + "setoxin-ref.scores:md5,c77aceec520beb56f08c342e01c56a14" + ] + ], + "versions": [ + "versions.yml:md5,438507517a1a831c7b7a1571b1fdd98d" + ] + } + ], + "timestamp": "2024-01-22T17:08:59.494237269" + } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/alncompare/tests/nextflow.config b/modules/class-modules/tcoffee/alncompare/tests/nextflow.config new file mode 100644 index 0000000..004820c --- /dev/null +++ b/modules/class-modules/tcoffee/alncompare/tests/nextflow.config @@ -0,0 +1,3 @@ +process { + ext.args = "-compare_mode tc" +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/alncompare/tests/tags.yml b/modules/class-modules/tcoffee/alncompare/tests/tags.yml new file mode 100644 index 0000000..1dd179b --- /dev/null +++ b/modules/class-modules/tcoffee/alncompare/tests/tags.yml @@ -0,0 +1,2 @@ +tcoffee/alncompare: + - "modules/nf-core/tcoffee/alncompare/**" diff --git a/modules/class-modules/tcoffee/irmsd/environment.yml b/modules/class-modules/tcoffee/irmsd/environment.yml new file mode 100644 index 0000000..4065fe7 --- /dev/null +++ b/modules/class-modules/tcoffee/irmsd/environment.yml @@ -0,0 +1,8 @@ +name: "tcoffee_irmsd" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::t-coffee=13.46.0.919e8c6b + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/tcoffee/irmsd/main.nf b/modules/class-modules/tcoffee/irmsd/main.nf new file mode 100644 index 0000000..95e6b61 --- /dev/null +++ b/modules/class-modules/tcoffee/irmsd/main.nf @@ -0,0 +1,55 @@ +process TCOFFEE_IRMSD { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0': + 'biocontainers/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0' }" + + input: + tuple val(meta), file (msa) + tuple val(meta2), file(template), file(structures) + + output: + tuple val(meta), path ("${prefix}.irmsd"), emit: irmsd + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${msa.baseName}" + """ + export TEMP='./' + + if [[ \$(basename $msa) == *.gz ]] ; then + unpigz -f $msa + fi + + t_coffee -other_pg irmsd \ + \$(basename $msa .gz) \ + $args \ + -template_file $template > ${prefix}.irmsd + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${msa.baseName}" + """ + touch ${prefix}.irmsd + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/tcoffee/irmsd/meta.yml b/modules/class-modules/tcoffee/irmsd/meta.yml new file mode 100644 index 0000000..f55fca7 --- /dev/null +++ b/modules/class-modules/tcoffee/irmsd/meta.yml @@ -0,0 +1,55 @@ +name: "tcoffee_irmsd" +description: Computes the irmsd score for a given alignment and the structures. +keywords: + - alignment + - MSA + - evaluation +tools: + - "tcoffee": + description: "A collection of tools for Multiple Alignments of DNA, RNA, Protein Sequence" + homepage: "http://www.tcoffee.org/Projects/tcoffee/" + documentation: "https://tcoffee.readthedocs.io/en/latest/tcoffee_main_documentation.html" + tool_dev_url: "https://github.com/cbcrg/tcoffee" + doi: "10.1006/jmbi.2000.4042" + licence: ["GPL v3"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', ... ] + - msa: + type: file + description: fasta file containing the alignment to be evaluated. May be gzipped or uncompressed. + pattern: "*.{aln,fa,fasta,fas}{.gz,}" + - template: + type: file + description: Template file matching the structures to the sequences in the alignment. + pattern: "*" + - structures: + type: directory + description: Directory containing the structures file matching the sequences in the alignment in PDB format + pattern: "*" + +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" + - irmsd: + type: file + description: File containing the irmsd of the alignment + pattern: "*" + +authors: + - "@luisas" diff --git a/modules/class-modules/tcoffee/irmsd/tests/main.nf.test b/modules/class-modules/tcoffee/irmsd/tests/main.nf.test new file mode 100644 index 0000000..55a574a --- /dev/null +++ b/modules/class-modules/tcoffee/irmsd/tests/main.nf.test @@ -0,0 +1,99 @@ +nextflow_process { + + name "Test Process TCOFFEE_IRMSD" + script "../main.nf" + process "TCOFFEE_IRMSD" + tag "modules" + tag "modules_nfcore" + tag "tcoffee" + tag "tcoffee/irmsd" + tag "untar" + tag "pigz/compress" + + test("seatoxin") { + + setup { + + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/structures/seatoxin-ref.tar.gz", checkIfExists: true) + ] + + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test' ], // meta map + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin.ref", checkIfExists: true) + ] + input[1] = UNTAR.out.untar.map { meta,dir -> [[ id:'test' ], file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/templates/seatoxin-ref_template.txt", checkIfExists: true) ,file(dir).listFiles().collect()]} + """ + } + + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.irmsd.get(0).get(1)).getText().contains("1ahl") } + ) + } + + } + + test("seatoxin - compressed") { + + setup { + + run("UNTAR") { + script "../../../untar/main.nf" + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/structures/seatoxin-ref.tar.gz", checkIfExists: true) + ] + + """ + } + } + + run("PIGZ_COMPRESS") { + script "../../../pigz/compress/main.nf" + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin.ref", checkIfExists: true) + ] + + """ + } + } + } + + when { + process { + """ + input[0] = PIGZ_COMPRESS.out.archive + input[1] = UNTAR.out.untar.map { meta,dir -> [[ id:'test' ], file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/templates/seatoxin-ref_template.txt", checkIfExists: true) ,file(dir).listFiles().collect()]} + """ + } + + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.irmsd.get(0).get(1)).getText().contains("1ahl") } + ) + } + + } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/irmsd/tests/main.nf.test.snap b/modules/class-modules/tcoffee/irmsd/tests/main.nf.test.snap new file mode 100644 index 0000000..c036642 --- /dev/null +++ b/modules/class-modules/tcoffee/irmsd/tests/main.nf.test.snap @@ -0,0 +1,31 @@ +{ + "seatoxin": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "setoxin.irmsd:md5,a8f49fb2621cdc9fe39690a813ad0ca5" + ] + ], + "1": [ + "versions.yml:md5,60646e38ef71127e3736a06c91c2983f" + ], + "irmsd": [ + [ + { + "id": "test" + }, + "setoxin.irmsd:md5,a8f49fb2621cdc9fe39690a813ad0ca5" + ] + ], + "versions": [ + "versions.yml:md5,60646e38ef71127e3736a06c91c2983f" + ] + } + ], + "timestamp": "2023-12-13T12:26:46.827121" + } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/irmsd/tests/tags.yml b/modules/class-modules/tcoffee/irmsd/tests/tags.yml new file mode 100644 index 0000000..637c3c5 --- /dev/null +++ b/modules/class-modules/tcoffee/irmsd/tests/tags.yml @@ -0,0 +1,2 @@ +tcoffee/irmsd: + - "modules/nf-core/tcoffee/irmsd/**" diff --git a/modules/class-modules/tcoffee/seqreformat/environment.yml b/modules/class-modules/tcoffee/seqreformat/environment.yml new file mode 100644 index 0000000..84afe8a --- /dev/null +++ b/modules/class-modules/tcoffee/seqreformat/environment.yml @@ -0,0 +1,7 @@ +name: tcoffee_seqreformat +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - bioconda::t-coffee=13.46.0.919e8c6b diff --git a/modules/class-modules/tcoffee/seqreformat/main.nf b/modules/class-modules/tcoffee/seqreformat/main.nf new file mode 100644 index 0000000..774ae2b --- /dev/null +++ b/modules/class-modules/tcoffee/seqreformat/main.nf @@ -0,0 +1,50 @@ +process TCOFFEE_SEQREFORMAT { + tag "$meta.id" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/t-coffee:13.46.0.919e8c6b--hfc96bf3_0': + 'biocontainers/t-coffee:13.46.0.919e8c6b--hfc96bf3_0' }" + + input: + tuple val(meta), path(infile) + + output: + tuple val(meta), path("${prefix}.txt"), emit: formatted_file + path "versions.yml" , emit: versions + + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + """ + export TEMP='./' + t_coffee -other_pg seq_reformat \ + -in ${infile} \ + $args \ + > "${prefix}.txt" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + prefix = task.ext.prefix ?: "${meta.id}" + """ + touch "${prefix}.txt" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + END_VERSIONS + """ +} + + diff --git a/modules/class-modules/tcoffee/seqreformat/meta.yml b/modules/class-modules/tcoffee/seqreformat/meta.yml new file mode 100644 index 0000000..9c7d9ce --- /dev/null +++ b/modules/class-modules/tcoffee/seqreformat/meta.yml @@ -0,0 +1,46 @@ +name: "tcoffee_seqreformat" +description: Reformats files with t-coffee +keywords: + - reformatting + - alignment + - genomics +tools: + - "tcoffee": + description: "A collection of tools for Computing, Evaluating and Manipulating Multiple Alignments of DNA, RNA, Protein Sequences and Structures." + homepage: "http://www.tcoffee.org/Projects/tcoffee/" + documentation: "https://tcoffee.readthedocs.io/en/latest/tcoffee_main_documentation.html" + tool_dev_url: "https://github.com/cbcrg/tcoffee" + doi: "10.1006/jmbi.2000.4042" + licence: ["GPL v3"] +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test' ]` + + - fasta: + type: file + description: Input file to be reformatted + pattern: "*" + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test' ]` + + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + + - formatted_file: + type: file + description: Formatted file + pattern: "*" + +authors: + - "@luisas" + - "@JoseEspinosa" diff --git a/modules/class-modules/tcoffee/seqreformat/tests/main.nf.test b/modules/class-modules/tcoffee/seqreformat/tests/main.nf.test new file mode 100644 index 0000000..7a5492c --- /dev/null +++ b/modules/class-modules/tcoffee/seqreformat/tests/main.nf.test @@ -0,0 +1,33 @@ +nextflow_process { + + name "Test Process TCOFFEE_SEQREFORMAT" + script "../main.nf" + process "TCOFFEE_SEQREFORMAT" + + tag "modules" + tag "modules_nfcore" + tag "tcoffee" + tag "tcoffee/seqreformat" + + test("sarscov2 - bam") { + + when { + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + """ + } + } + + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.formatted_file).match("formatted_file")}, + { assert snapshot(process.out.versions).match("versions") } + ) + } + } +} diff --git a/modules/class-modules/tcoffee/seqreformat/tests/main.nf.test.snap b/modules/class-modules/tcoffee/seqreformat/tests/main.nf.test.snap new file mode 100644 index 0000000..150102e --- /dev/null +++ b/modules/class-modules/tcoffee/seqreformat/tests/main.nf.test.snap @@ -0,0 +1,23 @@ +{ + "formatted_file": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.txt:md5,fcd4691daf120c88ec5def7ac06fb562" + ] + ] + ], + "timestamp": "2023-11-28T11:56:22.705185493" + }, + "versions": { + "content": [ + [ + "versions.yml:md5,68fb841e6e44274d430a1382bb0bbd14" + ] + ], + "timestamp": "2023-11-28T11:56:22.717235196" + } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/seqreformat/tests/nextflow.config b/modules/class-modules/tcoffee/seqreformat/tests/nextflow.config new file mode 100644 index 0000000..910cc17 --- /dev/null +++ b/modules/class-modules/tcoffee/seqreformat/tests/nextflow.config @@ -0,0 +1,3 @@ +process { + ext.args = "-output=sim_idscore" +} diff --git a/modules/class-modules/tcoffee/seqreformat/tests/tags.yml b/modules/class-modules/tcoffee/seqreformat/tests/tags.yml new file mode 100644 index 0000000..268d881 --- /dev/null +++ b/modules/class-modules/tcoffee/seqreformat/tests/tags.yml @@ -0,0 +1,2 @@ +tcoffee/seqreformat: + - "modules/nf-core/tcoffee/seqreformat/**" diff --git a/modules/class-modules/tcoffee/tcs/environment.yml b/modules/class-modules/tcoffee/tcs/environment.yml new file mode 100644 index 0000000..50480cd --- /dev/null +++ b/modules/class-modules/tcoffee/tcs/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +name: "tcoffee_tcs" +channels: + - conda-forge + - bioconda + - defaults +dependencies: + - "bioconda::t-coffee=13.46.0.919e8c6b" + - conda-forge::pigz=2.8 diff --git a/modules/class-modules/tcoffee/tcs/main.nf b/modules/class-modules/tcoffee/tcs/main.nf new file mode 100644 index 0000000..0c50f52 --- /dev/null +++ b/modules/class-modules/tcoffee/tcs/main.nf @@ -0,0 +1,75 @@ +process TCOFFEE_TCS { + tag "$meta.id" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0': + 'biocontainers/mulled-v2-a76a981c07359a31ff55b9dc13bd3da5ce1909c1:84c8f17f1259b49e2f7783b95b7a89c6f2cb199e-0' }" + + input: + tuple val(meta), path(msa) + tuple val(meta2), path(lib) + + output: + tuple val(meta), path("*.tcs") , emit: tcs + tuple val(meta), path("*.scores"), emit: scores + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def lib_arg = lib ? "-lib ${lib}" : "" + def header = meta.keySet().join(",") + def values = meta.values().join(",") + def unzipped_name = msa.toString() - '.gz' + """ + export TEMP='./' + filename=${msa} + if [[ \$(basename $msa) == *.gz ]] ; then + unpigz -f $msa + filename=${unzipped_name} + fi + + # Bad hack to circumvent t_coffee bug + # Issue described already in: https://github.com/cbcrg/tcoffee/issues/3 + # Add an A in front of filename if the file begins with A + first_letter_filename=\${filename:0:1} + if [ "\$first_letter_filename" == "A" ]; then input="A"\$filename; else input=\$filename; fi + + t_coffee -infile \$input \ + -evaluate -output=score_ascii \ + ${lib_arg} \ + -outfile ${prefix}.tcs + + # Add metadata info to output file + echo "${header},TCS" > "${prefix}.scores" + + # Add values + scores=\$(grep 'SCORE=' ${prefix}.tcs | cut -d '=' -f 2 ) + echo "${values},\$scores" >> "${prefix}.scores" + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.tcs + touch ${prefix}.scores + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + tcoffee: \$( t_coffee -version | awk '{gsub("Version_", ""); print \$3}') + pigz: \$(echo \$(pigz --version 2>&1) | sed 's/^.*pigz\\w*//' )) + END_VERSIONS + """ +} diff --git a/modules/class-modules/tcoffee/tcs/meta.yml b/modules/class-modules/tcoffee/tcs/meta.yml new file mode 100644 index 0000000..a28efad --- /dev/null +++ b/modules/class-modules/tcoffee/tcs/meta.yml @@ -0,0 +1,57 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "tcoffee_tcs" +description: Compute the TCS score for a MSA or for a MSA plus a library file. Outputs the tcs as it is and a csv with just the total TCS score. +keywords: + - alignment + - MSA + - evaluation +tools: + - "tcoffee": + description: "A collection of tools for Multiple Alignments of DNA, RNA, Protein Sequence" + homepage: "http://www.tcoffee.org/Projects/tcoffee/" + documentation: "https://tcoffee.readthedocs.io/en/latest/tcoffee_main_documentation.html" + tool_dev_url: "https://github.com/cbcrg/tcoffee" + doi: "10.1006/jmbi.2000.4042" + licence: ["GPL v3"] + - "pigz": + description: "Parallel implementation of the gzip algorithm." + homepage: "https://zlib.net/pigz/" + documentation: "https://zlib.net/pigz/pigz.pdf" + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', ... ] + - msa: + type: file + description: fasta file containing the alignment to be evaluated. May be gzipped or uncompressed. + pattern: "*.{aln,fa,fasta,fas}{.gz,}" + - lib: + type: file + description: lib file containing the alignment library of the given msa. + pattern: "*{.tc_lib,*_lib}" + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:false ]` + - versions: + type: file + description: File containing software versions + pattern: "versions.yml" + - tcs: + type: file + description: The msa represented in tcs format, prepended with TCS scores + pattern: "*.tcs" + - scores: + type: file + description: a file containing the score of the alignment in csv format + pattern: "*.scores" + +authors: + - "@alessiovignoli" diff --git a/modules/class-modules/tcoffee/tcs/tests/lib.config b/modules/class-modules/tcoffee/tcs/tests/lib.config new file mode 100644 index 0000000..56712f6 --- /dev/null +++ b/modules/class-modules/tcoffee/tcs/tests/lib.config @@ -0,0 +1,5 @@ +process { + withName: "TCOFFEE_ALIGN"{ + ext.args = { "-output fasta_aln -out_lib sample_lib1.tc_lib" } + } +} diff --git a/modules/class-modules/tcoffee/tcs/tests/main.nf.test b/modules/class-modules/tcoffee/tcs/tests/main.nf.test new file mode 100644 index 0000000..35636ff --- /dev/null +++ b/modules/class-modules/tcoffee/tcs/tests/main.nf.test @@ -0,0 +1,114 @@ +nextflow_process { + + name "Test Process TCOFFEE_TCS" + script "../main.nf" + process "TCOFFEE_TCS" + tag "modules" + tag "modules_nfcore" + tag "tcoffee" + tag "tcoffee/tcs" + tag "pigz/compress" + tag "tcoffee/align" + + test("tcs - msa") { + + when { + process { + """ + input[0] = [ + [ id:'test'], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin.ref", checkIfExists: true) + ] + input[1] = [ + [ id:'test'], + [] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("tcs - msa - compressed") { + + setup { + run("PIGZ_COMPRESS") { + script "../../../pigz/compress/main.nf" + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin.ref", checkIfExists: true) + ] + + """ + } + } + } + + when { + process { + """ + input[0] = PIGZ_COMPRESS.out.archive.map { it -> [[ id:'test'], it[1]] } + input[1] = [ + [ id:'test'], + [] + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("tcs - msa - lib") { + + config "./lib.config" + + setup { + run("TCOFFEE_ALIGN") { + script "../../align/main.nf" + process { + """ + input[0] = [ [ id:'test' ], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin-ref.fa", checkIfExists: true) + ] + input[1] = [[:],[]] + input[2] = [[:],[],[]] + input[3] = true + """ + } + } + } + + when { + process { + """ + input[0] = [ + [ id:'test'], + file("https://raw.githubusercontent.com/nf-core/test-datasets/multiplesequencealign/testdata/setoxin.ref", checkIfExists: true) + ] + input[1] = TCOFFEE_ALIGN.out.lib.map { it -> [[ id:'test' ], it[1]] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/class-modules/tcoffee/tcs/tests/main.nf.test.snap b/modules/class-modules/tcoffee/tcs/tests/main.nf.test.snap new file mode 100644 index 0000000..8f6fca1 --- /dev/null +++ b/modules/class-modules/tcoffee/tcs/tests/main.nf.test.snap @@ -0,0 +1,149 @@ +{ + "tcs - msa - lib": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.tcs:md5,d6467c4c358a9fe2d21b5d6d3e128cdb" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.scores:md5,25576b8e2fef74953d28f4e3df689d93" + ] + ], + "2": [ + "versions.yml:md5,99775735c64e1ae150252a3b09576e91" + ], + "scores": [ + [ + { + "id": "test" + }, + "test.scores:md5,25576b8e2fef74953d28f4e3df689d93" + ] + ], + "tcs": [ + [ + { + "id": "test" + }, + "test.tcs:md5,d6467c4c358a9fe2d21b5d6d3e128cdb" + ] + ], + "versions": [ + "versions.yml:md5,99775735c64e1ae150252a3b09576e91" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-19T17:52:51.096817" + }, + "tcs - msa": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.tcs:md5,d6467c4c358a9fe2d21b5d6d3e128cdb" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.scores:md5,25576b8e2fef74953d28f4e3df689d93" + ] + ], + "2": [ + "versions.yml:md5,99775735c64e1ae150252a3b09576e91" + ], + "scores": [ + [ + { + "id": "test" + }, + "test.scores:md5,25576b8e2fef74953d28f4e3df689d93" + ] + ], + "tcs": [ + [ + { + "id": "test" + }, + "test.tcs:md5,d6467c4c358a9fe2d21b5d6d3e128cdb" + ] + ], + "versions": [ + "versions.yml:md5,99775735c64e1ae150252a3b09576e91" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-19T12:47:34.828638" + }, + "tcs - msa - compressed": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.tcs:md5,d6467c4c358a9fe2d21b5d6d3e128cdb" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test.scores:md5,25576b8e2fef74953d28f4e3df689d93" + ] + ], + "2": [ + "versions.yml:md5,99775735c64e1ae150252a3b09576e91" + ], + "scores": [ + [ + { + "id": "test" + }, + "test.scores:md5,25576b8e2fef74953d28f4e3df689d93" + ] + ], + "tcs": [ + [ + { + "id": "test" + }, + "test.tcs:md5,d6467c4c358a9fe2d21b5d6d3e128cdb" + ] + ], + "versions": [ + "versions.yml:md5,99775735c64e1ae150252a3b09576e91" + ] + } + ], + "meta": { + "nf-test": "0.8.4", + "nextflow": "23.10.1" + }, + "timestamp": "2024-03-19T17:37:52.408687" + } +} \ No newline at end of file diff --git a/modules/class-modules/tcoffee/tcs/tests/tags.yml b/modules/class-modules/tcoffee/tcs/tests/tags.yml new file mode 100644 index 0000000..f8ad86b --- /dev/null +++ b/modules/class-modules/tcoffee/tcs/tests/tags.yml @@ -0,0 +1,2 @@ +tcoffee/tcs: + - "modules/nf-core/tcoffee/tcs/**" diff --git a/modules/environment-schema.json b/modules/environment-schema.json new file mode 100644 index 0000000..ca7bdf6 --- /dev/null +++ b/modules/environment-schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "conda environment yaml", + "description": "Validate the environment.yml file for an nf-core module", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the component, same as in the meta.yml" + }, + "channels": { + "type": "array", + "items": [ + { + "enum": ["conda-forge"] + }, + { + "enum": ["bioconda"] + }, + { + "enum": ["defaults"] + } + ], + "minItems": 3 + }, + "dependencies": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["name", "channels", "dependencies"] +} diff --git a/modules/meta-schema.json b/modules/meta-schema.json new file mode 100644 index 0000000..d7cb01c --- /dev/null +++ b/modules/meta-schema.json @@ -0,0 +1,182 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "Meta yaml", + "description": "Validate the meta yaml file for an nf-core module", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the module" + }, + "description": { + "type": "string", + "description": "Description of the module" + }, + "keywords": { + "type": "array", + "description": "Keywords for the module", + "items": { + "type": "string" + }, + "minItems": 3 + }, + "authors": { + "type": "array", + "description": "Authors of the module", + "items": { + "type": "string" + } + }, + "maintainers": { + "type": "array", + "description": "Maintainers of the module", + "items": { + "type": "string" + } + }, + "input": { + "type": "array", + "description": "Input channels for the module", + "items": { + "type": "array", "items": { "$ref": "#/definitions/elementProperties" } + } + }, + "output": { + "type": "array", + "description": "Output channels for the module", + "items": { + "type": "object", "items": { "$ref": "#/definitions/elementProperties" } + } + }, + "tools": { + "type": "array", + "description": "Tools used by the module", + "items": { + "type": "object", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Description of the output channel" + }, + "homepage": { + "type": "string", + "description": "Homepage of the tool", + "pattern": "^(http|https)://.*$" + }, + "documentation": { + "type": "string", + "description": "Documentation of the tool", + "pattern": "^(http|https|ftp)://.*$" + }, + "tool_dev_url": { + "type": "string", + "description": "URL of the development version of the tool's documentation", + "pattern": "^(http|https)://.*$" + }, + "doi": { + "description": "DOI of the tool", + "anyOf": [ + { + "type": "string", + "pattern": "^10\\.\\d{4,9}\\/[^,]+$" + }, + { + "type": "string", + "enum": ["no DOI available"] + } + ] + }, + "licence": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Licence of the tool", + "minItems": 1, + "uniqueItems": true, + "message": "Licence must be an array of one or more entries, e.g. [\"MIT\"]" + }, + "identifier": { + "type": "string", + "description": "bio.tools identifier of the tool", + "pattern": "^biotools:.*$" + } + }, + "required": ["description"], + "anyOf": [ + { + "required": ["homepage"] + }, + { + "required": ["documentation"] + }, + { + "required": ["tool_dev_url"] + }, + { + "required": ["doi"] + } + ] + } + } + } + } + }, + "definitions": { + "elementProperties": { + "type": "object", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Type of the channel element", + "enum": ["map", "file", "directory", "string", "integer", "float", "boolean", "list"] + }, + "qualifier": { + "type": "string", + "description": "Type of the channel element qualifyer", + "enum": ["path", "val", "env", "stdout"] + }, + "description": { + "type": "string", + "description": "Description of the channel" + }, + "pattern": { + "type": "string", + "description": "Pattern of the channel, given in Java glob syntax" + }, + "enum": { + "type": "array", + "description": "List of allowed values for the channel", + "items": { + "type": ["string", "number", "boolean", "array", "object"] + }, + "uniqueItems": true + }, + "ontologies": { + "type": "array", + "description": "List of ontologies for the channel", + "uniqueItems": true, + "items": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string", + "pattern": "^(http|https)://.*" + } + } + } + } + }, + "required": ["qualifier", "description"] + } + } + } + }, + "required": ["name", "description", "keywords", "authors", "output", "tools"] +} \ No newline at end of file diff --git a/nf-test.config b/nf-test.config new file mode 100644 index 0000000..5f90cee --- /dev/null +++ b/nf-test.config @@ -0,0 +1,18 @@ +config { + // location for all nf-tests + testsDir "." + + // nf-test directory including temporary files for each test + workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + + // location of an optional nextflow.config file specific for executing tests + configFile "tests/config/nf-test.config" + + // run all test with the defined docker profile from the main nextflow.config + profile "" + + // load the necessary plugins + plugins { + load "nft-bam@0.2.0" + } +} diff --git a/tests/config/nf-test.config b/tests/config/nf-test.config new file mode 100644 index 0000000..269f2dc --- /dev/null +++ b/tests/config/nf-test.config @@ -0,0 +1,54 @@ +params { + publish_dir_mode = "copy" + singularity_pull_docker_container = false + test_data_base = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules' + modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/' +} + +process { + cpus = 2 + memory = 3.GB + time = 2.h +} + +profiles { + singularity { + singularity.enabled = true + singularity.autoMounts = true + } + conda { + conda.enabled = true + } + mamba { + conda.enabled = true + conda.useMamba = true + } + podman { + podman.enabled = true + podman.userEmulation = true + podman.runOptions = "--runtime crun --platform linux/x86_64 --systemd=always" + } + docker { + docker.enabled = true + docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + } + docker_self_hosted{ + docker.enabled = true + docker.fixOwnership = true + docker.runOptions = '--platform=linux/amd64' + } +} + +docker.registry = 'quay.io' +podman.registry = 'quay.io' +singularity.registry = 'quay.io' + +// Increase time available to build Conda environment +conda { createTimeout = "120 min" } + +// Load test_data.config containing paths to test data +includeConfig 'test_data.config' + +manifest { + nextflowVersion = '!>=23.04.0' +}