├── .github ├── ISSUE_TEMPLATE │ └── issue-report.md └── workflows │ ├── deploy.yml │ ├── generate.yml │ ├── test-repo.yml │ └── test.yml ├── .gitignore ├── CITATION.cff ├── LICENSE ├── Makefile ├── README.md ├── blacklist.txt ├── data.js ├── environment.yml ├── logo-snake.svg ├── make.bat ├── scripts ├── cleanup-catalog.py ├── common.py └── generate-catalog.py ├── skips.json ├── source ├── _static │ ├── custom.css │ ├── icon_modularity_grey.svg │ ├── icon_reproducibility_grey.svg │ ├── icon_scalability_grey.svg │ ├── logo-snake.svg │ └── redirect.js ├── _templates │ ├── all_other_workflows.md │ ├── all_standardized_workflows.md │ ├── layout.html │ ├── workflow_page.md │ └── workflows_by.md ├── build_wf_pages.py ├── build_wf_tables.py ├── conf.py ├── docs │ ├── about │ │ ├── adding_workflows.md │ │ ├── contributions.md │ │ ├── purpose.md │ │ └── using_workflows.md │ ├── catalog.md │ ├── snakemake.md │ └── workflows │ │ └── .gitignore └── index.md └── templates └── data.js /.github/ISSUE_TEMPLATE/issue-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Report an issue with the workflow catalog 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | workflow_run: 5 | workflows: ["Generate catalog"] 6 | types: 7 | - completed 8 | push: 9 | branches: [main, dev] 10 | 11 | defaults: 12 | run: 13 | shell: bash -leo pipefail {0} 14 | 15 | jobs: 16 | deploy: 17 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 18 | permissions: 19 | pages: write # to deploy to Pages 20 | id-token: write # to verify the deployment originates from an appropriate source 21 | environment: 22 | name: github-pages 23 | url: ${{ steps.deployment.outputs.page_url }} 24 | 25 | # Specify runner + deployment step 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v4 29 | 30 | - uses: mamba-org/setup-micromamba@v2 31 | with: 32 | environment-file: environment.yml 33 | init-shell: >- 34 | bash 35 | cache-environment: true 36 | post-cleanup: "all" 37 | 38 | - name: Building 39 | run: make html 40 | 41 | - name: Setup Pages 42 | uses: actions/configure-pages@v5 43 | 44 | - name: Upload artifact 45 | uses: actions/upload-pages-artifact@v3 46 | with: 47 | path: "build/html" 48 | 49 | - name: Deploy artifact 50 | id: deployment 51 | uses: actions/deploy-pages@v4 52 | -------------------------------------------------------------------------------- /.github/workflows/generate.yml: -------------------------------------------------------------------------------- 1 | name: Generate catalog 2 | 3 | on: 4 | schedule: 5 | - cron: 0 5 * * 1 6 | push: 7 | branches: [main, dev] 8 | 9 | jobs: 10 | generate-catalog: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | offset: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 15 | max-parallel: 1 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: deployment 20 | uses: mamba-org/setup-micromamba@v2 21 | with: 22 | environment-file: environment.yml 23 | 24 | - name: Pull latest changes 25 | run: | 26 | git pull --rebase origin ${{ github.ref }} 27 | 28 | - name: generate-catalog 29 | shell: bash -l {0} 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | OFFSET: ${{ matrix.offset }} 33 | LATEST_COMMIT: 7 34 | run: | 35 | python scripts/generate-catalog.py 36 | 37 | - name: Commit files 38 | run: | 39 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 40 | git config --local user.name "github-actions[bot]" 41 | git commit -m "Add changes" -a || echo "No changes to commit" 42 | 43 | - name: Push changes 44 | uses: ad-m/github-push-action@master 45 | with: 46 | github_token: ${{ secrets.GITHUB_TOKEN }} 47 | branch: ${{ github.ref }} 48 | 49 | cleanup-catalog: 50 | runs-on: ubuntu-latest 51 | needs: generate-catalog 52 | strategy: 53 | matrix: 54 | offset: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 55 | max-parallel: 1 56 | steps: 57 | - uses: actions/checkout@v4 58 | 59 | - name: deployment 60 | uses: mamba-org/setup-micromamba@v2 61 | with: 62 | environment-file: environment.yml 63 | 64 | - name: Pull latest changes 65 | run: | 66 | git pull --rebase origin ${{ github.ref }} 67 | 68 | - name: cleanup-catalog 69 | shell: bash -l {0} 70 | env: 71 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | OFFSET: ${{ matrix.offset }} 73 | run: | 74 | python scripts/cleanup-catalog.py 75 | 76 | - name: Commit files 77 | run: | 78 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 79 | git config --local user.name "github-actions[bot]" 80 | git commit -m "Add changes" -a || echo "No changes to commit" 81 | 82 | - name: Push changes 83 | uses: ad-m/github-push-action@master 84 | with: 85 | github_token: ${{ secrets.GITHUB_TOKEN }} 86 | branch: ${{ github.ref }} 87 | -------------------------------------------------------------------------------- /.github/workflows/test-repo.yml: -------------------------------------------------------------------------------- 1 | name: Test repo 2 | 3 | on: 4 | issue_comment: 5 | types: 6 | - created 7 | - edited 8 | 9 | jobs: 10 | test-repo: 11 | runs-on: ubuntu-latest 12 | if: >- 13 | startsWith(github.event.comment.body, '/catalog test repo') 14 | steps: 15 | - uses: actions/github-script@v5 16 | id: info 17 | env: 18 | BODY: ${{ github.event.comment.body }} 19 | with: 20 | script: | 21 | const process = require("process") 22 | const sleep = require('util').promisify(setTimeout) 23 | 24 | const test_repo = process.env.BODY.match(/\/catalog test repo ([^\/]+\/[^\/]+)/)[1] 25 | 26 | while (true) { 27 | const rate_limit = (await github.rest.rateLimit.get()).data.rate 28 | 29 | if (rate_limit.remaining <= 0) { 30 | console.log(rate_limit.reset) 31 | console.log(Date.now() / 1000) 32 | const tosleep = rate_limit.reset - (Date.now() / 1000) + 5 33 | console.log(`Rate limit exceeded, waiting for ${tosleep} seconds.`) 34 | await sleep(tosleep * 1000) 35 | } 36 | 37 | github.rest.issues.createComment({ 38 | issue_number: context.issue.number, 39 | owner: context.repo.owner, 40 | repo: context.repo.repo, 41 | body: `Testing catalog parsing for repository https://github.com/${test_repo}.\nResults: https://github.com/snakemake/snakemake-workflow-catalog/actions/workflows/test-repo.yml` 42 | }) 43 | 44 | return { 45 | test_repo: test_repo 46 | } 47 | } 48 | - name: Post action link 49 | uses: peter-evans/create-or-update-comment@v1 50 | with: 51 | issue-number: ${{ github.event.issue.number }} 52 | body: | 53 | Testing catalog parsing for repository https://github.com/${{ fromJSON(steps.info.outputs.result).test_repo }}. 54 | Results: https://github.com/snakemake/snakemake-workflow-catalog/actions/workflows/test-repo.yml 55 | - uses: actions/checkout@v1 56 | - name: deployment 57 | uses: mamba-org/setup-micromamba@v2 58 | - name: generate-catalog 59 | shell: bash -l {0} 60 | env: 61 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 62 | TEST_REPO: ${{ fromJSON(steps.info.outputs.result).test_repo }} 63 | run: | 64 | python scripts/generate-catalog.py 65 | 66 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | branches: [main, dev] 6 | 7 | jobs: 8 | generate-catalog: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | 13 | - name: deployment 14 | uses: mamba-org/setup-micromamba@v2 15 | with: 16 | environment-file: environment.yml 17 | 18 | # Test the normal catalog generation but restrict to first three repos for speed 19 | - name: test-generate-catalog 20 | shell: bash -l {0} 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | OFFSET: 0 24 | N_REPOS: 3 25 | LATEST_COMMIT: 7 26 | run: | 27 | python scripts/generate-catalog.py 28 | 29 | # Test specific repo, ensuring that the whole catalog generation script is 30 | # executed, in case the first repos above are skipped because it contains no 31 | # updates or no real snakemake workflow 32 | - name: test-generate-catalog-specific-repo 33 | shell: bash -l {0} 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | TEST_REPO: snakemake-workflows/dna-seq-varlociraptor 37 | run: | 38 | python scripts/generate-catalog.py 39 | 40 | cleanup-catalog: 41 | runs-on: ubuntu-latest 42 | needs: generate-catalog 43 | steps: 44 | - uses: actions/checkout@v4 45 | 46 | - name: deployment 47 | uses: mamba-org/setup-micromamba@v2 48 | with: 49 | environment-file: environment.yml 50 | 51 | # Test the cleanup script 52 | - name: cleanup-catalog 53 | shell: bash -l {0} 54 | env: 55 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | OFFSET: 0 57 | N_REPOS: 3 58 | run: | 59 | python scripts/cleanup-catalog.py 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | source/docs/workflows/*.md 73 | source/docs/*.md 74 | 75 | # PyBuilder 76 | .pybuilder/ 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | ENV/ 92 | env.bak/ 93 | venv.bak/ 94 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this workflow catalog in your research, please cite it using the following metadata." 3 | title: "Snakemake Workflow Catalog" 4 | authors: 5 | - family-names: "Koester" 6 | given-names: "Johannes" 7 | orcid: "https://orcid.org/0000-0001-9818-9320" 8 | - family-names: "Jahn" 9 | given-names: "Michael" 10 | orcid: "https://orcid.org/0000-0002-3913-153X" 11 | abstract: > 12 | The Snakemake Workflow Catalog is a collection of standardized workflows 13 | for reproducible and scalable data analysis using Snakemake. Workflows 14 | are automatically retrieved from Github and tested for compliance. 15 | repository-code: "https://github.com/snakemake/snakemake-workflow-catalog" 16 | version: "1.0.0" 17 | date-released: "2025-03-17" 18 | keywords: 19 | - snakemake 20 | - workflow 21 | - reproducibility 22 | - data Analysis 23 | license: "MIT" 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Algorithms for reproducible bioinformatics (Koesterlab) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # snakemake-workflow-catalog 2 | 3 | [![Generate catalog](https://github.com/snakemake/snakemake-workflow-catalog/actions/workflows/generate.yml/badge.svg)](https://github.com/snakemake/snakemake-workflow-catalog/actions/workflows/generate.yml) 4 | [![Deploy catalog](https://github.com/snakemake/snakemake-workflow-catalog/actions/workflows/deploy.yml/badge.svg)](https://github.com/snakemake/snakemake-workflow-catalog/actions/workflows/deploy.yml) 5 | ![GitHub last commit](https://img.shields.io/github/last-commit/snakemake/snakemake-workflow-catalog?label=latest%20update) 6 | ![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/snakemake/snakemake-workflow-catalog) 7 | 8 | A statically generated catalog of available Snakemake workflows 9 | 10 | This repository serves as a centralized collection of workflows designed to facilitate reproducible and scalable data analyses using the [**Snakemake**](https://snakemake.github.io/) workflow management system. 11 | 12 | ## Purpose 13 | 14 | The Snakemake Workflow Catalog aims to provide a regularly updated list of high-quality workflows that can be easily reused and adapted for various data analysis tasks. By leveraging the power of [**Snakemake**](https://snakemake.github.io/), these workflows promote: 15 | 16 | - Reproducibility: Snakemake workflows produce consistent results, making it easier to share and validate scientific findings. 17 | - Scalability: Snakemake workflows can be executed on various computing environments, from local machines to high-performance computing clusters and cloud services. 18 | - Modularity: Snakemake workflows are structured to allow easy customization and extension, enabling users to adapt them to their specific needs. 19 | 20 | ## Workflows 21 | 22 | Workflows are automatically added to the Workflow Catalog. This is done by regularly searching Github repositories for matching workflow structures. The catalog includes workflows based on the following criteria. 23 | 24 | ### All workflows 25 | 26 | - The workflow is contained in a public Github repository. 27 | - The repository has a `README.md` file, containing the words "snakemake" and "workflow" (case insensitive). 28 | - The repository contains a workflow definition named either `Snakefile` or `workflow/Snakefile`. 29 | - If the repository contains a folder `rules` or `workflow/rules`, that folder must at least contain one file ending on `.smk`. 30 | - The repository is small enough to be cloned into a [Github Actions](https://docs.github.com/en/actions/about-github-actions/understanding-github-actions) job (very large files should be handled via [Git LFS](https://docs.github.com/en/repositories/working-with-files/managing-large-files), so that they can be stripped out during cloning). 31 | - The repository is not blacklisted here. 32 | 33 | ### Standardized usage workflows 34 | 35 | In order to additionally appear in the "standardized usage" area, repositories additionally have to: 36 | 37 | - have their main workflow definition named `workflow/Snakefile` (unlike for plain inclusion (see above), which also allows just `Snakefile` in the root of the repository), 38 | - provide configuration instructions under `config/README.md` 39 | - contain a `YAML` file `.snakemake-workflow-catalog.yml` in their root directory, which configures the usage instructions displayed by this workflow catalog. 40 | 41 | Typical content of the `.snakemake-workflow-catalog.yml` file: 42 | 43 | ```yaml 44 | usage: 45 | mandatory-flags: 46 | desc: # describe your flags here in a few sentences 47 | flags: # put your flags here 48 | software-stack-deployment: 49 | conda: true # whether pipeline works with '--sdm conda' 50 | apptainer: true # whether pipeline works with '--sdm apptainer/singularity' 51 | apptainer+conda: true # whether pipeline works with '--sdm conda apptainer/singularity' 52 | report: true # whether creation of reports using 'snakemake --report report.zip' is supported 53 | ``` 54 | 55 | Once included in the standardized usage area you can link directly to the workflow page using the URL `https://snakemake.github.io/snakemake-workflow-catalog/docs/workflows//`. Do not forget to replace the `` and `` tags at the end of the URL. 56 | 57 | ### Release handling 58 | 59 | If your workflow provides Github releases, the catalog will always just scrape the latest non-preview release. Hence, in order to update your workflow's records here, you need to release a new version on Github. 60 | 61 | ## Contributing 62 | 63 | Contributions to the Snakemake Workflow Catalog are welcome! 64 | Ideas can be discussed on the [catalog's Issues page](https://github.com/snakemake/snakemake-workflow-catalog/issues) first, and contributions made through Github Pull Requests, see the [next section](#working-with-a-local-copy) for details. 65 | 66 | ## Working with a local copy 67 | 68 | In order to make contributions, you can set up a local copy of the catalog and test your changes. 69 | 70 | First, fork the repository on Github: 71 | 72 | 1. Go to the [Snakemake Workflow Catalog repository](https://github.com/snakemake/snakemake-workflow-catalog) on Github. 73 | 2. Click on the "Fork" button in the top right corner ([Github documentation: Forking a repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo)). 74 | 75 | Then, clone the forked repository: 76 | 77 | 1. Open a terminal on your local machine. 78 | 2. Run `git clone https://github.com/{your-username}/snakemake-workflow-catalog.git` to clone the repository ([Github documentation: Cloning a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository)). 79 | 80 | Make your changes to the catalog: 81 | 82 | 1. Create a conda/mamba environment in order to work with the catalog locally. 83 | 84 | ```bash 85 | cd /snakemake-workflow-catalog 86 | conda env create -n snakemake-workflow-catalog -f environment.yml 87 | conda activate snakemake-workflow-catalog 88 | ``` 89 | 90 | 2. Set required environmental variables. The variable `TEST_REPO` is used fetch only data from a single workflow. 91 | **Note:** Building the entire catalog from scratch will take several hours due to searching and testing thousands of Github repos. 92 | 93 | ```bash 94 | export GITHUB_TOKEN="" 95 | export OFFSET=0 96 | export LATEST_COMMIT=1000 97 | export TEST_REPO="snakemake-workflows/rna-seq-star-deseq2" 98 | ``` 99 | 100 | 3. Build the catalog data sources using the test repository. 101 | 102 | ```bash 103 | python scripts/generate-catalog.py 104 | python scripts/cleanup-catalog.py 105 | ``` 106 | 107 | 4. Build the catalog web page using sphinx autobuild (live reload). 108 | 109 | ```bash 110 | sphinx-autobuild source/ build/ 111 | ``` 112 | 113 | ... or using the make file (static build). 114 | 115 | ```bash 116 | make html 117 | ``` 118 | 119 | 5. Run `git add .` to stage your changes. 120 | 6. Run `git commit -m "fix: your commit message"` to commit your changes. 121 | 7. Run `git push` to push your changes to your fork on Github. 122 | 123 | Finally, create a pull request: 124 | 125 | 1. Go to your fork on Github. 126 | 2. Follow the instructions on the [Github documentation: Creating a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). 127 | 128 | ## Using workflows from the catalog 129 | 130 | To get started with a workflow from the catalog: 131 | 132 | 1. Clone the repository or download the specific workflow directory. 133 | 2. Review the documentation provided with the workflow to understand its requirements and usage. 134 | 3. Configure the workflow by editing the `config.yml` files as needed. 135 | 4. Execute the workflow using Snakemake. 136 | 137 | For more detailed instructions, please refer to the documentation within each workflow directory. 138 | 139 | ## License 140 | 141 | The Snakemake Workflow Catalog is open-source and available under the MIT License. 142 | For more information and to explore the available workflows, visit https://snakemake.github.io/snakemake-workflow-catalog/. 143 | 144 | Note: All workflows collected and presented on the Catalog are licensed under their own terms! 145 | -------------------------------------------------------------------------------- /blacklist.txt: -------------------------------------------------------------------------------- 1 | snakemake/snakemake-wrappers 2 | snakemake/snakemake 3 | snakemake/snakemake-workflow-catalog 4 | tdayris/fair_bowtie2_mapping 5 | tdayris/fair_fastqc_multiqc 6 | GiulioCentorame/FADS-by-breastfeeding -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: snakemake-workflow-catalog 2 | channels: 3 | - conda-forge 4 | - bioconda 5 | dependencies: 6 | - jinja2=3.1.4 7 | - pygithub=2.5.0 8 | - gitpython=3.1.43 9 | - snakemake >=9.1 # always use the latest release with new syntax support 10 | - snakefmt >=0.11 # always use the latest release with new syntax support 11 | - python=3.12.8 12 | - ratelimit=2.2.1 13 | - mdutils=1.6.0 14 | - sphinx=7.2.6 15 | - sphinxawesome-theme=5.2.0 16 | - sphinx-design=0.6.1 17 | - myst-parser=4.0.1 18 | - pip 19 | - pip: 20 | - sphinxcontrib-jquery 21 | - sphinx-datatables 22 | -------------------------------------------------------------------------------- /logo-snake.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 66 | 71 | 72 | 75 | 80 | 81 | 84 | 89 | 90 | 93 | 98 | 99 | 102 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /scripts/cleanup-catalog.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import math 3 | import os 4 | import time 5 | 6 | from common import store_data, check_repo_exists, g, previous_repos, previous_skips, offset 7 | 8 | def cleanup(repos): 9 | _offset = int(offset / 100 * len(repos)) 10 | n = int(os.environ.get("N_REPOS", math.ceil(len(repos) / 10))) 11 | logging.info(f"Checking {n} repos for existence.") 12 | for i, repo_name in enumerate(list(repos.keys())[_offset:min(_offset + n, len(repos))]): 13 | if i != 0: 14 | time.sleep(5) 15 | 16 | if not check_repo_exists(g, repo_name): 17 | logging.info(f"Repo {repo_name} has been deleted or moved") 18 | del repos[repo_name] 19 | continue 20 | else: 21 | logging.info(f"Repo {repo_name} still exists, keeping data.") 22 | 23 | logging.info("Remove superfluous repos.") 24 | cleanup(previous_repos) 25 | logging.info("Remove superfluous skips.") 26 | cleanup(previous_skips) 27 | 28 | store_data(list(previous_repos.values()), list(previous_skips.values())) -------------------------------------------------------------------------------- /scripts/common.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import subprocess as sp 3 | import os 4 | import json 5 | import calendar 6 | import time 7 | 8 | from ratelimit import limits, sleep_and_retry 9 | from jinja2 import Environment, FileSystemLoader, select_autoescape 10 | from github import Github 11 | from github.ContentFile import ContentFile 12 | from github.GithubException import UnknownObjectException, RateLimitExceededException 13 | 14 | logging.basicConfig(level=logging.INFO) 15 | 16 | test_repo = os.environ.get("TEST_REPO") 17 | offset = int(os.environ.get("OFFSET", 0)) 18 | 19 | env = Environment( 20 | autoescape=select_autoescape(["html"]), loader=FileSystemLoader("templates") 21 | ) 22 | 23 | # do not clone LFS files 24 | os.environ["GIT_LFS_SKIP_SMUDGE"] = "1" 25 | g = Github(os.environ["GITHUB_TOKEN"]) 26 | get_rate_limit = lambda api_type: getattr(g.get_rate_limit(), api_type) 27 | 28 | with open("data.js", "r") as f: 29 | next(f) 30 | previous_repos = {repo["full_name"]: repo for repo in json.loads(f.read())} 31 | 32 | with open("skips.json", "r") as f: 33 | previous_skips = {repo["full_name"]: repo for repo in json.load(f)} 34 | 35 | blacklist = set(l.strip() for l in open("blacklist.txt", "r")) 36 | 37 | snakefmt_version = ( 38 | sp.run(["snakefmt", "--version"], capture_output=True, check=True) 39 | .stdout.decode() 40 | .strip() 41 | .split()[-1] 42 | ) 43 | 44 | 45 | def rate_limit_wait(api_type): 46 | curr_timestamp = calendar.timegm(time.gmtime()) 47 | reset_timestamp = calendar.timegm(get_rate_limit(api_type).reset.timetuple()) 48 | # add 5 seconds to be sure the rate limit has been reset 49 | sleep_time = max(0, reset_timestamp - curr_timestamp) + 5 50 | logging.warning(f"Rate limit exceeded, waiting {sleep_time} seconds") 51 | time.sleep(sleep_time) 52 | 53 | 54 | @sleep_and_retry 55 | @limits(calls=990, period=3600) 56 | def call_rate_limit_aware(func, api_type="core"): 57 | while True: 58 | try: 59 | return func() 60 | except RateLimitExceededException: 61 | rate_limit_wait(api_type) 62 | 63 | 64 | def store_data(repos, skips): 65 | repos.sort(key=lambda repo: repo["stargazers_count"]) 66 | 67 | with open("data.js", "w") as out: 68 | print(env.get_template("data.js").render(data=repos), file=out) 69 | with open("skips.json", "w") as out: 70 | json.dump(skips, out, sort_keys=True, indent=2) 71 | 72 | 73 | def check_repo_exists(g, full_name): 74 | def inner(): 75 | try: 76 | repo = g.get_repo(full_name) 77 | # return true if repo has not been moved (i.e. full name did not change) 78 | # otherwise, we would have retrieved it under the other name in the search 79 | return repo.full_name == full_name 80 | except UnknownObjectException: 81 | logging.info(f"Repo {full_name} has been deleted") 82 | return False 83 | 84 | return call_rate_limit_aware(inner) 85 | -------------------------------------------------------------------------------- /scripts/generate-catalog.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import tempfile 3 | import subprocess as sp 4 | import os 5 | from pathlib import Path 6 | import time 7 | import urllib 8 | import tarfile 9 | import re 10 | from datetime import timedelta, datetime 11 | import git 12 | import yaml 13 | 14 | from common import ( 15 | store_data, 16 | call_rate_limit_aware, 17 | g, 18 | previous_repos, 19 | previous_skips, 20 | blacklist, 21 | snakefmt_version, 22 | offset, 23 | ) 24 | 25 | logging.basicConfig(level=logging.INFO) 26 | 27 | test_repo = os.environ.get("TEST_REPO") 28 | offset = int(offset * 10) 29 | n_repos = int(os.environ.get("N_REPOS", 100)) 30 | assert n_repos >= 1 31 | 32 | repos = [] 33 | skips = [] 34 | 35 | 36 | def register_skip(repo): 37 | skips.append( 38 | {"full_name": repo.full_name, "updated_at": repo.updated_at.timestamp()} 39 | ) 40 | 41 | 42 | class Repo: 43 | data_format = 2 44 | 45 | def __init__( 46 | self, 47 | github_repo, 48 | linting, 49 | formatting, 50 | config_readme, 51 | settings: dict, 52 | release, 53 | updated_at, 54 | topics, 55 | ): 56 | for attr in [ 57 | "full_name", 58 | "description", 59 | "stargazers_count", 60 | "subscribers_count", 61 | ]: 62 | setattr(self, attr, getattr(github_repo, attr)) 63 | 64 | self.topics = topics 65 | self.updated_at = updated_at.timestamp() 66 | 67 | self.linting = linting 68 | 69 | self.formatting = formatting 70 | if formatting is not None: 71 | self.formatting += f"\nsnakefmt version: {snakefmt_version}" 72 | 73 | if release is not None: 74 | self.latest_release = release.tag_name 75 | else: 76 | self.latest_release = None 77 | 78 | if settings is not None and config_readme is not None: 79 | self.mandatory_flags = settings.get("usage", {}).get( 80 | "mandatory-flags", None 81 | ) 82 | self.report = settings.get("usage", {}).get("report", False) 83 | self.software_stack_deployment = settings.get("usage", {}).get( 84 | "software-stack-deployment", {} 85 | ) 86 | self.config_readme = config_readme 87 | self.standardized = True 88 | else: 89 | self.mandatory_flags = [] 90 | self.software_stack_deployment = None 91 | self.config_readme = None 92 | self.report = False 93 | self.standardized = False 94 | 95 | # increase this if fields above change 96 | self.data_format = Repo.data_format 97 | 98 | 99 | if test_repo is not None: 100 | repo_search = [g.get_repo(test_repo)] 101 | total_count = 1 102 | offset = 0 103 | else: 104 | latest_commit = int(os.environ.get("LATEST_COMMIT")) 105 | 106 | date_threshold = datetime.today() - timedelta(latest_commit) 107 | date_threshold = datetime.strftime(date_threshold, "%Y-%m-%d") 108 | repo_search = g.search_repositories( 109 | f"snakemake workflow in:readme archived:false pushed:>={date_threshold}", 110 | sort="updated", 111 | ) 112 | time.sleep(5) 113 | total_count = call_rate_limit_aware( 114 | lambda: repo_search.totalCount, api_type="search" 115 | ) 116 | 117 | end = min(offset + n_repos, total_count) 118 | logging.info(f"Checking {total_count} repos, repo {offset}-{end-1}.") 119 | 120 | for i in range(offset, end): 121 | if i != offset: 122 | # sleep for one minute +x to avoid running into secondary rate limit 123 | time.sleep(63) 124 | 125 | # We access each repo by index instead of using an iterator 126 | # in order to be able to retry the access in case we reach the search 127 | # rate limit. 128 | repo = call_rate_limit_aware(lambda: repo_search[i], api_type="search") 129 | 130 | if i % 10 == 0: 131 | logging.info(f"{i} of {total_count} repos done.") 132 | 133 | log_skip = lambda reason: logging.info( 134 | f"Skipped {repo.full_name} because {reason}." 135 | ) 136 | 137 | logging.info(f"Processing {repo.full_name}.") 138 | if repo.full_name in blacklist: 139 | log_skip("it is blacklisted") 140 | continue 141 | 142 | updated_at = repo.updated_at 143 | releases = call_rate_limit_aware(repo.get_releases) 144 | try: 145 | release = releases[0] 146 | updated_at = max(updated_at, release.created_at) 147 | except IndexError: 148 | # no releases 149 | release = None 150 | 151 | prev = previous_repos.get(repo.full_name) 152 | if ( 153 | prev is not None 154 | and Repo.data_format == prev["data_format"] 155 | and prev["updated_at"] == updated_at.timestamp() 156 | ): 157 | # keep old data, it hasn't changed 158 | logging.info("Repo hasn't changed, keeping old data.") 159 | repos.append(prev) 160 | continue 161 | 162 | prev_skip = previous_skips.get(repo.full_name) 163 | if prev_skip is not None and prev_skip["updated_at"] == updated_at.timestamp(): 164 | # keep old data, it hasn't changed 165 | logging.info("Repo hasn't changed, skipping again based on old data.") 166 | skips.append(prev_skip) 167 | continue 168 | 169 | snakefile = "Snakefile" 170 | rules = "rules" 171 | 172 | with tempfile.TemporaryDirectory() as tmp: 173 | tmp = Path(tmp) 174 | 175 | if release is not None: 176 | # download release tag (use hardcoded url, because repo.tarball_url can sometimes 177 | # cause ambiguity errors if a branch is called the same as the release). 178 | tarball_url = f"https://github.com/{repo.full_name}/tarball/refs/tags/{release.tag_name}" 179 | get_tarfile = lambda: tarfile.open( 180 | fileobj=urllib.request.urlopen(tarball_url), mode="r|gz" 181 | ) 182 | root_dir = get_tarfile().getmembers()[0].name 183 | get_tarfile().extractall(path=tmp, filter="tar") 184 | tmp /= root_dir 185 | else: 186 | # no latest release, clone main branch 187 | try: 188 | gitrepo = git.Repo.clone_from(repo.clone_url, str(tmp), depth=1) 189 | except git.GitCommandError: 190 | log_skip("error cloning repository") 191 | register_skip(repo) 192 | continue 193 | 194 | workflow = tmp / "workflow" 195 | if not workflow.exists(): 196 | workflow = tmp 197 | 198 | rules = workflow / "rules" 199 | snakefile = workflow / "Snakefile" 200 | 201 | if not snakefile.exists(): 202 | log_skip("of missing Snakefile") 203 | register_skip(repo) 204 | continue 205 | 206 | if rules.exists() and rules.is_dir(): 207 | if not any( 208 | rule_file.suffix == ".smk" 209 | for rule_file in rules.iterdir() 210 | if rule_file.is_file() 211 | ): 212 | log_skip("rule modules are not using .smk extension") 213 | register_skip(repo) 214 | continue 215 | 216 | # catalog settings 217 | settings = None 218 | settings_file = tmp / ".snakemake-workflow-catalog.yml" 219 | if settings_file.exists(): 220 | with open(settings_file) as settings_file: 221 | try: 222 | settings = yaml.load(settings_file, yaml.SafeLoader) 223 | except yaml.scanner.ScannerError as e: 224 | logging.info( 225 | "No standardized usage possible because " 226 | "there was an error parsing " 227 | ".snakemake-workflow-catalog.yml:\n{}".format(e) 228 | ) 229 | 230 | linting = None 231 | formatting = None 232 | 233 | # config readme 234 | config_readme = None 235 | config_readme_path = tmp / "config" / "README.md" 236 | if config_readme_path.exists(): 237 | with open(config_readme_path, "r") as f: 238 | config_readme = f.read() 239 | 240 | # linting 241 | try: 242 | out = sp.run( 243 | ["snakemake", "--lint"], capture_output=True, cwd=tmp, check=True 244 | ) 245 | except sp.CalledProcessError as e: 246 | linting = e.stderr.decode() 247 | linting = re.sub("gh[pousr]\\_[a-zA-Z0-9_]{36}@?", "", linting) 248 | if test_repo is not None: 249 | logging.error(linting) 250 | 251 | # formatting 252 | snakefiles = [workflow / "Snakefile"] + list(rules.glob("*.smk")) 253 | fmt_mode = "--check" if test_repo is None else "--diff" 254 | try: 255 | sp.run( 256 | ["snakefmt", fmt_mode, "-v"] + snakefiles, 257 | cwd=tmp, 258 | check=True, 259 | stderr=sp.STDOUT, 260 | stdout=sp.PIPE, 261 | ) 262 | except sp.CalledProcessError as e: 263 | formatting = e.stdout.decode() 264 | if test_repo is not None: 265 | logging.error(formatting) 266 | 267 | topics = call_rate_limit_aware(repo.get_topics) 268 | 269 | repos.append( 270 | Repo( 271 | repo, 272 | linting, 273 | formatting, 274 | config_readme, 275 | settings, 276 | release, 277 | updated_at, 278 | topics, 279 | ).__dict__ 280 | ) 281 | 282 | if test_repo is None: 283 | # Now add all old repos that haven't been covered by the current search. 284 | # This is necessary because Github limits search queries to 1000 items, 285 | # and we always use the 1000 with the most recent changes. 286 | 287 | def add_old(old_repos, current_repos): 288 | visited = set(repo["full_name"] for repo in current_repos) 289 | current_repos.extend( 290 | repo for repo_name, repo in old_repos.items() if repo_name not in visited 291 | ) 292 | 293 | logging.info("Adding all old repos not covered by the current query.") 294 | add_old(previous_repos, repos) 295 | logging.info("Adding all old skipped repos not covered by the current query.") 296 | add_old(previous_skips, skips) 297 | 298 | logging.info("Processed all available repositories.") 299 | if len(repos) < (len(previous_repos) / 2.0): 300 | raise RuntimeError( 301 | "Previous repos have been twice as big, " 302 | "likely something went wrong in the github search, aborting." 303 | ) 304 | 305 | store_data(repos, skips) 306 | -------------------------------------------------------------------------------- /source/_static/custom.css: -------------------------------------------------------------------------------- 1 | .image-reference img { 2 | display: inline; 3 | } 4 | 5 | .image-reference { 6 | border-bottom: none !important; 7 | } 8 | 9 | table code.literal { 10 | white-space: nowrap !important; 11 | } 12 | 13 | #content { 14 | overflow-x: auto; 15 | } 16 | 17 | figure { 18 | padding: 20px; 19 | margin: auto; 20 | text-align: left; 21 | } 22 | 23 | figcaption { 24 | padding: 2px; 25 | text-align: center; 26 | } 27 | 28 | :root { 29 | --sd-color-primary: #059669; 30 | --sd-color-primary-highlight: #056d4c; 31 | --sd-color-secondary: #6c757d; 32 | --sd-color-secondary-highlight: #5c636a; 33 | --sd-color-success: #3cad6e; 34 | } 35 | -------------------------------------------------------------------------------- /source/_static/logo-snake.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 66 | 71 | 72 | 75 | 80 | 81 | 84 | 89 | 90 | 93 | 98 | 99 | 102 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /source/_static/redirect.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function () { 2 | const params = new URLSearchParams(window.location.search); 3 | const usage = params.get("usage"); 4 | 5 | if (usage) { 6 | // Dynamically construct the target URL 7 | const targetUrl = `docs/workflows/${usage}.html`; 8 | 9 | // Redirect to the dynamically constructed URL 10 | window.location.href = targetUrl; 11 | } else { 12 | console.error("No usage parameter found in the URL."); 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /source/_templates/all_other_workflows.md: -------------------------------------------------------------------------------- 1 | --- 2 | notoc: true 3 | description: "all other workflows" 4 | --- 5 | 6 | # All other workflows 7 | 8 | 9 | 10 | ```{csv-table} All other workflows deviating from 'standardized usage' 11 | :header: Workflow,Description,Topics,Reporting,Stars,Watchers 12 | :class: sphinx-datatable 13 | :width: 100% 14 | :widths: auto 15 | 16 | {% for repo in input -%} 17 | [{{ repo["full_name"] }}](){% raw %},{% endraw %} 18 | "{{ repo["description"] }}"{% raw %},{% endraw %} 19 | {%- for t in repo["topics"] -%}{bdg-secondary}`{{ t }}` {% endfor %}{% raw %},{% endraw %} 20 | {bdg-muted}`last update {{ repo["last_update"] }}` 21 | {%- for qc in ["formatting", "linting"] -%} 22 | {%- if repo[qc] == None -%} 23 | {bdg-success}`{{qc}}: passed` 24 | {%- else -%} 25 | {bdg-danger}`{{qc}}: failed` 26 | {%- endif -%} 27 | {% endfor %}{% raw %},{% endraw %} 28 | {{ repo["stargazers_count"] }}{% raw %},{% endraw %} 29 | {{ repo["subscribers_count"] }} 30 | {% endfor %} 31 | ``` 32 | -------------------------------------------------------------------------------- /source/_templates/all_standardized_workflows.md: -------------------------------------------------------------------------------- 1 | --- 2 | notoc: true 3 | description: "all standardized workflows" 4 | --- 5 | 6 | # All standardized workflows 7 | 8 | 9 | 10 | ```{csv-table} All workflows according to 'standardized usage' 11 | :header: Workflow,Description,Topics,Reporting,Stars,Watchers 12 | :class: sphinx-datatable 13 | :width: 100% 14 | :widths: auto 15 | 16 | {% for repo in input -%} 17 | [{{ repo["full_name"] }}](){% raw %},{% endraw %} 18 | "{{ repo["description"] }}"{% raw %},{% endraw %} 19 | {%- for t in repo["topics"] -%}{bdg-secondary}`{{ t }}` {% endfor %}{% raw %},{% endraw %} 20 | {bdg-muted}`last update {{ repo["last_update"] }}` 21 | {%- for qc in ["formatting", "linting"] -%} 22 | {%- if repo[qc] == None -%} 23 | {bdg-success}`{{qc}}: passed` 24 | {%- else -%} 25 | {bdg-ref-danger}`{{qc}}: failed <{{qc}}-{{ repo["full_name"]|slugify }}>` 26 | {%- endif -%} 27 | {% endfor %}{% raw %},{% endraw %} 28 | {{ repo["stargazers_count"] }}{% raw %},{% endraw %} 29 | {{ repo["subscribers_count"] }} 30 | {% endfor %} 31 | ``` 32 | -------------------------------------------------------------------------------- /source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "!layout.html" %} 2 | 3 | {{ super() }} 4 | 5 | {%- block main %} 6 | {%- if meta is defined and meta is not none and 'notoc' in meta %} 7 |
8 | {%- else %} 9 |
10 | {%- endif %} 11 | {%- block body %}{%- endblock %} 12 |
13 | {%- endblock main %} 14 | -------------------------------------------------------------------------------- /source/_templates/workflow_page.md: -------------------------------------------------------------------------------- 1 | 2 | # {{ wf["full_name"] }} 3 | 4 | ::::{grid} 4 5 | {% for badge in ["license", "issues", "stars", "watchers"] %} 6 | :::{grid-item} 7 | :columns: auto 8 | :margin: 0 9 | :padding: 1 10 | ![](https://img.shields.io/github/{{ badge }}/{{ wf["full_name"] }}?style=flat&label={{ badge }}) 11 | ::: 12 | {% endfor %} 13 | :::{grid-item} 14 | :columns: auto 15 | :margin: 0 16 | :padding: 1 17 | [![](https://img.shields.io/badge/GitHub%20page-blue?style=flat)](https://github.com/{{ wf["full_name"] }}) 18 | ::: 19 | :::: 20 | 21 | {{ wf["description"] }} 22 | 23 | ## Overview 24 | 25 | **Topics:** {% for t in wf["topics"] %} {bdg-secondary}`{{ t }}` {% endfor %} 26 | 27 | 28 | **Latest release:** {bdg-primary}`{{ wf["release"] }}`, **Last update:** {bdg-primary}`{{ wf["last_update"] }}` 29 | 30 | 31 | **Linting:** 32 | {% if wf["linting"] == None -%} 33 | {bdg-success}`linting: passed` 34 | {%- else -%} 35 | {bdg-ref-danger}`linting: failed ` 36 | {%- endif -%}, 37 | **Formatting:** 38 | {% if wf["formatting"] == None -%} 39 | {bdg-success}`formatting: passed` 40 | {%- else -%} 41 | {bdg-ref-danger}`formatting: failed ` 42 | {%- endif %} 43 | 44 | ## Deployment 45 | 46 | ### Step 1: Install Snakemake and Snakedeploy 47 | 48 | Snakemake and Snakedeploy are best installed via the [Mamba package manager](https://github.com/mamba-org/mamba) (a drop-in replacement for conda). If you have neither Conda nor Mamba, it is recommended to install [Miniforge](https://github.com/conda-forge/miniforge). 49 | More details regarding Mamba can be found [here](https://github.com/mamba-org/mamba). 50 | 51 | When using Mamba, run 52 | 53 | ```bash 54 | mamba create -c conda-forge -c bioconda --name snakemake snakemake snakedeploy 55 | ``` 56 | 57 | to install both Snakemake and Snakedeploy in an isolated environment. For all following commands ensure that this environment is activated _via_ 58 | 59 | ```bash 60 | conda activate snakemake 61 | ``` 62 | 63 | ### Step 2: Deploy workflow 64 | 65 | With Snakemake and Snakedeploy installed, the workflow can be deployed as follows. 66 | First, create an appropriate project working directory on your system and enter it: 67 | 68 | ```bash 69 | mkdir -p path/to/project-workdir 70 | cd path/to/project-workdir 71 | ``` 72 | 73 | In all following steps, we will assume that you are inside of that directory. Then run 74 | 75 | ```bash 76 | snakedeploy deploy-workflow https://github.com/{{ wf["full_name"] }} . --tag {{ wf["release"] }} 77 | ``` 78 | 79 | Snakedeploy will create two folders, `workflow` and `config`. The former contains the deployment of the chosen workflow as a [Snakemake module](https://snakemake.readthedocs.io/en/stable/snakefiles/deployment.html#using-and-combining-pre-exising-workflows), the latter contains configuration files which will be modified in the next step in order to configure the workflow to your needs. 80 | 81 | ### Step 3: Configure workflow 82 | 83 | To configure the workflow, adapt `config/config.yml` to your needs following the [instructions below](#configuration). 84 | 85 | ### Step 4: Run workflow 86 | 87 | The deployment method is controlled using the `--software-deployment-method` (short `--sdm`) argument. 88 | 89 | {% for depl in wf.deployment %} 90 | {%- if depl == 'conda' %} 91 | 92 | To run the workflow with automatic deployment of all required software via `conda`/`mamba`, use 93 | 94 | ```bash 95 | snakemake --cores all --sdm conda 96 | ``` 97 | 98 | {%- endif -%} 99 | {%- if depl == 'apptainer' %} 100 | 101 | To run the workflow using `apptainer`/`singularity`, use 102 | 103 | ```bash 104 | snakemake --cores all --sdm apptainer 105 | ``` 106 | 107 | {%- endif -%} 108 | {%- if depl == 'apptainer+conda' %} 109 | 110 | To run the workflow using a combination of `conda` and `apptainer`/`singularity` for software deployment, use 111 | 112 | ```bash 113 | snakemake --cores all --sdm conda apptainer 114 | ``` 115 | 116 | {%- endif -%} 117 | {% endfor %} 118 | 119 | Snakemake will automatically detect the main `Snakefile` in the `workflow` subfolder and execute the workflow module that has been defined by the deployment in [step 2](#step-2-deploy-workflow). 120 | 121 | For further options such as cluster and cloud execution, see [the docs](https://snakemake.readthedocs.io/). 122 | 123 | ### Step 5: Generate report 124 | 125 | After finalizing your data analysis, you can automatically generate an interactive visual HTML report for inspection of results together with parameters and code inside of the browser using 126 | 127 | ```bash 128 | snakemake --report report.zip 129 | ``` 130 | 131 | ## Configuration 132 | 133 | _The following section is imported from the workflow's `config/README.md`_. 134 | 135 | {{ wf["config_from_readme"] }} 136 | 137 | ## Linting and formatting 138 | 139 | (linting-{{ wf["full_name"]|slugify }})= 140 | ### Linting results 141 | 142 | {% if wf["linting"] == None %} 143 | ``` 144 | All tests passed! 145 | ``` 146 | {%- else -%} 147 | 148 |
149 | 150 | ```{code-block} 151 | :linenos: 152 | 153 | {{ wf["linting"] }} 154 | ``` 155 |
156 | 157 | {% endif %} 158 | 159 | (formatting-{{ wf["full_name"]|slugify }})= 160 | ### Formatting results 161 | 162 | {% if wf["formatting"] == None %} 163 | ``` 164 | All tests passed! 165 | ``` 166 | {%- else -%} 167 | 168 |
169 | 170 | ```{code-block} 171 | :linenos: 172 | 173 | {{ wf["formatting"] }} 174 | ``` 175 |
176 | 177 | {% endif %} 178 | -------------------------------------------------------------------------------- /source/_templates/workflows_by.md: -------------------------------------------------------------------------------- 1 | # Top workflows by {{ input[0]["metric"] }} 2 | 3 | ::::{grid} 3 4 | 5 | {% for repo in input -%} 6 | 7 | :::{grid-item-card} [{{ repo["name"] }}]() 8 | 9 | {{ repo["user"] }} 10 | 11 | ^^^ 12 | 13 | {{ repo["description"] }} 14 | 15 | --- 16 | 17 | {bdg-muted}`Updated: {{ repo["last_update"] }}` 18 | {bdg-muted}`Release: {{ repo["latest_release"] }}` 19 | {%- for qc in ["formatting", "linting"] -%} 20 | {%- if repo[qc] == None -%} 21 | {bdg-success}`{{qc}}: passed` 22 | {%- else -%} 23 | {bdg-danger}`{{qc}}: failed` 24 | {%- endif -%} 25 | {% endfor %} 26 | 27 | +++ 28 | 29 | {octicon}`feed-star;1.0em;sd-text-success` 30 | {bdg-primary-line}`{{ repo["stargazers_count"] }} stars` 31 | 32 | {octicon}`eye;1.0em;sd-text-success` 33 | {bdg-primary-line}`{{ repo["subscribers_count"] }} watchers` 34 | ::: 35 | {% endfor %} 36 | 37 | :::: 38 | 39 | ```{toctree} 40 | :hidden: 41 | 42 | {% for repo in input -%} 43 | workflows/{{ repo["full_name"] }} 44 | {% endfor %} 45 | ``` 46 | -------------------------------------------------------------------------------- /source/build_wf_pages.py: -------------------------------------------------------------------------------- 1 | import json 2 | import re 3 | from jinja2 import Environment, FileSystemLoader, select_autoescape 4 | from datetime import datetime 5 | from pathlib import Path 6 | 7 | 8 | def check_readme(readme): 9 | clean_readme = [] 10 | readme_split = readme.split("\n") 11 | code_block = False 12 | for i, j in zip(readme_split, range(0, len(readme_split))): 13 | if i.startswith("```"): 14 | code_block = not code_block 15 | if i.startswith("# ") and not code_block: 16 | clean_readme += [i.replace("# ", "## ")] 17 | else: 18 | clean_readme += [i] 19 | return "\n".join(clean_readme) 20 | 21 | 22 | def check_deployment(depl): 23 | result = {} 24 | for i in depl.keys(): 25 | if depl[i]: 26 | result[i.replace("singularity", "apptainer")] = True 27 | return result 28 | 29 | 30 | def check_qc_output(qc_item, max_lines=200): 31 | if qc_item is None: 32 | return None 33 | else: 34 | result = qc_item.split("\n") 35 | if len(result) > max_lines: 36 | return "\n".join(result[:max_lines]) + "\n\n... (truncated)" 37 | else: 38 | return "\n".join(result) 39 | 40 | 41 | def slugify(value): 42 | value = value.lower() 43 | value = re.sub(r"[^a-z0-9]+", "-", value) 44 | value = value.strip("-") 45 | return value 46 | 47 | 48 | def build_wf_pages(): 49 | # import jinja templates 50 | env = Environment( 51 | loader=FileSystemLoader("_templates"), 52 | autoescape=select_autoescape(), 53 | trim_blocks=True, 54 | lstrip_blocks=True, 55 | ) 56 | env.filters["slugify"] = slugify 57 | template = env.get_template("workflow_page.md") 58 | 59 | # import workflow data 60 | with open("../data.js", "r") as f: 61 | next(f) 62 | repos = {} 63 | for repo in json.loads(f.read()): 64 | if repo["standardized"]: 65 | repos[repo["full_name"]] = repo 66 | 67 | # render markdown template with jinja2 for each repo 68 | for current_repo in repos: 69 | repo = repos[current_repo] 70 | wf_data = {} 71 | wf_data["full_name"] = current_repo 72 | # prepare title, description, reporting, qc stats, etc. 73 | wf_data["description"] = repo["description"] 74 | wf_data["topics"] = repo["topics"] 75 | wf_data["linting"] = check_qc_output(repo["linting"]) 76 | wf_data["formatting"] = check_qc_output(repo["formatting"]) 77 | wf_data["release"] = repo["latest_release"] 78 | last_update = datetime.fromtimestamp(repo["updated_at"]) 79 | wf_data["last_update"] = datetime.strftime(last_update, "%Y-%m-%d") 80 | # add deployment options 81 | wf_data["deployment"] = check_deployment(repo["software_stack_deployment"]) 82 | # add configuration from readme; adjust header level if necessary 83 | wf_data["config_from_readme"] = check_readme(repo["config_readme"]) 84 | # render and export 85 | md_rendered = template.render(wf=wf_data) 86 | output_dir = Path(f"docs/workflows/{current_repo.split('/')[0]}") 87 | if not output_dir.exists(): 88 | output_dir.mkdir(parents=True, exist_ok=True) 89 | output_path = output_dir / f"{current_repo.split('/')[1]}.md" 90 | with open(output_path, "w", encoding="utf-8") as f: 91 | f.write(md_rendered) 92 | 93 | # closing statement 94 | print("Workflow pages rendered successfully.") 95 | return None 96 | -------------------------------------------------------------------------------- /source/build_wf_tables.py: -------------------------------------------------------------------------------- 1 | import json 2 | import re 3 | from jinja2 import Environment, FileSystemLoader, select_autoescape 4 | from datetime import datetime 5 | from pathlib import Path 6 | 7 | 8 | # clean repo items, can add more in future 9 | def clean_repo(repo): 10 | if repo["description"] is not None: 11 | repo["description"] = repo["description"].replace('"', "") 12 | if len(repo["description"]) > 100: 13 | repo["description"] = repo["description"][:100] + "..." 14 | else: 15 | repo["description"] = "No description available." 16 | return repo 17 | 18 | 19 | def slugify(value): 20 | value = value.lower() 21 | value = re.sub(r"[^a-z0-9]+", "-", value) 22 | value = value.strip("-") 23 | return value 24 | 25 | 26 | # function to render markdown tables and cards 27 | def render_markdown( 28 | type, 29 | repos, 30 | jinja_env, 31 | template, 32 | output, 33 | metric="stars", 34 | top_n=None, 35 | ): 36 | wf_standard = type == "standardized" 37 | if metric == "stars": 38 | sort_by = "stargazers_count" 39 | reverse = True 40 | elif metric == "update": 41 | sort_by = "updated_at" 42 | reverse = True 43 | elif metric == "watchers": 44 | sort_by = "subscribers_count" 45 | reverse = True 46 | elif metric == "tests": 47 | sort_by = "updated_at" 48 | reverse = True 49 | repos = { 50 | k: v 51 | for k, v in repos.items() 52 | if v["linting"] is None and v["formatting"] is None 53 | } 54 | repos = {k: v for k, v in repos.items() if v["standardized"] == wf_standard} 55 | repos = sorted(repos.values(), key=lambda x: x[sort_by], reverse=reverse) 56 | if top_n: 57 | repos = repos[:top_n] 58 | repos = [clean_repo(repo) for repo in repos] 59 | repos[0]["metric"] = metric 60 | template = jinja_env.get_template(template) 61 | md_rendered = template.render(input=repos) 62 | output_path = Path(output) 63 | with open(output_path, "w", encoding="utf-8") as f: 64 | f.write(md_rendered) 65 | 66 | 67 | def build_wf_tables(): 68 | # items to select from json file 69 | selected_items = [ 70 | "full_name", 71 | "standardized", 72 | "description", 73 | "topics", 74 | "latest_release", 75 | "updated_at", 76 | "linting", 77 | "formatting", 78 | "stargazers_count", 79 | "subscribers_count", 80 | ] 81 | 82 | # import workflow data 83 | with open("../data.js", "r") as f: 84 | next(f) 85 | repos = {} 86 | for repo in json.loads(f.read()): 87 | repo = {k: repo[k] for k in selected_items if k in repo} 88 | repo["user"] = repo["full_name"].split("/")[0] 89 | repo["name"] = repo["full_name"].split("/")[1] 90 | last_update = datetime.fromtimestamp(repo["updated_at"]) 91 | repo["last_update"] = datetime.strftime(last_update, "%Y-%m-%d") 92 | repos[repo["full_name"]] = repo 93 | 94 | # import jinja templates 95 | env = Environment( 96 | loader=FileSystemLoader("_templates"), 97 | autoescape=select_autoescape(), 98 | trim_blocks=True, 99 | lstrip_blocks=True, 100 | ) 101 | env.filters["slugify"] = slugify 102 | 103 | # render tables 104 | for wf_type in ["standardized", "other"]: 105 | render_markdown( 106 | type=wf_type, 107 | repos=repos, 108 | jinja_env=env, 109 | template=f"all_{wf_type}_workflows.md", 110 | output=f"docs/all_{wf_type}_workflows.md", 111 | ) 112 | 113 | # render cards 114 | for metric in ["stars", "watchers", "update", "tests"]: 115 | render_markdown( 116 | type="standardized", 117 | repos=repos, 118 | jinja_env=env, 119 | template="workflows_by.md", 120 | output=f"docs/workflows_by_{metric}.md", 121 | metric=metric, 122 | top_n=15, 123 | ) 124 | 125 | # closing statement 126 | print("Tables and cards rendered successfully.") 127 | return None 128 | -------------------------------------------------------------------------------- /source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | 9 | project = "snakemake-workflow-catalog" 10 | copyright = "2025, The Snakemake team. " 11 | author = "Johannes Koester, Michael Jahn" 12 | 13 | import sys 14 | import os 15 | 16 | sys.path.insert(0, os.path.abspath(".")) 17 | 18 | from build_wf_pages import build_wf_pages 19 | from build_wf_tables import build_wf_tables 20 | from sphinxawesome_theme.postprocess import Icons 21 | 22 | build_wf_pages() 23 | build_wf_tables() 24 | 25 | # -- General configuration --------------------------------------------------- 26 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 27 | 28 | extensions = [ 29 | "myst_parser", 30 | "sphinx_design", 31 | "sphinxcontrib.jquery", 32 | "sphinx_datatables", 33 | ] 34 | 35 | templates_path = ["_templates"] 36 | exclude_patterns = [] 37 | 38 | # -- Options for HTML output ------------------------------------------------- 39 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 40 | 41 | html_theme = "sphinxawesome_theme" 42 | html_static_path = ["_static"] 43 | html_css_files = ["custom.css"] 44 | html_theme_options = { 45 | "logo_light": "_static/logo-snake.svg", 46 | "logo_dark": "_static/logo-snake.svg", 47 | "show_breadcrumbs": True, 48 | "globaltoc_includehidden": True, 49 | "show_prev_next": True, 50 | "main_nav_links": { 51 | "GitHub page": "https://github.com/snakemake/snakemake-workflow-catalog", 52 | "Snakemake homepage": "https://snakemake.github.io", 53 | "Snakemake documentation": "https://snakemake.readthedocs.io", 54 | }, 55 | } 56 | html_title = "Snakemake worklow catalog" 57 | pygments_style = "sphinx" 58 | html_permalinks_icon = Icons.permalinks_icon 59 | suppress_warnings = ["myst.xref_missing", "myst.header"] 60 | myst_enable_extensions = ["colon_fence", "attrs_block"] 61 | myst_heading_anchors = 2 62 | html_sidebars = { 63 | "**": ["globaltoc.html"], 64 | } 65 | 66 | # -- Settings for data-tables plugin ----------------------------------------- 67 | # for all settings see https://datatables.net/reference/option/ 68 | datatables_version = "1.13.4" 69 | datatables_class = "sphinx-datatable" 70 | datatables_options = { 71 | "order": [[4, "desc"]], 72 | } 73 | 74 | # -- Manage redirection of old to new wf pages ------------------------------- 75 | html_js_files = [ 76 | "redirect.js", 77 | ] 78 | -------------------------------------------------------------------------------- /source/docs/about/adding_workflows.md: -------------------------------------------------------------------------------- 1 | 2 | ## Adding workflows 3 | 4 | Workflows are **automatically added** to the Workflow Catalog. This is done by regularly searching Github repositories for matching workflow structures. The catalog includes workflows based on the following criteria. 5 | 6 | ### Generic workflows 7 | 8 | - The workflow is contained in a public Github repository. 9 | - The repository has a `README.md` file, containing the words "snakemake" and "workflow" (case insensitive). 10 | - The repository contains a workflow definition named either `Snakefile` or `workflow/Snakefile`. 11 | - If the repository contains a folder `rules` or `workflow/rules`, that folder must at least contain one file ending on `.smk`. 12 | - The repository is small enough to be cloned into a [Github Actions](https://docs.github.com/en/actions/about-github-actions/understanding-github-actions) job (very large files should be handled via [Git LFS](https://docs.github.com/en/repositories/working-with-files/managing-large-files), so that they can be stripped out during cloning). 13 | - The repository is not blacklisted here. 14 | 15 | ### *Standardized Usage* workflows 16 | 17 | In order to additionally appear in the "standardized usage" area, repositories additionally have to: 18 | 19 | - have their main workflow definition named `workflow/Snakefile` (unlike for [plain inclusion](#generic-workflows), which also allows just `Snakefile` in the root of the repository), 20 | - provide configuration instructions under `config/README.md` 21 | - contain a `YAML` file `.snakemake-workflow-catalog.yml` in their root directory, which configures the usage instructions displayed by this workflow catalog. 22 | 23 | Typical content of the `.snakemake-workflow-catalog.yml` file: 24 | 25 | ```yaml 26 | usage: 27 | mandatory-flags: 28 | desc: # describe your flags here in a few sentences 29 | flags: # put your flags here 30 | software-stack-deployment: 31 | conda: true # whether pipeline works with '--sdm conda' 32 | apptainer: true # whether pipeline works with '--sdm apptainer/singularity' 33 | apptainer+conda: true # whether pipeline works with '--sdm conda apptainer/singularity' 34 | report: true # whether creation of reports using 'snakemake --report report.zip' is supported 35 | ``` 36 | 37 | :::{note} 38 | Definition of mandatory flags can happen through a list of strings (`['--a', '--b']`), or a single string (`'--a --b'`). 39 | ::: 40 | 41 | :::{note} 42 | The content of the `.snakemake-workflow-catalog.yml` file is subject to change. Flags might change in the near future, but current versions will always stay compatible with the catalog. 43 | ::: 44 | 45 | Once included in the standardized usage area you can link directly to the workflow page using the URL `https://snakemake.github.io/snakemake-workflow-catalog/docs/workflows//`. Do not forget to replace the `` and `` tags at the end of the URL. 46 | 47 | ### Release handling 48 | 49 | If your workflow provides Github releases, the catalog will always just scrape the latest non-preview release. Hence, in order to update your workflow's records here, you need to release a new version on Github. 50 | -------------------------------------------------------------------------------- /source/docs/about/contributions.md: -------------------------------------------------------------------------------- 1 | 2 | ## Contributions 3 | 4 | Contributions to the Snakemake Workflow Catalog are welcome! 5 | Ideas can be discussed on the [catalog's Issues page](https://github.com/snakemake/snakemake-workflow-catalog/issues) first, and contributions made through Github Pull Requests. 6 | 7 | ### License 8 | 9 | The Snakemake Workflow Catalog is open-source and available under the [MIT License](https://choosealicense.com/licenses/mit/). 10 | For more information about the individual workflows, browse the [list of *standardized usage* workflows](). 11 | 12 | :::{note} 13 | All workflows collected and presented on the Catalog are licensed under their own terms! 14 | ::: 15 | -------------------------------------------------------------------------------- /source/docs/about/purpose.md: -------------------------------------------------------------------------------- 1 | 2 | ## Purpose 3 | 4 | This repository serves as a centralized collection of workflows designed to facilitate reproducible and scalable data analyses using the [**Snakemake**](https://snakemake.github.io/) workflow management system. 5 | 6 | The Snakemake Workflow Catalog aims to provide a regularly updated list of high-quality workflows that can be easily reused and adapted for various data analysis tasks. By leveraging the power of [**Snakemake**](https://snakemake.github.io/), these workflows promote: 7 | 8 | - **Reproducibility**: Snakemake workflows produce consistent results, making it easier to share and validate scientific findings. 9 | - **Scalability**: Snakemake workflows can be executed on various computing environments, from local machines to high-performance computing clusters and cloud services. 10 | - **Modularity**: Snakemake workflows are structured to allow easy customization and extension, enabling users to adapt them to their specific needs. 11 | -------------------------------------------------------------------------------- /source/docs/about/using_workflows.md: -------------------------------------------------------------------------------- 1 | 2 | ## Using workflows 3 | 4 | ### Basic usage 5 | 6 | To get started with a workflow from the catalog: 7 | 8 | 1. Clone the repository or download the specific workflow directory. 9 | 10 | ```bash 11 | git clone https://github.com// 12 | ``` 13 | 14 | 2. Review the documentation provided with the workflow to understand its requirements and usage. 15 | 16 | 3. Configure the workflow by editing the `config.yml` files as needed. 17 | 18 | 4. Create an environment with access to Snakemake. It is recommended to use `mamba`. 19 | 20 | ```bash 21 | mamba create -n -c snakemake 22 | mamba activate 23 | ``` 24 | 25 | 5. Execute the workflow using Snakemake. 26 | 27 | ```bash 28 | cd 29 | snakemake --cores 2 30 | ``` 31 | 32 | :::{tip} 33 | Use the `--dry-run` option first to check if all inputs are found. 34 | ::: 35 | 36 | For more detailed instructions, please refer to the individual documentation for each [workflow](). 37 | 38 | ### Deployment options 39 | 40 | The deployment method is controlled using the `--software-deployment-method` (short `--sdm`) argument. 41 | 42 | To run the workflow with automatic deployment of all required software via `conda`/`mamba`, use 43 | 44 | ```bash 45 | snakemake --cores all --sdm conda 46 | ``` 47 | 48 | To run the workflow using `apptainer`/`singularity`, use 49 | 50 | ```bash 51 | snakemake --cores all --sdm apptainer 52 | ``` 53 | 54 | To run the workflow using a combination of `conda` and `apptainer`/`singularity` for software deployment, use 55 | 56 | ```bash 57 | snakemake --cores all --sdm conda apptainer 58 | ``` 59 | 60 | Snakemake will automatically detect the main `Snakefile` in the `workflow` subfolder and execute the workflow. 61 | 62 | For further options such as cluster and cloud execution, see [the docs](https://snakemake.readthedocs.io/). 63 | -------------------------------------------------------------------------------- /source/docs/catalog.md: -------------------------------------------------------------------------------- 1 | 2 | # The catalog 3 | 4 | ```{toctree} 5 | :hidden: 6 | ``` 7 | 8 | Here you can find the most important information about the **Snakemake workflow catalog**. 9 | 10 | ```{include} about/purpose.md 11 | ``` 12 | 13 | ```{include} about/using_workflows.md 14 | ``` 15 | 16 | ```{include} about/adding_workflows.md 17 | ``` 18 | 19 | ```{include} about/contributions.md 20 | ``` 21 | -------------------------------------------------------------------------------- /source/docs/snakemake.md: -------------------------------------------------------------------------------- 1 | 2 | # Snakemake 3 | 4 | ```{toctree} 5 | :hidden: 6 | ``` 7 | 8 | ## What is Snakemake? 9 | 10 | The Snakemake workflow management system is a tool to create reproducible and scalable data analyses. Workflows are described *via* a human readable, Python based language. They can be seamlessly scaled to server, cluster, grid and cloud environments, without the need to modify the workflow definition. 11 | 12 | - To learn more about Snakemake, visit the [Snakemake homepage!](https://snakemake.github.io/) 13 | 14 | - To get an impression of the Snakemake architecture, [read the Snakemake paper](https://doi.org/10.12688/f1000research.29032.2) 15 | 16 | - To learn how to use Snakemake workflows, [read the documentation](https://snakemake.readthedocs.io/en/stable/). 17 | 18 | ## Create your own workflows 19 | 20 | The best starting point to create your own workflows is the [Snakemake workflow template](https://github.com/snakemake-workflows/snakemake-workflow-template). 21 | 22 | The template comes with a pre-configured structure that is compatible with the Snakemake catalog ['standardized usage'](). Just fork or clone the template, start addiong rules and push your workflow to Github. The structure of 'standardized' workflows is like this: 23 | 24 | ``` 25 | ├── config/ 26 | │ └── config.yaml 27 | │ └── README.md 28 | ├── workflow/ 29 | │ ├── Snakefile 30 | │ ├── rules/ 31 | │ ├── scripts/ 32 | │ └── envs/ 33 | ├── .snakemake-workflow-catalog.yml 34 | └── README.md 35 | ``` 36 | 37 | :::{note} 38 | The template is currently not fully functional as it contains no actual `Snakefile` and test cases. This will be changed in the near future. 39 | ::: 40 | 41 | -------------------------------------------------------------------------------- /source/docs/workflows/.gitignore: -------------------------------------------------------------------------------- 1 | *.md 2 | -------------------------------------------------------------------------------- /source/index.md: -------------------------------------------------------------------------------- 1 | ```{toctree} 2 | :caption: Workflows 3 | :maxdepth: 2 4 | :hidden: 5 | 6 | docs/workflows_by_stars 7 | docs/workflows_by_watchers 8 | docs/workflows_by_update 9 | docs/workflows_by_tests 10 | docs/all_standardized_workflows 11 | docs/all_other_workflows 12 | ``` 13 | 14 | ```{toctree} 15 | :caption: About 16 | :maxdepth: 2 17 | :hidden: 18 | 19 | docs/snakemake 20 | docs/catalog 21 | ``` 22 | 23 | # Snakemake workflow catalog 24 | 25 |
26 | Snakemake workflow catalog 27 |
28 | 29 | The Snakemake Workflow Catalog aims to provide a regularly updated list of high-quality workflows that can be easily reused and adapted for various data analysis tasks. By leveraging the power of [**Snakemake**](https://snakemake.github.io/), these workflows promote: 30 | 31 | ::::{grid} 3 32 | :::{grid-item-card} **Reproducibility** 33 | Snakemake workflows produce consistent results, making it easier to share and validate scientific findings. 34 | 35 | ::: 36 | :::{grid-item-card} **Scalability** 37 | Snakemake workflows can be executed on various environments, from local machines to clusters and clouds. 38 | 39 | ::: 40 | :::{grid-item-card} **Modularity** 41 | Snakemake workflows allow easy customization and extension, enabling users to adapt them to their needs. 42 | 43 | ::: 44 | :::: 45 | 46 | ## Short cuts 47 | 48 | ::::{grid} 2 49 | :::{grid-item-card} 50 | :columns: auto 51 | ```{button-ref} docs/catalog 52 | :ref-type: myst 53 | :color: primary 54 | Read Introduction - 5 min ⏱️ 55 | ``` 56 | ::: 57 | :::{grid-item-card} 58 | :columns: auto 59 | ```{button-ref} docs/all_standardized_workflows 60 | :ref-type: myst 61 | :color: primary 62 | Explore workflows 🔭 63 | ``` 64 | ::: 65 | :::: 66 | 67 | ## Contributing 68 | 69 | - Improving PRs or issues with the workflow catalog (only the catalog, not the workflows themselves) can be made [here](http://github.com/snakemake/snakemake-workflow-catalog) 70 | - Improving PRs or issues with the listed workflows can be made at the respective workflow repository (see indivuidual [workflow pages]()). 71 | - Resources for creating new workflows can be found [here]() or in more detail on the [Snakemake documnentation](https://snakemake.readthedocs.io/en/stable/index.html) 72 | - New workflows will be [automatically added]() to the workflow catalog if they are contained in eligible Github repositories 73 | -------------------------------------------------------------------------------- /templates/data.js: -------------------------------------------------------------------------------- 1 | var data = 2 | {{ data|tojson(indent=2)|safe }} --------------------------------------------------------------------------------