diff --git a/modules/ensembl/fasta/recombine/main.nf b/modules/ensembl/fasta/recombine/main.nf index dfcf7b1..9eb7a4c 100644 --- a/modules/ensembl/fasta/recombine/main.nf +++ b/modules/ensembl/fasta/recombine/main.nf @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +nextflow.enable.types = true + process FASTA_RECOMBINE { tag "${meta.id}" @@ -22,11 +24,13 @@ process FASTA_RECOMBINE { container "docker.io/ensemblorg/ensembl-genomio:v1.7.0" input: - tuple val(meta), path(fasta_manifest), path(agp) + record(meta: Map, fasta_manifest: Path, agp: Path?) output: - tuple val(meta), path("${meta.id}.fa"), emit: recombined_fasta - tuple val("${task.process}"), val('fasta_recombine'), eval("fasta_recombine --version"), emit: versions_fasta_recombine, topic: versions + record(meta: meta, recombined_fasta: file("${meta.id}.fa")) + + topic: + tuple(task.process, 'fasta_recombine', eval("fasta_recombine --version 2>/dev/null || echo unknown")) >> 'versions' when: task.ext.when == null || task.ext.when diff --git a/modules/ensembl/fasta/recombine/meta.yml b/modules/ensembl/fasta/recombine/meta.yml index 858aabd..d6347c0 100644 --- a/modules/ensembl/fasta/recombine/meta.yml +++ b/modules/ensembl/fasta/recombine/meta.yml @@ -46,16 +46,6 @@ output: pattern: "*.fa" ontologies: - edam: http://edamontology.org/format_1929 # FASTA - versions_fasta_recombine: - - - ${task.process}: - type: string - description: The name of the process. - - fasta_recombine: - type: string - description: The name of the tool. - - "fasta_recombine --version": - type: eval - description: The expression to obtain the version of the tool topics: versions: - - ${task.process}: @@ -64,7 +54,7 @@ topics: - fasta_recombine: type: string description: The name of the tool. - - "fasta_recombine --version": + - "fasta_recombine --version 2>/dev/null || echo unknown": type: eval description: The expression to obtain the version of the tool authors: diff --git a/modules/ensembl/fasta/recombine/tests/main.nf.test b/modules/ensembl/fasta/recombine/tests/main.nf.test index 4448cf7..33d6add 100644 --- a/modules/ensembl/fasta/recombine/tests/main.nf.test +++ b/modules/ensembl/fasta/recombine/tests/main.nf.test @@ -24,6 +24,7 @@ nextflow_process { tag "modules_ensembl" tag "fasta" tag "fasta/recombine" + topics "versions" test("stub outputs: header mode") { @@ -38,18 +39,18 @@ nextflow_process { def no_file = file("NO_FILE") no_file.text = "" - input[0] = [ - [ id: 'test' ], - manifest, - no_file - ] + input[0] = record(meta: [ id: 'test' ], fasta_manifest: manifest, agp: no_file) """ } } then { assert process.trace.tasks().size() == 1 - assert process.out.recombined_fasta.size() == 1 + assert process.out[0].size() == 1 + assert file(process.out[0][0].recombined_fasta).name == 'test.fa' + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FASTA_RECOMBINE' assert process.success assert snapshot(process.out).match() } @@ -67,18 +68,18 @@ nextflow_process { def agp = file("test.agp") agp.text = "" - input[0] = [ - [ id: 'test' ], - manifest, - agp - ] + input[0] = record(meta: [ id: 'test' ], fasta_manifest: manifest, agp: agp) """ } } then { assert process.trace.tasks().size() == 1 - assert process.out.recombined_fasta.size() == 1 + assert process.out[0].size() == 1 + assert file(process.out[0][0].recombined_fasta).name == 'test.fa' + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FASTA_RECOMBINE' assert process.success assert snapshot(process.out).match() } diff --git a/modules/ensembl/fasta/recombine/tests/main.nf.test.snap b/modules/ensembl/fasta/recombine/tests/main.nf.test.snap index c138427..59a7453 100644 --- a/modules/ensembl/fasta/recombine/tests/main.nf.test.snap +++ b/modules/ensembl/fasta/recombine/tests/main.nf.test.snap @@ -3,82 +3,38 @@ "content": [ { "0": [ - [ - { + { + "meta": { "id": "test" }, - "test.fa:md5,c40116e7d725da4662e6bdd654f70075" - ] - ], - "1": [ - [ - "FASTA_RECOMBINE", - "fasta_recombine", - "1.7.0" - ] - ], - "recombined_fasta": [ - [ - { - "id": "test" - }, - "test.fa:md5,c40116e7d725da4662e6bdd654f70075" - ] - ], - "versions_fasta_recombine": [ - [ - "FASTA_RECOMBINE", - "fasta_recombine", - "1.7.0" - ] + "recombined_fasta": "test.fa:md5,c40116e7d725da4662e6bdd654f70075" + } ] } ], - "timestamp": "2026-06-11T18:08:46.722339", + "timestamp": "2026-09-29T12:53:47.242818", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.3" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } }, "stub outputs: header mode": { "content": [ { "0": [ - [ - { - "id": "test" - }, - "test.fa:md5,c40116e7d725da4662e6bdd654f70075" - ] - ], - "1": [ - [ - "FASTA_RECOMBINE", - "fasta_recombine", - "1.7.0" - ] - ], - "recombined_fasta": [ - [ - { + { + "meta": { "id": "test" }, - "test.fa:md5,c40116e7d725da4662e6bdd654f70075" - ] - ], - "versions_fasta_recombine": [ - [ - "FASTA_RECOMBINE", - "fasta_recombine", - "1.7.0" - ] + "recombined_fasta": "test.fa:md5,c40116e7d725da4662e6bdd654f70075" + } ] } ], - "timestamp": "2026-06-11T18:08:44.434921", + "timestamp": "2026-09-29T12:53:44.690151", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.3" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } } } \ No newline at end of file diff --git a/modules/ensembl/fasta/split/main.nf b/modules/ensembl/fasta/split/main.nf index ccccffa..c57f67b 100644 --- a/modules/ensembl/fasta/split/main.nf +++ b/modules/ensembl/fasta/split/main.nf @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +nextflow.enable.types = true + process FASTA_SPLIT { tag "${meta.id}" label 'process_medium' @@ -21,12 +23,17 @@ process FASTA_SPLIT { container "docker.io/ensemblorg/ensembl-genomio:v1.7.0" input: - tuple val(meta), path(fasta), val(longest_seq_bp) + record(meta: Map, fasta: Path, longest_seq_bp: Integer) output: - tuple val(meta), path("splits/**/*.fa"), emit: fastas - tuple val(meta), path("splits/*.agp"), emit: agp, optional: true - tuple val("${task.process}"), val('fasta_split'), eval("fasta_split --version"), emit: versions_fasta_split, topic: versions + record( + meta: meta, + fastas: files("splits/**/*.fa"), + agp: file("splits/*.agp", optional: true) + ) + + topic: + tuple(task.process, 'fasta_split', eval("fasta_split --version 2>/dev/null || echo unknown")) >> 'versions' when: task.ext.when == null || task.ext.when diff --git a/modules/ensembl/fasta/split/meta.yml b/modules/ensembl/fasta/split/meta.yml index 1e10f3a..ec2c04b 100644 --- a/modules/ensembl/fasta/split/meta.yml +++ b/modules/ensembl/fasta/split/meta.yml @@ -55,16 +55,6 @@ output: pattern: "splits/*.agp" ontologies: - edam: "http://edamontology.org/format_3693" # AGP - versions_fasta_split: - - - ${task.process}: - type: string - description: The name of the process. - - fasta_split: - type: string - description: The name of the tool. - - "fasta_split --version": - type: eval - description: The expression to obtain the version of the tool topics: versions: - - ${task.process}: @@ -73,7 +63,7 @@ topics: - fasta_split: type: string description: The name of the tool. - - "fasta_split --version": + - "fasta_split --version 2>/dev/null || echo unknown": type: eval description: The expression to obtain the version of the tool authors: diff --git a/modules/ensembl/fasta/split/tests/main.nf.test b/modules/ensembl/fasta/split/tests/main.nf.test index 79d4c07..7c3b40d 100644 --- a/modules/ensembl/fasta/split/tests/main.nf.test +++ b/modules/ensembl/fasta/split/tests/main.nf.test @@ -24,6 +24,7 @@ nextflow_process { tag "modules_ensembl" tag "fasta" tag "fasta/split" + topics "versions" test("stub outputs: default layout, no AGP") { @@ -38,28 +39,33 @@ nextflow_process { process { """ - input[0] = [[ id:'test' ], file('dummy.fa'), 1000] + input[0] = record(meta: [ id:'test' ], fasta: file('dummy.fa'), longest_seq_bp: 1000) """ } } then { - assert snapshot(process.out).match() + assert snapshot( + process.out[0].collect { output -> [ meta: output.meta, fastas: output.fastas.collect { path(it).toFile().name }.sort(), agp: output.agp ] }, + topics.versions + ).match() - assert process.out.fastas != null - assert process.out.fastas.size() == 1 + assert process.out[0] != null + assert process.out[0].size() == 1 - def fasta_out = process.out.fastas[0] - def meta = fasta_out[0] - def fas = fasta_out[1] + def fasta_out = process.out[0][0] + def meta = fasta_out.meta + def fas = fasta_out.fastas assert meta.id == "test" assert fas != null assert fas.size() == 2 assert fas.collect { path(it).toFile().name }.sort() == ["test.1.fa", "test.2.fa"] - assert process.out.agp != null - assert process.out.agp.size() == 0 + assert process.out[0][0].agp == null + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FASTA_SPLIT' assertAll( { assert process.success } @@ -79,23 +85,25 @@ nextflow_process { process { """ - input[0] = [[ id:'test' ], file('dummy.fa'), 1000] + input[0] = record(meta: [ id:'test' ], fasta: file('dummy.fa'), longest_seq_bp: 1000) """ } } then { - assert snapshot(process.out).match() - - assert process.out.fastas.size() == 1 - def fasta_out = process.out.fastas[0] - def fas = fasta_out[1] + assert snapshot( + process.out[0].collect { output -> [ meta: output.meta, fastas: output.fastas.collect { path(it).toFile().name }.sort(), agp: output.agp ] }, + topics.versions + ).match() + + assert process.out[0].size() == 1 + def fasta_out = process.out[0][0] + def fas = fasta_out.fastas assert fas.size() == 2 - assert process.out.agp.size() == 1 - def agp_out = process.out.agp[0] - def agp_meta = agp_out[0] - def agp = agp_out[1] + def agp_out = process.out[0][0] + def agp_meta = agp_out.meta + def agp = agp_out.agp def agp_paths = agp instanceof List ? agp : [agp] def agp_file = path(agp_paths[0]).toFile() @@ -121,19 +129,22 @@ nextflow_process { process { """ - input[0] = [[ id:'test' ], file('dummy.fa'), 1000] + input[0] = record(meta: [ id:'test' ], fasta: file('dummy.fa'), longest_seq_bp: 1000) """ } } then { - assert snapshot(process.out).match() + assert snapshot( + process.out[0].collect { output -> [ meta: output.meta, fastas: output.fastas.collect { path(it).toFile().name }.sort(), agp: output.agp ] }, + topics.versions + ).match() - def fasta_out = process.out.fastas[0] - def fas = fasta_out[1] + def fasta_out = process.out[0][0] + def fas = fasta_out.fastas assert fas.size() == 2 - assert process.out.agp.size() == 0 + assert process.out[0][0].agp == null // Contract check: names match the unique fixture pattern assert fas.collect { path(it).toFile().name }.sort() == ["test.0.1.fa", "test.0.2.fa"] @@ -158,17 +169,20 @@ nextflow_process { process { """ - input[0] = [[ id:'test' ], file('dummy.fa'), 1000] + input[0] = record(meta: [ id:'test' ], fasta: file('dummy.fa'), longest_seq_bp: 1000) """ } } then { - assert snapshot(process.out).match() + assert snapshot( + process.out[0].collect { output -> [ meta: output.meta, fastas: output.fastas.collect { path(it).toFile().name }.sort(), agp: output.agp ] }, + topics.versions + ).match() - def fastas = process.out.fastas[0][1] + def fastas = process.out[0][0].fastas assert fastas.size() == 2 - assert process.out.agp.size() == 0 + assert process.out[0][0].agp == null def rels = fastas.collect { path(it).toString() } assert rels.any { it.contains("splits/0/0/") } diff --git a/modules/ensembl/fasta/split/tests/main.nf.test.snap b/modules/ensembl/fasta/split/tests/main.nf.test.snap index d35b001..d3327c3 100644 --- a/modules/ensembl/fasta/split/tests/main.nf.test.snap +++ b/modules/ensembl/fasta/split/tests/main.nf.test.snap @@ -1,224 +1,114 @@ { "stub outputs: default layout, no AGP": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - [ - "test.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "1": [ - - ], - "2": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] - ], - "agp": [ - - ], - "fastas": [ - [ - { - "id": "test" - }, - [ - "test.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "versions_fasta_split": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] + [ + { + "meta": { + "id": "test" + }, + "fastas": [ + "test.1.fa", + "test.2.fa" + ], + "agp": null + } + ], + [ + [ + "FASTA_SPLIT", + "fasta_split", + "1.7.0" ] - } + ] ], - "timestamp": "2026-06-11T18:08:56.777146", + "timestamp": "2026-09-29T12:58:12.875276", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.3" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } }, "stub outputs: AGP optional output appears when enabled": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - [ - "test.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test.agp:md5,38e242a83da3c6d49933988b89ac1ed8" - ] - ], - "2": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] - ], - "agp": [ - [ - { - "id": "test" - }, - "test.agp:md5,38e242a83da3c6d49933988b89ac1ed8" - ] - ], - "fastas": [ - [ - { - "id": "test" - }, - [ - "test.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "versions_fasta_split": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] + [ + { + "meta": { + "id": "test" + }, + "fastas": [ + "test.1.fa", + "test.2.fa" + ], + "agp": "test.agp:md5,38e242a83da3c6d49933988b89ac1ed8" + } + ], + [ + [ + "FASTA_SPLIT", + "fasta_split", + "1.7.0" ] - } + ] ], - "timestamp": "2026-06-11T18:08:59.155435", + "timestamp": "2026-09-29T12:58:15.411763", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.3" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } }, "stub outputs: nested directory layout contract": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - [ - "test.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "1": [ - - ], - "2": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] - ], - "agp": [ - - ], - "fastas": [ - [ - { - "id": "test" - }, - [ - "test.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "versions_fasta_split": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] + [ + { + "meta": { + "id": "test" + }, + "fastas": [ + "test.1.fa", + "test.2.fa" + ], + "agp": null + } + ], + [ + [ + "FASTA_SPLIT", + "fasta_split", + "1.7.0" ] - } + ] ], - "timestamp": "2026-06-11T18:09:03.870638", + "timestamp": "2026-09-29T12:58:20.662075", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.3" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } }, "stub outputs: unique_file_names contract": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - [ - "test.0.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.0.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "1": [ - - ], - "2": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] - ], - "agp": [ - - ], - "fastas": [ - [ - { - "id": "test" - }, - [ - "test.0.1.fa:md5,9470e6594eeaecc474f45f1dbcc040bd", - "test.0.2.fa:md5,9470e6594eeaecc474f45f1dbcc040bd" - ] - ] - ], - "versions_fasta_split": [ - [ - "FASTA_SPLIT", - "fasta_split", - "1.7.0" - ] + [ + { + "meta": { + "id": "test" + }, + "fastas": [ + "test.0.1.fa", + "test.0.2.fa" + ], + "agp": null + } + ], + [ + [ + "FASTA_SPLIT", + "fasta_split", + "1.7.0" ] - } + ] ], - "timestamp": "2026-06-11T18:09:01.510794", + "timestamp": "2026-09-29T12:58:17.991847", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.3" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } } -} \ No newline at end of file +} diff --git a/modules/ensembl/fasta/stats/main.nf b/modules/ensembl/fasta/stats/main.nf index 94c404f..3456982 100644 --- a/modules/ensembl/fasta/stats/main.nf +++ b/modules/ensembl/fasta/stats/main.nf @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +nextflow.enable.types = true + process FASTA_STATS { tag "${meta.id}" @@ -22,11 +24,13 @@ process FASTA_STATS { container "docker.io/ensemblorg/ensembl-genomio:v1.7.0" input: - tuple val(meta), path(fasta) + record(meta: Map, fasta: Path) output: - tuple val(meta), path("${fasta.simpleName}.stats.json"), emit: stats - tuple val("${task.process}"), val('fasta_stats'), eval("fasta_stats --version"), emit: versions_fasta_stats, topic: versions + record(meta: meta, stats: file("${fasta.simpleName}.stats.json")) + + topic: + tuple(task.process, 'fasta_stats', eval("fasta_stats --version 2>/dev/null || echo unknown")) >> 'versions' script: """ diff --git a/modules/ensembl/fasta/stats/meta.yml b/modules/ensembl/fasta/stats/meta.yml index 608ec4b..f5dcb25 100644 --- a/modules/ensembl/fasta/stats/meta.yml +++ b/modules/ensembl/fasta/stats/meta.yml @@ -13,22 +13,23 @@ authors: - "ensembl-dev@ebi.ac.uk" input: - - meta: - type: map - description: Groovy meta map - - fasta: - type: file - description: FASTA file - pattern: "*.{fa,fasta,fna,fa.gz,fasta.gz,fna.gz}" + - - meta: + type: map + description: Groovy meta map + - fasta: + type: file + description: FASTA file + pattern: "*.{fa,fasta,fna,fa.gz,fasta.gz,fna.gz}" output: - - meta: - type: map - description: Groovy meta map - - stats: - type: file - description: JSON file containing FASTA statistics - pattern: "*.stats.json" + stats: + - - meta: + type: map + description: Groovy meta map + - stats: + type: file + description: JSON file containing FASTA statistics + pattern: "*.stats.json" topics: versions: @@ -38,6 +39,6 @@ topics: - fasta_stats: type: string description: The name of the tool. - - ? fasta_stats --version + - ? fasta_stats --version 2>/dev/null || echo unknown : type: eval - description: The expression to obtain the version of the tool \ No newline at end of file + description: The expression to obtain the version of the tool diff --git a/modules/ensembl/fasta/stats/tests/main.nf.test b/modules/ensembl/fasta/stats/tests/main.nf.test index f31bcb2..8e60b7e 100644 --- a/modules/ensembl/fasta/stats/tests/main.nf.test +++ b/modules/ensembl/fasta/stats/tests/main.nf.test @@ -23,6 +23,7 @@ nextflow_process { tag "modules_local" tag "fasta" tag "fasta/stats" + topics "versions" test("Stub outputs stats tuple and versions") { @@ -33,7 +34,7 @@ nextflow_process { """ def fasta = file("input.fa") - input[0] = [[ id:'test' ], fasta] + input[0] = record(meta: [ id:'test' ], fasta: fasta) """ } } @@ -41,11 +42,14 @@ nextflow_process { then { assert process.success assert process.trace.tasks().size() == 1 - assert process.out.stats.size() == 1 + assert process.out[0].size() == 1 - def stats_out = process.out.stats[0] - assert stats_out[0].id == "test" - assert file(stats_out[1]).name == "input.stats.json" + def stats_out = process.out[0][0] + assert stats_out.meta.id == "test" + assert file(stats_out.stats).name == "input.stats.json" + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FASTA_STATS' assert snapshot(process.out).match() } } diff --git a/modules/ensembl/fasta/stats/tests/main.nf.test.snap b/modules/ensembl/fasta/stats/tests/main.nf.test.snap index 8bb9783..e2bbf56 100644 --- a/modules/ensembl/fasta/stats/tests/main.nf.test.snap +++ b/modules/ensembl/fasta/stats/tests/main.nf.test.snap @@ -3,38 +3,16 @@ "content": [ { "0": [ - [ - { + { + "meta": { "id": "test" }, - "input.stats.json:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - "FASTA_STATS", - "fasta_stats", - "1.7.0" - ] - ], - "stats": [ - [ - { - "id": "test" - }, - "input.stats.json:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions_fasta_stats": [ - [ - "FASTA_STATS", - "fasta_stats", - "1.7.0" - ] + "stats": "input.stats.json:md5,d41d8cd98f00b204e9800998ecf8427e" + } ] } ], - "timestamp": "2026-06-17T21:16:28.217339", + "timestamp": "2026-09-29T12:53:55.741606", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.3" diff --git a/modules/ensembl/features/combine_json/main.nf b/modules/ensembl/features/combine_json/main.nf index 2ffe177..1ec1033 100644 --- a/modules/ensembl/features/combine_json/main.nf +++ b/modules/ensembl/features/combine_json/main.nf @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +nextflow.enable.types = true + process FEATURES_COMBINE_JSON { tag "${meta.id}" label 'process_medium' @@ -21,11 +23,18 @@ process FEATURES_COMBINE_JSON { container "docker.io/ensemblorg/ensembl-genomio:v1.7.0" input: - tuple val(meta), val(analysis), path(json_manifest), path(agp) + record( + meta: Map, + analysis: String, + json_manifest: Path, + agp: Path? + ) output: - tuple val(meta), path("${meta.id}.${analysis}.json"), emit: combined_json - tuple val("${task.process}"), val('features_combine_json'), eval("features_combine_json --version"), emit: versions_features_combine_json, topic: versions + record(meta: meta, combined_json: file("${meta.id}.${analysis}.json")) + + topic: + tuple(task.process, 'features_combine_json', eval("features_combine_json --version 2>/dev/null || echo unknown")) >> 'versions' when: task.ext.when == null || task.ext.when diff --git a/modules/ensembl/features/combine_json/meta.yml b/modules/ensembl/features/combine_json/meta.yml index 90a7b78..461904a 100644 --- a/modules/ensembl/features/combine_json/meta.yml +++ b/modules/ensembl/features/combine_json/meta.yml @@ -49,16 +49,6 @@ output: pattern: "*.json" ontologies: - edam: http://edamontology.org/format_3464 # JSON - versions_features_combine_json: - - - ${task.process}: - type: string - description: The name of the process. - - features_combine_json: - type: string - description: The name of the tool. - - "features_combine_json --version": - type: eval - description: The expression to obtain the version of the tool topics: versions: - - ${task.process}: @@ -67,7 +57,7 @@ topics: - features_combine_json: type: string description: The name of the tool. - - "features_combine_json --version": + - "features_combine_json --version 2>/dev/null || echo unknown": type: eval description: The expression to obtain the version of the tool authors: diff --git a/modules/ensembl/features/combine_json/tests/main.nf.test b/modules/ensembl/features/combine_json/tests/main.nf.test index e4bc969..a203f50 100644 --- a/modules/ensembl/features/combine_json/tests/main.nf.test +++ b/modules/ensembl/features/combine_json/tests/main.nf.test @@ -24,6 +24,7 @@ nextflow_process { tag "modules_ensembl" tag "features" tag "features/combine_json" + topics "versions" test("Stub outputs") { @@ -38,19 +39,23 @@ nextflow_process { def noFile = file("NO_FILE") noFile.text = "" - input[0] = [ - [ id:'test' ], - 'features', - manifest, - noFile - ] + input[0] = record( + meta: [ id:'test' ], + analysis: 'features', + json_manifest: manifest, + agp: noFile + ) """ } } then { assert process.trace.tasks().size() == 1 - assert process.out.combined_json.size() == 1 + assert process.out[0].size() == 1 + assert file(process.out[0][0].combined_json).name == 'test.features.json' + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FEATURES_COMBINE_JSON' assert process.success assert snapshot(process.out).match() } diff --git a/modules/ensembl/features/combine_json/tests/main.nf.test.snap b/modules/ensembl/features/combine_json/tests/main.nf.test.snap index c96b73a..795b77f 100644 --- a/modules/ensembl/features/combine_json/tests/main.nf.test.snap +++ b/modules/ensembl/features/combine_json/tests/main.nf.test.snap @@ -3,41 +3,19 @@ "content": [ { "0": [ - [ - { + { + "combined_json": "test.features.json:md5,8a80554c91d9fca8acb82f023de02f11", + "meta": { "id": "test" - }, - "test.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "1": [ - [ - "FEATURES_COMBINE_JSON", - "features_combine_json", - "1.7.0" - ] - ], - "combined_json": [ - [ - { - "id": "test" - }, - "test.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "versions_features_combine_json": [ - [ - "FEATURES_COMBINE_JSON", - "features_combine_json", - "1.7.0" - ] + } + } ] } ], - "timestamp": "2026-06-11T18:09:19.997741", + "timestamp": "2026-09-29T12:53:58.29327", "meta": { - "nf-test": "0.9.4", - "nextflow": "25.10.3" + "nf-test": "0.9.5", + "nextflow": "26.04.3" } } } \ No newline at end of file diff --git a/modules/ensembl/features/convert_to_json/main.nf b/modules/ensembl/features/convert_to_json/main.nf index 12459f9..daa640a 100644 --- a/modules/ensembl/features/convert_to_json/main.nf +++ b/modules/ensembl/features/convert_to_json/main.nf @@ -13,22 +13,30 @@ // See the License for the specific language governing permissions and // limitations under the License. +nextflow.enable.types = true + process FEATURES_CONVERT_TO_JSON { tag "${meta.id}" label 'process_small' container 'docker.io/ensemblorg/ensembl-genomio:v1.7.0' input: - tuple val(meta), path(features_out), path(repeatmasker_consensus_lib) - val(analysis_logic_name) - val(program_version) - val(program_parameters) - val(annotation_provider) - val(is_primary_source) + record( + meta: Map, + features_out: Path, + repeatmasker_consensus_lib: Path?, + analysis_logic_name: String, + program_version: String, + program_parameters: String?, + annotation_provider: String?, + is_primary_source: Boolean + ) output: - tuple val(meta), path("${meta.id}.${analysis_logic_name}.features.json"), emit: features_json - tuple val("${task.process}"), val('features_convert_to_genomio_json'), eval("features_convert_to_genomio_json --version"), emit: versions_convert_to_genomio_json, topic: versions + record(meta: meta, features_json: file("${meta.id}.${analysis_logic_name}.features.json")) + + topic: + tuple(task.process, 'features_convert_to_genomio_json', eval("features_convert_to_genomio_json --version 2>/dev/null || echo unknown")) >> 'versions' script: def prefix = '' @@ -70,4 +78,4 @@ process FEATURES_CONVERT_TO_JSON { {} EOF """ -} \ No newline at end of file +} diff --git a/modules/ensembl/features/convert_to_json/meta.yml b/modules/ensembl/features/convert_to_json/meta.yml index a8c568a..3286125 100644 --- a/modules/ensembl/features/convert_to_json/meta.yml +++ b/modules/ensembl/features/convert_to_json/meta.yml @@ -62,7 +62,7 @@ input: type: boolean description: Whether the annotation provider is the primary source. output: - json: + features_json: - - meta: type: map description: | @@ -74,25 +74,15 @@ output: pattern: "*.features.json" ontologies: - edam: http://edamontology.org/format_3464 - versions_features_convert_to_json: - - - ${task.process}: - type: string - description: The name of the process. - - features_convert_to_json: - type: string - description: The name of the tool. - - ? features_convert_to_json --version - : type: eval - description: The expression to obtain the version of the tool topics: versions: - - ${task.process}: type: string description: The name of the process. - - features_convert_to_json: + - features_convert_to_genomio_json: type: string description: The name of the tool. - - ? features_convert_to_json --version + - ? features_convert_to_genomio_json --version 2>/dev/null || echo unknown : type: eval description: The expression to obtain the version of the tool authors: diff --git a/modules/ensembl/features/convert_to_json/tests/main.nf.test b/modules/ensembl/features/convert_to_json/tests/main.nf.test index 8df097e..713c381 100644 --- a/modules/ensembl/features/convert_to_json/tests/main.nf.test +++ b/modules/ensembl/features/convert_to_json/tests/main.nf.test @@ -23,6 +23,7 @@ nextflow_process { tag "modules_local" tag "features" tag "features/convert_to_json" + topics "versions" test("Stub wires TRF input mode") { @@ -37,26 +38,33 @@ nextflow_process { def noFile = file("NO_FILE") noFile.text = "" - input[0] = [[ id:'test' ], featuresOut, noFile] - input[1] = "trf" - input[2] = "4.1.7" - input[3] = "-species stub" - input[4] = "stub_provider" - input[5] = false + input[0] = record( + meta: [ id:'test' ], + features_out: featuresOut, + repeatmasker_consensus_lib: noFile, + analysis_logic_name: 'trf', + program_version: '4.1.7', + program_parameters: '-species stub', + annotation_provider: 'stub_provider', + is_primary_source: false + ) """ } } then { assert process.success - assert process.out.features_json.size() == 1 + assert process.out[0].size() == 1 - def jsonPath = process.out.features_json[0][1] + def jsonPath = process.out[0][0].features_json def jsonFile = path(jsonPath).toFile() assert jsonFile.exists() assert jsonFile.name == "test.trf.features.json" - assert process.out.features_json[0][0].id == "test" + assert process.out[0][0].meta.id == "test" + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FEATURES_CONVERT_TO_JSON' assert snapshot(process.out).match() } } @@ -74,26 +82,33 @@ nextflow_process { def noFile = file("NO_FILE") noFile.text = "" - input[0] = [[ id:'test' ], featuresOut, noFile] - input[1] = "repeatmasker_repbase" - input[2] = "4.1.7" - input[3] = "-species stub" - input[4] = "stub_provider" - input[5] = false + input[0] = record( + meta: [ id:'test' ], + features_out: featuresOut, + repeatmasker_consensus_lib: noFile, + analysis_logic_name: 'repeatmasker_repbase', + program_version: '4.1.7', + program_parameters: '-species stub', + annotation_provider: 'stub_provider', + is_primary_source: false + ) """ } } then { assert process.success - assert process.out.features_json.size() == 1 + assert process.out[0].size() == 1 - def jsonPath = process.out.features_json[0][1] + def jsonPath = process.out[0][0].features_json def jsonFile = path(jsonPath).toFile() assert jsonFile.exists() assert jsonFile.name == "test.repeatmasker_repbase.features.json" - assert process.out.features_json[0][0].id == "test" + assert process.out[0][0].meta.id == "test" + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FEATURES_CONVERT_TO_JSON' assert snapshot(process.out).match() } } @@ -111,26 +126,33 @@ nextflow_process { def consensus = file("repeatmodeler.fa") consensus.text = ">consensus\\nACGT\\n" - input[0] = [[ id:'test' ], featuresOut, consensus] - input[1] = "repeatmask_customlib" - input[2] = "4.1.7" - input[3] = "-species stub" - input[4] = "stub_provider" - input[5] = true + input[0] = record( + meta: [ id:'test' ], + features_out: featuresOut, + repeatmasker_consensus_lib: consensus, + analysis_logic_name: 'repeatmask_customlib', + program_version: '4.1.7', + program_parameters: '-species stub', + annotation_provider: 'stub_provider', + is_primary_source: true + ) """ } } then { assert process.success - assert process.out.features_json.size() == 1 + assert process.out[0].size() == 1 - def jsonPath = process.out.features_json[0][1] + def jsonPath = process.out[0][0].features_json def jsonFile = path(jsonPath).toFile() assert jsonFile.exists() assert jsonFile.name == "test.repeatmask_customlib.features.json" - assert process.out.features_json[0][0].id == "test" + assert process.out[0][0].meta.id == "test" + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FEATURES_CONVERT_TO_JSON' assert snapshot(process.out).match() } } diff --git a/modules/ensembl/features/convert_to_json/tests/main.nf.test.snap b/modules/ensembl/features/convert_to_json/tests/main.nf.test.snap index 464cbd9..0dc7c07 100644 --- a/modules/ensembl/features/convert_to_json/tests/main.nf.test.snap +++ b/modules/ensembl/features/convert_to_json/tests/main.nf.test.snap @@ -3,38 +3,16 @@ "content": [ { "0": [ - [ - { + { + "features_json": "test.repeatmask_customlib.features.json:md5,8a80554c91d9fca8acb82f023de02f11", + "meta": { "id": "test" - }, - "test.repeatmask_customlib.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "1": [ - [ - "FEATURES_CONVERT_TO_JSON", - "features_convert_to_genomio_json", - "1.7.0" - ] - ], - "features_json": [ - [ - { - "id": "test" - }, - "test.repeatmask_customlib.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "versions_convert_to_genomio_json": [ - [ - "FEATURES_CONVERT_TO_JSON", - "features_convert_to_genomio_json", - "1.7.0" - ] + } + } ] } ], - "timestamp": "2026-06-23T11:49:16.328488", + "timestamp": "2026-09-29T12:54:04.437296", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.3" @@ -44,38 +22,16 @@ "content": [ { "0": [ - [ - { - "id": "test" - }, - "test.repeatmasker_repbase.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "1": [ - [ - "FEATURES_CONVERT_TO_JSON", - "features_convert_to_genomio_json", - "1.7.0" - ] - ], - "features_json": [ - [ - { + { + "features_json": "test.repeatmasker_repbase.features.json:md5,8a80554c91d9fca8acb82f023de02f11", + "meta": { "id": "test" - }, - "test.repeatmasker_repbase.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "versions_convert_to_genomio_json": [ - [ - "FEATURES_CONVERT_TO_JSON", - "features_convert_to_genomio_json", - "1.7.0" - ] + } + } ] } ], - "timestamp": "2026-06-23T11:49:13.92402", + "timestamp": "2026-09-29T12:54:02.363885", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.3" @@ -85,38 +41,16 @@ "content": [ { "0": [ - [ - { - "id": "test" - }, - "test.trf.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "1": [ - [ - "FEATURES_CONVERT_TO_JSON", - "features_convert_to_genomio_json", - "1.7.0" - ] - ], - "features_json": [ - [ - { + { + "features_json": "test.trf.features.json:md5,8a80554c91d9fca8acb82f023de02f11", + "meta": { "id": "test" - }, - "test.trf.features.json:md5,8a80554c91d9fca8acb82f023de02f11" - ] - ], - "versions_convert_to_genomio_json": [ - [ - "FEATURES_CONVERT_TO_JSON", - "features_convert_to_genomio_json", - "1.7.0" - ] + } + } ] } ], - "timestamp": "2026-06-23T11:49:11.562335", + "timestamp": "2026-09-29T12:54:00.329076", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.3" diff --git a/modules/ensembl/features/red/main.nf b/modules/ensembl/features/red/main.nf index 063ffa1..5e378d1 100644 --- a/modules/ensembl/features/red/main.nf +++ b/modules/ensembl/features/red/main.nf @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +nextflow.enable.types = true + process FEATURES_RED { tag "${meta.id}" label 'process_medium' @@ -21,11 +23,13 @@ process FEATURES_RED { container "quay.io/biocontainers/red:2018.09.10--h9948957_3" input: - tuple val(meta), path(fasta) + record(meta: Map, fasta: Path) output: - tuple val(meta), path("rpt/*.bed"), emit: bed - tuple val("${task.process}"), val('red'), eval("conda list red --json | python -c 'import sys,json; print(json.load(sys.stdin)[0][\"version\"])' || echo 2.0"), emit: versions_red, topic: versions + record(meta: meta, bed: file("rpt/*.bed")) + + topic: + tuple(task.process, 'red', eval("conda list red --json | python -c 'import sys,json; print(json.load(sys.stdin)[0][\"version\"])' || echo 2.0")) >> 'versions' when: task.ext.when == null || task.ext.when diff --git a/modules/ensembl/features/red/meta.yml b/modules/ensembl/features/red/meta.yml index 93d1319..05452dc 100644 --- a/modules/ensembl/features/red/meta.yml +++ b/modules/ensembl/features/red/meta.yml @@ -30,7 +30,7 @@ input: ontologies: - edam: "http://edamontology.org/format_1929" # FASTA output: - rpt: + bed: - - meta: type: map description: | @@ -40,16 +40,6 @@ output: type: file description: Red repeat report file. pattern: "*.bed" - versions_red: - - - ${task.process}: - type: string - description: The process the versions were collected from - - red: - type: string - description: The tool name - - conda list red --json | python -c 'import sys,json; print(json.load(sys.stdin)[0]["version"])' || echo 2.0: - type: eval - description: The expression to obtain the Red version topics: versions: - - ${task.process}: diff --git a/modules/ensembl/features/red/tests/main.nf.test b/modules/ensembl/features/red/tests/main.nf.test index 0371ef2..946bef0 100644 --- a/modules/ensembl/features/red/tests/main.nf.test +++ b/modules/ensembl/features/red/tests/main.nf.test @@ -23,6 +23,7 @@ nextflow_process { tag "modules_local" tag "features" tag "features/red" + topics "versions" test("Stub creates Red repeat report") { @@ -34,7 +35,7 @@ nextflow_process { def fasta = file("test.fa") fasta.text = ">test\\nACGT\\n" - input[0] = [[ id:'test' ], fasta] + input[0] = record(meta: [ id:'test' ], fasta: fasta) """ } } @@ -42,11 +43,13 @@ nextflow_process { then { assert process.success assert snapshot(process.out).match() - assert process.out.bed.size() == 1 - assert process.out.bed[0][0] == [ id: 'test' ] - assert file(process.out.bed[0][1]).name == "test.bed" - assert file(process.out.bed[0][1]).size() > 0 - assert process.out.versions_red.size() == 1 + assert process.out[0].size() == 1 + assert process.out[0][0].meta == [ id: 'test' ] + assert file(process.out[0][0].bed).name == "test.bed" + assert file(process.out[0][0].bed).size() > 0 + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FEATURES_RED' } } } diff --git a/modules/ensembl/features/red/tests/main.nf.test.snap b/modules/ensembl/features/red/tests/main.nf.test.snap index 3414eb0..7648c3c 100644 --- a/modules/ensembl/features/red/tests/main.nf.test.snap +++ b/modules/ensembl/features/red/tests/main.nf.test.snap @@ -3,38 +3,16 @@ "content": [ { "0": [ - [ - { + { + "bed": "test.bed:md5,aa604b48150afc506072a1f9656b6bb7", + "meta": { "id": "test" - }, - "test.bed:md5,aa604b48150afc506072a1f9656b6bb7" - ] - ], - "1": [ - [ - "FEATURES_RED", - "red", - "2.0" - ] - ], - "bed": [ - [ - { - "id": "test" - }, - "test.bed:md5,aa604b48150afc506072a1f9656b6bb7" - ] - ], - "versions_red": [ - [ - "FEATURES_RED", - "red", - "2.0" - ] + } + } ] } ], - "timestamp": "2026-07-14T16:03:16.866216", + "timestamp": "2026-09-29T12:54:06.783701", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.3" diff --git a/modules/ensembl/features/trf/main.nf b/modules/ensembl/features/trf/main.nf index 475dba6..55267c0 100644 --- a/modules/ensembl/features/trf/main.nf +++ b/modules/ensembl/features/trf/main.nf @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +nextflow.enable.types = true + process FEATURES_TRF { tag "${meta.id}" label 'process_medium' @@ -21,11 +23,13 @@ process FEATURES_TRF { container "quay.io/biocontainers/trf:4.10.0rc2--h7b50bb2_0" input: - tuple val(meta), path(fasta) + record(meta: Map, fasta: Path) output: - tuple val(meta), path("*.dat"), emit: dat - tuple val("${task.process}"), val('trf'), eval("trf -v 2>&1 | grep -oE '[0-9]+(\\.[0-9]+)+(rc[0-9]+)?(-[0-9]+)?' || echo 4.10.0"), emit: versions_trf, topic: versions + record(meta: meta, dat: file("*.dat")) + + topic: + tuple(task.process, 'trf', eval("trf -v 2>&1 | grep -oE '[0-9]+(\\.[0-9]+)+(rc[0-9]+)?(-[0-9]+)?' || echo 4.10.0")) >> 'versions' when: task.ext.when == null || task.ext.when diff --git a/modules/ensembl/features/trf/meta.yml b/modules/ensembl/features/trf/meta.yml index 043433c..0855ac9 100644 --- a/modules/ensembl/features/trf/meta.yml +++ b/modules/ensembl/features/trf/meta.yml @@ -39,16 +39,6 @@ output: type: file description: TRF repeat annotations in DAT format pattern: "*.dat" - versions_trf: - - - ${task.process}: - type: string - description: The process the versions were collected from - - trf: - type: string - description: The tool name - - trf -v 2>&1 | grep -oE '[0-9]+(\\.[0-9]+)+(rc[0-9]+)?(-[0-9]+)?' || echo 4.10.0: - type: eval - description: The expression to obtain the TRF version topics: versions: - - ${task.process}: diff --git a/modules/ensembl/features/trf/tests/main.nf.test b/modules/ensembl/features/trf/tests/main.nf.test index 348c575..ff4721c 100644 --- a/modules/ensembl/features/trf/tests/main.nf.test +++ b/modules/ensembl/features/trf/tests/main.nf.test @@ -22,6 +22,7 @@ nextflow_process { tag "features" tag "features/trf" + topics "versions" test("Stub: TRF") { when { @@ -29,8 +30,7 @@ nextflow_process { process { """ - input[0] = [[ id: 'test' ],file('dummy.fa') - ] + input[0] = record(meta: [ id: 'test' ], fasta: file('dummy.fa')) """ } } @@ -38,11 +38,13 @@ nextflow_process { then { assert process.success assert snapshot(process.out).match() - assert process.out.dat.size() == 1 - assert process.out.dat[0][0] == [ id: 'test' ] - assert file(process.out.dat[0][1]).name == 'dummy.fa.dat' - assert file(process.out.dat[0][1]).size() > 0 - assert process.out.versions_trf.size() == 1 + assert process.out[0].size() == 1 + assert process.out[0][0].meta == [ id: 'test' ] + assert file(process.out[0][0].dat).name == 'dummy.fa.dat' + assert file(process.out[0][0].dat).size() > 0 + assert topics.versions.size() == 1 + assert topics.versions[0].size() == 3 + assert topics.versions[0][0] == 'FEATURES_TRF' } } } diff --git a/modules/ensembl/features/trf/tests/main.nf.test.snap b/modules/ensembl/features/trf/tests/main.nf.test.snap index 7325e37..92300cd 100644 --- a/modules/ensembl/features/trf/tests/main.nf.test.snap +++ b/modules/ensembl/features/trf/tests/main.nf.test.snap @@ -3,38 +3,16 @@ "content": [ { "0": [ - [ - { + { + "dat": "dummy.fa.dat:md5,7afa5cc8da76212b28fe6a2c4db74917", + "meta": { "id": "test" - }, - "dummy.fa.dat:md5,7afa5cc8da76212b28fe6a2c4db74917" - ] - ], - "1": [ - [ - "FEATURES_TRF", - "trf", - "4.10.0" - ] - ], - "dat": [ - [ - { - "id": "test" - }, - "dummy.fa.dat:md5,7afa5cc8da76212b28fe6a2c4db74917" - ] - ], - "versions_trf": [ - [ - "FEATURES_TRF", - "trf", - "4.10.0" - ] + } + } ] } ], - "timestamp": "2026-06-25T13:50:41.590756", + "timestamp": "2026-09-29T12:54:08.817888", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.3"