├── .github └── workflows │ ├── build_binary.yml │ └── deploy.yml ├── .gitignore ├── .vscode └── settings.json ├── Dockerfile ├── LICENSE ├── README.md ├── deno.json ├── deno.lock ├── release.sh ├── src ├── args.ts ├── compare.ts ├── crate.ts ├── main.ts ├── mod.ts └── utils.ts └── tests ├── README.md ├── comparison_results ├── gatk_diff_env.log ├── gatk_same_env.log ├── jga_diff_env.log ├── jga_same_env.log ├── rnaseq_all_files.log ├── rnaseq_diff_env.log ├── rnaseq_diff_ver.log ├── rnaseq_missing_data.log └── rnaseq_same_env.log ├── dump_all_comparison_results.sh ├── example_crate ├── gatk_1st.json ├── gatk_2nd.json ├── gatk_mac.json ├── jga_1st.json ├── jga_2nd.json ├── jga_mac.json ├── rnaseq_1st.json ├── rnaseq_2nd.json ├── rnaseq_mac.json ├── rnaseq_only_sapporo.json ├── rnaseq_small.json ├── rnaseq_v3.6.json ├── trimming.json └── trimming_mac.json ├── gatk_mac_test.ts ├── gatk_test.ts ├── jga_mac_test.ts ├── jga_test.ts ├── rnaseq_all_files_test.ts ├── rnaseq_mac_test.ts ├── rnaseq_only_sapporo_test.ts ├── rnaseq_small_test.ts ├── rnaseq_test.ts ├── rnaseq_v3.6_test.ts └── trimming_mac_test.ts /.github/workflows/build_binary.yml: -------------------------------------------------------------------------------- 1 | name: build_binary 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "src/**" 9 | workflow_dispatch: {} 10 | 11 | jobs: 12 | build-binary: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: "Checkout" 16 | uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 1 19 | 20 | - name: "Setup deno" 21 | uses: denoland/setup-deno@v1 22 | with: 23 | deno-version: "1.40.2" 24 | 25 | - name: "Build binary" 26 | run: | 27 | deno compile --allow-read --allow-net --lock=lock.json --target x86_64-unknown-linux-gnu --output=./tonkaz_x86_64-unknown-linux-gnu src/main.ts 28 | deno compile --allow-read --allow-net --lock=lock.json --target x86_64-apple-darwin --output=./tonkaz_x86_64-apple-darwin src/main.ts 29 | deno compile --allow-read --allow-net --lock=lock.json --target aarch64-apple-darwin --output=./tonkaz_aarch64-apple-darwin src/main.ts 30 | 31 | - name: "Upload x86_64-unknown-linux-gnu binary" 32 | uses: actions/upload-artifact@v3 33 | with: 34 | name: tonkaz_x86_64-unknown-linux-gnu 35 | path: tonkaz_x86_64-unknown-linux-gnu 36 | 37 | - name: "Upload x86_64-apple-darwin binary" 38 | uses: actions/upload-artifact@v3 39 | with: 40 | name: tonkaz_x86_64-apple-darwin 41 | path: tonkaz_x86_64-apple-darwin 42 | 43 | - name: "Upload aarch64-apple-darwin binary" 44 | uses: actions/upload-artifact@v3 45 | with: 46 | name: tonkaz_aarch64-apple-darwin 47 | path: tonkaz_aarch64-apple-darwin 48 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: deploy 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*.*.*" 7 | 8 | jobs: 9 | build_binary: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "Checkout" 13 | uses: actions/checkout@v3 14 | with: 15 | fetch-depth: 1 16 | - name: "Setup deno" 17 | uses: denoland/setup-deno@v1 18 | with: 19 | deno-version: "1.40.2" 20 | - name: "Build binary" 21 | run: | 22 | deno compile --allow-read --allow-net --lock=lock.json --target x86_64-unknown-linux-gnu --output=./tonkaz_x86_64-unknown-linux-gnu src/main.ts 23 | deno compile --allow-read --allow-net --lock=lock.json --target x86_64-apple-darwin --output=./tonkaz_x86_64-apple-darwin src/main.ts 24 | deno compile --allow-read --allow-net --lock=lock.json --target aarch64-apple-darwin --output=./tonkaz_aarch64-apple-darwin src/main.ts 25 | - name: "Upload x86_64-unknown-linux-gnu binary" 26 | uses: actions/upload-artifact@v3 27 | with: 28 | name: tonkaz_x86_64-unknown-linux-gnu 29 | path: tonkaz_x86_64-unknown-linux-gnu 30 | - name: "Upload x86_64-apple-darwin binary" 31 | uses: actions/upload-artifact@v3 32 | with: 33 | name: tonkaz_x86_64-apple-darwin 34 | path: tonkaz_x86_64-apple-darwin 35 | - name: "Upload aarch64-apple-darwin binary" 36 | uses: actions/upload-artifact@v3 37 | with: 38 | name: tonkaz_aarch64-apple-darwin 39 | path: tonkaz_aarch64-apple-darwin 40 | 41 | create_release: 42 | needs: [build_binary] 43 | runs-on: ubuntu-latest 44 | steps: 45 | - name: "Download x86_64-unknown-linux-gnu binary" 46 | uses: actions/download-artifact@v3 47 | with: 48 | name: tonkaz_x86_64-unknown-linux-gnu 49 | - name: "Download x86_64-apple-darwin binary" 50 | uses: actions/download-artifact@v3 51 | with: 52 | name: tonkaz_x86_64-apple-darwin 53 | - name: "Download aarch64-apple-darwin binary" 54 | uses: actions/download-artifact@v3 55 | with: 56 | name: tonkaz_aarch64-apple-darwin 57 | - name: "Release" 58 | run: | 59 | gh release \ 60 | --repo ${{ github.repository }} \ 61 | create ${{ github.ref_name }} \ 62 | --title ${{ github.ref_name }} \ 63 | --generate-notes \ 64 | tonkaz_x86_64-unknown-linux-gnu \ 65 | tonkaz_x86_64-apple-darwin \ 66 | tonkaz_aarch64-apple-darwin 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | 70 | deploy_ghcr: 71 | needs: [create_release] 72 | runs-on: ubuntu-latest 73 | steps: 74 | - name: "Checkout" 75 | uses: actions/checkout@v3 76 | with: 77 | fetch-depth: 1 78 | - name: "Set up QEMU" 79 | uses: docker/setup-qemu-action@v2 80 | - name: "Set up Docker Buildx" 81 | uses: docker/setup-buildx-action@v2 82 | - name: "Login to GitHub Container Registry" 83 | uses: docker/login-action@v2 84 | with: 85 | registry: ghcr.io 86 | username: ${{ github.repository_owner }} 87 | password: ${{ secrets.GITHUB_TOKEN }} 88 | - name: "Build and push" 89 | uses: docker/build-push-action@v3 90 | with: 91 | context: . 92 | platforms: linux/amd64,linux/arm64 93 | push: true 94 | tags: | 95 | ghcr.io/${{ github.repository_owner }}/tonkaz:${{ github.ref_name }} 96 | ghcr.io/${{ github.repository_owner }}/tonkaz:latest 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sapporo-wes/tonkaz/172235d18a7f1fdd1aedb4e93540b7728fb9104a/.gitignore -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.unstable": true, 4 | "[typescript]": { 5 | "editor.defaultFormatter": "denoland.vscode-deno" 6 | }, 7 | "[json]": { 8 | "editor.defaultFormatter": "denoland.vscode-deno" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | LABEL org.opencontainers.image.authors="@suecharo " 4 | LABEL org.opencontainers.image.url="https://github.com/sapporo-wes/tonkaz" 5 | LABEL org.opencontainers.image.source="https://github.com/sapporo-wes/tonkaz/blob/main/Dockerfile" 6 | LABEL org.opencontainers.image.version="0.3.0" 7 | LABEL org.opencontainers.image.description="CLI tool to verify workflow reproducibility" 8 | LABEL org.opencontainers.image.licenses="Apache2.0" 9 | 10 | ADD https://github.com/sapporo-wes/tonkaz/releases/latest/download/tonkaz_x86_64-unknown-linux-gnu /usr/bin/tonkaz 11 | RUN chmod +x /usr/bin/tonkaz 12 | 13 | WORKDIR /app 14 | 15 | ENTRYPOINT ["tonkaz"] 16 | CMD [""] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 @suecharo(suehiro619@gmail.com) 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tonkaz 2 | 3 | [![DOI](https://zenodo.org/badge/195738176.svg)](https://zenodo.org/badge/latestdoi/195738176) 4 | [![Apache License](https://img.shields.io/badge/license-Apache%202.0-orange.svg?style=flat&color=important)](http://www.apache.org/licenses/LICENSE-2.0) 5 | 6 | **[Publication on GigaScience](https://doi.org/10.1093/gigascience/giad031)** 7 | 8 | Tonkaz is a CLI tool to verify workflow reproducibility. 9 | It compares the [RO-Crate](https://www.researchobject.org/ro-crate/) of workflow execution results and calculates the reproducibility level of each output file. 10 | 11 | Reproducibility level is defined as follows: 12 | 13 | ```text 14 | - Level3 ⭐⭐⭐ : Files are identical with the same checksum 15 | - Level2 ⭐⭐ : Files are different, but their features (file size, map rate, etc.) are similar (within threshold: 0.05) 16 | - Level1 ⭐ : Files are different, and their features are different (beyond threshold) 17 | - Level0 : File not found 18 | 19 | Level3: "Fully Reproduced" <---> Level0: "Not Reproduced" 20 | ``` 21 | 22 | If you want to try easily, run as follows. 23 | It compares the execution results of [nf-core/rnaseq v3.7](https://nf-co.re/rnaseq/3.7/usage) twice in the same Linux environment. 24 | 25 | ```bash 26 | $ tonkaz ./tests/example_crate/rnaseq_1st.json ./tests/example_crate/rnaseq_2nd.json 27 | 28 | # Example output: 29 | $ cat ./tests/comparison_results/rnaseq_same_env.log 30 | ``` 31 | 32 | We provide various examples in the [tests/README.md](./tests/README.md). 33 | Please check it out. 34 | 35 | ## Installation 36 | 37 | Use a single binary that is built without any dependencies. 38 | 39 | ```bash 40 | # for Linux x86_64 41 | $ curl -fsSL -o ./tonkaz https://github.com/sapporo-wes/tonkaz/releases/latest/download/tonkaz_x86_64-unknown-linux-gnu 42 | 43 | # for Mac x86_64 44 | $ curl -fsSL -o ./tonkaz https://github.com/sapporo-wes/tonkaz/releases/latest/download/tonkaz_x86_64-apple-darwin 45 | 46 | # for Mac Apple silicon 47 | $ curl -fsSL -o ./tonkaz https://github.com/sapporo-wes/tonkaz/releases/latest/download/tonkaz_aarch64-apple-darwin 48 | 49 | $ chmod +x ./tonkaz 50 | $ ./tonkaz --help 51 | ``` 52 | 53 | Or, use the Docker environment: 54 | 55 | ```bash 56 | docker run -it --rm ghcr.io/sapporo-wes/tonkaz:latest --help 57 | ``` 58 | 59 | ## Usage 60 | 61 | Pass two crates as arguments to the `tonkaz` command. (local file or URL) 62 | 63 | ```bash 64 | tonkaz crate1.json crate2.json 65 | ``` 66 | 67 | For more details: 68 | 69 | ```bash 70 | $ tonkaz -h 71 | Tonkaz 0.1.0 by @suecharo 72 | 73 | CLI tool to verify workflow reproducibility 74 | 75 | Usage: tonkaz [options] crate1 crate2 76 | 77 | Options: 78 | -a, --all Use all output files for comparison 79 | -t, --threshold Set threshold for comparison (default: 0.05) 80 | -h, --help Show this help message and exit 81 | -v, --version Show version and exit 82 | 83 | Examples: 84 | $ tonkaz crate1 crate2 85 | $ tonkaz crate1 https://example.com/crate2 86 | $ tonkaz https://example.com/crate1 https://example.com/crate2 87 | ``` 88 | 89 | ## How to prepare an RO-Crate for `Tonkaz`? 90 | 91 | Tonkaz supports **ONLY** RO-Crate generated by [`Sapporo-service`](https://github.com/sapporo-wes/sapporo-service) (version 1.6.0 or newer) or [`Yevis-cli`](https://github.com/sapporo-wes/yevis-cli). 92 | For more information about Sapporo and Yevis, please see these repositories. 93 | 94 | The RO-Crate can be generated to pass the `--fetch-ro-crate` option to Yevis-cli's `test` command as follows: 95 | 96 | ```bash 97 | # Execute the workflow 98 | $ yevis test --fetch-ro-crate https://example.com/path/to/yevis-metadata-file 99 | 100 | # The RO-Crate is generated in the `test-logs` directory 101 | $ ls test-logs/ 102 | ro-crate-metadata_c13b6e27-a4ee-426f-8bdb-8cf5c4310bad_1.0.0_test_1.json 103 | ``` 104 | 105 | Or, the RO-Crate can be generated from Sapporo's run_dir. 106 | 107 | ```bash 108 | # At Sapporo run_dir 109 | $ ls 110 | cmd.txt run.sh state.txt 111 | exe/ run_request.json stderr.log 112 | executable_workflows.json sapporo_config.json stdout.log 113 | outputs/ service_info.json workflow_engine_params.txt 114 | run.pid start_time.txt yevis-metadata.yml 115 | 116 | # Execute sapporo/ro_crate.py script 117 | $ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $PWD:$PWD -w $PWD ghcr.io/sapporo-wes/sapporo-service:latest python3 /app/sapporo/ro_crate.py $PWD 118 | ``` 119 | 120 | ## Comparison of MultiQC Statistics (New Feature in 0.3.0) 121 | 122 | Sapporo-service, from version 1.6.0 onwards, introduced a feature where MultiQC is executed after workflow completion, and its results are added to the RO-Crate. 123 | Tonkaz can compare these MultiQC results. 124 | MultiQC checks the workflow output, extracts units per sample, and aggregates statistical data from each tool for individual samples. 125 | 126 | Previously, Tonkaz facilitated comparisons at the file level, but with the introduction of MultiQC comparison, it is now possible to compare at the sample level. 127 | Please note that since it is difficult to handle file-level and sample-level comparisons in parallel, the MultiQC comparison is an additional feature. 128 | 129 | However, this sample-level comparison is considered beneficial as it allows for more detailed comparison of workflow results. 130 | 131 | An example of the comparison results is as follows: 132 | 133 | ```text 134 | - Salmon Num_mapped 135 | .--------------------------------------------------------------------------. 136 | | Sample | in Crate1 | in Crate2 | Level | 137 | |--------------------------------|--------------|--------------|-----------| 138 | | RAP1_IAA_30M_REP1 | 38268 | 40165 | ⭐⭐ | 139 | | RAP1_UNINDUCED_REP1 | 39317 | 39317 | ⭐⭐ | 140 | | RAP1_UNINDUCED_REP2 | 78884 | 81361 | ⭐⭐ | 141 | | WT_REP1 | 74109 | 74109 | ⭐⭐ | 142 | | WT_REP2 | 37368 | 37368 | ⭐⭐ | 143 | '--------------------------------------------------------------------------' 144 | 145 | - Samtools Flagstat_total 146 | .--------------------------------------------------------------------------. 147 | | Sample | in Crate1 | in Crate2 | Level | 148 | |--------------------------------|--------------|--------------|-----------| 149 | | RAP1_IAA_30M_REP1 | 94912 | 94912 | ⭐⭐ | 150 | | RAP1_UNINDUCED_REP1 | 49040 | 49040 | ⭐⭐ | 151 | | RAP1_UNINDUCED_REP2 | 98338 | 98338 | ⭐⭐ | 152 | | WT_REP1 | 188243 | 188241 | ⭐⭐ | 153 | | WT_REP2 | 94419 | 94419 | ⭐⭐ | 154 | '--------------------------------------------------------------------------' 155 | 156 | ## Development 157 | 158 | We use [Deno](https://deno.land/) `v1.40.2`. 159 | 160 | If you want to use the Docker environment, please run the following command: 161 | 162 | ```bash 163 | $ docker run -it --rm -v $PWD:$PWD -w $PWD denoland/deno:1.40.2 deno --version 164 | deno 1.40.2 (release, x86_64-unknown-linux-gnu) 165 | v8 12.1.285.6 166 | typescript 5.3.3 167 | ``` 168 | 169 | ### Testing 170 | 171 | Please see [`./tests`](./tests) directory. 172 | 173 | ## License 174 | 175 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0). 176 | See the [LICENSE](https://github.com/sapporo-wes/tonkaz/blob/main/LICENSE). 177 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "main": "deno run --allow-read --allow-net src/main.ts" 4 | }, 5 | "imports": { 6 | "ascii_table": "https://deno.land/x/ascii_table@v0.1.0/mod.ts", 7 | "colors": "https://deno.land/std@0.213.0/fmt/colors.ts", 8 | "datetime": "https://deno.land/std@0.213.0/datetime/mod.ts", 9 | "emoji": "https://deno.land/x/emoji@0.3.0/mod.ts", 10 | "parse_args": "https://deno.land/std@0.213.0/cli/parse_args.ts" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3", 3 | "remote": { 4 | "https://deno.land/std@0.213.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9", 5 | "https://deno.land/std@0.213.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", 6 | "https://deno.land/std@0.213.0/cli/parse_args.ts": "cc3e9ac1684a65bada17dbfe1b53cd7c1b1ce1f009fdd1ddb1d62e53a3d9732f", 7 | "https://deno.land/std@0.213.0/datetime/_common.ts": "a62214c1924766e008e27d3d843ceba4b545dc2aa9880de0ecdef9966d5736b6", 8 | "https://deno.land/std@0.213.0/datetime/constants.ts": "5c198b3b47fbcc4d913e61dcae1c37e053937affc2c9a6a5ad7e5473bab3e4a6", 9 | "https://deno.land/std@0.213.0/datetime/day_of_year.ts": "501924941a9b007dc4f6a805c14eb10397fa03af3db5670c5df8b67f40ca0e92", 10 | "https://deno.land/std@0.213.0/datetime/difference.ts": "eb32269322353e8c88375b98b20791311012a84a47050c690221ed5c820a58f1", 11 | "https://deno.land/std@0.213.0/datetime/format.ts": "aea98f9b51abebe79805cf4b6e566ae6cdf4f91dfd728e2e2505de4729e03f2a", 12 | "https://deno.land/std@0.213.0/datetime/is_leap.ts": "8c22857127daad38593124408382cd09b7f8f19d2b33b44b7d04e6a176d621e0", 13 | "https://deno.land/std@0.213.0/datetime/mod.ts": "e191e5498662322024f21e29875cb4d6c5a9bf55e54d571b144c17678b069044", 14 | "https://deno.land/std@0.213.0/datetime/parse.ts": "bb248bbcb3cd54bcaf504a1ee670fc4695e429d9019c06af954bbe2bcb8f1d02", 15 | "https://deno.land/std@0.213.0/datetime/week_of_year.ts": "efbafeff83418e049931d1668669396025020a73094af6291129761d68aa6a73", 16 | "https://deno.land/std@0.213.0/fmt/colors.ts": "aeaee795471b56fc62a3cb2e174ed33e91551b535f44677f6320336aabb54fbb", 17 | "https://deno.land/x/ascii_table@v0.1.0/mod.ts": "bd99729ffefd9e0792787b7aafd06c5257039b31ffe3b987fe5257d3fa0c39b5", 18 | "https://deno.land/x/emoji@0.3.0/all.json": "f0553b660db5e44e71ca46f637a06c2ec94f34445a920fcf319858094a91f46b", 19 | "https://deno.land/x/emoji@0.3.0/emoji.ts": "ad21fa393b2b96fb5999f58dec18e13628cc5d11aa370c42a2f7cc8e135d43d8", 20 | "https://deno.land/x/emoji@0.3.0/mod.ts": "9ef5a2fca1a633f29747b6d3254afd19545cef586128a8213a1003ee2808186d", 21 | "https://deno.land/x/emoji@0.3.0/types.ts": "5897345f500088c719a35388c5b192bc5d93fc2c13e37d94eafa8ff3480edd17", 22 | "https://deno.land/x/emoji@0.3.0/unicode.ts": "ac8079e8e1da66ae9e601c1fdd0e7641120c2b07ca7bd2875e65fe23e16e6199" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euxo pipefail 3 | 4 | if [[ $# -lt 1 ]]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | PREV_VERSION=$(git describe --abbrev=0 --tags) 10 | NEW_VERSION=$1 11 | 12 | read -p "Does update version from $PREV_VERSION to $NEW_VERSION? (y/n) :" YN 13 | 14 | if [[ "$YN" != "y" ]]; then 15 | echo "Aborted." 16 | exit 1 17 | fi 18 | 19 | NOW_BRANCH=$(git rev-parse --abbrev-ref HEAD) 20 | 21 | if [[ "$NOW_BRANCH" != "main" ]]; then 22 | echo "You must be on main branch." 23 | git checkout main 24 | fi 25 | 26 | echo "Rewrite files." 27 | sed -i "s/version=\"$PREV_VERSION\"/version=\"$NEW_VERSION\"/g" Dockerfile 28 | sed -i "s/TonkazVersion = \"$PREV_VERSION\"/TonkazVersion = \"$NEW_VERSION\"/g" src/main.ts 29 | 30 | echo "Commit and push." 31 | git add Dockerfile src/main.ts 32 | git commit -m "Update version to $NEW_VERSION" 33 | git push origin main 34 | 35 | echo "Tag and push." 36 | git tag $NEW_VERSION 37 | git push origin $NEW_VERSION 38 | 39 | echo "Done." 40 | 41 | echo "Summary of changes." 42 | git log --oneline --pretty=tformat:"%h %s" "$PREV_VERSION..$NEW_VERSION" 43 | 44 | exit 0 45 | -------------------------------------------------------------------------------- /src/args.ts: -------------------------------------------------------------------------------- 1 | import * as colors from "colors"; 2 | import { parseArgs as parse } from "parse_args"; 3 | 4 | import { compare, main, utils } from "./mod.ts"; 5 | 6 | function usage(): void { 7 | console.log(`\ 8 | Tonkaz ${main.TonkazVersion} by @suecharo 9 | 10 | CLI tool to verify workflow reproducibility 11 | 12 | ${colors.blue("Usage:")} tonkaz [options] crate1 crate2 13 | 14 | ${colors.blue("Options:")} 15 | -a, --all Use all output files for comparison 16 | -t, --threshold Set threshold for comparison (default: ${compare.DEFAULT_THRESHOLD}) 17 | -j, --json Output result as JSON 18 | -s, --suppressMultiqc Suppress comparison of MultiQC statistics 19 | -h, --help Show this help message and exit 20 | -v, --version Show version and exit 21 | 22 | ${colors.blue("Examples:")} 23 | $ tonkaz crate1 crate2 24 | $ tonkaz crate1 https://example.com/crate2 25 | $ tonkaz https://example.com/crate1 https://example.com/crate2`); 26 | Deno.exit(1); 27 | } 28 | 29 | export interface Args { 30 | all: boolean; 31 | threshold: number; 32 | loc1: string; 33 | loc2: string; 34 | json: boolean; 35 | suppressMultiqc: boolean; 36 | } 37 | 38 | export async function parseArgs(args: string[]): Promise { 39 | const parsedArgs = parse(args, { 40 | boolean: ["all", "help", "version", "json", "suppressMultiqc"], 41 | string: ["threshold"], 42 | alias: { 43 | a: "all", 44 | t: "threshold", 45 | h: "help", 46 | v: "version", 47 | j: "json", 48 | s: "suppressMultiqc", 49 | }, 50 | }); 51 | 52 | parsedArgs.help && usage(); 53 | if (parsedArgs.version) { 54 | console.log(main.TonkazVersion); 55 | Deno.exit(0); 56 | } 57 | if (parsedArgs._.length !== 2) { 58 | throw new Error("Invalid number of arguments (expected: 2)"); 59 | } 60 | 61 | const loc1 = `${parsedArgs._[0]}`; 62 | const loc1_isFileOrRemote = await utils.isFileOrRemote(loc1); 63 | if (!loc1_isFileOrRemote) { 64 | throw new Error(`Invalid location: ${loc1}`); 65 | } 66 | 67 | const loc2 = `${parsedArgs._[1]}`; 68 | const loc2_isFileOrRemote = await utils.isFileOrRemote(loc2); 69 | if (!loc2_isFileOrRemote) { 70 | throw new Error(`Invalid location: ${loc2}`); 71 | } 72 | 73 | let threshold: number; 74 | if (parsedArgs.threshold == undefined) { 75 | threshold = compare.DEFAULT_THRESHOLD; 76 | } else { 77 | threshold = Number(parsedArgs.threshold); 78 | if (Number.isNaN(threshold)) { 79 | throw new Error("Threshold must be a number"); 80 | } 81 | if (threshold < 0 || threshold > 1) { 82 | throw new Error("Threshold must be between 0 and 1"); 83 | } 84 | } 85 | 86 | return { 87 | all: parsedArgs.all, 88 | threshold: threshold, 89 | loc1, 90 | loc2, 91 | json: parsedArgs.json, 92 | suppressMultiqc: parsedArgs.suppressMultiqc, 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /src/compare.ts: -------------------------------------------------------------------------------- 1 | import { crate, main, utils } from "./mod.ts"; 2 | import * as ascii_table from "ascii_table"; 3 | import * as emoji from "emoji"; 4 | import * as colors from "colors"; 5 | import * as datetime from "datetime"; 6 | export const DEFAULT_THRESHOLD = 0.05; 7 | export const OUTPUTS_ID_PREFIX_RE = new RegExp(`^outputs/`); 8 | 9 | export function compare( 10 | crate1: crate.Crate, 11 | crate2: crate.Crate, 12 | all = false, 13 | threshold: number = DEFAULT_THRESHOLD, 14 | json = false, 15 | suppressMultiqc = false, 16 | ): void { 17 | crate1.summarize(); 18 | crate2.summarize(); 19 | const c1OutputsIds = all 20 | ? crate1.summary.outputs 21 | : crate1.summary.outputsWithEdam; 22 | const c2OutputsIds = all 23 | ? crate2.summary.outputs 24 | : crate2.summary.outputsWithEdam; 25 | const compareResult = compareFiles( 26 | crate1, 27 | crate2, 28 | c1OutputsIds, 29 | c2OutputsIds, 30 | threshold, 31 | ); 32 | 33 | const multiqcCompareResult = 34 | crate1.multiqcStats !== undefined && crate2.multiqcStats !== undefined 35 | ? compareMultiqcStats( 36 | crate1.multiqcStats, 37 | crate2.multiqcStats, 38 | threshold, 39 | ) 40 | : undefined; 41 | 42 | if (!json) { 43 | renderFirstMsg(crate1, crate2); 44 | renderSummaryTable(crate1, crate2); 45 | renderEdamExt(); 46 | renderRepLevelExplanation(all, threshold); 47 | renderCompareResult(compareResult, crate1, crate2, threshold); 48 | if (!suppressMultiqc) renderMultiqcResult(multiqcCompareResult); 49 | } else { 50 | renderJson(compareResult); 51 | } 52 | } 53 | 54 | export function renderFirstMsg(crate1: crate.Crate, crate2: crate.Crate): void { 55 | console.log(`\ 56 | Tonkaz ${main.TonkazVersion} 57 | 58 | ${colors.green("Checking")} Crate2 based on Crate1: 59 | 60 | Crate1: ${colors.cyan(crate1.location)} 61 | Crate2: ${colors.cyan(crate2.location)} 62 | `); 63 | } 64 | 65 | export function renderSummaryTable( 66 | crate1: crate.Crate, 67 | crate2: crate.Crate, 68 | ): void { 69 | const ellipseVal = (val: string) => { 70 | if (val.length <= 36) return val; 71 | return val.slice(0, 10) + " ... " + val.slice(-21); 72 | }; 73 | 74 | // alignFuncs 75 | const a1 = (val: string) => ascii_table.default.alignLeft(val, 14, " "); 76 | const a23Header = (val: string) => 77 | ascii_table.default.alignCenter(val, 36, " "); 78 | const a23 = (val: string) => 79 | ascii_table.default.alignLeft(ellipseVal(val), 36, " "); 80 | 81 | const data: ascii_table.AsciiData = { 82 | title: "", 83 | heading: [a1(""), a23Header("Crate1"), a23Header("Crate2")], 84 | rows: [], 85 | }; 86 | 87 | const headerKeys: [string, keyof crate.CrateSummary][] = [ 88 | ["WF Name", "wfName"], 89 | ["WF Type", "wfType"], 90 | ["WF Type Ver", "wfTypeVersion"], 91 | ["Run State", "state"], 92 | ["ExitCode", "exitCode"], 93 | ["Start Time", "startTime"], 94 | ["End Time", "endTime"], 95 | ["Duration", "duration"], 96 | ["# Attachments", "wfAttachments"], 97 | ["# Outputs", "outputs"], 98 | ["# Outputs with EDAM", "outputsWithEdam"], 99 | ]; 100 | 101 | headerKeys.forEach(([header, key]) => { 102 | header = a1(header); 103 | if (header.includes("#")) { 104 | if (key === "outputsWithEdam") { 105 | // do nothing 106 | } else { 107 | data.rows.push([ 108 | header, 109 | ...utils.warningColor( 110 | [crate1, crate2].map((c) => { 111 | const val = `${(c.summary[key] as string[]).length} files${ 112 | key === "outputs" 113 | ? ` (${c.summary.outputsWithEdam.length} EDAM-assigned files)` 114 | : "" 115 | }`; 116 | return a23(val); 117 | }), 118 | ), 119 | ]); 120 | } 121 | } else if (header.includes("Time")) { 122 | data.rows.push([ 123 | header, 124 | ...[crate1, crate2].map((c) => { 125 | const val = c.summary[key] != undefined 126 | ? datetime.format(c.summary[key] as Date, "yyyy-MM-dd HH:mm:ss") 127 | : ""; 128 | return a23(val); 129 | }), 130 | ]); 131 | } else if (key === "duration") { 132 | data.rows.push([ 133 | header, 134 | ...[crate1, crate2].map((c) => { 135 | let val = ""; 136 | if (c.summary[key] != undefined) { 137 | const duration = c.summary[key] as ReturnType< 138 | typeof datetime.difference 139 | >; 140 | val = utils.formatDuration(duration); 141 | } 142 | return a23(val); 143 | }), 144 | ]); 145 | } else { 146 | data.rows.push([ 147 | header, 148 | ...utils.warningColor( 149 | [crate1, crate2].map((c) => { 150 | const val = c.summary[key] != undefined 151 | ? ellipseVal(`${c.summary[key]}`) 152 | : ""; 153 | return a23(val); 154 | }), 155 | ), 156 | ]); 157 | } 158 | }); 159 | 160 | const table = ascii_table.default.fromJSON(data); 161 | console.log(utils.ourTableToString(table)); 162 | } 163 | 164 | export function renderEdamExt(): void { 165 | const ext = Object.keys(crate.EDAM_MAPPING); 166 | console.log(` * EDAM extensions: ${ext.join("/")}`); 167 | console.log(""); // empty line 168 | } 169 | 170 | // generated by compareFiles 171 | export interface CompareResult { 172 | bothIds: string[]; 173 | onlyCrate1Ids: string[]; // ReproducibilityLevel.NO_FILE 174 | onlyCrate2Ids: string[]; // ReproducibilityLevel.NO_FILE 175 | level3Ids: string[]; // ReproducibilityLevel.SAME_CHECKSUM 176 | level2Ids: string[]; // ReproducibilityLevel.SIMILAR_FEATURES 177 | level1Ids: string[]; // ReproducibilityLevel.DIFFERENT_FEATURES 178 | } 179 | 180 | // Result file reproducibility level is: 181 | // 182 | // level3. same checksum 183 | // level2. checksum are different, but its features (file size, map rate, etc.) are similar (within threshold) 184 | // level1. checksum are different, and its features are different (beyond threshold) 185 | // level0. file not found 186 | export enum ReproducibilityLevel { 187 | SAME_CHECKSUM = 3, 188 | SIMILAR_FEATURES = 2, 189 | DIFFERENT_FEATURES = 1, 190 | NO_FILE = 0, 191 | } 192 | 193 | export function compareFiles( 194 | crate1: crate.Crate, 195 | crate2: crate.Crate, 196 | ids1: string[], 197 | ids2: string[], 198 | threshold: number, 199 | ): CompareResult { 200 | const compareResult = { 201 | bothIds: [] as string[], 202 | onlyCrate1Ids: [] as string[], 203 | onlyCrate2Ids: [] as string[], 204 | level3Ids: [] as string[], 205 | level2Ids: [] as string[], 206 | level1Ids: [] as string[], 207 | level0Ids: [] as string[], 208 | }; 209 | 210 | compareResult.bothIds = utils.intersection(ids1, ids2); 211 | compareResult.onlyCrate1Ids = utils.difference(ids1, ids2); 212 | compareResult.onlyCrate2Ids = utils.difference(ids2, ids1); 213 | 214 | const stats = compareResult.bothIds.map((id) => { 215 | return { 216 | id, 217 | c1: crate1.findEntity(id).stats(), 218 | c2: crate2.findEntity(id).stats(), 219 | }; 220 | }); 221 | stats.forEach((s) => { 222 | const level = compareSummary(s.c1, s.c2, threshold); 223 | switch (level) { 224 | case ReproducibilityLevel.SAME_CHECKSUM: 225 | compareResult.level3Ids.push(s.id); 226 | break; 227 | case ReproducibilityLevel.SIMILAR_FEATURES: 228 | compareResult.level2Ids.push(s.id); 229 | break; 230 | case ReproducibilityLevel.DIFFERENT_FEATURES: 231 | compareResult.level1Ids.push(s.id); 232 | break; 233 | default: 234 | throw new Error(`Unexpected reproducibility level: ${level}`); 235 | } 236 | }); 237 | 238 | return compareResult; 239 | } 240 | 241 | export function compareSummary( 242 | s1: crate.FileStats, 243 | s2: crate.FileStats, 244 | threshold: number, 245 | ): ReproducibilityLevel { 246 | let level: ReproducibilityLevel; 247 | if (s1.checksum === s2.checksum) { 248 | level = ReproducibilityLevel.SAME_CHECKSUM; 249 | } else { 250 | level = ReproducibilityLevel.SIMILAR_FEATURES; 251 | 252 | const updateLevel = ( 253 | level: ReproducibilityLevel, 254 | val1: number | undefined, 255 | val2: number | undefined, 256 | ): ReproducibilityLevel => { 257 | if (val1 == undefined && val2 == undefined) { 258 | return level; 259 | } else { 260 | const newLevel = compareSummaryContent(val1, val2, threshold); 261 | return Math.min(level, newLevel); 262 | } 263 | }; 264 | 265 | const keys = Object.keys(s1) as (keyof crate.FileStats)[]; 266 | keys.forEach((k) => { 267 | if (k === "checksum" || k == "duration") { 268 | // do nothing 269 | } else if (k === "contentSize" || k == "lineCount") { 270 | level = updateLevel(level, s1[k], s2[k]); 271 | } else if (k === "samtoolsStats") { 272 | const [s1Sam, s2Sam] = [s1, s2].map((s) => s.samtoolsStats); 273 | if (s1Sam != undefined && s2Sam != undefined) { 274 | ( 275 | ["totalReads", "mappedReads", "duplicateReads"] as Array< 276 | keyof crate.SamtoolsStats 277 | > 278 | ).forEach((k2) => { 279 | level = updateLevel(level, s1Sam[k2], s2Sam[k2]); 280 | }); 281 | } 282 | } else if (k === "vcftoolsStats") { 283 | const [s1Vcf, s2Vcf] = [s1, s2].map((s) => s.vcftoolsStats); 284 | if (s1Vcf != undefined && s2Vcf != undefined) { 285 | ( 286 | ["variantCount", "snpsCount", "indelsCount"] as Array< 287 | keyof crate.VcftoolsStats 288 | > 289 | ).forEach((k2) => { 290 | level = updateLevel(level, s1Vcf[k2], s2Vcf[k2]); 291 | }); 292 | } 293 | } 294 | }); 295 | } 296 | 297 | return level; 298 | } 299 | 300 | export function compareSummaryContent( 301 | val1: number | undefined, 302 | val2: number | undefined, 303 | threshold: number, 304 | ): ReproducibilityLevel { 305 | if (val1 == undefined && val2 == undefined) { 306 | throw new Error("Both values are undefined"); 307 | } 308 | if (val1 == undefined || val2 == undefined) { 309 | return ReproducibilityLevel.DIFFERENT_FEATURES; 310 | } 311 | if (val1 === 0) { 312 | if (val2 === 0) { 313 | return ReproducibilityLevel.SIMILAR_FEATURES; 314 | } else { 315 | return ReproducibilityLevel.DIFFERENT_FEATURES; 316 | } 317 | } 318 | if (Math.abs(val1 - val2) / val1 <= threshold) { 319 | return ReproducibilityLevel.SIMILAR_FEATURES; 320 | } else { 321 | return ReproducibilityLevel.DIFFERENT_FEATURES; 322 | } 323 | } 324 | 325 | const STAR = emoji.get("star"); 326 | const LEVEL_EXP = { 327 | 3: "Files are identical with the same checksum", 328 | 2: "Files are different, but their features (file size, map rate, etc.) are similar (within threshold)", 329 | 1: "Files are different, and their features are different (beyond threshold)", 330 | 0: "File not found", 331 | }; 332 | 333 | export function renderRepLevelExplanation( 334 | all: boolean, 335 | threshold: number, 336 | ): void { 337 | console.log(`${colors.green("Comparing")} workflow results...`); 338 | if (!all) { 339 | console.log( 340 | "Calculate the reproducibility level by comparing the EDAM-assigned output files of Crate1 and Crate2. (option `--all` to use all output files)", 341 | ); 342 | } else { 343 | console.log( 344 | "Calculate the reproducibility level by comparing the output files of Crate1 and Crate2.", 345 | ); 346 | } 347 | console.log(""); // empty line 348 | console.log("Reproducibility level is defined as follows:"); 349 | console.log(""); // empty line 350 | 351 | const levels: Array = Object.keys(LEVEL_EXP) 352 | .map((k) => parseInt(k) as keyof typeof LEVEL_EXP) 353 | .sort() 354 | .reverse(); 355 | levels.forEach((l) => { 356 | console.log( 357 | ` - ${colors.blue(`Level${l}`)} ${STAR.repeat(l)}${ 358 | " ".repeat( 359 | 3 - l, 360 | ) 361 | } : ${ 362 | l === 2 363 | ? LEVEL_EXP[l].replace("threshold", `threshold: ${threshold}`) 364 | : LEVEL_EXP[l] 365 | }`, 366 | ); 367 | }); 368 | 369 | console.log(""); // empty line 370 | console.log( 371 | ` ${colors.blue("Level3")}: "Fully Reproduced" <---> ${ 372 | colors.blue( 373 | "Level0", 374 | ) 375 | }: "Not Reproduced"`, 376 | ); 377 | console.log(""); 378 | } 379 | 380 | export function renderCompareResult( 381 | result: CompareResult, 382 | crate1: crate.Crate, 383 | crate2: crate.Crate, 384 | threshold: number, 385 | ): void { 386 | renderLevel3Files(result); 387 | renderLevel2Files(result, crate1, crate2, threshold); 388 | renderLevel1Files(result, crate1, crate2, threshold); 389 | renderLevel0Files(result); 390 | 391 | renderCompareSummary(result); 392 | } 393 | 394 | export function renderLevel3Files(result: CompareResult): void { 395 | console.log( 396 | `=== ${colors.blue("Level3")} ${ 397 | STAR.repeat(3) 398 | } (Same Checksum, ${result.level3Ids.length}/${result.bothIds.length} files)`, 399 | ); 400 | console.log(""); // empty line 401 | 402 | const ids = result.level3Ids 403 | .map((id) => id.replace(OUTPUTS_ID_PREFIX_RE, "")) 404 | .sort(); 405 | if (ids.length > 0) { 406 | ids.forEach((id) => { 407 | console.log(` - ${id}`); 408 | }); 409 | console.log(""); // empty line 410 | } 411 | } 412 | 413 | export function renderLevel2Files( 414 | result: CompareResult, 415 | crate1: crate.Crate, 416 | crate2: crate.Crate, 417 | threshold: number, 418 | ): void { 419 | console.log( 420 | `=== ${colors.blue("Level2")} ${ 421 | STAR.repeat(2) 422 | } (Similar Features, ${result.level2Ids.length}/${result.bothIds.length} files)`, 423 | ); 424 | console.log(""); // empty line 425 | 426 | const ids = result.level2Ids.sort(); 427 | ids.forEach((id) => { 428 | renderFileStats(id, crate1, crate2, threshold, OUTPUTS_ID_PREFIX_RE); 429 | }); 430 | } 431 | 432 | export function renderLevel1Files( 433 | result: CompareResult, 434 | crate1: crate.Crate, 435 | crate2: crate.Crate, 436 | threshold: number, 437 | ): void { 438 | console.log( 439 | `=== ${colors.blue("Level1")} ${ 440 | STAR.repeat(1) 441 | } (Different Features, ${result.level1Ids.length}/${result.bothIds.length} files)`, 442 | ); 443 | console.log(""); // empty line 444 | 445 | const ids = result.level1Ids.sort(); 446 | ids.forEach((id) => { 447 | renderFileStats(id, crate1, crate2, threshold, OUTPUTS_ID_PREFIX_RE); 448 | }); 449 | } 450 | 451 | export function renderLevel0Files(result: CompareResult): void { 452 | console.log( 453 | `=== ${ 454 | colors.blue("Level0") 455 | } (Not Found, Crate1: ${result.onlyCrate1Ids.length} files, Crate2: ${result.onlyCrate2Ids.length} files)`, 456 | ); 457 | console.log(""); // empty line 458 | 459 | const ids1 = result.onlyCrate1Ids.sort(); 460 | if (ids1.length > 0) { 461 | console.log(" - Only in Crate1:"); 462 | console.log(""); // empty line 463 | ids1.forEach((id) => { 464 | console.log(` - ${id}`); 465 | }); 466 | console.log(""); // empty line 467 | } 468 | 469 | const ids2 = result.onlyCrate2Ids.sort(); 470 | if (ids2.length > 0) { 471 | console.log(" - Only in Crate2:"); 472 | console.log(""); // empty line 473 | ids2.forEach((id) => { 474 | console.log(` - ${id}`); 475 | }); 476 | console.log(""); // empty line 477 | } 478 | } 479 | 480 | export function renderFileStats( 481 | id: string, 482 | crate1: crate.Crate, 483 | crate2: crate.Crate, 484 | threshold: number, 485 | trim_prefix_regex: RegExp, 486 | ): void { 487 | const e1 = crate1.findEntity(id); 488 | const e2 = crate2.findEntity(id); 489 | const s1 = e1.stats(); 490 | const s2 = e2.stats(); 491 | 492 | // alignFuncs 493 | const a1 = (val: string) => ascii_table.default.alignLeft(val, 14, " "); 494 | const a23Header = (val: string) => 495 | ascii_table.default.alignCenter(val, 23, " "); 496 | const a23 = (val: string) => ascii_table.default.alignLeft(val, 23, " "); 497 | 498 | const data: ascii_table.AsciiData = { 499 | title: "", 500 | heading: [a1(""), a23Header("in Crate1"), a23Header("in Crate2")], 501 | rows: [], 502 | }; 503 | 504 | // compareVal -> format -> align -> colorsized 505 | const appendRow = ( 506 | header: string, 507 | val1: number | undefined, 508 | val2: number | undefined, 509 | formatFunc: typeof outToString = outToString, 510 | arg1: number | undefined = undefined, 511 | arg2: number | undefined = undefined, 512 | ): void => { 513 | const result = compareSummaryContent(val1, val2, threshold); 514 | let formattedVal1 = a23(formatFunc(val1, arg1)); 515 | let formattedVal2 = a23(formatFunc(val2, arg2)); 516 | if (result === ReproducibilityLevel.DIFFERENT_FEATURES) { 517 | formattedVal1 = colors.red(formattedVal1); 518 | formattedVal2 = colors.red(formattedVal2); 519 | } else if (result === ReproducibilityLevel.SIMILAR_FEATURES) { 520 | if (val1 == val2) { 521 | // do nothing => same value 522 | } else { 523 | formattedVal1 = colors.yellow(formattedVal1); 524 | formattedVal2 = colors.yellow(formattedVal2); 525 | } 526 | } 527 | data.rows.push([a1(header), formattedVal1, formattedVal2]); 528 | }; 529 | 530 | appendRow("File Size", s1.contentSize, s2.contentSize, utils.formatFileSize); 531 | if (s1.lineCount != undefined && s2.lineCount != undefined) { 532 | appendRow("Line Count", s1.lineCount, s2.lineCount); 533 | } 534 | 535 | if (s1.samtoolsStats != undefined || s2.samtoolsStats != undefined) { 536 | crate.SAM_HEADER_KEYS.forEach(([header, key]) => { 537 | if (key == "totalReads") { 538 | appendRow(header, s1.samtoolsStats?.[key], s2.samtoolsStats?.[key]); 539 | } else { 540 | // key == "mappedReads", "duplicateReads" 541 | const s1Read = s1.samtoolsStats?.[key]; 542 | const s1Rate = s1.samtoolsStats?.[ 543 | key.replace("Reads", "Rate") as keyof crate.SamtoolsStats 544 | ]; 545 | const s2Read = s2.samtoolsStats?.[key]; 546 | const s2Rate = s2.samtoolsStats?.[ 547 | key.replace("Reads", "Rate") as keyof crate.SamtoolsStats 548 | ]; 549 | const appendRate = ( 550 | read: number | undefined, 551 | rate: number | undefined, 552 | ): string => { 553 | if (read == undefined) return "-"; 554 | if (rate == undefined) return `${read}`; 555 | return `${read} (${(rate * 100).toFixed(2)}%)`; 556 | }; 557 | appendRow(header, s1Read, s2Read, appendRate, s1Rate, s2Rate); 558 | } 559 | }); 560 | } 561 | 562 | if (s1.vcftoolsStats != undefined || s2.vcftoolsStats != undefined) { 563 | crate.VCF_HEADER_KEYS.forEach(([header, key]) => { 564 | appendRow(header, s1.vcftoolsStats?.[key], s2.vcftoolsStats?.[key]); 565 | }); 566 | } 567 | 568 | const table = ascii_table.default.fromJSON(data); 569 | 570 | console.log(` - ${id.replace(trim_prefix_regex, "")}`); 571 | console.log( 572 | utils.tablePaddingLeft(utils.ourTableToString(table), 4), 573 | ); 574 | console.log(""); // empty line 575 | } 576 | 577 | export function outToString( 578 | val: number | undefined, 579 | _extra: number | undefined, 580 | ): string { 581 | return val == undefined ? "-" : `${val}`; 582 | } 583 | 584 | export function appendLineUnderGeneralMetadata(table: string): string { 585 | // append line under general metadata (Line Count or File Size) 586 | const lines = table.split("\n"); 587 | if (lines.length < 8) { 588 | return table; 589 | } 590 | const line = lines[2]; 591 | const lineCountIndex = lines.findIndex((l) => l.includes("Line Count")); 592 | const contentSizeIndex = lines.findIndex((l) => l.includes("File Size")); 593 | const insertIndex = lineCountIndex > -1 ? lineCountIndex : contentSizeIndex; 594 | const insertedLines = [ 595 | ...lines.slice(0, insertIndex + 1), 596 | line, 597 | ...lines.slice(insertIndex + 1), 598 | ]; 599 | return insertedLines.join("\n"); 600 | } 601 | 602 | export function renderJson(compareResult: CompareResult): void { 603 | console.log(JSON.stringify(compareResult, null, 2)); 604 | } 605 | 606 | export function renderCompareSummary(compareResult: CompareResult): void { 607 | // alignFuncs 608 | const aHeader = (val: string, len: number) => 609 | ascii_table.default.alignCenter(val, len, " "); 610 | const a = (val: string, len: number) => 611 | ascii_table.default.alignLeft(val, len, " "); 612 | const col1Len = 9; 613 | const col2Len = 25; 614 | const col3Len = 19; 615 | const col4Len = 11; 616 | 617 | const data: ascii_table.AsciiData = { 618 | title: "", 619 | heading: [ 620 | aHeader("Reproducibility", col2Len), 621 | aHeader("Level", col1Len), 622 | aHeader("Definition", col3Len), 623 | aHeader("File #", col4Len), 624 | ], 625 | rows: [], 626 | }; 627 | 628 | const addRow = (c1: number, c2: string, c3: string, c4: number): void => { 629 | data.rows.push([ 630 | a(c2, col2Len), 631 | a(STAR.repeat(c1), col1Len - c1), 632 | a(c3, col3Len), 633 | a(`${c4} files`, col4Len), 634 | ]); 635 | }; 636 | 637 | addRow( 638 | 3, 639 | "Fully Reproduced", 640 | "Same Checksum", 641 | compareResult.level3Ids.length, 642 | ); 643 | addRow( 644 | 2, 645 | "Acceptable Differences", 646 | "Similar Features", 647 | compareResult.level2Ids.length, 648 | ); 649 | addRow( 650 | 1, 651 | "Unacceptable Differences", 652 | "Different Features", 653 | compareResult.level1Ids.length, 654 | ); 655 | addRow( 656 | 0, 657 | "Not Reproduced", 658 | "Not Found", 659 | compareResult.onlyCrate1Ids.length + compareResult.onlyCrate2Ids.length, 660 | ); 661 | 662 | console.log(`${colors.green("Summarize")} compare result:`); 663 | console.log(""); // empty line 664 | const table = ascii_table.default.fromJSON(data); 665 | console.log(utils.tablePaddingLeft(utils.ourTableToString(table), 2)); 666 | console.log(""); // empty line 667 | } 668 | 669 | // generated by compareMultiqcStats 670 | export interface CompareMultiqcResult { 671 | [field: string]: { 672 | [sample: string]: { 673 | c1: number | undefined; 674 | c2: number | undefined; 675 | level: ReproducibilityLevel; 676 | }; 677 | }; 678 | } 679 | 680 | export function compareMultiqcStats( 681 | e1: crate.Entity, 682 | e2: crate.Entity, 683 | threshold: number, 684 | ): CompareMultiqcResult | undefined { 685 | try { 686 | const result = {} as CompareMultiqcResult; 687 | const stats1 = JSON.parse(e1.self["text"] as string); 688 | const stats2 = JSON.parse(e2.self["text"] as string); 689 | const samples = utils.union(Object.keys(stats1), Object.keys(stats2)); 690 | for (const sample of samples) { 691 | if (sample in stats1) { 692 | Object.entries(stats1[sample]).forEach(([field, val]) => { 693 | if (typeof val !== "number") return; 694 | result[field] = result[field] ?? {}; 695 | result[field][sample] = result[field][sample] ?? {}; 696 | result[field][sample]["c1"] = val; 697 | }); 698 | } 699 | if (sample in stats2) { 700 | Object.entries(stats2[sample]).forEach(([field, val]) => { 701 | if (typeof val !== "number") return; 702 | result[field] = result[field] ?? {}; 703 | result[field][sample] = result[field][sample] ?? {}; 704 | result[field][sample]["c2"] = val; 705 | }); 706 | } 707 | } 708 | const modifiedResult = {} as CompareMultiqcResult; 709 | for (const field in result) { 710 | for (const sample in result[field]) { 711 | result[field][sample]["level"] = compareSummaryContent( 712 | result[field][sample]["c1"], 713 | result[field][sample]["c2"], 714 | threshold, 715 | ); 716 | } 717 | modifiedResult[modifyMultiqcFieldName(field)] = result[field]; 718 | } 719 | return modifiedResult; 720 | } catch (e) { 721 | console.error(`Failed to compare multiqc stats with error: ${e}`); 722 | return undefined; 723 | } 724 | } 725 | 726 | export function modifyMultiqcFieldName(field: string): string { 727 | // from: QualiMap_mqc-generalstats-qualimap-5_3_bias 728 | // to: Qualimap 5_3_bias 729 | const parts = field.split("-"); 730 | const index = parts.indexOf("generalstats"); 731 | if (index > -1) { 732 | parts.splice(0, index + 1); 733 | } 734 | return parts.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" "); 735 | } 736 | 737 | export function renderMultiqcResult( 738 | result: CompareMultiqcResult | undefined, 739 | ): void { 740 | if (result == undefined) return; 741 | 742 | console.log(`${colors.green("Comparing")} multiqc stats...`); 743 | console.log( 744 | "Crates contain MultiQC stats, which we will be comparing. MultiQC stats are aggregated on a sample level.", 745 | ); 746 | console.log(""); // empty line 747 | 748 | let maxSampleNameLen = 0; 749 | for (const field in result) { 750 | for (const sample in result[field]) { 751 | maxSampleNameLen = Math.max(maxSampleNameLen, sample.length); 752 | } 753 | } 754 | 755 | for (const field of Object.keys(result).sort()) { 756 | console.log(` - ${field}`); 757 | const rows = [] as string[][]; 758 | for (const sample of Object.keys(result[field]).sort()) { 759 | const obj = result[field][sample]; 760 | const sampleStr = ascii_table.default.alignLeft( 761 | sample, 762 | maxSampleNameLen, 763 | " ", 764 | ); 765 | let formattedVal1 = ascii_table.default.alignLeft( 766 | outToString(obj["c1"], 12).substring(0, 12), 767 | 12, 768 | " ", 769 | ); 770 | let formattedVal2 = ascii_table.default.alignLeft( 771 | outToString(obj["c2"], 12).substring(0, 12), 772 | 12, 773 | " ", 774 | ); 775 | if (obj["level"] === ReproducibilityLevel.DIFFERENT_FEATURES) { 776 | formattedVal1 = colors.red(formattedVal1); 777 | formattedVal2 = colors.red(formattedVal2); 778 | } else if (obj["level"] === ReproducibilityLevel.SIMILAR_FEATURES) { 779 | if (obj["c1"] == obj["c2"]) { 780 | // do nothing => same value 781 | } else { 782 | formattedVal1 = colors.yellow(formattedVal1); 783 | formattedVal2 = colors.yellow(formattedVal2); 784 | } 785 | } 786 | const levelStr = ascii_table.default.alignLeft( 787 | STAR.repeat(obj["level"]), 788 | 9 - obj["level"], 789 | " ", 790 | ); 791 | rows.push([sampleStr, formattedVal1, formattedVal2, levelStr]); 792 | } 793 | const data: ascii_table.AsciiData = { 794 | title: "", 795 | heading: [ 796 | ascii_table.default.alignCenter("Sample", maxSampleNameLen, " "), 797 | ascii_table.default.alignCenter("in Crate1", 12, " "), 798 | ascii_table.default.alignCenter("in Crate2", 12, " "), 799 | ascii_table.default.alignCenter("Level", 9, " "), 800 | ], 801 | rows, 802 | }; 803 | const table = ascii_table.default.fromJSON(data); 804 | console.log(utils.tablePaddingLeft(utils.ourTableToString(table), 4)); 805 | console.log(""); // empty line 806 | } 807 | } 808 | -------------------------------------------------------------------------------- /src/crate.ts: -------------------------------------------------------------------------------- 1 | import { utils } from "./mod.ts"; 2 | import { difference as datetime_diff } from "datetime"; 3 | 4 | export interface CrateSummary { 5 | wfName: string; 6 | wfType: string; 7 | wfTypeVersion: string; 8 | startTime: Date; 9 | endTime: Date; 10 | duration: ReturnType; 11 | exitCode: string; 12 | state: string; 13 | wfAttachments: string[]; 14 | outputs: string[]; 15 | outputsWithEdam: string[]; 16 | } 17 | 18 | export class Crate { 19 | "location": string; 20 | "json": utils.Json; 21 | "entities": Record; 22 | "rootdataEntity": Entity; 23 | "mainWf": Entity; 24 | "createAction": Entity; 25 | "summary": CrateSummary; 26 | "multiqcStats": Entity | undefined; 27 | 28 | constructor(loc: string) { 29 | this.location = loc; 30 | } 31 | 32 | async initialize(): Promise { 33 | try { 34 | await this.load(); 35 | const context = this.json["@context"]; 36 | if (context == undefined) { 37 | throw new Error(`Crate ${this.location} has no @context`); 38 | } 39 | const graph = this.json["@graph"]; 40 | if (graph == undefined) { 41 | throw new Error(`Crate ${this.location} has no @graph`); 42 | } 43 | if (!Array.isArray(graph)) { 44 | throw new Error(`Crate ${this.location} has invalid @graph`); 45 | } 46 | 47 | this.entities = {}; 48 | graph.map((entity_json) => { 49 | const entity = new Entity(this, entity_json); 50 | this.entities[entity.id] = entity; 51 | }); 52 | 53 | this.rootdataEntity = this.findEntity("./"); 54 | this.mainWf = this.getChildEntity(this.rootdataEntity, "mainEntity"); 55 | this.createAction = this.getChildEntity(this.rootdataEntity, "mentions"); 56 | try { 57 | this.multiqcStats = this.getChildEntity( 58 | this.createAction, 59 | "multiqcStats", 60 | ); 61 | } catch (_) { 62 | this.multiqcStats = undefined; 63 | } 64 | } catch (e) { 65 | throw new Error( 66 | `Failed to initialize crate ${this.location}: ${e.message}`, 67 | ); 68 | } 69 | } 70 | 71 | async load(): Promise { 72 | this.json = await utils.loadJson(this.location); 73 | } 74 | 75 | findEntity(id: string): Entity { 76 | const entity = this.entities[id]; 77 | if (entity == undefined) { 78 | throw new Error(`Entity ${id} not found`); 79 | } 80 | return entity; 81 | } 82 | 83 | getChildEntity(parentEntity: Entity, field: string): Entity { 84 | const nextIds = parentEntity.flattenIds(field); 85 | if (nextIds.length !== 1) { 86 | throw new Error(`Entity ${parentEntity.id} has invalid ${field}`); 87 | } 88 | return this.findEntity(nextIds[0]); 89 | } 90 | 91 | summarize(): void { 92 | const unknownToStr = (val: unknown) => { 93 | return val == undefined ? "" : `${val}`; 94 | }; 95 | 96 | try { 97 | // General Metadata 98 | const wfName = unknownToStr( 99 | this.getValRecursively(this.createAction, ["name"]), 100 | ); 101 | const wfType = unknownToStr( 102 | this.getValRecursively(this.mainWf, ["programmingLanguage", "name"]), 103 | ); 104 | const wfTypeVersion = unknownToStr( 105 | this.getValRecursively(this.mainWf, ["programmingLanguage", "version"]), 106 | ); 107 | const exitCode = unknownToStr( 108 | this.getValRecursively(this.createAction, ["exitCode"]), 109 | ); 110 | const state = unknownToStr( 111 | this.getValRecursively(this.createAction, ["wesState"]), 112 | ); 113 | 114 | // File IDs 115 | let wfAttachments: string[] = []; 116 | try { 117 | wfAttachments = this.createAction.flattenIds("object"); 118 | } catch (_) { 119 | // do nothing 120 | } 121 | let outputs: string[] = []; 122 | try { 123 | outputs = this.createAction.flattenIds("result"); 124 | } catch (_) { 125 | // do nothing 126 | } 127 | const outputsWithEdam = this.filterHasEdam(outputs); 128 | 129 | // Time 130 | const startTimeStr = unknownToStr( 131 | this.getValRecursively(this.createAction, ["startTime"]), 132 | ); 133 | let startTime: Date; 134 | try { 135 | startTime = utils.parseDatetime(startTimeStr); 136 | } catch (_) { 137 | throw new Error(`Invalid start time ${startTimeStr}`); 138 | } 139 | const endTimeStr = unknownToStr( 140 | this.getValRecursively(this.createAction, ["endTime"]), 141 | ); 142 | let endTime: Date; 143 | try { 144 | endTime = utils.parseDatetime(endTimeStr); 145 | } catch (_) { 146 | throw new Error(`Invalid end time ${endTimeStr}`); 147 | } 148 | const duration = datetime_diff(startTime, endTime); 149 | 150 | const summary: CrateSummary = { 151 | wfName, 152 | wfType, 153 | wfTypeVersion, 154 | startTime, 155 | endTime, 156 | duration, 157 | exitCode, 158 | state, 159 | wfAttachments, 160 | outputs, 161 | outputsWithEdam, 162 | }; 163 | 164 | this.summary = summary; 165 | } catch (e) { 166 | throw new Error( 167 | `Failed to summarize crate ${this.location}: ${e.message}`, 168 | ); 169 | } 170 | } 171 | 172 | getValRecursively( 173 | entity: Entity, 174 | fields: string[], 175 | ): unknown { 176 | if (fields.length == 0) { 177 | throw new Error("Fields cannot be empty"); 178 | } 179 | if (fields.length == 1) { 180 | return entity.self[fields[0]]; 181 | } else { 182 | const nextIds = entity.flattenIds(fields[0]); 183 | if (nextIds.length !== 1) { 184 | throw new Error(`Entity ${entity.id} has invalid ${fields[0]}`); 185 | } 186 | const nextEntity = this.findEntity(nextIds[0]); 187 | return this.getValRecursively(nextEntity, fields.slice(1)); 188 | } 189 | } 190 | 191 | filterHasEdam(ids: string[]): string[] { 192 | return ids.filter((id) => this.findEntity(id).hasEdam()); 193 | } 194 | } 195 | 196 | export class Entity { 197 | "crate": Crate; 198 | "id": string; 199 | "type": string | string[]; 200 | "self": utils.Json; 201 | "fileStats": FileStats | undefined; 202 | 203 | constructor(crate: Crate, json: utils.Json) { 204 | this.crate = crate; 205 | const id = json["@id"]; 206 | if (id == undefined) { 207 | throw new Error(`Entity has no @id`); 208 | } 209 | if (typeof id !== "string") { 210 | throw new Error(`Entity has invalid @id`); 211 | } 212 | this.id = id; 213 | 214 | const type = json["@type"]; 215 | if (type == undefined) { 216 | throw new Error(`Entity has no @type`); 217 | } 218 | if (typeof type !== "string" && !Array.isArray(type)) { 219 | throw new Error(`Entity has invalid @type`); 220 | } 221 | this.type = type; 222 | 223 | this.self = json; 224 | this.fileStats = undefined; 225 | } 226 | 227 | flattenIds(field: string): string[] { 228 | // 'field': {"@id": "id_str"} 229 | // 'field': [{"@id": "id_str"}] 230 | const val = this.self[field]; 231 | if (val == undefined) { 232 | throw new Error(`Entity ${this.id} has no ${field}`); 233 | } 234 | 235 | if (typeof val === "string") { 236 | return [val]; 237 | } else if (Array.isArray(val)) { 238 | const ids = val.map((v) => { 239 | const id = v["@id"]; 240 | if (id == undefined) { 241 | throw new Error(`Entity ${this.id} has invalid ${field}`); 242 | } 243 | if (typeof id !== "string") { 244 | throw new Error(`Entity ${this.id} has invalid ${field}`); 245 | } 246 | return id; 247 | }); 248 | return ids; 249 | } else if (typeof val === "object") { 250 | const val_obj = JSON.parse(JSON.stringify(val)); 251 | const id = val_obj["@id"]; 252 | if (id == undefined) { 253 | throw new Error(`Entity ${this.id} has invalid ${field}`); 254 | } 255 | if (typeof id !== "string") { 256 | throw new Error(`Entity ${this.id} has invalid ${field}`); 257 | } 258 | return [id]; 259 | } else { 260 | throw new Error(`Entity ${this.id} has invalid ${field}`); 261 | } 262 | } 263 | 264 | hasEdam(): boolean { 265 | if (!("encodingFormat" in this.self)) { 266 | return false; 267 | } 268 | const encodingFormat = this.flattenIds("encodingFormat")[0]; 269 | return encodingFormat.startsWith("http://edamontology.org"); 270 | } 271 | 272 | getEdamUrl(): string | undefined { 273 | if (!this.hasEdam()) { 274 | return undefined; 275 | } 276 | return this.flattenIds("encodingFormat")[0]; 277 | } 278 | 279 | getStatId(): string | undefined { 280 | let statsId: string | undefined = undefined; 281 | try { 282 | statsId = this.flattenIds("stats")[0]; 283 | } catch (_) { 284 | return undefined; 285 | } 286 | if (statsId == undefined) { 287 | return undefined; 288 | } 289 | return statsId; 290 | } 291 | 292 | stats(): FileStats { 293 | if (this.fileStats != undefined) { 294 | return this.fileStats; 295 | } 296 | 297 | const contentSize = this.self["contentSize"]; 298 | if (contentSize == undefined || typeof contentSize !== "number") { 299 | throw new Error(`Entity ${this.id} has no contentSize`); 300 | } 301 | const lineCount = this.self["lineCount"] as number | undefined; 302 | if (lineCount != undefined && typeof lineCount !== "number") { 303 | throw new Error(`Entity ${this.id} has invalid lineCount`); 304 | } 305 | const checksum = this.self["sha512"] as string; 306 | if (checksum == undefined) { 307 | throw new Error(`Entity ${this.id} has no sha512`); 308 | } 309 | 310 | const dateModified = this.self["dateModified"] as string; 311 | if (dateModified == undefined) { 312 | throw new Error(`Entity ${this.id} has no dateModified`); 313 | } 314 | const dateModifiedDate = utils.parseDatetime(dateModified); 315 | const duration = datetime_diff( 316 | this.crate.summary.startTime, 317 | dateModifiedDate, 318 | ); 319 | 320 | const fileStats: FileStats = { 321 | contentSize, 322 | duration, 323 | lineCount, 324 | checksum, 325 | samtoolsStats: this.getSamtoolsStats(this.crate), 326 | vcftoolsStats: this.getVcftoolsStats(this.crate), 327 | }; 328 | this.fileStats = fileStats; 329 | 330 | return fileStats; 331 | } 332 | 333 | getSamtoolsStats(crate: Crate): SamtoolsStats | undefined { 334 | if (this.hasEdam()) { 335 | const edamUrl = this.getEdamUrl(); 336 | if (edamUrl != undefined && SAM_EDAM.includes(edamUrl)) { 337 | const statsId = this.getStatId(); 338 | if (statsId == undefined) { 339 | return undefined; 340 | } 341 | const statsEntity = crate.findEntity(statsId); 342 | 343 | const keys: Array = [ 344 | "totalReads", 345 | "mappedReads", 346 | "unmappedReads", 347 | "duplicateReads", 348 | "mappedRate", 349 | "unmappedRate", 350 | "duplicateRate", 351 | ]; 352 | const stats: SamtoolsStats = {} as SamtoolsStats; 353 | keys.forEach((key) => { 354 | const val = statsEntity.self[key]; 355 | if (val == undefined) { 356 | throw new Error(`Entity ${statsId} has no ${key}`); 357 | } 358 | if (typeof val !== "number") { 359 | throw new Error(`Entity ${statsId} has invalid ${key}`); 360 | } 361 | stats[key] = val; 362 | }); 363 | 364 | return stats; 365 | } 366 | } 367 | 368 | return undefined; 369 | } 370 | 371 | getVcftoolsStats(crate: Crate): VcftoolsStats | undefined { 372 | if (this.hasEdam()) { 373 | const edamUrl = this.getEdamUrl(); 374 | if (edamUrl != undefined && VCF_EDAM.includes(edamUrl)) { 375 | const statsId = this.getStatId(); 376 | if (statsId == undefined) { 377 | return undefined; 378 | } 379 | const statsEntity = crate.findEntity(statsId); 380 | const keys: Array = [ 381 | "variantCount", 382 | "snpsCount", 383 | "indelsCount", 384 | ]; 385 | const stats: VcftoolsStats = {} as VcftoolsStats; 386 | keys.forEach((key) => { 387 | const val = statsEntity.self[key]; 388 | if (val == undefined) { 389 | throw new Error(`Entity ${statsId} has no ${key}`); 390 | } 391 | if (typeof val !== "number") { 392 | throw new Error(`Entity ${statsId} has invalid ${key}`); 393 | } 394 | stats[key] = val; 395 | }); 396 | 397 | return stats; 398 | } 399 | } 400 | 401 | return undefined; 402 | } 403 | } 404 | 405 | export interface FileStats { 406 | contentSize: number; 407 | duration: ReturnType; 408 | lineCount?: number; 409 | checksum: string; 410 | samtoolsStats?: SamtoolsStats; 411 | vcftoolsStats?: VcftoolsStats; 412 | } 413 | 414 | export const EDAM_MAPPING = { 415 | ".bam": { 416 | "url": "http://edamontology.org/format_2572", 417 | "name": 418 | "BAM format, the binary, BGZF-formatted compressed version of SAM format for alignment of nucleotide sequences (e.g. sequencing reads) to (a) reference sequence(s). May contain base-call and alignment qualities and other data.", 419 | }, 420 | ".bb": { 421 | "url": "http://edamontology.org/format_3004", 422 | "name": 423 | "bigBed format for large sequence annotation tracks, similar to textual BED format.", 424 | }, 425 | ".bed": { 426 | "url": "http://edamontology.org/format_3003", 427 | "name": 428 | "Browser Extensible Data (BED) format of sequence annotation track, typically to be displayed in a genome browser.", 429 | }, 430 | ".bw": { 431 | "url": "http://edamontology.org/format_3006", 432 | "name": 433 | "bigWig format for large sequence annotation tracks that consist of a value for each sequence position. Similar to textual WIG format.", 434 | }, 435 | ".fa": { 436 | "url": "http://edamontology.org/format_1929", 437 | "name": "FASTA format including NCBI-style IDs.", 438 | }, 439 | ".fasta": { 440 | "url": "http://edamontology.org/format_1929", 441 | "name": "FASTA format including NCBI-style IDs.", 442 | }, 443 | ".fastq": { 444 | "url": "http://edamontology.org/format_1930", 445 | "name": "FASTQ short read format ignoring quality scores.", 446 | }, 447 | ".fastq.gz": { 448 | "url": "http://edamontology.org/format_1930", 449 | "name": "FASTQ short read format ignoring quality scores.", 450 | }, 451 | ".fq": { 452 | "url": "http://edamontology.org/format_1930", 453 | "name": "FASTQ short read format ignoring quality scores.", 454 | }, 455 | ".fq.gz": { 456 | "url": "http://edamontology.org/format_1930", 457 | "name": "FASTQ short read format ignoring quality scores.", 458 | }, 459 | ".gtf": { 460 | "url": "http://edamontology.org/format_2306", 461 | "name": "Gene Transfer Format (GTF), a restricted version of GFF.", 462 | }, 463 | ".gff": { 464 | "url": "http://edamontology.org/format_1975", 465 | "name": "Generic Feature Format version 3 (GFF3) of sequence features.", 466 | }, 467 | ".sam": { 468 | "url": "http://edamontology.org/format_2573", 469 | "name": 470 | "Sequence Alignment/Map (SAM) format for alignment of nucleotide sequences (e.g. sequencing reads) to (a) reference sequence(s). May contain base-call and alignment qualities and other data.", 471 | }, 472 | ".vcf": { 473 | "url": "http://edamontology.org/format_3016", 474 | "name": 475 | "Variant Call Format (VCF) for sequence variation (indels, polymorphisms, structural variation).", 476 | }, 477 | ".vcf.gz": { 478 | "url": "http://edamontology.org/format_3016", 479 | "name": 480 | "Variant Call Format (VCF) for sequence variation (indels, polymorphisms, structural variation).", 481 | }, 482 | ".wig": { 483 | "url": "http://edamontology.org/format_3005", 484 | "name": 485 | "Wiggle format (WIG) of a sequence annotation track that consists of a value for each sequence position. Typically to be displayed in a genome browser.", 486 | }, 487 | }; 488 | 489 | // .bam, .sam 490 | export const SAM_EDAM = [ 491 | "http://edamontology.org/format_2572", 492 | "http://edamontology.org/format_2573", 493 | ]; 494 | 495 | // .vcf 496 | export const VCF_EDAM = [ 497 | "http://edamontology.org/format_3016", 498 | ]; 499 | 500 | export const HAS_ONTOLOGY_EDAM = [ 501 | ...SAM_EDAM, 502 | ...VCF_EDAM, 503 | ]; 504 | 505 | export interface SamtoolsStats { 506 | totalReads: number; 507 | mappedReads: number; 508 | unmappedReads: number; 509 | duplicateReads: number; 510 | mappedRate: number; 511 | unmappedRate: number; 512 | duplicateRate: number; 513 | } 514 | 515 | export const SAM_HEADER_KEYS: [string, keyof SamtoolsStats][] = [ 516 | ["Total Reads", "totalReads"], 517 | [" # Mapped", "mappedReads"], 518 | [" # Duplicate", "duplicateReads"], 519 | ]; 520 | 521 | export interface VcftoolsStats { 522 | variantCount: number; 523 | snpsCount: number; 524 | indelsCount: number; 525 | } 526 | 527 | export const VCF_HEADER_KEYS: [string, keyof VcftoolsStats][] = [ 528 | ["Variant Count", "variantCount"], 529 | ["SNPs Count", "snpsCount"], 530 | ["Indels Count", "indelsCount"], 531 | ]; 532 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "./mod.ts"; 2 | import * as colors from "colors"; 3 | 4 | export const TonkazVersion = "0.3.0"; 5 | 6 | export async function main(): Promise { 7 | try { 8 | const parsedArgs = await args.parseArgs(Deno.args); 9 | const crate1 = new crate.Crate(parsedArgs.loc1); 10 | await crate1.initialize(); 11 | const crate2 = new crate.Crate(parsedArgs.loc2); 12 | await crate2.initialize(); 13 | compare.compare( 14 | crate1, 15 | crate2, 16 | parsedArgs.all, 17 | parsedArgs.threshold, 18 | parsedArgs.json, 19 | parsedArgs.suppressMultiqc, 20 | ); 21 | } catch (e) { 22 | console.error(`${colors.red("Error occurred!!")}: ${e.message}`); 23 | Deno.exit(1); 24 | } 25 | Deno.exit(0); 26 | } 27 | 28 | if (import.meta.main) { 29 | await main(); 30 | } 31 | -------------------------------------------------------------------------------- /src/mod.ts: -------------------------------------------------------------------------------- 1 | export * as args from "./args.ts"; 2 | export * as compare from "./compare.ts"; 3 | export * as crate from "./crate.ts"; 4 | export * as main from "./main.ts"; 5 | export * as utils from "./utils.ts"; 6 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as ascii_table from "ascii_table"; 2 | import * as colors from "colors"; 3 | import * as datetime from "datetime"; 4 | 5 | export async function isFile(loc: string): Promise { 6 | return await Deno.stat(loc).then((stat) => stat.isFile).catch(() => false); 7 | } 8 | 9 | export async function isRemote(loc: string): Promise { 10 | return await fetch(loc).then((res) => res.ok).catch(() => false); 11 | } 12 | 13 | export async function isFileOrRemote(loc: string): Promise { 14 | return await isFile(loc) || await isRemote(loc); 15 | } 16 | 17 | export type Json = Record; 18 | 19 | export async function loadJson( 20 | loc: string, 21 | ): Promise> { 22 | if (await isFile(loc)) { 23 | const file_content = await Deno.readTextFile(loc); 24 | const json = JSON.parse(file_content); 25 | return json; 26 | } 27 | 28 | if (await isRemote(loc)) { 29 | const res = await fetch(loc); 30 | const json = await res.json(); 31 | return json; 32 | } 33 | 34 | throw new Error(`Invalid location: ${loc}`); 35 | } 36 | 37 | export function intersection(ids_1: string[], ids_2: string[]): string[] { 38 | return ids_1.filter((id) => ids_2.includes(id)); 39 | } 40 | 41 | export function difference(ids_1: string[], ids_2: string[]): string[] { 42 | return ids_1.filter((id) => !ids_2.includes(id)); 43 | } 44 | 45 | export function union(ids_1: string[], ids_2: string[]): string[] { 46 | return [...new Set([...ids_1, ...ids_2])]; 47 | } 48 | 49 | export function formatDuration( 50 | duration: ReturnType, 51 | ): string { 52 | const days = duration.days || 0; 53 | const hours = duration.hours != undefined ? duration.hours % 24 : 0; 54 | const minutes = duration.minutes != undefined ? duration.minutes % 60 : 0; 55 | const seconds = duration.seconds != undefined ? duration.seconds % 60 : 0; 56 | let formattedStr = ""; 57 | if (days > 0) formattedStr += `${days}d `; 58 | if (hours > 0) formattedStr += `${hours}h `; 59 | if (minutes > 0) formattedStr += `${minutes}m `; 60 | if (seconds > 0) formattedStr += `${seconds}s`; 61 | if (formattedStr === "") formattedStr = "0s"; 62 | return formattedStr.trim(); 63 | } 64 | 65 | export function formatFileSize( 66 | fileSize: number | undefined, 67 | _extra: number | undefined = undefined, 68 | ): string { 69 | if (fileSize == undefined) return "-"; 70 | const fileSizeOri = `${fileSize}`; 71 | const units = ["B", "KB", "MB", "GB", "TB"]; 72 | let unit = 0; 73 | while (fileSize > 1024) { 74 | fileSize /= 1024; 75 | unit += 1; 76 | } 77 | return `${fileSize.toFixed(2)} ${units[unit]} (${fileSizeOri})`; 78 | } 79 | 80 | // Use after table.toString() 81 | export function tablePaddingLeft(table: string, padding: number): string { 82 | return table.split("\n").map((line) => " ".repeat(padding) + line).join("\n"); 83 | } 84 | 85 | // considering color code, all items must be aligned 86 | export function ourTableToString(table: ascii_table.default): string { 87 | const colLenArr = table.getHeading().map((h: string) => h.length); 88 | const body = [] as string[]; 89 | 90 | // top bar 91 | body.push( 92 | `.${ 93 | "-".repeat( 94 | colLenArr.reduce((a: number, b: number) => a + b) + 95 | 3 * colLenArr.length - 1, 96 | ) 97 | }.`, 98 | ); 99 | // heading 100 | body.push(`| ${table.getHeading().join(" | ")} |`); 101 | // middle bar 102 | body.push( 103 | `|${colLenArr.map((len: number) => "-".repeat(len + 2)).join("|")}|`, 104 | ); 105 | // body 106 | table.getRows().forEach((row: string[]) => { 107 | body.push(`| ${row.join(" | ")} |`); 108 | }); 109 | // bottom bar 110 | body.push( 111 | `'${ 112 | "-".repeat( 113 | colLenArr.reduce((a: number, b: number) => a + b) + 114 | 3 * colLenArr.length - 1, 115 | ) 116 | }'`, 117 | ); 118 | 119 | return body.join("\n"); 120 | } 121 | 122 | export function warningColor(pair: string[]): string[] { 123 | return pair[0] !== pair[1] 124 | ? [colors.yellow(pair[0]), colors.yellow(pair[1])] 125 | : pair; 126 | } 127 | 128 | export function parseDatetime(datetimeStr: string): Date { 129 | const datetime = new Date(datetimeStr); 130 | if (isNaN(datetime.getTime())) { 131 | throw new Error(`Invalid datetime: ${datetimeStr}`); 132 | } 133 | return datetime; 134 | } 135 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | This directory contains tests for `Tonkaz`. 4 | 5 | These test data are generated using [`sapporo-wes/sapporo-service`](https://github.com/sapporo-wes/sapporo-service), [`sapporo-wes/yevis-cli`](https://github.com/sapporo-wes/yevis-cli) and Tonkaz. 6 | 7 | The procedure of generating each data is as follows: 8 | 9 | ```text 10 | workflow -- (Sapporo-service/Yevis) --> execution_results + ro_crate -- (Tonkaz) --> comparison_results 11 | ``` 12 | 13 | ## Run tests 14 | 15 | Several combinations of crates are available as follows: 16 | 17 | ```bash 18 | # GATK (Linux, 1st) <-> GATK (Linux, 2nd) 19 | # Use case: Same environment 20 | # Result: ./comparison_results/gatk_same_env.log 21 | $ deno test -A ./tests/gatk_test.ts 22 | 23 | # GATK (Linux) <-> GATK (Mac) 24 | # Use case: Different environment 25 | # Result: ./comparison_results/gatk_diff_env.log 26 | $ deno test -A ./tests/gatk_mac_test.ts 27 | 28 | # JGA (Linux, 1st) <-> JGA (Linux, 2nd) 29 | # Use case: Same environment 30 | # Result: ./comparison_results/jga_same_env.log 31 | $ deno test -A ./tests/jga_test.ts 32 | 33 | # JGA (Linux) <-> JGA (Mac) 34 | # Use case: Different environment 35 | # Result: ./comparison_results/jga_diff_env.log 36 | $ deno test -A ./tests/jga_mac_test.ts 37 | 38 | # RNA-seq (Linux, 1st) <-> RNA-seq (Linux, 2nd) 39 | # Use case: Same environment 40 | # Result: ./comparison_results/rnaseq_same_env.log 41 | $ deno test -A ./tests/rnaseq_test.ts 42 | 43 | # RNA-seq (Linux) <-> RNA-seq (Mac) 44 | # Use case: Different environment 45 | # Result: ./comparison_results/rnaseq_diff_env.log 46 | $ deno test -A ./tests/rnaseq_mac_test.ts 47 | 48 | # RNA-seq (Linux, 1st) <-> RNA-seq (Linux, v3.6) 49 | # Use case: Different version 50 | # Result: ./comparison_results/rnaseq_diff_ver.log 51 | $ deno test -A ./tests/rnaseq_v3.6_test.ts 52 | 53 | # RNA-seq (Linux, 1st) <-> RNA-seq (Linux, small) 54 | # Use case: Missing dataset 55 | # Result: ./comparison_results/rnaseq_missing_data.log 56 | $ deno test -A ./tests/rnaseq_small_test.ts 57 | 58 | # RNA-seq (Linux, 1st) <-> RNA-seq (Linux, small) 59 | # Use case: All files 60 | # Result: ./comparison_results/rnaseq_all_files.log 61 | $ deno test -A ./tests/rnaseq_all_files_test.ts 62 | 63 | # RNA-seq (Linux, with yevis) <-> RNA-seq (Linux, only sapporo) 64 | $ deno test -A ./tests/rnaseq_only_sapporo_test.ts 65 | 66 | # Trimming (Linux) <-> Trimming (Mac) 67 | $ deno test -A ./tests/trimming_mac_test.ts 68 | ``` 69 | 70 | ## About test data 71 | 72 | The raw data of workflow execution results are stored in [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7098336.svg)](https://doi.org/10.5281/zenodo.7098336). 73 | 74 | The crate files contained in [`example_crate`](./example_crate): 75 | 76 | ```text 77 | example_crate/ 78 | ├── gatk_1st.json 79 | ├── gatk_2nd.json 80 | ├── gatk_mac.json 81 | ├── jga_1st.json 82 | ├── jga_2nd.json 83 | ├── jga_mac.json 84 | ├── rnaseq_1st.json 85 | ├── rnaseq_2nd.json 86 | ├── rnaseq_mac.json 87 | ├── rnaseq_only_sapporo.json 88 | ├── rnaseq_small.json 89 | ├── rnaseq_v3.6.json 90 | ├── trimming.json 91 | └── trimming_mac.json 92 | ``` 93 | 94 | ### Executed environment 95 | 96 | About the environment in which these crates were generated. 97 | 98 | | Field | Linux env | Mac Apple silicon env | 99 | | ----------------------- | ------------------------------------------ | --------------------- | 100 | | OS | `Ubuntu 20.04.5 LTS` | `macOS 12.5.1` | 101 | | CPU | `Intel(R) Xeon(R) CPU E5-2640 0 @ 2.50GHz` | `Apple M1 Max` | 102 | | CPU cores | `4` | `10` | 103 | | CPU Architecture | `x86_64` | `arm64` | 104 | | Memory | `24.0 GiB` | `64.0 GiB` | 105 | | Docker version | `20.10.8` | `20.10.16` | 106 | | Sapporo-service version | `1.4.8` | `1.4.8` | 107 | | Yevis-cli version | `0.5.4` | `0.5.4` | 108 | 109 | ### GATK 110 | 111 | - Crate: 112 | - [`gatk_1st.json`](./example_crate/gatk_1st.json) 113 | - Crate generated on `Linux` environment. (1st execution) 114 | - [`gatk_2nd.json`](./example_crate/gatk_2nd.json) 115 | - Crate generated on `Linux` environment. (2nd execution (same settings)) 116 | - [`gatk_mac.json`](./example_crate/gatk_mac.json) 117 | - Crate generated on `Mac Apple silicon` environment. 118 | 119 | See for more details about the executed workflow. 120 | 121 | Executed as follows: 122 | 123 | ```bash 124 | yevis test --fetch-ro-crate https://raw.githubusercontent.com/sapporo-wes/test-workflow/main/yevis-metadata_gatk-workflows_mitochondria-pipeline.yml 125 | ``` 126 | 127 | ### JGA 128 | 129 | - Crate: 130 | - [`jga_1st.json`](./example_crate/jga_1st.json) 131 | - Crate generated on `Linux` environment. (1st execution) 132 | - [`jga_2nd.json`](./example_crate/jga_2nd.json) 133 | - Crate generated on `Linux` environment. (2nd execution (same settings)) 134 | - [`jga_mac.json`](./example_crate/jga_mac.json) 135 | - Crate generated on `Mac Apple silicon` environment. 136 | 137 | See for more details about the executed workflow. 138 | 139 | Executed as follows: 140 | 141 | ```bash 142 | yevis test --fetch-ro-crate https://raw.githubusercontent.com/sapporo-wes/test-workflow/main/yevis-metadata_jga-workflow_per-sample.yml 143 | ``` 144 | 145 | ### RNA-seq 146 | 147 | - Crate: 148 | - [`rnaseq_1st.json`](./example_crate/rnaseq_1st.json) 149 | - Crate generated on `Linux` environment. (1st execution) 150 | - [`rnaseq_2nd.json`](./example_crate/rnaseq_2nd.json) 151 | - Crate generated on `Linux` environment. (2nd execution (same settings)) 152 | - [`rnaseq_mac.json`](./example_crate/rnaseq_mac.json) 153 | - Crate generated on `Mac Apple silicon` environment. 154 | - [`rnaseq_small.json`](./example_crate/rnaseq_small.json) 155 | - Crate generated on `Linux` environment. (small dataset) 156 | - [`rnaseq_v3.6.json`](./example_crate/rnaseq_v3.6.json) 157 | - Crate generated on `Linux` environment. 158 | - Using `nf-core/rnaseq` version is `3.6`. (Normal one is `3.7`) 159 | - [`rnaseq_only_sapporo.json`](./example_crate/rnaseq_only_sapporo.json) 160 | - Crate generated on `Linux` environment. 161 | - Using `nf-core/rnaseq` version is `3.7`. 162 | - Using `Sapporo` only. (Not using `Yevis`) 163 | 164 | See for more details about the executed workflow. 165 | 166 | Executed as follows: 167 | 168 | ```bash 169 | # Normal one (v3.7) 170 | $ yevis test --fetch-ro-crate https://raw.githubusercontent.com/sapporo-wes/test-workflow/main/yevis-metadata_nf-core_rnaseq.yml 171 | 172 | # Small dataset 173 | $ yevis test --fetch-ro-crate https://raw.githubusercontent.com/sapporo-wes/test-workflow/main/yevis-metadata_nf-core_rnaseq_small_test.yml 174 | 175 | # v3.6 176 | $ yevis test --fetch-ro-crate https://raw.githubusercontent.com/sapporo-wes/test-workflow/main/yevis-metadata_nf-core_rnaseq_v3.6.yml 177 | ``` 178 | 179 | ### Trimming 180 | 181 | - Crate: 182 | - [`trimming.json`](./example_crate/trimming.json) 183 | - Crate generated on `Linux` environment. 184 | - [`trimming_mac.json`](./example_crate/trimming_mac.json) 185 | - Crate generated on `Mac Apple silicon` environment. 186 | 187 | Workflow is 188 | 189 | Executed as follows: 190 | 191 | ```bash 192 | yevis test --fetch-ro-crate https://raw.githubusercontent.com/sapporo-wes/yevis-cli/main/tests/test-metadata-CWL.yml 193 | ``` 194 | -------------------------------------------------------------------------------- /tests/comparison_results/gatk_diff_env.log: -------------------------------------------------------------------------------- 1 | running 1 test from ./tests/gatk_mac_test.ts 2 | GATK Mac test ... 3 | ------- output ------- 4 | Tonkaz 0.2.5 5 | 6 | Checking Crate2 based on Crate1: 7 | 8 | Crate1: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/gatk_1st.json 9 | Crate2: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/gatk_mac.json 10 | 11 | .----------------------------------------------------------------------------------------------. 12 | | | Crate1 | Crate2 | 13 | |----------------|--------------------------------------|--------------------------------------| 14 | | WF Name | Sapporo workflow run gatk_1st  | Sapporo workflow run gatk_mac  | 15 | | WF Type | Workflow Description Language | Workflow Description Language | 16 | | WF Type Ver | 1.0 | 1.0 | 17 | | Run State | COMPLETE  | EXECUTOR_ERROR  | 18 | | ExitCode | 0  | 1  | 19 | | Start Time | 2022-09-08 09:30:03 | 2022-09-14 05:42:22 | 20 | | End Time | 2022-09-08 09:58:32 | 2022-09-14 05:44:11 | 21 | | Duration | 28m 29s | 1m 49s | 22 | | # Attachments | 28 files | 28 files | 23 | | # Outputs | 13 files (5 EDAM-assigned files)  | 0 files (0 EDAM-assigned files)  | 24 | '----------------------------------------------------------------------------------------------' 25 | * EDAM extensions: .bam/.bb/.bed/.bw/.fa/.fasta/.fastq/.fastq.gz/.fq/.fq.gz/.gtf/.gff/.sam/.vcf/.vcf.gz/.wig 26 | 27 | Comparing workflow results... 28 | Calculate the reproducibility level by comparing the EDAM-assigned output files of Crate1 and Crate2. (option `--all` to use all output files) 29 | 30 | Reproducibility level is defined as follows: 31 | 32 | - Level3 ⭐⭐⭐ : Files are identical with the same checksum 33 | - Level2 ⭐⭐ : Files are different, but their features (file size, map rate, etc.) are similar (within threshold: 0.05) 34 | - Level1 ⭐ : Files are different, and their features are different (beyond threshold) 35 | - Level0 : File not found 36 | 37 | Level3: "Fully Reproduced" <---> Level0: "Not Reproduced" 38 | 39 | === Level3 ⭐⭐⭐ (Same Checksum, 0/0 files) 40 | 41 | === Level2 ⭐⭐ (Similar Features, 0/0 files) 42 | 43 | === Level1 ⭐ (Different Features, 0/0 files) 44 | 45 | === Level0 (Not Found, Crate1: 5 files, Crate2: 0 files) 46 | 47 | - Only in Crate1: 48 | 49 | - outputs/G97753.NA12878.bam 50 | - outputs/G97753.NA12878.final.split.vcf 51 | - outputs/G97753.NA12878.realigned.bam 52 | - outputs/G97753.NA12878.vcf 53 | - outputs/splitAndPassOnly.vcf 54 | 55 | Summarize compare result: 56 | 57 | .---------------------------------------------------------------------------. 58 | | Reproducibility | Level | Definition | File # | 59 | |---------------------------|-----------|---------------------|-------------| 60 | | Fully Reproduced | ⭐⭐⭐ | Same Checksum | 0 files | 61 | | Acceptable Differences | ⭐⭐ | Similar Features | 0 files | 62 | | Unacceptable Differences | ⭐ | Different Features | 0 files | 63 | | Not Reproduced | | Not Found | 5 files | 64 | '---------------------------------------------------------------------------' 65 | 66 | ----- output end ----- 67 | GATK Mac test ... ok (6ms) 68 | 69 | ok | 1 passed | 0 failed (7ms) 70 | 71 | -------------------------------------------------------------------------------- /tests/comparison_results/gatk_same_env.log: -------------------------------------------------------------------------------- 1 | running 1 test from ./tests/gatk_test.ts 2 | GATK Linux test ... 3 | ------- output ------- 4 | Tonkaz 0.2.5 5 | 6 | Checking Crate2 based on Crate1: 7 | 8 | Crate1: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/gatk_1st.json 9 | Crate2: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/gatk_2nd.json 10 | 11 | .----------------------------------------------------------------------------------------------. 12 | | | Crate1 | Crate2 | 13 | |----------------|--------------------------------------|--------------------------------------| 14 | | WF Name | Sapporo workflow run gatk_1st  | Sapporo workflow run gatk_2nd  | 15 | | WF Type | Workflow Description Language | Workflow Description Language | 16 | | WF Type Ver | 1.0 | 1.0 | 17 | | Run State | COMPLETE | COMPLETE | 18 | | ExitCode | 0 | 0 | 19 | | Start Time | 2022-09-08 09:30:03 | 2022-09-08 08:59:34 | 20 | | End Time | 2022-09-08 09:58:32 | 2022-09-08 09:26:25 | 21 | | Duration | 28m 29s | 26m 51s | 22 | | # Attachments | 28 files | 28 files | 23 | | # Outputs | 13 files (5 EDAM-assigned files) | 13 files (5 EDAM-assigned files) | 24 | '----------------------------------------------------------------------------------------------' 25 | * EDAM extensions: .bam/.bb/.bed/.bw/.fa/.fasta/.fastq/.fastq.gz/.fq/.fq.gz/.gtf/.gff/.sam/.vcf/.vcf.gz/.wig 26 | 27 | Comparing workflow results... 28 | Calculate the reproducibility level by comparing the EDAM-assigned output files of Crate1 and Crate2. (option `--all` to use all output files) 29 | 30 | Reproducibility level is defined as follows: 31 | 32 | - Level3 ⭐⭐⭐ : Files are identical with the same checksum 33 | - Level2 ⭐⭐ : Files are different, but their features (file size, map rate, etc.) are similar (within threshold: 0.05) 34 | - Level1 ⭐ : Files are different, and their features are different (beyond threshold) 35 | - Level0 : File not found 36 | 37 | Level3: "Fully Reproduced" <---> Level0: "Not Reproduced" 38 | 39 | === Level3 ⭐⭐⭐ (Same Checksum, 0/5 files) 40 | 41 | === Level2 ⭐⭐ (Similar Features, 5/5 files) 42 | 43 | - G97753.NA12878.bam 44 | .--------------------------------------------------------------------. 45 | | | in Crate1 | in Crate2 | 46 | |----------------|-------------------------|-------------------------| 47 | | File Size | 147.78 MB (154962060)  | 147.78 MB (154962147)  | 48 | | Total Reads | 2349886 | 2349886 | 49 | | # Mapped | 2349886 (100.00%) | 2349886 (100.00%) | 50 | | # Duplicate | 719878 (30.63%) | 719878 (30.63%) | 51 | '--------------------------------------------------------------------' 52 | 53 | - G97753.NA12878.final.split.vcf 54 | .--------------------------------------------------------------------. 55 | | | in Crate1 | in Crate2 | 56 | |----------------|-------------------------|-------------------------| 57 | | File Size | 18.51 KB (18955)  | 18.51 KB (18953)  | 58 | | Line Count | 107 | 107 | 59 | '--------------------------------------------------------------------' 60 | 61 | - G97753.NA12878.realigned.bam 62 | .--------------------------------------------------------------------. 63 | | | in Crate1 | in Crate2 | 64 | |----------------|-------------------------|-------------------------| 65 | | File Size | 98.46 MB (103241649)  | 98.46 MB (103241732)  | 66 | | Total Reads | 2361236 | 2361236 | 67 | | # Mapped | 2361223 (100.00%) | 2361223 (100.00%) | 68 | | # Duplicate | 723304 (30.63%) | 723304 (30.63%) | 69 | '--------------------------------------------------------------------' 70 | 71 | - G97753.NA12878.vcf 72 | .--------------------------------------------------------------------. 73 | | | in Crate1 | in Crate2 | 74 | |----------------|-------------------------|-------------------------| 75 | | File Size | 24.48 KB (25069)  | 24.48 KB (25063)  | 76 | | Line Count | 99 | 99 | 77 | '--------------------------------------------------------------------' 78 | 79 | - splitAndPassOnly.vcf 80 | .--------------------------------------------------------------------. 81 | | | in Crate1 | in Crate2 | 82 | |----------------|-------------------------|-------------------------| 83 | | File Size | 15.85 KB (16229)  | 15.85 KB (16228)  | 84 | | Line Count | 96 | 96 | 85 | | Variant Count | 18 | 18 | 86 | | SNPs Count | 16 | 16 | 87 | | Indels Count | 2 | 2 | 88 | '--------------------------------------------------------------------' 89 | 90 | === Level1 ⭐ (Different Features, 0/5 files) 91 | 92 | === Level0 (Not Found, Crate1: 0 files, Crate2: 0 files) 93 | 94 | Summarize compare result: 95 | 96 | .---------------------------------------------------------------------------. 97 | | Reproducibility | Level | Definition | File # | 98 | |---------------------------|-----------|---------------------|-------------| 99 | | Fully Reproduced | ⭐⭐⭐ | Same Checksum | 0 files | 100 | | Acceptable Differences | ⭐⭐ | Similar Features | 5 files | 101 | | Unacceptable Differences | ⭐ | Different Features | 0 files | 102 | | Not Reproduced | | Not Found | 0 files | 103 | '---------------------------------------------------------------------------' 104 | 105 | Comparing multiqc stats... 106 | Crates contain MultiQC stats, which we will be comparing. MultiQC stats are aggregated on a sample level. 107 | 108 | - Picard_hsmetrics FOLD_ENRICHMENT 109 | .--------------------------------------------------------------------. 110 | | Sample | in Crate1 | in Crate2 | Level | 111 | |--------------------------|--------------|--------------|-----------| 112 | | G97753.NA12878.realigned | 1.003477 | 1.003477 | ⭐⭐ | 113 | '--------------------------------------------------------------------' 114 | 115 | - Picard_hsmetrics MEDIAN_TARGET_COVERAGE 116 | .--------------------------------------------------------------------. 117 | | Sample | in Crate1 | in Crate2 | Level | 118 | |--------------------------|--------------|--------------|-----------| 119 | | G97753.NA12878.realigned | 10199 | 10199 | ⭐⭐ | 120 | '--------------------------------------------------------------------' 121 | 122 | - Picard_hsmetrics PCT_TARGET_BASES_30X 123 | .--------------------------------------------------------------------. 124 | | Sample | in Crate1 | in Crate2 | Level | 125 | |--------------------------|--------------|--------------|-----------| 126 | | G97753.NA12878.realigned | 1 | 1 | ⭐⭐ | 127 | '--------------------------------------------------------------------' 128 | 129 | - Picard_mark_duplicates PERCENT_DUPLICATION 130 | .--------------------------------------------------------------------. 131 | | Sample | in Crate1 | in Crate2 | Level | 132 | |--------------------------|--------------|--------------|-----------| 133 | | mba | 0.306351 | 0.306351 | ⭐⭐ | 134 | '--------------------------------------------------------------------' 135 | 136 | - Picard_wgsmetrics MEAN_COVERAGE 137 | .--------------------------------------------------------------------. 138 | | Sample | in Crate1 | in Crate2 | Level | 139 | |--------------------------|--------------|--------------|-----------| 140 | | G97753.NA12878.realigned | 10183.851823 | 10183.851823 | ⭐⭐ | 141 | '--------------------------------------------------------------------' 142 | 143 | - Picard_wgsmetrics MEDIAN_COVERAGE 144 | .--------------------------------------------------------------------. 145 | | Sample | in Crate1 | in Crate2 | Level | 146 | |--------------------------|--------------|--------------|-----------| 147 | | G97753.NA12878.realigned | 10255 | 10255 | ⭐⭐ | 148 | '--------------------------------------------------------------------' 149 | 150 | - Picard_wgsmetrics PCT_30X 151 | .--------------------------------------------------------------------. 152 | | Sample | in Crate1 | in Crate2 | Level | 153 | |--------------------------|--------------|--------------|-----------| 154 | | G97753.NA12878.realigned | 1 | 1 | ⭐⭐ | 155 | '--------------------------------------------------------------------' 156 | 157 | - Picard_wgsmetrics SD_COVERAGE 158 | .--------------------------------------------------------------------. 159 | | Sample | in Crate1 | in Crate2 | Level | 160 | |--------------------------|--------------|--------------|-----------| 161 | | G97753.NA12878.realigned | 714.392471 | 714.392471 | ⭐⭐ | 162 | '--------------------------------------------------------------------' 163 | 164 | ----- output end ----- 165 | GATK Linux test ... ok (8ms) 166 | 167 | ok | 1 passed | 0 failed (9ms) 168 | 169 | -------------------------------------------------------------------------------- /tests/comparison_results/jga_diff_env.log: -------------------------------------------------------------------------------- 1 | running 1 test from ./tests/jga_mac_test.ts 2 | JGA Mac test ... 3 | ------- output ------- 4 | Tonkaz 0.2.5 5 | 6 | Checking Crate2 based on Crate1: 7 | 8 | Crate1: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/jga_1st.json 9 | Crate2: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/jga_mac.json 10 | 11 | .----------------------------------------------------------------------------------------------. 12 | | | Crate1 | Crate2 | 13 | |----------------|--------------------------------------|--------------------------------------| 14 | | WF Name | Sapporo workflow run jga_1st  | Sapporo workflow run jga_mac  | 15 | | WF Type | Common Workflow Language | Common Workflow Language | 16 | | WF Type Ver | 1.1 | 1.1 | 17 | | Run State | COMPLETE  | CANCELED  | 18 | | ExitCode | 0  | 138  | 19 | | Start Time | 2022-09-10 13:33:40 | 2022-09-15 06:49:26 | 20 | | End Time | 2022-09-10 15:03:05 | 2022-09-15 10:28:54 | 21 | | Duration | 1h 29m 25s | 3h 39m 28s | 22 | | # Attachments | 23 files | 23 files | 23 | | # Outputs | 48 files (4 EDAM-assigned files)  | 0 files (0 EDAM-assigned files)  | 24 | '----------------------------------------------------------------------------------------------' 25 | * EDAM extensions: .bam/.bb/.bed/.bw/.fa/.fasta/.fastq/.fastq.gz/.fq/.fq.gz/.gtf/.gff/.sam/.vcf/.vcf.gz/.wig 26 | 27 | Comparing workflow results... 28 | Calculate the reproducibility level by comparing the EDAM-assigned output files of Crate1 and Crate2. (option `--all` to use all output files) 29 | 30 | Reproducibility level is defined as follows: 31 | 32 | - Level3 ⭐⭐⭐ : Files are identical with the same checksum 33 | - Level2 ⭐⭐ : Files are different, but their features (file size, map rate, etc.) are similar (within threshold: 0.05) 34 | - Level1 ⭐ : Files are different, and their features are different (beyond threshold) 35 | - Level0 : File not found 36 | 37 | Level3: "Fully Reproduced" <---> Level0: "Not Reproduced" 38 | 39 | === Level3 ⭐⭐⭐ (Same Checksum, 0/0 files) 40 | 41 | === Level2 ⭐⭐ (Similar Features, 0/0 files) 42 | 43 | === Level1 ⭐ (Different Features, 0/0 files) 44 | 45 | === Level0 (Not Found, Crate1: 4 files, Crate2: 0 files) 46 | 47 | - Only in Crate1: 48 | 49 | - outputs/NA19023.autosome_PAR_ploidy_2.g.vcf.gz 50 | - outputs/NA19023.chrX_nonPAR_ploidy_1.g.vcf.gz 51 | - outputs/NA19023.chrX_nonPAR_ploidy_2.g.vcf.gz 52 | - outputs/NA19023.chrY_nonPAR_ploidy_1.g.vcf.gz 53 | 54 | Summarize compare result: 55 | 56 | .---------------------------------------------------------------------------. 57 | | Reproducibility | Level | Definition | File # | 58 | |---------------------------|-----------|---------------------|-------------| 59 | | Fully Reproduced | ⭐⭐⭐ | Same Checksum | 0 files | 60 | | Acceptable Differences | ⭐⭐ | Similar Features | 0 files | 61 | | Unacceptable Differences | ⭐ | Different Features | 0 files | 62 | | Not Reproduced | | Not Found | 4 files | 63 | '---------------------------------------------------------------------------' 64 | 65 | ----- output end ----- 66 | JGA Mac test ... ok (6ms) 67 | 68 | ok | 1 passed | 0 failed (7ms) 69 | 70 | -------------------------------------------------------------------------------- /tests/comparison_results/jga_same_env.log: -------------------------------------------------------------------------------- 1 | running 1 test from ./tests/jga_test.ts 2 | JGA Linux test ... 3 | ------- output ------- 4 | Tonkaz 0.2.5 5 | 6 | Checking Crate2 based on Crate1: 7 | 8 | Crate1: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/jga_1st.json 9 | Crate2: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/jga_2nd.json 10 | 11 | .----------------------------------------------------------------------------------------------. 12 | | | Crate1 | Crate2 | 13 | |----------------|--------------------------------------|--------------------------------------| 14 | | WF Name | Sapporo workflow run jga_1st  | Sapporo workflow run jga_2nd  | 15 | | WF Type | Common Workflow Language | Common Workflow Language | 16 | | WF Type Ver | 1.1 | 1.1 | 17 | | Run State | COMPLETE | COMPLETE | 18 | | ExitCode | 0 | 0 | 19 | | Start Time | 2022-09-10 13:33:40 | 2022-09-10 20:40:42 | 20 | | End Time | 2022-09-10 15:03:05 | 2022-09-10 22:09:08 | 21 | | Duration | 1h 29m 25s | 1h 28m 26s | 22 | | # Attachments | 23 files | 23 files | 23 | | # Outputs | 48 files (4 EDAM-assigned files) | 48 files (4 EDAM-assigned files) | 24 | '----------------------------------------------------------------------------------------------' 25 | * EDAM extensions: .bam/.bb/.bed/.bw/.fa/.fasta/.fastq/.fastq.gz/.fq/.fq.gz/.gtf/.gff/.sam/.vcf/.vcf.gz/.wig 26 | 27 | Comparing workflow results... 28 | Calculate the reproducibility level by comparing the EDAM-assigned output files of Crate1 and Crate2. (option `--all` to use all output files) 29 | 30 | Reproducibility level is defined as follows: 31 | 32 | - Level3 ⭐⭐⭐ : Files are identical with the same checksum 33 | - Level2 ⭐⭐ : Files are different, but their features (file size, map rate, etc.) are similar (within threshold: 0.05) 34 | - Level1 ⭐ : Files are different, and their features are different (beyond threshold) 35 | - Level0 : File not found 36 | 37 | Level3: "Fully Reproduced" <---> Level0: "Not Reproduced" 38 | 39 | === Level3 ⭐⭐⭐ (Same Checksum, 0/4 files) 40 | 41 | === Level2 ⭐⭐ (Similar Features, 4/4 files) 42 | 43 | - NA19023.autosome_PAR_ploidy_2.g.vcf.gz 44 | .--------------------------------------------------------------------. 45 | | | in Crate1 | in Crate2 | 46 | |----------------|-------------------------|-------------------------| 47 | | File Size | 33.59 KB (34397)  | 33.59 KB (34398)  | 48 | | Variant Count | 1061 | 1061 | 49 | | SNPs Count | 14 | 14 | 50 | | Indels Count | 1 | 1 | 51 | '--------------------------------------------------------------------' 52 | 53 | - NA19023.chrX_nonPAR_ploidy_1.g.vcf.gz 54 | .--------------------------------------------------------------------. 55 | | | in Crate1 | in Crate2 | 56 | |----------------|-------------------------|-------------------------| 57 | | File Size | 23.84 KB (24408)  | 23.84 KB (24409)  | 58 | | Variant Count | 2 | 2 | 59 | | SNPs Count | 0 | 0 | 60 | | Indels Count | 0 | 0 | 61 | '--------------------------------------------------------------------' 62 | 63 | - NA19023.chrX_nonPAR_ploidy_2.g.vcf.gz 64 | .--------------------------------------------------------------------. 65 | | | in Crate1 | in Crate2 | 66 | |----------------|-------------------------|-------------------------| 67 | | File Size | 24.03 KB (24602)  | 24.02 KB (24601)  | 68 | | Variant Count | 2 | 2 | 69 | | SNPs Count | 0 | 0 | 70 | | Indels Count | 0 | 0 | 71 | '--------------------------------------------------------------------' 72 | 73 | - NA19023.chrY_nonPAR_ploidy_1.g.vcf.gz 74 | .--------------------------------------------------------------------. 75 | | | in Crate1 | in Crate2 | 76 | |----------------|-------------------------|-------------------------| 77 | | File Size | 24.35 KB (24931)  | 24.35 KB (24935)  | 78 | | Variant Count | 42 | 42 | 79 | | SNPs Count | 4 | 4 | 80 | | Indels Count | 0 | 0 | 81 | '--------------------------------------------------------------------' 82 | 83 | === Level1 ⭐ (Different Features, 0/4 files) 84 | 85 | === Level0 (Not Found, Crate1: 0 files, Crate2: 0 files) 86 | 87 | Summarize compare result: 88 | 89 | .---------------------------------------------------------------------------. 90 | | Reproducibility | Level | Definition | File # | 91 | |---------------------------|-----------|---------------------|-------------| 92 | | Fully Reproduced | ⭐⭐⭐ | Same Checksum | 0 files | 93 | | Acceptable Differences | ⭐⭐ | Similar Features | 4 files | 94 | | Unacceptable Differences | ⭐ | Different Features | 0 files | 95 | | Not Reproduced | | Not Found | 0 files | 96 | '---------------------------------------------------------------------------' 97 | 98 | Comparing multiqc stats... 99 | Crates contain MultiQC stats, which we will be comparing. MultiQC stats are aggregated on a sample level. 100 | 101 | - Bcftools_stats Number_of_MNPs 102 | .---------------------------------------------------------------------------. 103 | | Sample | in Crate1 | in Crate2 | Level | 104 | |---------------------------------|--------------|--------------|-----------| 105 | | NA19023.autosome_PAR_ploidy_2.g | 0 | 0 | ⭐⭐ | 106 | | NA19023.chrX_nonPAR_ploidy_1.g | 0 | 0 | ⭐⭐ | 107 | | NA19023.chrX_nonPAR_ploidy_2.g | 0 | 0 | ⭐⭐ | 108 | | NA19023.chrY_nonPAR_ploidy_1.g | 0 | 0 | ⭐⭐ | 109 | '---------------------------------------------------------------------------' 110 | 111 | - Bcftools_stats Number_of_SNPs 112 | .---------------------------------------------------------------------------. 113 | | Sample | in Crate1 | in Crate2 | Level | 114 | |---------------------------------|--------------|--------------|-----------| 115 | | NA19023.autosome_PAR_ploidy_2.g | 14 | 14 | ⭐⭐ | 116 | | NA19023.chrX_nonPAR_ploidy_1.g | 0 | 0 | ⭐⭐ | 117 | | NA19023.chrX_nonPAR_ploidy_2.g | 0 | 0 | ⭐⭐ | 118 | | NA19023.chrY_nonPAR_ploidy_1.g | 4 | 4 | ⭐⭐ | 119 | '---------------------------------------------------------------------------' 120 | 121 | - Bcftools_stats Number_of_indels 122 | .---------------------------------------------------------------------------. 123 | | Sample | in Crate1 | in Crate2 | Level | 124 | |---------------------------------|--------------|--------------|-----------| 125 | | NA19023.autosome_PAR_ploidy_2.g | 1 | 1 | ⭐⭐ | 126 | | NA19023.chrX_nonPAR_ploidy_1.g | 0 | 0 | ⭐⭐ | 127 | | NA19023.chrX_nonPAR_ploidy_2.g | 0 | 0 | ⭐⭐ | 128 | | NA19023.chrY_nonPAR_ploidy_1.g | 0 | 0 | ⭐⭐ | 129 | '---------------------------------------------------------------------------' 130 | 131 | - Bcftools_stats Number_of_records 132 | .---------------------------------------------------------------------------. 133 | | Sample | in Crate1 | in Crate2 | Level | 134 | |---------------------------------|--------------|--------------|-----------| 135 | | NA19023.autosome_PAR_ploidy_2.g | 1061 | 1061 | ⭐⭐ | 136 | | NA19023.chrX_nonPAR_ploidy_1.g | 2 | 2 | ⭐⭐ | 137 | | NA19023.chrX_nonPAR_ploidy_2.g | 2 | 2 | ⭐⭐ | 138 | | NA19023.chrY_nonPAR_ploidy_1.g | 42 | 42 | ⭐⭐ | 139 | '---------------------------------------------------------------------------' 140 | 141 | - Bcftools_stats Tstv 142 | .---------------------------------------------------------------------------. 143 | | Sample | in Crate1 | in Crate2 | Level | 144 | |---------------------------------|--------------|--------------|-----------| 145 | | NA19023.autosome_PAR_ploidy_2.g | 2.5 | 2.5 | ⭐⭐ | 146 | | NA19023.chrX_nonPAR_ploidy_1.g | 0 | 0 | ⭐⭐ | 147 | | NA19023.chrX_nonPAR_ploidy_2.g | 0 | 0 | ⭐⭐ | 148 | | NA19023.chrY_nonPAR_ploidy_1.g | 1 | 1 | ⭐⭐ | 149 | '---------------------------------------------------------------------------' 150 | 151 | - Picard_mark_duplicates PERCENT_DUPLICATION 152 | .---------------------------------------------------------------------------. 153 | | Sample | in Crate1 | in Crate2 | Level | 154 | |---------------------------------|--------------|--------------|-----------| 155 | | ERR1347662 | 0.000966 | 0.000966 | ⭐⭐ | 156 | '---------------------------------------------------------------------------' 157 | 158 | - Picard_wgsmetrics MEAN_COVERAGE 159 | .---------------------------------------------------------------------------. 160 | | Sample | in Crate1 | in Crate2 | Level | 161 | |---------------------------------|--------------|--------------|-----------| 162 | | NA19023 | 0 | 0 | ⭐⭐ | 163 | '---------------------------------------------------------------------------' 164 | 165 | - Picard_wgsmetrics MEDIAN_COVERAGE 166 | .---------------------------------------------------------------------------. 167 | | Sample | in Crate1 | in Crate2 | Level | 168 | |---------------------------------|--------------|--------------|-----------| 169 | | NA19023 | 0 | 0 | ⭐⭐ | 170 | '---------------------------------------------------------------------------' 171 | 172 | - Picard_wgsmetrics PCT_30X 173 | .---------------------------------------------------------------------------. 174 | | Sample | in Crate1 | in Crate2 | Level | 175 | |---------------------------------|--------------|--------------|-----------| 176 | | NA19023 | 0 | 0 | ⭐⭐ | 177 | '---------------------------------------------------------------------------' 178 | 179 | - Picard_wgsmetrics SD_COVERAGE 180 | .---------------------------------------------------------------------------. 181 | | Sample | in Crate1 | in Crate2 | Level | 182 | |---------------------------------|--------------|--------------|-----------| 183 | | NA19023 | 0 | 0 | ⭐⭐ | 184 | '---------------------------------------------------------------------------' 185 | 186 | - Samtools Flagstat_total 187 | .---------------------------------------------------------------------------. 188 | | Sample | in Crate1 | in Crate2 | Level | 189 | |---------------------------------|--------------|--------------|-----------| 190 | | NA19023 | 21866 | 21866 | ⭐⭐ | 191 | '---------------------------------------------------------------------------' 192 | 193 | - Samtools Mapped_passed 194 | .---------------------------------------------------------------------------. 195 | | Sample | in Crate1 | in Crate2 | Level | 196 | |---------------------------------|--------------|--------------|-----------| 197 | | NA19023 | 21838 | 21838 | ⭐⭐ | 198 | '---------------------------------------------------------------------------' 199 | 200 | - Samtools Mapped_passed_pct 201 | .---------------------------------------------------------------------------. 202 | | Sample | in Crate1 | in Crate2 | Level | 203 | |---------------------------------|--------------|--------------|-----------| 204 | | NA19023 | 99.87 | 99.87 | ⭐⭐ | 205 | '---------------------------------------------------------------------------' 206 | 207 | ----- output end ----- 208 | JGA Linux test ... ok (9ms) 209 | 210 | ok | 1 passed | 0 failed (10ms) 211 | 212 | -------------------------------------------------------------------------------- /tests/comparison_results/rnaseq_diff_env.log: -------------------------------------------------------------------------------- 1 | running 1 test from ./tests/rnaseq_mac_test.ts 2 | RNA-seq Mac test ... 3 | ------- output ------- 4 | Tonkaz 0.2.5 5 | 6 | Checking Crate2 based on Crate1: 7 | 8 | Crate1: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/rnaseq_1st.json 9 | Crate2: /home/suecharo/git/github.com/sapporo-wes/tonkaz/tests/example_crate/rnaseq_mac.json 10 | 11 | .----------------------------------------------------------------------------------------------. 12 | | | Crate1 | Crate2 | 13 | |----------------|--------------------------------------|--------------------------------------| 14 | | WF Name | Sapporo workflow run rnaseq_1st  | Sapporo workflow run rnaseq_mac  | 15 | | WF Type | Nextflow | Nextflow | 16 | | WF Type Ver | 1.0 | 1.0 | 17 | | Run State | COMPLETE  | EXECUTOR_ERROR  | 18 | | ExitCode | 0  | 1  | 19 | | Start Time | 2022-09-08 06:28:11 | 2022-09-14 08:42:09 | 20 | | End Time | 2022-09-08 06:45:53 | 2022-09-14 08:44:23 | 21 | | Duration | 17m 42s | 2m 14s | 22 | | # Attachments | 147 files | 147 files | 23 | | # Outputs | 872 files (25 EDAM-assigned files)  | 4 files (0 EDAM-assigned files)  | 24 | '----------------------------------------------------------------------------------------------' 25 | * EDAM extensions: .bam/.bb/.bed/.bw/.fa/.fasta/.fastq/.fastq.gz/.fq/.fq.gz/.gtf/.gff/.sam/.vcf/.vcf.gz/.wig 26 | 27 | Comparing workflow results... 28 | Calculate the reproducibility level by comparing the EDAM-assigned output files of Crate1 and Crate2. (option `--all` to use all output files) 29 | 30 | Reproducibility level is defined as follows: 31 | 32 | - Level3 ⭐⭐⭐ : Files are identical with the same checksum 33 | - Level2 ⭐⭐ : Files are different, but their features (file size, map rate, etc.) are similar (within threshold: 0.05) 34 | - Level1 ⭐ : Files are different, and their features are different (beyond threshold) 35 | - Level0 : File not found 36 | 37 | Level3: "Fully Reproduced" <---> Level0: "Not Reproduced" 38 | 39 | === Level3 ⭐⭐⭐ (Same Checksum, 0/0 files) 40 | 41 | === Level2 ⭐⭐ (Similar Features, 0/0 files) 42 | 43 | === Level1 ⭐ (Different Features, 0/0 files) 44 | 45 | === Level0 (Not Found, Crate1: 25 files, Crate2: 0 files) 46 | 47 | - Only in Crate1: 48 | 49 | - outputs/star_salmon/RAP1_IAA_30M_REP1.markdup.sorted.bam 50 | - outputs/star_salmon/RAP1_UNINDUCED_REP1.markdup.sorted.bam 51 | - outputs/star_salmon/RAP1_UNINDUCED_REP2.markdup.sorted.bam 52 | - outputs/star_salmon/WT_REP1.markdup.sorted.bam 53 | - outputs/star_salmon/WT_REP2.markdup.sorted.bam 54 | - outputs/star_salmon/rseqc/junction_annotation/bed/RAP1_IAA_30M_REP1.junction.Interact.bed 55 | - outputs/star_salmon/rseqc/junction_annotation/bed/RAP1_IAA_30M_REP1.junction.bed 56 | - outputs/star_salmon/rseqc/junction_annotation/bed/RAP1_UNINDUCED_REP1.junction.Interact.bed 57 | - outputs/star_salmon/rseqc/junction_annotation/bed/RAP1_UNINDUCED_REP1.junction.bed 58 | - outputs/star_salmon/rseqc/junction_annotation/bed/RAP1_UNINDUCED_REP2.junction.Interact.bed 59 | - outputs/star_salmon/rseqc/junction_annotation/bed/RAP1_UNINDUCED_REP2.junction.bed 60 | - outputs/star_salmon/rseqc/junction_annotation/bed/WT_REP1.junction.Interact.bed 61 | - outputs/star_salmon/rseqc/junction_annotation/bed/WT_REP1.junction.bed 62 | - outputs/star_salmon/rseqc/junction_annotation/bed/WT_REP2.junction.Interact.bed 63 | - outputs/star_salmon/rseqc/junction_annotation/bed/WT_REP2.junction.bed 64 | - outputs/star_salmon/stringtie/RAP1_IAA_30M_REP1.coverage.gtf 65 | - outputs/star_salmon/stringtie/RAP1_IAA_30M_REP1.transcripts.gtf 66 | - outputs/star_salmon/stringtie/RAP1_UNINDUCED_REP1.coverage.gtf 67 | - outputs/star_salmon/stringtie/RAP1_UNINDUCED_REP1.transcripts.gtf 68 | - outputs/star_salmon/stringtie/RAP1_UNINDUCED_REP2.coverage.gtf 69 | - outputs/star_salmon/stringtie/RAP1_UNINDUCED_REP2.transcripts.gtf 70 | - outputs/star_salmon/stringtie/WT_REP1.coverage.gtf 71 | - outputs/star_salmon/stringtie/WT_REP1.transcripts.gtf 72 | - outputs/star_salmon/stringtie/WT_REP2.coverage.gtf 73 | - outputs/star_salmon/stringtie/WT_REP2.transcripts.gtf 74 | 75 | Summarize compare result: 76 | 77 | .---------------------------------------------------------------------------. 78 | | Reproducibility | Level | Definition | File # | 79 | |---------------------------|-----------|---------------------|-------------| 80 | | Fully Reproduced | ⭐⭐⭐ | Same Checksum | 0 files | 81 | | Acceptable Differences | ⭐⭐ | Similar Features | 0 files | 82 | | Unacceptable Differences | ⭐ | Different Features | 0 files | 83 | | Not Reproduced | | Not Found | 25 files | 84 | '---------------------------------------------------------------------------' 85 | 86 | ----- output end ----- 87 | RNA-seq Mac test ... ok (14ms) 88 | 89 | ok | 1 passed | 0 failed (15ms) 90 | 91 | -------------------------------------------------------------------------------- /tests/dump_all_comparison_results.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | HERE=$( 5 | cd $(dirname $0) 6 | pwd 7 | ) 8 | cd $HERE/.. 9 | 10 | declare -A tests=( 11 | "gatk_same_env" "gatk_test.ts" 12 | "gatk_diff_env" "gatk_mac_test.ts" 13 | "jga_same_env" "jga_test.ts" 14 | "jga_diff_env" "jga_mac_test.ts" 15 | "rnaseq_same_env" "rnaseq_test.ts" 16 | "rnaseq_diff_env" "rnaseq_mac_test.ts" 17 | "rnaseq_diff_ver" "rnaseq_v3.6_test.ts" 18 | "rnaseq_missing_data" "rnaseq_small_test.ts" 19 | "rnaseq_all_files" "rnaseq_all_files_test.ts" 20 | ) 21 | 22 | for test in "${!tests[@]}"; do 23 | echo "Running test: $test" 24 | deno test -A ./tests/${tests[$test]} > >(tee ./tests/comparison_results/$test.log) 25 | done 26 | -------------------------------------------------------------------------------- /tests/example_crate/gatk_mac.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/ro/crate/1.1/context", 4 | "https://w3id.org/ro/terms/sapporo", 5 | "https://w3id.org/ro/terms/workflow-run" 6 | ], 7 | "@graph": [ 8 | { 9 | "@id": "./", 10 | "@type": "Dataset", 11 | "conformsTo": [ 12 | { 13 | "@id": "https://w3id.org/ro/wfrun/process/0.1" 14 | }, 15 | { 16 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1" 17 | }, 18 | { 19 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 20 | } 21 | ], 22 | "datePublished": "2024-01-29T04:20:40+00:00", 23 | "hasPart": [ 24 | { 25 | "@id": "https://raw.githubusercontent.com/broadinstitute/gatk/bd640eaf935c56155c4caa23922a96cfd5f14b6e/scripts/mitochondria_m2_wdl/MitochondriaPipeline.wdl" 26 | }, 27 | { 28 | "@id": "exe/AlignAndCall.wdl" 29 | }, 30 | { 31 | "@id": "exe/AlignmentPipeline.wdl" 32 | }, 33 | { 34 | "@id": "exe/G97753.NA12878.bam" 35 | }, 36 | { 37 | "@id": "exe/G97753.NA12878.bai" 38 | }, 39 | { 40 | "@id": "exe/Homo_sapiens_assembly38.fasta" 41 | }, 42 | { 43 | "@id": "exe/Homo_sapiens_assembly38.dict" 44 | }, 45 | { 46 | "@id": "exe/Homo_sapiens_assembly38.fasta.fai" 47 | }, 48 | { 49 | "@id": "exe/Homo_sapiens_assembly38.chrM.dict" 50 | }, 51 | { 52 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta" 53 | }, 54 | { 55 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.fai" 56 | }, 57 | { 58 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.amb" 59 | }, 60 | { 61 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.ann" 62 | }, 63 | { 64 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.bwt" 65 | }, 66 | { 67 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.pac" 68 | }, 69 | { 70 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.sa" 71 | }, 72 | { 73 | "@id": "exe/blacklist_sites.hg38.chrM.bed" 74 | }, 75 | { 76 | "@id": "exe/blacklist_sites.hg38.chrM.bed.idx" 77 | }, 78 | { 79 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.dict" 80 | }, 81 | { 82 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta" 83 | }, 84 | { 85 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.fai" 86 | }, 87 | { 88 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.amb" 89 | }, 90 | { 91 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.ann" 92 | }, 93 | { 94 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.bwt" 95 | }, 96 | { 97 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.pac" 98 | }, 99 | { 100 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.sa" 101 | }, 102 | { 103 | "@id": "exe/ShiftBack.chain" 104 | }, 105 | { 106 | "@id": "exe/control_region_shifted.chrM.interval_list" 107 | }, 108 | { 109 | "@id": "exe/non_control_region.chrM.interval_list" 110 | }, 111 | { 112 | "@id": "stdout.log" 113 | }, 114 | { 115 | "@id": "stderr.log" 116 | } 117 | ], 118 | "mainEntity": { 119 | "@id": "https://raw.githubusercontent.com/broadinstitute/gatk/bd640eaf935c56155c4caa23922a96cfd5f14b6e/scripts/mitochondria_m2_wdl/MitochondriaPipeline.wdl" 120 | }, 121 | "mentions": [ 122 | { 123 | "@id": "#gatk_mac" 124 | } 125 | ] 126 | }, 127 | { 128 | "@id": "ro-crate-metadata.json", 129 | "@type": "CreativeWork", 130 | "about": { 131 | "@id": "./" 132 | }, 133 | "conformsTo": [ 134 | { 135 | "@id": "https://w3id.org/ro/crate/1.1" 136 | }, 137 | { 138 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 139 | } 140 | ] 141 | }, 142 | { 143 | "@id": "https://w3id.org/ro/wfrun/process/0.1", 144 | "@type": "CreativeWork", 145 | "name": "Process Run Crate", 146 | "version": "0.1" 147 | }, 148 | { 149 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1", 150 | "@type": "CreativeWork", 151 | "name": "Workflow Run Crate", 152 | "version": "0.1" 153 | }, 154 | { 155 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0", 156 | "@type": "CreativeWork", 157 | "name": "Workflow RO-Crate", 158 | "version": "1.0" 159 | }, 160 | { 161 | "@id": "https://raw.githubusercontent.com/broadinstitute/gatk/bd640eaf935c56155c4caa23922a96cfd5f14b6e/scripts/mitochondria_m2_wdl/MitochondriaPipeline.wdl", 162 | "@type": [ 163 | "File", 164 | "SoftwareSourceCode", 165 | "ComputationalWorkflow" 166 | ], 167 | "name": "https://raw.githubusercontent.com/broadinstitute/gatk/bd640eaf935c56155c4caa23922a96cfd5f14b6e/scripts/mitochondria_m2_wdl/MitochondriaPipeline", 168 | "programmingLanguage": { 169 | "@id": "#https://openwdl.org" 170 | } 171 | }, 172 | { 173 | "@id": "#https://openwdl.org", 174 | "@type": "ComputerLanguage", 175 | "alternateName": "WDL", 176 | "identifier": { 177 | "@id": "#https://openwdl.org" 178 | }, 179 | "name": "Workflow Description Language", 180 | "url": { 181 | "@id": "#https://openwdl.org" 182 | }, 183 | "version": "1.0" 184 | }, 185 | { 186 | "@id": "#gatk_mac", 187 | "@type": "CreateAction", 188 | "actionStatus": "FailedActionStatus", 189 | "endTime": "2022-09-14T05:44:11", 190 | "exitCode": 1, 191 | "instrument": { 192 | "@id": "https://raw.githubusercontent.com/broadinstitute/gatk/bd640eaf935c56155c4caa23922a96cfd5f14b6e/scripts/mitochondria_m2_wdl/MitochondriaPipeline.wdl" 193 | }, 194 | "name": "Sapporo workflow run gatk_mac", 195 | "object": [ 196 | { 197 | "@id": "exe/AlignAndCall.wdl" 198 | }, 199 | { 200 | "@id": "exe/AlignmentPipeline.wdl" 201 | }, 202 | { 203 | "@id": "exe/G97753.NA12878.bam" 204 | }, 205 | { 206 | "@id": "exe/G97753.NA12878.bai" 207 | }, 208 | { 209 | "@id": "exe/Homo_sapiens_assembly38.fasta" 210 | }, 211 | { 212 | "@id": "exe/Homo_sapiens_assembly38.dict" 213 | }, 214 | { 215 | "@id": "exe/Homo_sapiens_assembly38.fasta.fai" 216 | }, 217 | { 218 | "@id": "exe/Homo_sapiens_assembly38.chrM.dict" 219 | }, 220 | { 221 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta" 222 | }, 223 | { 224 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.fai" 225 | }, 226 | { 227 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.amb" 228 | }, 229 | { 230 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.ann" 231 | }, 232 | { 233 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.bwt" 234 | }, 235 | { 236 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.pac" 237 | }, 238 | { 239 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.sa" 240 | }, 241 | { 242 | "@id": "exe/blacklist_sites.hg38.chrM.bed" 243 | }, 244 | { 245 | "@id": "exe/blacklist_sites.hg38.chrM.bed.idx" 246 | }, 247 | { 248 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.dict" 249 | }, 250 | { 251 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta" 252 | }, 253 | { 254 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.fai" 255 | }, 256 | { 257 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.amb" 258 | }, 259 | { 260 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.ann" 261 | }, 262 | { 263 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.bwt" 264 | }, 265 | { 266 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.pac" 267 | }, 268 | { 269 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.sa" 270 | }, 271 | { 272 | "@id": "exe/ShiftBack.chain" 273 | }, 274 | { 275 | "@id": "exe/control_region_shifted.chrM.interval_list" 276 | }, 277 | { 278 | "@id": "exe/non_control_region.chrM.interval_list" 279 | } 280 | ], 281 | "startTime": "2022-09-14T05:42:22", 282 | "subjectOf": [ 283 | { 284 | "@id": "stdout.log" 285 | }, 286 | { 287 | "@id": "stderr.log" 288 | } 289 | ], 290 | "wesState": "EXECUTOR_ERROR" 291 | }, 292 | { 293 | "@id": "exe/AlignAndCall.wdl", 294 | "@type": "File", 295 | "contentSize": 19616, 296 | "dateModified": "2022-09-14T14:38:34", 297 | "encodingFormat": "text/x-objective-c", 298 | "lineCount": 637, 299 | "sha512": "f343ca31e5cbfd37e4b29c197dce289d8788a9232678ba1333786628930a897cca954cab3d7a27116a1ba46f9d0d79a9936511d9b1911795640f55c790f59841", 300 | "url": "https://raw.githubusercontent.com/broadinstitute/gatk/bd640eaf935c56155c4caa23922a96cfd5f14b6e/scripts/mitochondria_m2_wdl/AlignAndCall.wdl" 301 | }, 302 | { 303 | "@id": "exe/AlignmentPipeline.wdl", 304 | "@type": "File", 305 | "contentSize": 5329, 306 | "dateModified": "2022-09-14T14:38:34", 307 | "encodingFormat": "text/plain", 308 | "lineCount": 184, 309 | "sha512": "8c39ba17371924cb268237e0e867475855f7af2494cf448045e24223fe0ec0956e551bba3601a808c120e7e779bb63fabf6f7a3d0d0808f0e2ea8c569ac043b4", 310 | "url": "https://raw.githubusercontent.com/broadinstitute/gatk/bd640eaf935c56155c4caa23922a96cfd5f14b6e/scripts/mitochondria_m2_wdl/AlignmentPipeline.wdl" 311 | }, 312 | { 313 | "@id": "exe/G97753.NA12878.bam", 314 | "@type": "File", 315 | "contentSize": 120633043, 316 | "dateModified": "2022-09-14T14:38:42", 317 | "encodingFormat": "http://edamontology.org/format_2572", 318 | "sha512": "8d099a208a63b3ce2c14a01a2ffddf7c97d7ae5997a2433cc79cd0fe1f1c3e93bed4d4c26c850bfdff68444e1cfcac9cb683f90fabf975fccb8f376e48a52a75", 319 | "url": "https://storage.googleapis.com/gatk-best-practices/mitochondria-pipeline/G97753.NA12878.bam" 320 | }, 321 | { 322 | "@id": "exe/G97753.NA12878.bai", 323 | "@type": "File", 324 | "contentSize": 1712968, 325 | "dateModified": "2022-09-14T14:38:42", 326 | "encodingFormat": "application/octet-stream", 327 | "sha512": "de71983d22edec88c37e1472bd89f64c82665aaa5f5ffecdc6a97137fa2c7b64393e5e33b219660fe61e96c0439cf5c778e525c0d1eb2b6e8f9f05b3e3b49a10", 328 | "url": "https://raw.githubusercontent.com/sapporo-wes/test-workflow/fd9bdef7d657f8b29c159dcbc2d59d191b08ae22/assets/G97753.NA12878.bai" 329 | }, 330 | { 331 | "@id": "exe/Homo_sapiens_assembly38.fasta", 332 | "@type": "File", 333 | "contentSize": 3249912778, 334 | "dateModified": "2022-09-14T14:42:06", 335 | "encodingFormat": "http://edamontology.org/format_1929", 336 | "lineCount": 32178545, 337 | "sha512": "41a0edb97c470b327464d37a4efe8d36f1796e1148191f1c5be1d7d868c4bfb91958f66de4234d402ec0360fac07b6fdd766b5c1100ae909c073425551256915", 338 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/Homo_sapiens_assembly38.fasta" 339 | }, 340 | { 341 | "@id": "exe/Homo_sapiens_assembly38.dict", 342 | "@type": "File", 343 | "contentSize": 581712, 344 | "dateModified": "2022-09-14T14:42:07", 345 | "encodingFormat": "text/plain", 346 | "lineCount": 3367, 347 | "sha512": "9b64fa47412becaab2e41ecc7c4132fe5a5763980b27f2d16e52c8c712309f33efb1bc2fc713fcf75317e32386ebd8f06009e608c4d6e7252612a755b61e22bd", 348 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/Homo_sapiens_assembly38.dict" 349 | }, 350 | { 351 | "@id": "exe/Homo_sapiens_assembly38.fasta.fai", 352 | "@type": "File", 353 | "contentSize": 160928, 354 | "dateModified": "2022-09-14T14:42:07", 355 | "encodingFormat": "text/plain", 356 | "lineCount": 3366, 357 | "sha512": "cfcc85de41b11afddc0013653f9d55c8c0d0e9f20962432ecdbd9445e42fd56601f91eeed1bdc31c257d35ef3a4d81ced720112018310b2db74cbb2730738feb", 358 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/Homo_sapiens_assembly38.fasta.fai" 359 | }, 360 | { 361 | "@id": "exe/Homo_sapiens_assembly38.chrM.dict", 362 | "@type": "File", 363 | "contentSize": 192, 364 | "dateModified": "2022-09-14T14:42:08", 365 | "encodingFormat": "text/plain", 366 | "lineCount": 2, 367 | "sha512": "3ebde8539497cadd164b3ccfe4a5fe54638e5502fea822926d689e7dc52dd403253ff64b886d09a36a6e448105be8707fb34dc37d83c990fc5f61418485ccabf", 368 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.dict" 369 | }, 370 | { 371 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta", 372 | "@type": "File", 373 | "contentSize": 16857, 374 | "dateModified": "2022-09-14T14:42:09", 375 | "encodingFormat": "http://edamontology.org/format_1929", 376 | "lineCount": 167, 377 | "sha512": "25ca84c9bb966248305984b92b16629dd45be8dae3b0269f2c13e20c07583f09efba3f3b67775fc47430f6240a7dca9c08cfff1953b0872bbecf3b6ab4448b91", 378 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.fasta" 379 | }, 380 | { 381 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.fai", 382 | "@type": "File", 383 | "contentSize": 23, 384 | "dateModified": "2022-09-14T14:42:09", 385 | "encodingFormat": "text/plain", 386 | "lineCount": 1, 387 | "sha512": "6e86a5d539d55613c00e36ab6c08f25c365b16e9a31e4de4e70574c6edfdc5ac189c9f3d248cf723dc4e0b316abd1a734af6162a660fa0938b31fbef1ce48802", 388 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.fasta.fai" 389 | }, 390 | { 391 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.amb", 392 | "@type": "File", 393 | "contentSize": 19, 394 | "dateModified": "2022-09-14T14:42:10", 395 | "encodingFormat": "text/plain", 396 | "lineCount": 2, 397 | "sha512": "3af4a499fde6da834e9b1987b8d380c7c2c53d2d5395acf5cea475e7722a4843b2e3c65e3c06bc180677693eb3dd269f047688911bfcd0656012a60a89ad2e01", 398 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.fasta.amb" 399 | }, 400 | { 401 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.ann", 402 | "@type": "File", 403 | "contentSize": 144, 404 | "dateModified": "2022-09-14T14:42:11", 405 | "encodingFormat": "text/plain", 406 | "lineCount": 3, 407 | "sha512": "7dbeb4099ab8027cd3aa3c87b4f31b0926c054c3995191832bb0d9d2426a7db9fd440e3142920b74c6f651db5c86d0bf3f64682f179dfec19e32638accf4e9e1", 408 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.fasta.ann" 409 | }, 410 | { 411 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.bwt", 412 | "@type": "File", 413 | "contentSize": 16648, 414 | "dateModified": "2022-09-14T14:42:11", 415 | "encodingFormat": "application/octet-stream", 416 | "sha512": "98a87aece30d7a5266e391fe8fdbf13158b269bb1f8afce6307076e309bf080821d6208384151eeb5678714743b383fcc161950ca3372493385ff3f1839e3466", 417 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.fasta.bwt" 418 | }, 419 | { 420 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.pac", 421 | "@type": "File", 422 | "contentSize": 4144, 423 | "dateModified": "2022-09-14T14:42:12", 424 | "encodingFormat": "application/octet-stream", 425 | "sha512": "7059335681cf2894ca54e8ed5052928897804834e3b925a8aafd7c35ee8f8523348413e2249c2b6b7bfb90882ada6e713ec66f32cecb52e52ea42b50d7318e93", 426 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.fasta.pac" 427 | }, 428 | { 429 | "@id": "exe/Homo_sapiens_assembly38.chrM.fasta.sa", 430 | "@type": "File", 431 | "contentSize": 8336, 432 | "dateModified": "2022-09-14T14:42:13", 433 | "encodingFormat": "application/octet-stream", 434 | "sha512": "1cfb7ce9ee4968bc98bad8342f1063eb0eaf24b6fbd5f92f899b644b39ce629775ef0a30d4b18e83e32bfb4ca7b724d2fabc89ed7900fed7b06cde137824491c", 435 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.fasta.sa" 436 | }, 437 | { 438 | "@id": "exe/blacklist_sites.hg38.chrM.bed", 439 | "@type": "File", 440 | "contentSize": 132, 441 | "dateModified": "2022-09-14T14:42:14", 442 | "encodingFormat": "http://edamontology.org/format_3003", 443 | "lineCount": 6, 444 | "sha512": "25b8583da9a940ada917897aac821b857244086695a014201985ddf58c1b1ca198b15d134f1e675f3495440b4fef674cb4c0c5575a1f8f9241c292aeabb7216b", 445 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/blacklist_sites.hg38.chrM.bed" 446 | }, 447 | { 448 | "@id": "exe/blacklist_sites.hg38.chrM.bed.idx", 449 | "@type": "File", 450 | "contentSize": 283, 451 | "dateModified": "2022-09-14T14:42:14", 452 | "encodingFormat": "application/octet-stream", 453 | "sha512": "39fffeacd6948b400324eadbe992498bc2d9bff27584f9d8e13020ac970f04245061a76fcb4818404b2916f13a75f454831b9ab83830d9af46e770dc18dee268", 454 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/blacklist_sites.hg38.chrM.bed.idx" 455 | }, 456 | { 457 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.dict", 458 | "@type": "File", 459 | "contentSize": 214, 460 | "dateModified": "2022-09-14T14:42:15", 461 | "encodingFormat": "text/plain", 462 | "lineCount": 2, 463 | "sha512": "090175ae4096bffdf32407ae3a70aae51376fe59ceaae8f73dbc559b82e365894e9e2744622c932768e8c8ac2efc6c2ed1fbec99d98f3ff44d9410988a945a77", 464 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.dict" 465 | }, 466 | { 467 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta", 468 | "@type": "File", 469 | "contentSize": 16857, 470 | "dateModified": "2022-09-14T14:42:16", 471 | "encodingFormat": "http://edamontology.org/format_1929", 472 | "lineCount": 167, 473 | "sha512": "e6728c78cc2976b6c7a2da43f8523738aa2673d9611005b6a879243eeb2015375425a265a845a3a4199275e84dd9c5a74ef77a330c1c1d6446d6579cd43d22ca", 474 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta" 475 | }, 476 | { 477 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.fai", 478 | "@type": "File", 479 | "contentSize": 23, 480 | "dateModified": "2022-09-14T14:42:16", 481 | "encodingFormat": "text/plain", 482 | "lineCount": 1, 483 | "sha512": "6e86a5d539d55613c00e36ab6c08f25c365b16e9a31e4de4e70574c6edfdc5ac189c9f3d248cf723dc4e0b316abd1a734af6162a660fa0938b31fbef1ce48802", 484 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.fai" 485 | }, 486 | { 487 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.amb", 488 | "@type": "File", 489 | "contentSize": 20, 490 | "dateModified": "2022-09-14T14:42:17", 491 | "encodingFormat": "text/plain", 492 | "lineCount": 2, 493 | "sha512": "58cb448da9a3890a1f8f48698fcb8e1bcf23218bfc157a53031ed4b4276d4a8dda4d6f70e8542dd4c5cd7f1db77c8ce09434f3c73bad73436a1b68d22b432d2e", 494 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.amb" 495 | }, 496 | { 497 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.ann", 498 | "@type": "File", 499 | "contentSize": 144, 500 | "dateModified": "2022-09-14T14:42:18", 501 | "encodingFormat": "text/plain", 502 | "lineCount": 3, 503 | "sha512": "7dbeb4099ab8027cd3aa3c87b4f31b0926c054c3995191832bb0d9d2426a7db9fd440e3142920b74c6f651db5c86d0bf3f64682f179dfec19e32638accf4e9e1", 504 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.ann" 505 | }, 506 | { 507 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.bwt", 508 | "@type": "File", 509 | "contentSize": 16648, 510 | "dateModified": "2022-09-14T14:42:18", 511 | "encodingFormat": "application/octet-stream", 512 | "sha512": "c24d422df241a0c477db6882562622531321cf34b153f08f3ba395b82238207e599532aa8b69c36af9a7c3766de33640c2d3b49e50e308c24a76962e51c8fb07", 513 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.bwt" 514 | }, 515 | { 516 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.pac", 517 | "@type": "File", 518 | "contentSize": 4144, 519 | "dateModified": "2022-09-14T14:42:19", 520 | "encodingFormat": "application/octet-stream", 521 | "sha512": "ecee39595da480842b5a10859ba523e3a2dbfcc7fd71c3f9a33ee496f1dd0e79c5dd4e4ff6852e56675bf29e2388ff610adc7feb89fe6c8d97717428b842ce10", 522 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.pac" 523 | }, 524 | { 525 | "@id": "exe/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.sa", 526 | "@type": "File", 527 | "contentSize": 8336, 528 | "dateModified": "2022-09-14T14:42:20", 529 | "encodingFormat": "application/octet-stream", 530 | "sha512": "82218965a7c8ba6462041e83b47adb57a5a696ea5c3b8a5ea770f868432c0c3333aa23c57a326ee147898bd52b94869ff1d8344223817cf515e858f1e181fc3e", 531 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/Homo_sapiens_assembly38.chrM.shifted_by_8000_bases.fasta.sa" 532 | }, 533 | { 534 | "@id": "exe/ShiftBack.chain", 535 | "@type": "File", 536 | "contentSize": 125, 537 | "dateModified": "2022-09-14T14:42:20", 538 | "encodingFormat": "text/plain", 539 | "lineCount": 5, 540 | "sha512": "c640b343088777a965b28c50c41c4c503f10347045852e31af46999efe5055c3d4f5edc1b7ab02b99b607694031228b3dbcaf761b78cccfb5862624176e36a6a", 541 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/ShiftBack.chain" 542 | }, 543 | { 544 | "@id": "exe/control_region_shifted.chrM.interval_list", 545 | "@type": "File", 546 | "contentSize": 233, 547 | "dateModified": "2022-09-14T14:42:21", 548 | "encodingFormat": "text/plain", 549 | "lineCount": 3, 550 | "sha512": "d0f476dbc33b4dceb1bfe786f9163e4b31b5da0b7c8f5984e040895b356586bdb241618690e4d2745874a6257a4ba93a08737ebbed7df163b927f1712911bfca", 551 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/control_region_shifted.chrM.interval_list" 552 | }, 553 | { 554 | "@id": "exe/non_control_region.chrM.interval_list", 555 | "@type": "File", 556 | "contentSize": 211, 557 | "dateModified": "2022-09-14T14:42:22", 558 | "encodingFormat": "text/plain", 559 | "lineCount": 3, 560 | "sha512": "dd8174bed03ef61ed1316a0a8d37b33d95e41509611175e489e7dd21d30ed660d2326431b05a6e1f13aea5a4475661ca47f9d9ae524dff639eb8cfccdd7055af", 561 | "url": "https://storage.googleapis.com/gcp-public-data--broad-references/hg38/v0/chrM/non_control_region.chrM.interval_list" 562 | }, 563 | { 564 | "@id": "stdout.log", 565 | "@type": "File", 566 | "contentSize": 29803, 567 | "dateModified": "2022-09-14T14:44:10", 568 | "encodingFormat": "text/plain", 569 | "lineCount": 280, 570 | "name": "Sapporo stdout", 571 | "sha512": "1a9f9ed0676a036593a05677332c6bced0f94dc367cc0b3521c8142eaae03a12d7e592e3378c3441d6233060f3b1c84dc920b55f916dbd0cff00e17887503b18" 572 | }, 573 | { 574 | "@id": "stderr.log", 575 | "@type": "File", 576 | "contentSize": 69370, 577 | "dateModified": "2022-09-14T14:44:10", 578 | "encodingFormat": "text/plain", 579 | "lineCount": 1111, 580 | "name": "Sapporo stderr", 581 | "sha512": "638b9fb25736d83dc86ef35f9a75e5d649f32ec562e709f45293eaa11505b12535b16dde94e31d72359ecc23ab69952a6e43a41c401e2c4fec65ef26a2113c0a" 582 | } 583 | ] 584 | } -------------------------------------------------------------------------------- /tests/example_crate/jga_mac.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/ro/crate/1.1/context", 4 | "https://w3id.org/ro/terms/sapporo", 5 | "https://w3id.org/ro/terms/workflow-run" 6 | ], 7 | "@graph": [ 8 | { 9 | "@id": "./", 10 | "@type": "Dataset", 11 | "conformsTo": [ 12 | { 13 | "@id": "https://w3id.org/ro/wfrun/process/0.1" 14 | }, 15 | { 16 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1" 17 | }, 18 | { 19 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 20 | } 21 | ], 22 | "datePublished": "2024-01-29T04:23:06+00:00", 23 | "hasPart": [ 24 | { 25 | "@id": "https://gist.githubusercontent.com/suecharo/f9678286cc876c91d8968dfbd7cd4aac/raw/12ebacca526f65fd6e1a9248aa248818ce300ba3/per-sample.packed.cwl" 26 | }, 27 | { 28 | "@id": "exe/autosome-PAR.bed" 29 | }, 30 | { 31 | "@id": "exe/autosome-PAR.interval_list" 32 | }, 33 | { 34 | "@id": "exe/chrX-nonPAR.bed" 35 | }, 36 | { 37 | "@id": "exe/chrX-nonPAR.interval_list" 38 | }, 39 | { 40 | "@id": "exe/chrY-nonPAR.bed" 41 | }, 42 | { 43 | "@id": "exe/chrY-nonPAR.interval_list" 44 | }, 45 | { 46 | "@id": "exe/ERR1347662.small_1.fastq.gz" 47 | }, 48 | { 49 | "@id": "exe/ERR1347662.small_2.fastq.gz" 50 | }, 51 | { 52 | "@id": "exe/Homo_sapiens_assembly38.dbsnp138.vcf" 53 | }, 54 | { 55 | "@id": "exe/Homo_sapiens_assembly38.dbsnp138.vcf.idx" 56 | }, 57 | { 58 | "@id": "exe/Homo_sapiens_assembly38.dict" 59 | }, 60 | { 61 | "@id": "exe/Homo_sapiens_assembly38.fasta" 62 | }, 63 | { 64 | "@id": "exe/Homo_sapiens_assembly38.fasta.alt" 65 | }, 66 | { 67 | "@id": "exe/Homo_sapiens_assembly38.fasta.amb" 68 | }, 69 | { 70 | "@id": "exe/Homo_sapiens_assembly38.fasta.ann" 71 | }, 72 | { 73 | "@id": "exe/Homo_sapiens_assembly38.fasta.bwt" 74 | }, 75 | { 76 | "@id": "exe/Homo_sapiens_assembly38.fasta.fai" 77 | }, 78 | { 79 | "@id": "exe/Homo_sapiens_assembly38.fasta.pac" 80 | }, 81 | { 82 | "@id": "exe/Homo_sapiens_assembly38.fasta.sa" 83 | }, 84 | { 85 | "@id": "exe/Homo_sapiens_assembly38.known_indels.vcf.gz" 86 | }, 87 | { 88 | "@id": "exe/Homo_sapiens_assembly38.known_indels.vcf.gz.tbi" 89 | }, 90 | { 91 | "@id": "exe/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz" 92 | }, 93 | { 94 | "@id": "exe/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi" 95 | }, 96 | { 97 | "@id": "stdout.log" 98 | }, 99 | { 100 | "@id": "stderr.log" 101 | } 102 | ], 103 | "mainEntity": { 104 | "@id": "https://gist.githubusercontent.com/suecharo/f9678286cc876c91d8968dfbd7cd4aac/raw/12ebacca526f65fd6e1a9248aa248818ce300ba3/per-sample.packed.cwl" 105 | }, 106 | "mentions": [ 107 | { 108 | "@id": "#jga_mac" 109 | } 110 | ] 111 | }, 112 | { 113 | "@id": "ro-crate-metadata.json", 114 | "@type": "CreativeWork", 115 | "about": { 116 | "@id": "./" 117 | }, 118 | "conformsTo": [ 119 | { 120 | "@id": "https://w3id.org/ro/crate/1.1" 121 | }, 122 | { 123 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 124 | } 125 | ] 126 | }, 127 | { 128 | "@id": "https://w3id.org/ro/wfrun/process/0.1", 129 | "@type": "CreativeWork", 130 | "name": "Process Run Crate", 131 | "version": "0.1" 132 | }, 133 | { 134 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1", 135 | "@type": "CreativeWork", 136 | "name": "Workflow Run Crate", 137 | "version": "0.1" 138 | }, 139 | { 140 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0", 141 | "@type": "CreativeWork", 142 | "name": "Workflow RO-Crate", 143 | "version": "1.0" 144 | }, 145 | { 146 | "@id": "https://gist.githubusercontent.com/suecharo/f9678286cc876c91d8968dfbd7cd4aac/raw/12ebacca526f65fd6e1a9248aa248818ce300ba3/per-sample.packed.cwl", 147 | "@type": [ 148 | "File", 149 | "SoftwareSourceCode", 150 | "ComputationalWorkflow" 151 | ], 152 | "name": "https://gist.githubusercontent.com/suecharo/f9678286cc876c91d8968dfbd7cd4aac/raw/12ebacca526f65fd6e1a9248aa248818ce300ba3/per-sample.packed", 153 | "programmingLanguage": { 154 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate#cwl" 155 | } 156 | }, 157 | { 158 | "@id": "https://w3id.org/cwl/v1.1/", 159 | "@type": [ 160 | "WebPage" 161 | ] 162 | }, 163 | { 164 | "@id": "https://www.commonwl.org/", 165 | "@type": [ 166 | "WebPage" 167 | ] 168 | }, 169 | { 170 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate#cwl", 171 | "@type": "ComputerLanguage", 172 | "alternateName": "CWL", 173 | "identifier": { 174 | "@id": "https://w3id.org/cwl/v1.1/" 175 | }, 176 | "name": "Common Workflow Language", 177 | "url": { 178 | "@id": "https://www.commonwl.org/" 179 | }, 180 | "version": "1.1" 181 | }, 182 | { 183 | "@id": "#jga_mac", 184 | "@type": "CreateAction", 185 | "actionStatus": "FailedActionStatus", 186 | "endTime": "2022-09-15T10:28:54", 187 | "exitCode": 138, 188 | "instrument": { 189 | "@id": "https://gist.githubusercontent.com/suecharo/f9678286cc876c91d8968dfbd7cd4aac/raw/12ebacca526f65fd6e1a9248aa248818ce300ba3/per-sample.packed.cwl" 190 | }, 191 | "name": "Sapporo workflow run jga_mac", 192 | "object": [ 193 | { 194 | "@id": "exe/autosome-PAR.bed" 195 | }, 196 | { 197 | "@id": "exe/autosome-PAR.interval_list" 198 | }, 199 | { 200 | "@id": "exe/chrX-nonPAR.bed" 201 | }, 202 | { 203 | "@id": "exe/chrX-nonPAR.interval_list" 204 | }, 205 | { 206 | "@id": "exe/chrY-nonPAR.bed" 207 | }, 208 | { 209 | "@id": "exe/chrY-nonPAR.interval_list" 210 | }, 211 | { 212 | "@id": "exe/ERR1347662.small_1.fastq.gz" 213 | }, 214 | { 215 | "@id": "exe/ERR1347662.small_2.fastq.gz" 216 | }, 217 | { 218 | "@id": "exe/Homo_sapiens_assembly38.dbsnp138.vcf" 219 | }, 220 | { 221 | "@id": "exe/Homo_sapiens_assembly38.dbsnp138.vcf.idx" 222 | }, 223 | { 224 | "@id": "exe/Homo_sapiens_assembly38.dict" 225 | }, 226 | { 227 | "@id": "exe/Homo_sapiens_assembly38.fasta" 228 | }, 229 | { 230 | "@id": "exe/Homo_sapiens_assembly38.fasta.alt" 231 | }, 232 | { 233 | "@id": "exe/Homo_sapiens_assembly38.fasta.amb" 234 | }, 235 | { 236 | "@id": "exe/Homo_sapiens_assembly38.fasta.ann" 237 | }, 238 | { 239 | "@id": "exe/Homo_sapiens_assembly38.fasta.bwt" 240 | }, 241 | { 242 | "@id": "exe/Homo_sapiens_assembly38.fasta.fai" 243 | }, 244 | { 245 | "@id": "exe/Homo_sapiens_assembly38.fasta.pac" 246 | }, 247 | { 248 | "@id": "exe/Homo_sapiens_assembly38.fasta.sa" 249 | }, 250 | { 251 | "@id": "exe/Homo_sapiens_assembly38.known_indels.vcf.gz" 252 | }, 253 | { 254 | "@id": "exe/Homo_sapiens_assembly38.known_indels.vcf.gz.tbi" 255 | }, 256 | { 257 | "@id": "exe/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz" 258 | }, 259 | { 260 | "@id": "exe/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi" 261 | } 262 | ], 263 | "startTime": "2022-09-15T06:49:26", 264 | "subjectOf": [ 265 | { 266 | "@id": "stdout.log" 267 | }, 268 | { 269 | "@id": "stderr.log" 270 | } 271 | ], 272 | "wesState": "CANCELED" 273 | }, 274 | { 275 | "@id": "exe/autosome-PAR.bed", 276 | "@type": "File", 277 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/autosome-PAR.bed" 278 | }, 279 | { 280 | "@id": "exe/autosome-PAR.interval_list", 281 | "@type": "File", 282 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/autosome-PAR.interval_list" 283 | }, 284 | { 285 | "@id": "exe/chrX-nonPAR.bed", 286 | "@type": "File", 287 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/chrX-nonPAR.bed" 288 | }, 289 | { 290 | "@id": "exe/chrX-nonPAR.interval_list", 291 | "@type": "File", 292 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/chrX-nonPAR.interval_list" 293 | }, 294 | { 295 | "@id": "exe/chrY-nonPAR.bed", 296 | "@type": "File", 297 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/chrY-nonPAR.bed" 298 | }, 299 | { 300 | "@id": "exe/chrY-nonPAR.interval_list", 301 | "@type": "File", 302 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/chrY-nonPAR.interval_list" 303 | }, 304 | { 305 | "@id": "exe/ERR1347662.small_1.fastq.gz", 306 | "@type": "File", 307 | "contentSize": 767112, 308 | "dateModified": "2022-09-10T17:15:19", 309 | "encodingFormat": "http://edamontology.org/format_1930", 310 | "sha512": "5f757898c4b183d02e996cf179311ae58b716a9b2d9ff63101b4111931bd04efcf7230ac11b39700a3f3ac6a9f06a985330fd60a02bd6b4d4c1179039dfa5508", 311 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/ERR1347662.small_1.fastq.gz" 312 | }, 313 | { 314 | "@id": "exe/ERR1347662.small_2.fastq.gz", 315 | "@type": "File", 316 | "contentSize": 746812, 317 | "dateModified": "2022-09-10T17:15:23", 318 | "encodingFormat": "http://edamontology.org/format_1930", 319 | "sha512": "4e6b7247f6adf98a8639b81d0a137eb906904a4a0f584ce66e168ea1594779bb607d40b3b9d1c3337b90775166b39d0132d2d0e2acbbdd498e43f97c18417da6", 320 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/ERR1347662.small_2.fastq.gz" 321 | }, 322 | { 323 | "@id": "exe/Homo_sapiens_assembly38.dbsnp138.vcf", 324 | "@type": "File", 325 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.dbsnp138.vcf" 326 | }, 327 | { 328 | "@id": "exe/Homo_sapiens_assembly38.dbsnp138.vcf.idx", 329 | "@type": "File", 330 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.dbsnp138.vcf.idx" 331 | }, 332 | { 333 | "@id": "exe/Homo_sapiens_assembly38.dict", 334 | "@type": "File", 335 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.dict" 336 | }, 337 | { 338 | "@id": "exe/Homo_sapiens_assembly38.fasta", 339 | "@type": "File", 340 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta" 341 | }, 342 | { 343 | "@id": "exe/Homo_sapiens_assembly38.fasta.alt", 344 | "@type": "File", 345 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta.alt" 346 | }, 347 | { 348 | "@id": "exe/Homo_sapiens_assembly38.fasta.amb", 349 | "@type": "File", 350 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta.amb" 351 | }, 352 | { 353 | "@id": "exe/Homo_sapiens_assembly38.fasta.ann", 354 | "@type": "File", 355 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta.ann" 356 | }, 357 | { 358 | "@id": "exe/Homo_sapiens_assembly38.fasta.bwt", 359 | "@type": "File", 360 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta.bwt" 361 | }, 362 | { 363 | "@id": "exe/Homo_sapiens_assembly38.fasta.fai", 364 | "@type": "File", 365 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta.fai" 366 | }, 367 | { 368 | "@id": "exe/Homo_sapiens_assembly38.fasta.pac", 369 | "@type": "File", 370 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta.pac" 371 | }, 372 | { 373 | "@id": "exe/Homo_sapiens_assembly38.fasta.sa", 374 | "@type": "File", 375 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.fasta.sa" 376 | }, 377 | { 378 | "@id": "exe/Homo_sapiens_assembly38.known_indels.vcf.gz", 379 | "@type": "File", 380 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.known_indels.vcf.gz" 381 | }, 382 | { 383 | "@id": "exe/Homo_sapiens_assembly38.known_indels.vcf.gz.tbi", 384 | "@type": "File", 385 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Homo_sapiens_assembly38.known_indels.vcf.gz.tbi" 386 | }, 387 | { 388 | "@id": "exe/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz", 389 | "@type": "File", 390 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz" 391 | }, 392 | { 393 | "@id": "exe/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi", 394 | "@type": "File", 395 | "url": "https://zenodo.org/api/files/caab5cda-485e-4238-b532-6452b06d4c88/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi" 396 | }, 397 | { 398 | "@id": "stdout.log", 399 | "@type": "File", 400 | "contentSize": 2275, 401 | "dateModified": "2022-09-15T19:28:52", 402 | "encodingFormat": "application/json", 403 | "lineCount": 45, 404 | "name": "Sapporo stdout", 405 | "sha512": "49715f33649628332bfbb450883bb349f69bb50c8ff707bac66606ed65f338f8dddb16fa916fab0ca91a65931410d31928d041b69bb3e71eaca791a9ce43aa2d", 406 | "text": "{\n \"bcftools_stats\": null,\n \"bcftools_stats_log\": null,\n \"bgzip_log\": null,\n \"bqsr_log\": null,\n \"crai_log\": null,\n \"cram\": null,\n \"cram_log\": null,\n \"haplotypecaller_autosome_PAR_ploidy_2_vcf_gz\": null,\n \"haplotypecaller_autosome_PAR_ploidy_2_wgs_metrics\": null,\n \"haplotypecaller_autosome_PAR_ploidy_2_wgs_metrics_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_bcftools_stats\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_bcftools_stats_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_bgzip_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_haplotypecaller_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_tabix_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_vcf_gz\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_wgs_metrics\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_1_wgs_metrics_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_bcftools_stats\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_bcftools_stats_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_bgzip_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_haplotypecaller_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_tabix_log\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_vcf_gz\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_wgs_metrics\": null,\n \"haplotypecaller_chrX_nonPAR_ploidy_2_wgs_metrics_log\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_bcftools_stats\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_bcftools_stats_log\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_bgzip_log\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_haplotypecaller_log\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_tabix_log\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_vcf_gz\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_wgs_metrics\": null,\n \"haplotypecaller_chrY_nonPAR_ploidy_1_wgs_metrics_log\": null,\n \"haplotypecaller_log\": null,\n \"markdup_log\": null,\n \"markdup_metrics\": null,\n \"picard-CollectBaseDistributionByCycle-chart-pdf\": null,\n \"picard-CollectBaseDistributionByCycle-chart-png\": null,\n \"picard-CollectBaseDistributionByCycle-collect_base_dist_by_cycle\": null,\n \"samtools_flagstat_flagstat\": null,\n \"samtools_idxstats_idxstats\": null,\n \"tabix_log\": null\n}\n" 407 | }, 408 | { 409 | "@id": "stderr.log", 410 | "@type": "File", 411 | "contentSize": 15165, 412 | "dateModified": "2022-09-15T19:28:52", 413 | "encodingFormat": "text/plain", 414 | "lineCount": 153, 415 | "name": "Sapporo stderr", 416 | "sha512": "81fa52a591b496f2c16f8f8224f9a9747f37fd79806bdc6387092c23b05a92e3a060dee4fe2c36e06ee4f0b2dae34b2438d24a879915ca533662f72736c05bca" 417 | } 418 | ] 419 | } -------------------------------------------------------------------------------- /tests/example_crate/trimming.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/ro/crate/1.1/context", 4 | "https://w3id.org/ro/terms/sapporo", 5 | "https://w3id.org/ro/terms/workflow-run" 6 | ], 7 | "@graph": [ 8 | { 9 | "@id": "./", 10 | "@type": "Dataset", 11 | "conformsTo": [ 12 | { 13 | "@id": "https://w3id.org/ro/wfrun/process/0.1" 14 | }, 15 | { 16 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1" 17 | }, 18 | { 19 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 20 | } 21 | ], 22 | "datePublished": "2024-01-29T04:25:59+00:00", 23 | "hasPart": [ 24 | { 25 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl" 26 | }, 27 | { 28 | "@id": "exe/fastqc.cwl" 29 | }, 30 | { 31 | "@id": "exe/trimmomatic_pe.cwl" 32 | }, 33 | { 34 | "@id": "exe/ERR034597_1.small.fq.gz" 35 | }, 36 | { 37 | "@id": "exe/ERR034597_2.small.fq.gz" 38 | }, 39 | { 40 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2P.fq" 41 | }, 42 | { 43 | "@id": "outputs/ERR034597_1.small_fastqc.html" 44 | }, 45 | { 46 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1P.fq" 47 | }, 48 | { 49 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1U.fq" 50 | }, 51 | { 52 | "@id": "outputs/ERR034597_2.small_fastqc.html" 53 | }, 54 | { 55 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2U.fq" 56 | }, 57 | { 58 | "@id": "stdout.log" 59 | }, 60 | { 61 | "@id": "stderr.log" 62 | } 63 | ], 64 | "mainEntity": { 65 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl" 66 | }, 67 | "mentions": [ 68 | { 69 | "@id": "#trimming" 70 | } 71 | ] 72 | }, 73 | { 74 | "@id": "ro-crate-metadata.json", 75 | "@type": "CreativeWork", 76 | "about": { 77 | "@id": "./" 78 | }, 79 | "conformsTo": [ 80 | { 81 | "@id": "https://w3id.org/ro/crate/1.1" 82 | }, 83 | { 84 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 85 | } 86 | ] 87 | }, 88 | { 89 | "@id": "https://w3id.org/ro/wfrun/process/0.1", 90 | "@type": "CreativeWork", 91 | "name": "Process Run Crate", 92 | "version": "0.1" 93 | }, 94 | { 95 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1", 96 | "@type": "CreativeWork", 97 | "name": "Workflow Run Crate", 98 | "version": "0.1" 99 | }, 100 | { 101 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0", 102 | "@type": "CreativeWork", 103 | "name": "Workflow RO-Crate", 104 | "version": "1.0" 105 | }, 106 | { 107 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl", 108 | "@type": [ 109 | "File", 110 | "SoftwareSourceCode", 111 | "ComputationalWorkflow" 112 | ], 113 | "name": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc", 114 | "programmingLanguage": { 115 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate#cwl" 116 | } 117 | }, 118 | { 119 | "@id": "https://w3id.org/cwl/v1.0/", 120 | "@type": [ 121 | "WebPage" 122 | ] 123 | }, 124 | { 125 | "@id": "https://www.commonwl.org/", 126 | "@type": [ 127 | "WebPage" 128 | ] 129 | }, 130 | { 131 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate#cwl", 132 | "@type": "ComputerLanguage", 133 | "alternateName": "CWL", 134 | "identifier": { 135 | "@id": "https://w3id.org/cwl/v1.0/" 136 | }, 137 | "name": "Common Workflow Language", 138 | "url": { 139 | "@id": "https://www.commonwl.org/" 140 | }, 141 | "version": "1.0" 142 | }, 143 | { 144 | "@id": "#trimming", 145 | "@type": "CreateAction", 146 | "actionStatus": "CompletedActionStatus", 147 | "endTime": "2022-09-12T06:13:50", 148 | "exitCode": 0, 149 | "instrument": { 150 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl" 151 | }, 152 | "name": "Sapporo workflow run trimming", 153 | "object": [ 154 | { 155 | "@id": "exe/fastqc.cwl" 156 | }, 157 | { 158 | "@id": "exe/trimmomatic_pe.cwl" 159 | }, 160 | { 161 | "@id": "exe/ERR034597_1.small.fq.gz" 162 | }, 163 | { 164 | "@id": "exe/ERR034597_2.small.fq.gz" 165 | } 166 | ], 167 | "result": [ 168 | { 169 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2P.fq" 170 | }, 171 | { 172 | "@id": "outputs/ERR034597_1.small_fastqc.html" 173 | }, 174 | { 175 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1P.fq" 176 | }, 177 | { 178 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1U.fq" 179 | }, 180 | { 181 | "@id": "outputs/ERR034597_2.small_fastqc.html" 182 | }, 183 | { 184 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2U.fq" 185 | } 186 | ], 187 | "startTime": "2022-09-12T06:13:09", 188 | "subjectOf": [ 189 | { 190 | "@id": "stdout.log" 191 | }, 192 | { 193 | "@id": "stderr.log" 194 | } 195 | ], 196 | "wesState": "COMPLETE" 197 | }, 198 | { 199 | "@id": "exe/fastqc.cwl", 200 | "@type": "File", 201 | "contentSize": 577, 202 | "dateModified": "2022-09-12T15:13:06", 203 | "encodingFormat": "text/plain", 204 | "lineCount": 33, 205 | "sha512": "af6d23d05f8b42739feb4db4f3222e0201f7186953a4200bc3a72668589db672d738f27275eb5298cd2d4a1f5f3aa854f5f56a8561f5a8217a7f1c9663627b95", 206 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/fastqc.cwl" 207 | }, 208 | { 209 | "@id": "exe/trimmomatic_pe.cwl", 210 | "@type": "File", 211 | "contentSize": 1570, 212 | "dateModified": "2022-09-12T15:13:07", 213 | "encodingFormat": "text/plain", 214 | "lineCount": 66, 215 | "sha512": "cc384f32389e588706860139d843194bef48d53081183f12fc3ed32d3bc56bfca868c2965d5e9dd4e50a66e913b7b3afc0e0f9766353a14ad87f3b4a33b2ed2e", 216 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimmomatic_pe.cwl" 217 | }, 218 | { 219 | "@id": "exe/ERR034597_1.small.fq.gz", 220 | "@type": "File", 221 | "contentSize": 1926244, 222 | "dateModified": "2022-09-12T15:13:08", 223 | "encodingFormat": "http://edamontology.org/format_1930", 224 | "sha512": "9cbc3dd0207944975b4e603e9e145c109bd6e698eb4c07061ea7c00c371e7c7a280c2d290447f793d9f9f6073821b617b8c875273443b2fed98e827ad083ca04", 225 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/test/ERR034597_1.small.fq.gz" 226 | }, 227 | { 228 | "@id": "exe/ERR034597_2.small.fq.gz", 229 | "@type": "File", 230 | "contentSize": 1888012, 231 | "dateModified": "2022-09-12T15:13:09", 232 | "encodingFormat": "http://edamontology.org/format_1930", 233 | "sha512": "aacec4c9461ad93b1f2737cf75cc5c207faabd1fe9bcedf9c36082fe2a8d12e623647f00009c0907eac7e7e23c38d57fee25d3c5ae4facc1d06884e39d0499c1", 234 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/test/ERR034597_2.small.fq.gz" 235 | }, 236 | { 237 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2P.fq", 238 | "@type": "File", 239 | "contentSize": 5560582, 240 | "dateModified": "2022-09-12T15:13:43", 241 | "encodingFormat": "http://edamontology.org/format_1930", 242 | "lineCount": 94556, 243 | "sha512": "908eccc73c48bb1ae1accd0ff91aaf13f41a6340288357199da3944f2801a94935dd314c3c8877bed7959ba77d3c88b2c0b58f937f77b9ba6167c103a85a027a", 244 | "url": "http://localhost:1122/runs/f961dd4c-5933-4a6a-b043-bbf03157fc9b/data/outputs/ERR034597_1.small.fq.trimmed.2P.fq" 245 | }, 246 | { 247 | "@id": "outputs/ERR034597_1.small_fastqc.html", 248 | "@type": "File", 249 | "contentSize": 592394, 250 | "dateModified": "2022-09-12T15:13:48", 251 | "encodingFormat": "text/html", 252 | "lineCount": 186, 253 | "sha512": "fa6592df941275ec9d80bf610b78d034ee7c42741b5ae92d31e7cf17f5a2c6cbcd19e7460650bcff6fcfe77459ed505c95b99d1d62fcf5c6baa3f3a6fdad588c", 254 | "url": "http://localhost:1122/runs/f961dd4c-5933-4a6a-b043-bbf03157fc9b/data/outputs/ERR034597_1.small_fastqc.html" 255 | }, 256 | { 257 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1P.fq", 258 | "@type": "File", 259 | "contentSize": 5566650, 260 | "dateModified": "2022-09-12T15:13:43", 261 | "encodingFormat": "http://edamontology.org/format_1930", 262 | "lineCount": 94556, 263 | "sha512": "b5d5b088550ef1cd1b8d1760d6e7bc93fe1500cded15df196e5173e7b5e2732b0a63ccb3dcc535c1991ad95faaf81eda5e61958d0ef42a561d1daa2fae5858b6", 264 | "url": "http://localhost:1122/runs/f961dd4c-5933-4a6a-b043-bbf03157fc9b/data/outputs/ERR034597_1.small.fq.trimmed.1P.fq" 265 | }, 266 | { 267 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1U.fq", 268 | "@type": "File", 269 | "contentSize": 187289, 270 | "dateModified": "2022-09-12T15:13:43", 271 | "encodingFormat": "http://edamontology.org/format_1930", 272 | "lineCount": 3424, 273 | "sha512": "dba779dbc2280232dcc64c3aee9dca5ad56508d13a9905e986d0b30c04ff2eb14a7dabc3055cf8a02a1805dad6daa736d98e1df89385847e1884a3ea80bf8b23", 274 | "url": "http://localhost:1122/runs/f961dd4c-5933-4a6a-b043-bbf03157fc9b/data/outputs/ERR034597_1.small.fq.trimmed.1U.fq" 275 | }, 276 | { 277 | "@id": "outputs/ERR034597_2.small_fastqc.html", 278 | "@type": "File", 279 | "contentSize": 592566, 280 | "dateModified": "2022-09-12T15:13:38", 281 | "encodingFormat": "text/html", 282 | "lineCount": 186, 283 | "sha512": "f7d6b0334629255f3de854ad3e2b518f17f090349bfac5473dfefacd56a3d02041cce69e3747488ec3ad90548e2486906b8251e1bdc023e0e197311eb576df92", 284 | "url": "http://localhost:1122/runs/f961dd4c-5933-4a6a-b043-bbf03157fc9b/data/outputs/ERR034597_2.small_fastqc.html" 285 | }, 286 | { 287 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2U.fq", 288 | "@type": "File", 289 | "contentSize": 80131, 290 | "dateModified": "2022-09-12T15:13:43", 291 | "encodingFormat": "http://edamontology.org/format_1930", 292 | "lineCount": 1468, 293 | "sha512": "ff2ac389f7a48bd87576c27935c436899dd9ad4929d8b0a3e85fd4ca711dcb17c6b323b1be3d68ff8353e94b83be14637081a66eccb27daa69b95fba5b5eaf63", 294 | "url": "http://localhost:1122/runs/f961dd4c-5933-4a6a-b043-bbf03157fc9b/data/outputs/ERR034597_1.small.fq.trimmed.2U.fq" 295 | }, 296 | { 297 | "@id": "stdout.log", 298 | "@type": "File", 299 | "contentSize": 3242, 300 | "dateModified": "2022-09-12T15:13:49", 301 | "encodingFormat": "application/json", 302 | "lineCount": 50, 303 | "name": "Sapporo stdout", 304 | "sha512": "6bb738a8545e058c664c3e6925158da4162554a92c6b608f743a997bb46b423676535e9802ff7e4eae88dae62c12d275c2dc77c197fbf840cc4a1ff56897a8e3", 305 | "text": "{\n \"qc_result_1\": {\n \"location\": \"file:///home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small_fastqc.html\",\n \"basename\": \"ERR034597_1.small_fastqc.html\",\n \"class\": \"File\",\n \"checksum\": \"sha1$f48216814a28ddee7bafd6621afff07edef7bf6f\",\n \"size\": 592394,\n \"path\": \"/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small_fastqc.html\"\n },\n \"qc_result_2\": {\n \"location\": \"file:///home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_2.small_fastqc.html\",\n \"basename\": \"ERR034597_2.small_fastqc.html\",\n \"class\": \"File\",\n \"checksum\": \"sha1$8d82da82561921fcdbddff906280c3ddf9b93f60\",\n \"size\": 592566,\n \"path\": \"/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_2.small_fastqc.html\"\n },\n \"trimmed_fastq1P\": {\n \"location\": \"file:///home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.1P.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.1P.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$5188cdb59cab8010eb673e8bc113b7fd7a686660\",\n \"size\": 5566650,\n \"path\": \"/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.1P.fq\"\n },\n \"trimmed_fastq1U\": {\n \"location\": \"file:///home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.1U.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.1U.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$be4d3444537d2596d122db1ca8e5955954094f6b\",\n \"size\": 187289,\n \"path\": \"/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.1U.fq\"\n },\n \"trimmed_fastq2P\": {\n \"location\": \"file:///home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.2P.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.2P.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$cd1451093c91a9b619337a7bfbe592ad76554745\",\n \"size\": 5560582,\n \"path\": \"/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.2P.fq\"\n },\n \"trimmed_fastq2U\": {\n \"location\": \"file:///home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.2U.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.2U.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$dd7edf1b2d599eb3c8fa49426be55d8a0360561c\",\n \"size\": 80131,\n \"path\": \"/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/outputs/ERR034597_1.small.fq.trimmed.2U.fq\"\n }\n}\n" 306 | }, 307 | { 308 | "@id": "stderr.log", 309 | "@type": "File", 310 | "contentSize": 4216, 311 | "dateModified": "2022-09-12T15:13:50", 312 | "encodingFormat": "text/plain", 313 | "lineCount": 89, 314 | "name": "Sapporo stderr", 315 | "sha512": "3019e8052340e0afde96cb4fd72bef007f2e9da54d6c55cb85698ad2b00a346efa2e587a1247d4928c4172fa7a6af9efb5ce964fb65439390603234451bba075", 316 | "text": "jq: error (at /home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/run_request.json:10): null (null) only strings can be parsed\nb qc_2] /tmp/odj_asjx$ docker \\\n run \\\n -i \\\n --mount=type=bind,source=/tmp/odj_asjx,target=/ZplaYq \\\n --mount=type=bind,source=/tmp/aijhw610,target=/tmp \\\n --mount=type=bind,source=/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/exe/ERR034597_2.small.fq.gz,target=/var/lib/cwl/stg142c1e5b-b91e-4936-b1c1-197344a730ee/ERR034597_2.small.fq.gz,readonly \\\n --workdir=/ZplaYq \\\n --read-only=true \\\n --log-driver=none \\\n --user=0:0 \\\n --rm \\\n --cidfile=/tmp/8r_h46tw/20220912061330-983392.cid \\\n --env=TMPDIR=/tmp \\\n --env=HOME=/ZplaYq \\\n quay.io/biocontainers/fastqc:0.11.9--0 \\\n fastqc \\\n -o \\\n . \\\n --threads \\\n 2 \\\n /var/lib/cwl/stg142c1e5b-b91e-4936-b1c1-197344a730ee/ERR034597_2.small.fq.gz > /tmp/odj_asjx/fastqc-stdout.log 2> /tmp/odj_asjx/fastqc-stderr.log\n\u001b[1;30mINFO\u001b[0m [job qc_2] Max memory used: 144MiB\n\u001b[1;30mINFO\u001b[0m [job qc_2] completed success\n\u001b[1;30mINFO\u001b[0m [step qc_2] completed success\n\u001b[1;30mINFO\u001b[0m [workflow ] starting step trimming\n\u001b[1;30mINFO\u001b[0m [step trimming] start\n\u001b[1;30mINFO\u001b[0m [job trimming] /tmp/tem8s58c$ docker \\\n run \\\n -i \\\n --mount=type=bind,source=/tmp/tem8s58c,target=/ZplaYq \\\n --mount=type=bind,source=/tmp/7u4ml8x3,target=/tmp \\\n --mount=type=bind,source=/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/exe/ERR034597_1.small.fq.gz,target=/var/lib/cwl/stgda735211-23c6-4134-898c-39199f149921/ERR034597_1.small.fq.gz,readonly \\\n --mount=type=bind,source=/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/exe/ERR034597_2.small.fq.gz,target=/var/lib/cwl/stgb93f3246-cd76-4f47-8315-acbf7151f2c4/ERR034597_2.small.fq.gz,readonly \\\n --workdir=/ZplaYq \\\n --read-only=true \\\n --log-driver=none \\\n --user=0:0 \\\n --rm \\\n --cidfile=/tmp/f2p6cfq5/20220912061339-696100.cid \\\n --env=TMPDIR=/tmp \\\n --env=HOME=/ZplaYq \\\n quay.io/biocontainers/trimmomatic:0.38--1 \\\n trimmomatic \\\n PE \\\n -threads \\\n 2 \\\n /var/lib/cwl/stgda735211-23c6-4134-898c-39199f149921/ERR034597_1.small.fq.gz \\\n /var/lib/cwl/stgb93f3246-cd76-4f47-8315-acbf7151f2c4/ERR034597_2.small.fq.gz \\\n ERR034597_1.small.fq.trimmed.1P.fq \\\n ERR034597_1.small.fq.trimmed.1U.fq \\\n ERR034597_1.small.fq.trimmed.2P.fq \\\n ERR034597_1.small.fq.trimmed.2U.fq \\\n ILLUMINACLIP:/usr/local/share/trimmomatic/adapters/TruSeq2-PE.fa:2:40:15 \\\n LEADING:20 \\\n TRAILING:20 \\\n SLIDINGWINDOW:4:15 \\\n MINLEN:36 > /tmp/tem8s58c/trimmomatic-pe-stdout.log 2> /tmp/tem8s58c/trimmomatic-pe-stderr.log\n\u001b[1;30mINFO\u001b[0m [job trimming] Max memory used: 88MiB\n\u001b[1;30mINFO\u001b[0m [job trimming] completed success\n\u001b[1;30mINFO\u001b[0m [step trimming] completed success\n\u001b[1;30mINFO\u001b[0m [workflow ] starting step qc_1\n\u001b[1;30mINFO\u001b[0m [step qc_1] start\n\u001b[1;30mINFO\u001b[0m [job qc_1] /tmp/9s6pjszw$ docker \\\n run \\\n -i \\\n --mount=type=bind,source=/tmp/9s6pjszw,target=/ZplaYq \\\n --mount=type=bind,source=/tmp/rccp7i0n,target=/tmp \\\n --mount=type=bind,source=/home/ubuntu/git/github.com/sapporo-wes/yevis-cli/sapporo-run/f9/f961dd4c-5933-4a6a-b043-bbf03157fc9b/exe/ERR034597_1.small.fq.gz,target=/var/lib/cwl/stg1a213db7-41e8-4126-9aab-cb282291688e/ERR034597_1.small.fq.gz,readonly \\\n --workdir=/ZplaYq \\\n --read-only=true \\\n --log-driver=none \\\n --user=0:0 \\\n --rm \\\n --cidfile=/tmp/j6ith35c/20220912061344-112864.cid \\\n --env=TMPDIR=/tmp \\\n --env=HOME=/ZplaYq \\\n quay.io/biocontainers/fastqc:0.11.9--0 \\\n fastqc \\\n -o \\\n . \\\n --threads \\\n 2 \\\n /var/lib/cwl/stg1a213db7-41e8-4126-9aab-cb282291688e/ERR034597_1.small.fq.gz > /tmp/9s6pjszw/fastqc-stdout.log 2> /tmp/9s6pjszw/fastqc-stderr.log\n\u001b[1;30mINFO\u001b[0m [job qc_1] Max memory used: 134MiB\n\u001b[1;30mINFO\u001b[0m [job qc_1] completed success\n\u001b[1;30mINFO\u001b[0m [step qc_1] completed success\n\u001b[1;30mINFO\u001b[0m [workflow ] completed success\n\u001b[1;30mINFO\u001b[0m Final process status is success\n" 317 | } 318 | ] 319 | } -------------------------------------------------------------------------------- /tests/example_crate/trimming_mac.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | "https://w3id.org/ro/crate/1.1/context", 4 | "https://w3id.org/ro/terms/sapporo", 5 | "https://w3id.org/ro/terms/workflow-run" 6 | ], 7 | "@graph": [ 8 | { 9 | "@id": "./", 10 | "@type": "Dataset", 11 | "conformsTo": [ 12 | { 13 | "@id": "https://w3id.org/ro/wfrun/process/0.1" 14 | }, 15 | { 16 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1" 17 | }, 18 | { 19 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 20 | } 21 | ], 22 | "datePublished": "2024-01-29T04:25:57+00:00", 23 | "hasPart": [ 24 | { 25 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl" 26 | }, 27 | { 28 | "@id": "exe/fastqc.cwl" 29 | }, 30 | { 31 | "@id": "exe/trimmomatic_pe.cwl" 32 | }, 33 | { 34 | "@id": "exe/ERR034597_1.small.fq.gz" 35 | }, 36 | { 37 | "@id": "exe/ERR034597_2.small.fq.gz" 38 | }, 39 | { 40 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2P.fq" 41 | }, 42 | { 43 | "@id": "outputs/ERR034597_1.small_fastqc.html" 44 | }, 45 | { 46 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1P.fq" 47 | }, 48 | { 49 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1U.fq" 50 | }, 51 | { 52 | "@id": "outputs/ERR034597_2.small_fastqc.html" 53 | }, 54 | { 55 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2U.fq" 56 | }, 57 | { 58 | "@id": "stdout.log" 59 | }, 60 | { 61 | "@id": "stderr.log" 62 | } 63 | ], 64 | "mainEntity": { 65 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl" 66 | }, 67 | "mentions": [ 68 | { 69 | "@id": "#trimming_mac" 70 | } 71 | ] 72 | }, 73 | { 74 | "@id": "ro-crate-metadata.json", 75 | "@type": "CreativeWork", 76 | "about": { 77 | "@id": "./" 78 | }, 79 | "conformsTo": [ 80 | { 81 | "@id": "https://w3id.org/ro/crate/1.1" 82 | }, 83 | { 84 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" 85 | } 86 | ] 87 | }, 88 | { 89 | "@id": "https://w3id.org/ro/wfrun/process/0.1", 90 | "@type": "CreativeWork", 91 | "name": "Process Run Crate", 92 | "version": "0.1" 93 | }, 94 | { 95 | "@id": "https://w3id.org/ro/wfrun/workflow/0.1", 96 | "@type": "CreativeWork", 97 | "name": "Workflow Run Crate", 98 | "version": "0.1" 99 | }, 100 | { 101 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0", 102 | "@type": "CreativeWork", 103 | "name": "Workflow RO-Crate", 104 | "version": "1.0" 105 | }, 106 | { 107 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl", 108 | "@type": [ 109 | "File", 110 | "SoftwareSourceCode", 111 | "ComputationalWorkflow" 112 | ], 113 | "name": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc", 114 | "programmingLanguage": { 115 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate#cwl" 116 | } 117 | }, 118 | { 119 | "@id": "https://w3id.org/cwl/v1.0/", 120 | "@type": [ 121 | "WebPage" 122 | ] 123 | }, 124 | { 125 | "@id": "https://www.commonwl.org/", 126 | "@type": [ 127 | "WebPage" 128 | ] 129 | }, 130 | { 131 | "@id": "https://w3id.org/workflowhub/workflow-ro-crate#cwl", 132 | "@type": "ComputerLanguage", 133 | "alternateName": "CWL", 134 | "identifier": { 135 | "@id": "https://w3id.org/cwl/v1.0/" 136 | }, 137 | "name": "Common Workflow Language", 138 | "url": { 139 | "@id": "https://www.commonwl.org/" 140 | }, 141 | "version": "1.0" 142 | }, 143 | { 144 | "@id": "#trimming_mac", 145 | "@type": "CreateAction", 146 | "actionStatus": "CompletedActionStatus", 147 | "endTime": "2022-09-14T05:30:14", 148 | "exitCode": 0, 149 | "instrument": { 150 | "@id": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimming_and_qc.cwl" 151 | }, 152 | "name": "Sapporo workflow run trimming_mac", 153 | "object": [ 154 | { 155 | "@id": "exe/fastqc.cwl" 156 | }, 157 | { 158 | "@id": "exe/trimmomatic_pe.cwl" 159 | }, 160 | { 161 | "@id": "exe/ERR034597_1.small.fq.gz" 162 | }, 163 | { 164 | "@id": "exe/ERR034597_2.small.fq.gz" 165 | } 166 | ], 167 | "result": [ 168 | { 169 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2P.fq" 170 | }, 171 | { 172 | "@id": "outputs/ERR034597_1.small_fastqc.html" 173 | }, 174 | { 175 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1P.fq" 176 | }, 177 | { 178 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1U.fq" 179 | }, 180 | { 181 | "@id": "outputs/ERR034597_2.small_fastqc.html" 182 | }, 183 | { 184 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2U.fq" 185 | } 186 | ], 187 | "startTime": "2022-09-14T05:28:55", 188 | "subjectOf": [ 189 | { 190 | "@id": "stdout.log" 191 | }, 192 | { 193 | "@id": "stderr.log" 194 | } 195 | ], 196 | "wesState": "COMPLETE" 197 | }, 198 | { 199 | "@id": "exe/fastqc.cwl", 200 | "@type": "File", 201 | "contentSize": 577, 202 | "dateModified": "2022-09-14T14:28:53", 203 | "encodingFormat": "text/plain", 204 | "lineCount": 33, 205 | "sha512": "af6d23d05f8b42739feb4db4f3222e0201f7186953a4200bc3a72668589db672d738f27275eb5298cd2d4a1f5f3aa854f5f56a8561f5a8217a7f1c9663627b95", 206 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/fastqc.cwl" 207 | }, 208 | { 209 | "@id": "exe/trimmomatic_pe.cwl", 210 | "@type": "File", 211 | "contentSize": 1570, 212 | "dateModified": "2022-09-14T14:28:53", 213 | "encodingFormat": "text/plain", 214 | "lineCount": 66, 215 | "sha512": "cc384f32389e588706860139d843194bef48d53081183f12fc3ed32d3bc56bfca868c2965d5e9dd4e50a66e913b7b3afc0e0f9766353a14ad87f3b4a33b2ed2e", 216 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/wf/trimmomatic_pe.cwl" 217 | }, 218 | { 219 | "@id": "exe/ERR034597_1.small.fq.gz", 220 | "@type": "File", 221 | "contentSize": 1926244, 222 | "dateModified": "2022-09-14T14:28:54", 223 | "encodingFormat": "http://edamontology.org/format_1930", 224 | "sha512": "9cbc3dd0207944975b4e603e9e145c109bd6e698eb4c07061ea7c00c371e7c7a280c2d290447f793d9f9f6073821b617b8c875273443b2fed98e827ad083ca04", 225 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/test/ERR034597_1.small.fq.gz" 226 | }, 227 | { 228 | "@id": "exe/ERR034597_2.small.fq.gz", 229 | "@type": "File", 230 | "contentSize": 1888012, 231 | "dateModified": "2022-09-14T14:28:55", 232 | "encodingFormat": "http://edamontology.org/format_1930", 233 | "sha512": "aacec4c9461ad93b1f2737cf75cc5c207faabd1fe9bcedf9c36082fe2a8d12e623647f00009c0907eac7e7e23c38d57fee25d3c5ae4facc1d06884e39d0499c1", 234 | "url": "https://raw.githubusercontent.com/sapporo-wes/yevis-cli/8d3275b4126700fcd4eb1a4e377409d3f1d15d26/tests/CWL/test/ERR034597_2.small.fq.gz" 235 | }, 236 | { 237 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2P.fq", 238 | "@type": "File", 239 | "contentSize": 5560582, 240 | "dateModified": "2022-09-14T14:29:56", 241 | "encodingFormat": "http://edamontology.org/format_1930", 242 | "lineCount": 94556, 243 | "sha512": "908eccc73c48bb1ae1accd0ff91aaf13f41a6340288357199da3944f2801a94935dd314c3c8877bed7959ba77d3c88b2c0b58f937f77b9ba6167c103a85a027a", 244 | "url": "http://localhost:2000/runs/d3c7e943-4b41-4fdc-a224-e227f5e518a0/data/outputs/ERR034597_1.small.fq.trimmed.2P.fq" 245 | }, 246 | { 247 | "@id": "outputs/ERR034597_1.small_fastqc.html", 248 | "@type": "File", 249 | "contentSize": 592394, 250 | "dateModified": "2022-09-14T14:29:35", 251 | "encodingFormat": "text/html", 252 | "lineCount": 186, 253 | "sha512": "dcc7b8c3df3406400449d97bbb9046ebcad73f865de390253a9d081a039e0b5a225f4d1bceed61c5093d04dc0c1fffb79256ac48e383e27a36781eb3ebd01d37", 254 | "url": "http://localhost:2000/runs/d3c7e943-4b41-4fdc-a224-e227f5e518a0/data/outputs/ERR034597_1.small_fastqc.html" 255 | }, 256 | { 257 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1P.fq", 258 | "@type": "File", 259 | "contentSize": 5566650, 260 | "dateModified": "2022-09-14T14:29:56", 261 | "encodingFormat": "http://edamontology.org/format_1930", 262 | "lineCount": 94556, 263 | "sha512": "b5d5b088550ef1cd1b8d1760d6e7bc93fe1500cded15df196e5173e7b5e2732b0a63ccb3dcc535c1991ad95faaf81eda5e61958d0ef42a561d1daa2fae5858b6", 264 | "url": "http://localhost:2000/runs/d3c7e943-4b41-4fdc-a224-e227f5e518a0/data/outputs/ERR034597_1.small.fq.trimmed.1P.fq" 265 | }, 266 | { 267 | "@id": "outputs/ERR034597_1.small.fq.trimmed.1U.fq", 268 | "@type": "File", 269 | "contentSize": 187289, 270 | "dateModified": "2022-09-14T14:29:56", 271 | "encodingFormat": "http://edamontology.org/format_1930", 272 | "lineCount": 3424, 273 | "sha512": "dba779dbc2280232dcc64c3aee9dca5ad56508d13a9905e986d0b30c04ff2eb14a7dabc3055cf8a02a1805dad6daa736d98e1df89385847e1884a3ea80bf8b23", 274 | "url": "http://localhost:2000/runs/d3c7e943-4b41-4fdc-a224-e227f5e518a0/data/outputs/ERR034597_1.small.fq.trimmed.1U.fq" 275 | }, 276 | { 277 | "@id": "outputs/ERR034597_2.small_fastqc.html", 278 | "@type": "File", 279 | "contentSize": 592566, 280 | "dateModified": "2022-09-14T14:30:12", 281 | "encodingFormat": "text/html", 282 | "lineCount": 186, 283 | "sha512": "aa7d4849a54f855ba6edf1277e4e668819fcbe6cba113576f7f979ea34955c2dc6929c09406fa40b65aa61f4ae8ed576bfd428d44eae92613dc0ac75f9eea5a5", 284 | "url": "http://localhost:2000/runs/d3c7e943-4b41-4fdc-a224-e227f5e518a0/data/outputs/ERR034597_2.small_fastqc.html" 285 | }, 286 | { 287 | "@id": "outputs/ERR034597_1.small.fq.trimmed.2U.fq", 288 | "@type": "File", 289 | "contentSize": 80131, 290 | "dateModified": "2022-09-14T14:29:56", 291 | "encodingFormat": "http://edamontology.org/format_1930", 292 | "lineCount": 1468, 293 | "sha512": "ff2ac389f7a48bd87576c27935c436899dd9ad4929d8b0a3e85fd4ca711dcb17c6b323b1be3d68ff8353e94b83be14637081a66eccb27daa69b95fba5b5eaf63", 294 | "url": "http://localhost:2000/runs/d3c7e943-4b41-4fdc-a224-e227f5e518a0/data/outputs/ERR034597_1.small.fq.trimmed.2U.fq" 295 | }, 296 | { 297 | "@id": "stdout.log", 298 | "@type": "File", 299 | "contentSize": 3254, 300 | "dateModified": "2022-09-14T14:30:13", 301 | "encodingFormat": "application/json", 302 | "lineCount": 50, 303 | "name": "Sapporo stdout", 304 | "sha512": "db7f4b2e4e61891942298c5e0a8be1dca1ee54d61ecd777b53e912c46e6aa403bf633719e493be64cc826444edfb41a317ee376d862ef33096b7d23e82bf8fba", 305 | "text": "{\n \"qc_result_1\": {\n \"location\": \"file:///Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small_fastqc.html\",\n \"basename\": \"ERR034597_1.small_fastqc.html\",\n \"class\": \"File\",\n \"checksum\": \"sha1$bef5575ecb691ef6e31754996e06a476146634dd\",\n \"size\": 592394,\n \"path\": \"/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small_fastqc.html\"\n },\n \"qc_result_2\": {\n \"location\": \"file:///Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_2.small_fastqc.html\",\n \"basename\": \"ERR034597_2.small_fastqc.html\",\n \"class\": \"File\",\n \"checksum\": \"sha1$def91e401bcbbc6c6e27a8fc67cb3d850d6e2979\",\n \"size\": 592566,\n \"path\": \"/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_2.small_fastqc.html\"\n },\n \"trimmed_fastq1P\": {\n \"location\": \"file:///Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.1P.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.1P.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$5188cdb59cab8010eb673e8bc113b7fd7a686660\",\n \"size\": 5566650,\n \"path\": \"/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.1P.fq\"\n },\n \"trimmed_fastq1U\": {\n \"location\": \"file:///Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.1U.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.1U.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$be4d3444537d2596d122db1ca8e5955954094f6b\",\n \"size\": 187289,\n \"path\": \"/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.1U.fq\"\n },\n \"trimmed_fastq2P\": {\n \"location\": \"file:///Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.2P.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.2P.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$cd1451093c91a9b619337a7bfbe592ad76554745\",\n \"size\": 5560582,\n \"path\": \"/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.2P.fq\"\n },\n \"trimmed_fastq2U\": {\n \"location\": \"file:///Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.2U.fq\",\n \"basename\": \"ERR034597_1.small.fq.trimmed.2U.fq\",\n \"class\": \"File\",\n \"checksum\": \"sha1$dd7edf1b2d599eb3c8fa49426be55d8a0360561c\",\n \"size\": 80131,\n \"path\": \"/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/outputs/ERR034597_1.small.fq.trimmed.2U.fq\"\n }\n}\n" 306 | }, 307 | { 308 | "@id": "stderr.log", 309 | "@type": "File", 310 | "contentSize": 5085, 311 | "dateModified": "2022-09-14T14:30:14", 312 | "encodingFormat": "text/plain", 313 | "lineCount": 111, 314 | "name": "Sapporo stderr", 315 | "sha512": "e4ab1823f641723be7a4644329e00f2c31f8be9a88665cd2cf105acb5e5401e95acb0e81c11dc6928271a40edfd2762794aab274e9037797a14da9bc46b71856", 316 | "text": "jq: error (at /Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/run_request.json:10): null (null) only strings can be parsed\n/bin/cwltool 3.1\n\u001b[1;30mINFO\u001b[0m [workflow ] start\n\u001b[1;30mINFO\u001b[0m [workflow ] starting step qc_1\n\u001b[1;30mINFO\u001b[0m [step qc_1] start\n\u001b[1;30mINFO\u001b[0m [job qc_1] /tmp/zsfkhslc$ docker \\\n run \\\n -i \\\n --mount=type=bind,source=/tmp/zsfkhslc,target=/DEfEIc \\\n --mount=type=bind,source=/tmp/7in3_il8,target=/tmp \\\n --mount=type=bind,source=/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/exe/ERR034597_1.small.fq.gz,target=/var/lib/cwl/stg4e317a1c-eb24-4eed-9cfe-0341896496ad/ERR034597_1.small.fq.gz,readonly \\\n --workdir=/DEfEIc \\\n --read-only=true \\\n --log-driver=none \\\n --user=0:0 \\\n --rm \\\n --cidfile=/tmp/5w8ndlyq/20220914052920-414423.cid \\\n --env=TMPDIR=/tmp \\\n --env=HOME=/DEfEIc \\\n quay.io/biocontainers/fastqc:0.11.9--0 \\\n fastqc \\\n -o \\\n . \\\n --threads \\\n 2 \\\n /var/lib/cwl/stg4e317a1c-eb24-4eed-9cfe-0341896496ad/ERR034597_1.small.fq.gz > /tmp/zsfkhslc/fastqc-stdout.log 2> /tmp/zsfkhslc/fastqc-stderr.log\n\u001b[1;30mINFO\u001b[0m [job qc_1] Max memory used: 356MiB\n\u001b[1;30mINFO\u001b[0m [job qc_1] completed success\n\u001b[1;30mINFO\u001b[0m [step qc_1] completed success\n\u001b[1;30mINFO\u001b[0m [workflow ] starting step trimming\n\u001b[1;30mINFO\u001b[0m [step trimming] start\n\u001b[1;30mINFO\u001b[0m ['docker', 'pull', 'quay.io/biocontainers/trimmomatic:0.38--1']\n0.38--1: Pulling from biocontainers/trimmomatic\na3ed95caeb02: Already exists\n77c6c00e8b61: Already exists\n3aaade50789a: Already exists\n00cf8b9f3d2a: Already exists\n7ff999a2256f: Already exists\nd2ba336f2e44: Already exists\ndfda3e01f2b6: Already exists\na3ed95caeb02: Already exists\n10c3bb32200b: Already exists\n216868b000fb: Pulling fs layer\n216868b000fb: Verifying Checksum\n216868b000fb: Download complete\n216868b000fb: Pull complete\nDigest: sha256:e5a9dc8750d9413c09693cf9157f98f5ef0f1fc71cddbe501bc33db53c09d2cf\nStatus: Downloaded newer image for quay.io/biocontainers/trimmomatic:0.38--1\nquay.io/biocontainers/trimmomatic:0.38--1\n\u001b[1;30mINFO\u001b[0m [job trimming] /tmp/li2fr932$ docker \\\n run \\\n -i \\\n --mount=type=bind,source=/tmp/li2fr932,target=/DEfEIc \\\n --mount=type=bind,source=/tmp/dr3vw2o5,target=/tmp \\\n --mount=type=bind,source=/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/exe/ERR034597_1.small.fq.gz,target=/var/lib/cwl/stg399f1774-43ff-40a2-8ff3-4e709f48e27c/ERR034597_1.small.fq.gz,readonly \\\n --mount=type=bind,source=/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/exe/ERR034597_2.small.fq.gz,target=/var/lib/cwl/stg51a86b51-66f8-420a-85a7-bd423134b2bf/ERR034597_2.small.fq.gz,readonly \\\n --workdir=/DEfEIc \\\n --read-only=true \\\n --log-driver=none \\\n --user=0:0 \\\n --rm \\\n --cidfile=/tmp/4tth6tcx/20220914052951-543463.cid \\\n --env=TMPDIR=/tmp \\\n --env=HOME=/DEfEIc \\\n quay.io/biocontainers/trimmomatic:0.38--1 \\\n trimmomatic \\\n PE \\\n -threads \\\n 2 \\\n /var/lib/cwl/stg399f1774-43ff-40a2-8ff3-4e709f48e27c/ERR034597_1.small.fq.gz \\\n /var/lib/cwl/stg51a86b51-66f8-420a-85a7-bd423134b2bf/ERR034597_2.small.fq.gz \\\n ERR034597_1.small.fq.trimmed.1P.fq \\\n ERR034597_1.small.fq.trimmed.1U.fq \\\n ERR034597_1.small.fq.trimmed.2P.fq \\\n ERR034597_1.small.fq.trimmed.2U.fq \\\n ILLUMINACLIP:/usr/local/share/trimmomatic/adapters/TruSeq2-PE.fa:2:40:15 \\\n LEADING:20 \\\n TRAILING:20 \\\n SLIDINGWINDOW:4:15 \\\n MINLEN:36 > /tmp/li2fr932/trimmomatic-pe-stdout.log 2> /tmp/li2fr932/trimmomatic-pe-stderr.log\n\u001b[1;30mINFO\u001b[0m [job trimming] Max memory used: 343MiB\n\u001b[1;30mINFO\u001b[0m [job trimming] completed success\n\u001b[1;30mINFO\u001b[0m [step trimming] completed success\n\u001b[1;30mINFO\u001b[0m [workflow ] starting step qc_2\n\u001b[1;30mINFO\u001b[0m [step qc_2] start\n\u001b[1;30mINFO\u001b[0m [job qc_2] /tmp/k3e6nk21$ docker \\\n run \\\n -i \\\n --mount=type=bind,source=/tmp/k3e6nk21,target=/DEfEIc \\\n --mount=type=bind,source=/tmp/r007zbot,target=/tmp \\\n --mount=type=bind,source=/Users/suecharo/git/github.com/sapporo-wes/sapporo-service/run/d3/d3c7e943-4b41-4fdc-a224-e227f5e518a0/exe/ERR034597_2.small.fq.gz,target=/var/lib/cwl/stgb3bef596-a880-4dbf-9b48-492cb3d552c6/ERR034597_2.small.fq.gz,readonly \\\n --workdir=/DEfEIc \\\n --read-only=true \\\n --log-driver=none \\\n --user=0:0 \\\n --rm \\\n --cidfile=/tmp/lghv_rfh/20220914052957-260345.cid \\\n --env=TMPDIR=/tmp \\\n --env=HOME=/DEfEIc \\\n quay.io/biocontainers/fastqc:0.11.9--0 \\\n fastqc \\\n -o \\\n . \\\n --threads \\\n 2 \\\n /var/lib/cwl/stgb3bef596-a880-4dbf-9b48-492cb3d552c6/ERR034597_2.small.fq.gz > /tmp/k3e6nk21/fastqc-stdout.log 2> /tmp/k3e6nk21/fastqc-stderr.log\n\u001b[1;30mINFO\u001b[0m [job qc_2] Max memory used: 350MiB\n\u001b[1;30mINFO\u001b[0m [job qc_2] completed success\n\u001b[1;30mINFO\u001b[0m [step qc_2] completed success\n\u001b[1;30mINFO\u001b[0m [workflow ] completed success\n\u001b[1;30mINFO\u001b[0m Final process status is success\n" 317 | } 318 | ] 319 | } -------------------------------------------------------------------------------- /tests/gatk_mac_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("GATK Mac test", async () => { 6 | const loc1 = `${CRATE_DIR}/gatk_1st.json`; 7 | const loc2 = `${CRATE_DIR}/gatk_mac.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/gatk_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("GATK Linux test", async () => { 6 | const loc1 = `${CRATE_DIR}/gatk_1st.json`; 7 | const loc2 = `${CRATE_DIR}/gatk_2nd.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/jga_mac_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("JGA Mac test", async () => { 6 | const loc1 = `${CRATE_DIR}/jga_1st.json`; 7 | const loc2 = `${CRATE_DIR}/jga_mac.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/jga_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("JGA Linux test", async () => { 6 | const loc1 = `${CRATE_DIR}/jga_1st.json`; 7 | const loc2 = `${CRATE_DIR}/jga_2nd.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/rnaseq_all_files_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("RNA-seq Linux test", async () => { 6 | const loc1 = `${CRATE_DIR}/rnaseq_1st.json`; 7 | const loc2 = `${CRATE_DIR}/rnaseq_2nd.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2, "--all"]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/rnaseq_mac_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("RNA-seq Mac test", async () => { 6 | const loc1 = `${CRATE_DIR}/rnaseq_1st.json`; 7 | const loc2 = `${CRATE_DIR}/rnaseq_mac.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/rnaseq_only_sapporo_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("RNA-seq using only Sapporo test", async () => { 6 | const loc1 = `${CRATE_DIR}/rnaseq_1st.json`; 7 | const loc2 = `${CRATE_DIR}/rnaseq_only_sapporo.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/rnaseq_small_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("RNA-seq small test", async () => { 6 | const loc1 = `${CRATE_DIR}/rnaseq_1st.json`; 7 | const loc2 = `${CRATE_DIR}/rnaseq_small.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/rnaseq_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("RNA-seq Linux test", async () => { 6 | const loc1 = `${CRATE_DIR}/rnaseq_1st.json`; 7 | const loc2 = `${CRATE_DIR}/rnaseq_2nd.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/rnaseq_v3.6_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("RNA-seq v3.6 test", async () => { 6 | const loc1 = `${CRATE_DIR}/rnaseq_1st.json`; 7 | const loc2 = `${CRATE_DIR}/rnaseq_v3.6.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/trimming_mac_test.ts: -------------------------------------------------------------------------------- 1 | import { args, compare, crate } from "../src/mod.ts"; 2 | 3 | const CRATE_DIR = `${new URL(".", import.meta.url).pathname}example_crate`; 4 | 5 | Deno.test("Trimming Mac test", async () => { 6 | const loc1 = `${CRATE_DIR}/trimming.json`; 7 | const loc2 = `${CRATE_DIR}/trimming_mac.json`; 8 | 9 | const parsedArgs = await args.parseArgs([loc1, loc2]); 10 | const crate1 = new crate.Crate(parsedArgs.loc1); 11 | await crate1.initialize(); 12 | const crate2 = new crate.Crate(parsedArgs.loc2); 13 | await crate2.initialize(); 14 | compare.compare(crate1, crate2, parsedArgs.all, parsedArgs.threshold); 15 | }); 16 | --------------------------------------------------------------------------------