From 839ca40131434ee6e7b4cb36705f879ca1b5aca6 Mon Sep 17 00:00:00 2001 From: lyh970817 Date: Wed, 27 May 2026 02:38:16 +0800 Subject: [PATCH 1/3] Add REGENIE splitl0 module --- .../nf-core/regenie/splitl0/environment.yml | 7 + modules/nf-core/regenie/splitl0/main.nf | 58 +++++++ modules/nf-core/regenie/splitl0/meta.yml | 156 ++++++++++++++++++ .../regenie/splitl0/tests/main.nf.test | 148 +++++++++++++++++ .../regenie/splitl0/tests/main.nf.test.snap | 84 ++++++++++ .../regenie/splitl0/tests/nextflow.config | 5 + 6 files changed, 458 insertions(+) create mode 100644 modules/nf-core/regenie/splitl0/environment.yml create mode 100644 modules/nf-core/regenie/splitl0/main.nf create mode 100644 modules/nf-core/regenie/splitl0/meta.yml create mode 100644 modules/nf-core/regenie/splitl0/tests/main.nf.test create mode 100644 modules/nf-core/regenie/splitl0/tests/main.nf.test.snap create mode 100644 modules/nf-core/regenie/splitl0/tests/nextflow.config diff --git a/modules/nf-core/regenie/splitl0/environment.yml b/modules/nf-core/regenie/splitl0/environment.yml new file mode 100644 index 000000000000..98fe8277cc05 --- /dev/null +++ b/modules/nf-core/regenie/splitl0/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - "bioconda::regenie=4.1.2" diff --git a/modules/nf-core/regenie/splitl0/main.nf b/modules/nf-core/regenie/splitl0/main.nf new file mode 100644 index 000000000000..38f3435f52f4 --- /dev/null +++ b/modules/nf-core/regenie/splitl0/main.nf @@ -0,0 +1,58 @@ +process REGENIE_SPLITL0 { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/7a/7a05bf71ea09adc5ebf9f0c656c9b326c0f16ba8e4966914972e58313469a466/data' + : 'community.wave.seqera.io/library/regenie:4.1.2--5d361f9fcb2f85cf'}" + + input: + tuple val(meta), path(plink_genotype_file), path(plink_variant_file), path(plink_sample_file) + tuple val(meta2), path(pheno) + tuple val(meta3), path(covar) + val bsize + val n_jobs + + output: + tuple val(meta), path("*.master"), emit: master + tuple val(meta), path("*_job*.snplist"), emit: snplists + tuple val(meta), path("*.log"), emit: log + tuple val("${task.process}"), val('regenie'), eval('regenie --version 2>&1 | sed -n "1{s/^v//;s/\\.gz$//;p}"'), topic: versions, emit: versions_regenie + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def input_prefix = plink_genotype_file.baseName + def prefix = task.ext.prefix ?: input_prefix + def genotype_flag = plink_genotype_file.name.endsWith('.pgen') ? '--pgen' : '--bed' + def covar_arg = covar ? "--covarFile ${covar}" : '' + def bsize_arg = bsize ?: 1000 + """ + regenie \\ + --step 1 \\ + ${genotype_flag} ${input_prefix} \\ + --phenoFile ${pheno} \\ + ${covar_arg} \\ + --bsize ${bsize_arg} \\ + --gz \\ + --threads ${task.cpus} \\ + ${args} \\ + --out ${prefix} \\ + --split-l0 ${prefix},${n_jobs} + """ + + stub: + def input_prefix = plink_genotype_file.baseName + def prefix = task.ext.prefix ?: input_prefix + def job_count = n_jobs as Integer + def snplist_lines = (1..job_count).collect { job -> "touch ${prefix}_job${job}.snplist" }.join('\n') + def master_lines = (1..job_count).collect { job -> "${prefix}_job${job} ${prefix}_job${job}.snplist" }.join('\\n') + """ + printf 'job snplist\\n${master_lines}\\n' > ${prefix}.master + ${snplist_lines} + touch ${prefix}.log + """ +} diff --git a/modules/nf-core/regenie/splitl0/meta.yml b/modules/nf-core/regenie/splitl0/meta.yml new file mode 100644 index 000000000000..7a2de6f6cce6 --- /dev/null +++ b/modules/nf-core/regenie/splitl0/meta.yml @@ -0,0 +1,156 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "regenie_splitl0" +description: Split REGENIE step 1 level-0 ridge-regression blocks into parallel jobs +keywords: + - regenie + - gwas + - association + - genomics + - parallel +tools: + - "regenie": + description: "Regenie is a C++ program for whole genome regression modelling of large genome-wide association studies (GWAS)." + homepage: "https://rgcgithub.github.io/regenie/" + documentation: "https://rgcgithub.github.io/regenie/options/" + tool_dev_url: "https://github.com/rgcgithub/regenie" + doi: "10.1038/s41588-021-00870-7" + licence: ["MIT"] + identifier: "biotools:regenie" + +input: + - - meta: + type: map + description: | + Groovy Map containing genotype information + Keep only the genotype analysis identifier in this map + REGENIE consumes the staged basename of `plink_genotype_file` as the `--bed` or `--pgen` prefix, so the `.bed/.bim/.fam` or `.pgen/.pvar/.psam` files must share one basename + e.g. `[ id:'cohort' ]` + - plink_genotype_file: + type: file + description: PLINK primary genotype file in BED or PGEN format + pattern: "*.{bed,pgen}" + ontologies: + - edam: "http://edamontology.org/format_3003" # BED + - plink_variant_file: + type: file + description: PLINK variant metadata file in BIM or PVAR format + pattern: "*.{bim,pvar,zst}" + ontologies: [] + - plink_sample_file: + type: file + description: PLINK sample metadata file in FAM or PSAM format + pattern: "*.{fam,psam}" + ontologies: [] + - - meta2: + type: map + description: | + Groovy Map containing genotype/sample information associated with the phenotype file input + Use the same phenotype file and phenotype-selection arguments for all `regenie/splitl0`, `regenie/runl0`, and `regenie/runl1` jobs in the same chunked step 1 analysis + e.g. `[ id:'plink_simulated' ]` + - pheno: + type: file + description: Phenotype file passed to `--phenoFile` + pattern: "*.{phe,pheno,txt,tsv}" + ontologies: + - edam: "http://edamontology.org/format_3475" # TSV + - - meta3: + type: map + description: | + Groovy Map containing genotype/sample information associated with the covariate input + Use compatible covariate inputs for all stages in the same chunked step 1 analysis + e.g. `[ id:'plink_simulated' ]` + - covar: + type: file + optional: true + description: Optional covariate file passed to `--covarFile`; provide `[]` when absent + pattern: "*.{covar,cov,txt,tsv}" + ontologies: + - edam: "http://edamontology.org/format_3475" # TSV + - bsize: + type: integer + description: Optional block size passed to `--bsize`; pass `[]` to use the module default of `1000` + - n_jobs: + type: integer + description: Number of level-0 jobs requested with `--split-l0` + +output: + master: + - - meta: + type: map + description: | + Groovy Map containing genotype/sample information + e.g. `[ id:'plink_simulated' ]` + - "*.master": + type: file + description: REGENIE split level-0 master file + pattern: "*.master" + ontologies: + - edam: "http://edamontology.org/format_2330" # Text + snplists: + - - meta: + type: map + description: | + Groovy Map containing genotype/sample information + e.g. `[ id:'plink_simulated' ]` + - "*_job*.snplist": + type: file + description: REGENIE per-job variant list files referenced by the master file + pattern: "*_job*.snplist" + ontologies: + - edam: "http://edamontology.org/format_2330" # Text + log: + - - meta: + type: map + description: | + Groovy Map containing genotype information + e.g. `[ id:'plink_simulated' ]` + - "*.log": + type: file + description: REGENIE split level-0 log file + pattern: "*.log" + ontologies: + - edam: "http://edamontology.org/format_2330" # Text + versions_regenie: + - - "${task.process}": + type: string + description: The process the versions were collected from + - "regenie": + type: string + description: The tool name + - 'regenie --version 2>&1 | sed -n "1{s/^v//;s/\.gz$//;p}"': + type: eval + description: The command used to generate the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - regenie: + type: string + description: The tool name + - 'regenie --version 2>&1 | sed -n "1{s/^v//;s/\.gz$//;p}"': + type: eval + description: The command used to generate the version of the tool + +notes: | + `task.ext.args` is passed directly to REGENIE and can be used for stage-consistent options such as `--phenoColList`, `--bt`, `--loocv`, or `--keep-l0`. + The same phenotype file, phenotype-selection arguments, trait mode arguments such as `--bt`, and compatible genotype/covariate inputs must be used across `regenie/splitl0`, every matching `regenie/runl0` job, and `regenie/runl1`. +authors: + - "@lyh970817" +maintainers: + - "@lyh970817" +containers: + conda: + linux_amd64: + lock_file: "modules/nf-core/regenie/splitl0/.conda-lock/linux_amd64-bd-5d361f9fcb2f85cf_1.txt" + docker: + linux_amd64: + build_id: "bd-5d361f9fcb2f85cf_1" + name: "community.wave.seqera.io/library/regenie:4.1.2--5d361f9fcb2f85cf" + scanId: "sc-cc9eb5ed5eb381dd_2" + singularity: + linux_amd64: + build_id: "bd-7c121fb4ecd57890_1" + name: "oras://community.wave.seqera.io/library/regenie:4.1.2--7c121fb4ecd57890" + https: "https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/7a/7a05bf71ea09adc5ebf9f0c656c9b326c0f16ba8e4966914972e58313469a466/data" diff --git a/modules/nf-core/regenie/splitl0/tests/main.nf.test b/modules/nf-core/regenie/splitl0/tests/main.nf.test new file mode 100644 index 000000000000..3932aca10356 --- /dev/null +++ b/modules/nf-core/regenie/splitl0/tests/main.nf.test @@ -0,0 +1,148 @@ +nextflow_process { + + name "Test Process REGENIE_SPLITL0" + config "./nextflow.config" + script "../main.nf" + process "REGENIE_SPLITL0" + + tag "modules" + tag "modules_nfcore" + tag "regenie" + tag "regenie/splitl0" + + test("homo_sapiens popgen - quantitative plink1 with covariates") { + + when { + params { + module_args = '--phenoColList QuantitativeTrait' + } + process { + """ + input[0] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.bed', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.bim', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.fam', checkIfExists: true) + ] + + input[1] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated_quantitative_phenoname.phe', checkIfExists: true) + ] + + input[2] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated_covariates.txt', checkIfExists: true) + ] + + input[3] = 100 + input[4] = 2 + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.master.size() == 1 }, + { assert process.out.snplists.size() == 1 }, + { assert process.out.log.size() == 1 }, + { assert process.out.master.get(0).get(0).id == 'plink_simulated' }, + { assert process.out.snplists.get(0).get(0).id == 'plink_simulated' }, + { assert process.out.log.get(0).get(0).id == 'plink_simulated' }, + { + def master = path(process.out.master.get(0).get(1)) + def lines = master.text.readLines().findAll { it } + assert master.exists() + assert lines.size() == 3 + assert lines[0] ==~ /\d+\s+\d+/ + assert lines.drop(1).every { line -> + line.contains('plink_simulated_job') && !line.contains('/') + } + }, + { + def snplists = process.out.snplists.get(0).get(1) + assert snplists.size() == 2 + assert snplists.collect { path(it).getFileName().toString() }.sort() == [ + 'plink_simulated_job1.snplist', + 'plink_simulated_job2.snplist' + ] + }, + { assert path(process.out.log.get(0).get(1)).exists() }, + { + def stableMaster = process.out.master.collect { master -> + [master[0], path(master[1]).getFileName().toString()] + } + def stableSnplists = process.out.snplists.collect { snplist -> + [snplist[0], snplist[1].collect { path(it).getFileName().toString() }.sort()] + } + assert snapshot( + stableMaster, + stableSnplists, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() + } + ) + } + + } + + test("homo_sapiens popgen - plink1 - stub") { + + options "-stub" + + when { + params { + module_args = '--phenoColList QuantitativeTrait' + } + process { + """ + input[0] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.bed', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.bim', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.fam', checkIfExists: true) + ] + + input[1] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated_quantitative_phenoname.phe', checkIfExists: true) + ] + + input[2] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated_covariates.txt', checkIfExists: true) + ] + + input[3] = 100 + input[4] = 2 + """ + } + } + + then { + assertAll( + { assert process.success }, + { + def stableMaster = process.out.master.collect { master -> + [master[0], path(master[1]).getFileName().toString()] + } + def stableSnplists = process.out.snplists.collect { snplist -> + [snplist[0], snplist[1].collect { path(it).getFileName().toString() }.sort()] + } + def stableLogs = process.out.log.collect { log -> + [log[0], path(log[1]).getFileName().toString()] + } + assert snapshot( + stableMaster, + stableSnplists, + stableLogs, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() + } + ) + } + + } + +} diff --git a/modules/nf-core/regenie/splitl0/tests/main.nf.test.snap b/modules/nf-core/regenie/splitl0/tests/main.nf.test.snap new file mode 100644 index 000000000000..a89bab88ca8f --- /dev/null +++ b/modules/nf-core/regenie/splitl0/tests/main.nf.test.snap @@ -0,0 +1,84 @@ +{ + "homo_sapiens popgen - quantitative plink1 with covariates": { + "content": [ + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.master" + ] + ], + [ + [ + { + "id": "plink_simulated" + }, + [ + "plink_simulated_job1.snplist", + "plink_simulated_job2.snplist" + ] + ] + ], + { + "versions_regenie": [ + [ + "REGENIE_SPLITL0", + "regenie", + "4.1.2" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-05-21T22:23:00.198898381" + }, + "homo_sapiens popgen - plink1 - stub": { + "content": [ + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.master" + ] + ], + [ + [ + { + "id": "plink_simulated" + }, + [ + "plink_simulated_job1.snplist", + "plink_simulated_job2.snplist" + ] + ] + ], + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.log" + ] + ], + { + "versions_regenie": [ + [ + "REGENIE_SPLITL0", + "regenie", + "4.1.2" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-05-21T22:23:14.857699924" + } +} \ No newline at end of file diff --git a/modules/nf-core/regenie/splitl0/tests/nextflow.config b/modules/nf-core/regenie/splitl0/tests/nextflow.config new file mode 100644 index 000000000000..a21fcfdd4745 --- /dev/null +++ b/modules/nf-core/regenie/splitl0/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: REGENIE_SPLITL0 { + ext.args = params.module_args + } +} From 6861c91817513feb19f989d59c9382fe0edb2b33 Mon Sep 17 00:00:00 2001 From: lyh970817 Date: Thu, 28 May 2026 18:15:17 +0800 Subject: [PATCH 2/3] Update REGENIE splitl0 metadata --- modules/nf-core/regenie/splitl0/meta.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/nf-core/regenie/splitl0/meta.yml b/modules/nf-core/regenie/splitl0/meta.yml index 7a2de6f6cce6..2590342868a3 100644 --- a/modules/nf-core/regenie/splitl0/meta.yml +++ b/modules/nf-core/regenie/splitl0/meta.yml @@ -4,6 +4,7 @@ description: Split REGENIE step 1 level-0 ridge-regression blocks into parallel keywords: - regenie - gwas + - genome-wide association study - association - genomics - parallel @@ -141,9 +142,6 @@ authors: maintainers: - "@lyh970817" containers: - conda: - linux_amd64: - lock_file: "modules/nf-core/regenie/splitl0/.conda-lock/linux_amd64-bd-5d361f9fcb2f85cf_1.txt" docker: linux_amd64: build_id: "bd-5d361f9fcb2f85cf_1" From f2ee851b9341a3c49ce9a97bf480b2f95bbcf823 Mon Sep 17 00:00:00 2001 From: lyh970817 Date: Thu, 28 May 2026 18:15:17 +0800 Subject: [PATCH 3/3] Use shared test params for REGENIE splitl0 --- .../regenie/splitl0/tests/main.nf.test | 162 +++++++++++++++++- .../regenie/splitl0/tests/main.nf.test.snap | 103 ++++++++++- .../regenie/splitl0/tests/nextflow.config | 8 +- 3 files changed, 261 insertions(+), 12 deletions(-) diff --git a/modules/nf-core/regenie/splitl0/tests/main.nf.test b/modules/nf-core/regenie/splitl0/tests/main.nf.test index 3932aca10356..740de93fbc5a 100644 --- a/modules/nf-core/regenie/splitl0/tests/main.nf.test +++ b/modules/nf-core/regenie/splitl0/tests/main.nf.test @@ -1,9 +1,9 @@ nextflow_process { name "Test Process REGENIE_SPLITL0" - config "./nextflow.config" script "../main.nf" process "REGENIE_SPLITL0" + config "./nextflow.config" tag "modules" tag "modules_nfcore" @@ -14,7 +14,7 @@ nextflow_process { when { params { - module_args = '--phenoColList QuantitativeTrait' + module_args = "--phenoColList QuantitativeTrait" } process { """ @@ -42,6 +42,11 @@ nextflow_process { } then { + def command = path(process.out.master.get(0).get(1)).parent.resolve('.command.sh').text + .replaceAll(/\\\s*\n/, ' ') + .replaceAll(/\s+/, ' ') + .trim() + assertAll( { assert process.success }, { assert process.out.master.size() == 1 }, @@ -62,6 +67,7 @@ nextflow_process { }, { def snplists = process.out.snplists.get(0).get(1) + snplists = snplists instanceof List ? snplists : [snplists] assert snplists.size() == 2 assert snplists.collect { path(it).getFileName().toString() }.sort() == [ 'plink_simulated_job1.snplist', @@ -69,16 +75,108 @@ nextflow_process { ] }, { assert path(process.out.log.get(0).get(1)).exists() }, + { assert command.contains('--split-l0 plink_simulated,2') }, + { assert command.contains('--out plink_simulated') }, + { assert command.contains('--bed plink_simulated') }, + { assert !command.contains('--bed /') }, + { assert command.contains('--phenoColList QuantitativeTrait') }, + { assert command.contains('--covarFile plink_simulated_covariates.txt') }, + { assert command.contains('--bsize 100') }, + { + def stableMaster = process.out.master.collect { master -> + [master[0], path(master[1]).getFileName().toString()] + } + def stableSnplists = process.out.snplists.collect { snplist -> + def snplistFiles = snplist[1] instanceof List ? snplist[1] : [snplist[1]] + [snplist[0], snplistFiles.collect { path(it).getFileName().toString() }.sort()] + } + def stableLogs = process.out.log.collect { logTuple -> + [logTuple[0], path(logTuple[1]).getFileName().toString()] + } + assert snapshot( + stableMaster, + stableSnplists, + stableLogs, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() + } + ) + } + + } + + test("homo_sapiens popgen - quantitative plink2 without covariates") { + + when { + params { + module_args = "--phenoColList QuantitativeTrait" + } + process { + """ + input[0] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.pgen', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.pvar', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.psam', checkIfExists: true) + ] + + input[1] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated_quantitative_phenoname.phe', checkIfExists: true) + ] + + input[2] = [[:], []] + input[3] = [] + input[4] = 2 + """ + } + } + + then { + def command = path(process.out.master.get(0).get(1)).parent.resolve('.command.sh').text + .replaceAll(/\\\s*\n/, ' ') + .replaceAll(/\s+/, ' ') + .trim() + + assertAll( + { assert process.success }, + { assert process.out.master.size() == 1 }, + { assert process.out.snplists.size() == 1 }, + { assert process.out.log.size() == 1 }, + { assert process.out.master.get(0).get(0).id == 'plink_simulated' }, + { assert process.out.snplists.get(0).get(0).id == 'plink_simulated' }, + { assert process.out.log.get(0).get(0).id == 'plink_simulated' }, + { + def snplists = process.out.snplists.get(0).get(1) + snplists = snplists instanceof List ? snplists : [snplists] + assert snplists.size() >= 1 + assert snplists.collect { path(it).getFileName().toString() }.sort() == [ + 'plink_simulated_job1.snplist' + ] + }, + { assert path(process.out.log.get(0).get(1)).exists() }, + { assert command.contains('--split-l0 plink_simulated,2') }, + { assert command.contains('--out plink_simulated') }, + { assert command.contains('--pgen plink_simulated') }, + { assert !command.contains('--pgen /') }, + { assert command.contains('--phenoColList QuantitativeTrait') }, + { assert !command.contains('--covarFile') }, + { assert command.contains('--bsize 1000') }, { def stableMaster = process.out.master.collect { master -> [master[0], path(master[1]).getFileName().toString()] } def stableSnplists = process.out.snplists.collect { snplist -> - [snplist[0], snplist[1].collect { path(it).getFileName().toString() }.sort()] + def snplistFiles = snplist[1] instanceof List ? snplist[1] : [snplist[1]] + [snplist[0], snplistFiles.collect { path(it).getFileName().toString() }.sort()] + } + def stableLogs = process.out.log.collect { logTuple -> + [logTuple[0], path(logTuple[1]).getFileName().toString()] } assert snapshot( stableMaster, stableSnplists, + stableLogs, process.out.findAll { key, val -> key.startsWith('versions') } ).match() } @@ -92,9 +190,6 @@ nextflow_process { options "-stub" when { - params { - module_args = '--phenoColList QuantitativeTrait' - } process { """ input[0] = [ @@ -128,7 +223,60 @@ nextflow_process { [master[0], path(master[1]).getFileName().toString()] } def stableSnplists = process.out.snplists.collect { snplist -> - [snplist[0], snplist[1].collect { path(it).getFileName().toString() }.sort()] + def snplistFiles = snplist[1] instanceof List ? snplist[1] : [snplist[1]] + [snplist[0], snplistFiles.collect { path(it).getFileName().toString() }.sort()] + } + def stableLogs = process.out.log.collect { log -> + [log[0], path(log[1]).getFileName().toString()] + } + assert snapshot( + stableMaster, + stableSnplists, + stableLogs, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() + } + ) + } + + } + + test("homo_sapiens popgen - plink2 - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.pgen', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.pvar', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated.psam', checkIfExists: true) + ] + + input[1] = [ + [ id:'plink_simulated' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/popgen/plink_simulated_quantitative_phenoname.phe', checkIfExists: true) + ] + + input[2] = [[:], []] + input[3] = [] + input[4] = 2 + """ + } + } + + then { + assertAll( + { assert process.success }, + { + def stableMaster = process.out.master.collect { master -> + [master[0], path(master[1]).getFileName().toString()] + } + def stableSnplists = process.out.snplists.collect { snplist -> + def snplistFiles = snplist[1] instanceof List ? snplist[1] : [snplist[1]] + [snplist[0], snplistFiles.collect { path(it).getFileName().toString() }.sort()] } def stableLogs = process.out.log.collect { log -> [log[0], path(log[1]).getFileName().toString()] diff --git a/modules/nf-core/regenie/splitl0/tests/main.nf.test.snap b/modules/nf-core/regenie/splitl0/tests/main.nf.test.snap index a89bab88ca8f..1afe6704f91b 100644 --- a/modules/nf-core/regenie/splitl0/tests/main.nf.test.snap +++ b/modules/nf-core/regenie/splitl0/tests/main.nf.test.snap @@ -20,6 +20,58 @@ ] ] ], + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.log" + ] + ], + { + "versions_regenie": [ + [ + "REGENIE_SPLITL0", + "regenie", + "4.1.2" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-05-27T14:40:00" + }, + "homo_sapiens popgen - quantitative plink2 without covariates": { + "content": [ + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.master" + ] + ], + [ + [ + { + "id": "plink_simulated" + }, + [ + "plink_simulated_job1.snplist" + ] + ] + ], + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.log" + ] + ], { "versions_regenie": [ [ @@ -34,7 +86,7 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-05-21T22:23:00.198898381" + "timestamp": "2026-05-27T14:40:00" }, "homo_sapiens popgen - plink1 - stub": { "content": [ @@ -79,6 +131,51 @@ "nf-test": "0.9.3", "nextflow": "25.10.4" }, - "timestamp": "2026-05-21T22:23:14.857699924" + "timestamp": "2026-05-27T14:40:00" + }, + "homo_sapiens popgen - plink2 - stub": { + "content": [ + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.master" + ] + ], + [ + [ + { + "id": "plink_simulated" + }, + [ + "plink_simulated_job1.snplist", + "plink_simulated_job2.snplist" + ] + ] + ], + [ + [ + { + "id": "plink_simulated" + }, + "plink_simulated.log" + ] + ], + { + "versions_regenie": [ + [ + "REGENIE_SPLITL0", + "regenie", + "4.1.2" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-05-27T14:40:00" } -} \ No newline at end of file +} diff --git a/modules/nf-core/regenie/splitl0/tests/nextflow.config b/modules/nf-core/regenie/splitl0/tests/nextflow.config index a21fcfdd4745..426255745bc5 100644 --- a/modules/nf-core/regenie/splitl0/tests/nextflow.config +++ b/modules/nf-core/regenie/splitl0/tests/nextflow.config @@ -1,5 +1,9 @@ +params { + module_args = "" +} + process { - withName: REGENIE_SPLITL0 { - ext.args = params.module_args + withName: "REGENIE_SPLITL0" { + ext.args = { params.module_args ?: "" } } }