diff --git a/README.md b/README.md index ec93644..a80be07 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ nextflow run nf-core/seqsubmit \ -profile \ --mode \ --input \ - --centre_name \ + --center_name \ --submission_study \ --outdir ``` diff --git a/bin/submit_study.py b/bin/submit_study.py index 5c9a7ff..7ed0857 100755 --- a/bin/submit_study.py +++ b/bin/submit_study.py @@ -308,6 +308,9 @@ def build_submission_xml( hold_until: str | None = None, action: str = "ADD", test: bool = False, + center_name: str | None = None, + submission_tool: str | None = None, + submission_tool_version: str | None = None, ) -> ET.Element: """Build a ```` XML document for submitting studies. @@ -319,6 +322,12 @@ def build_submission_xml( or ``"MODIFY"`` to update existing ones. test: If ``True``, append a timestamp-based hash to aliases for uniqueness in test submissions. + center_name: Optional submitting center name, set as the + ``center_name`` attribute of each ````. + submission_tool: Optional name of the tool used for submission, + added as ``SUBMISSION_TOOL`` project attribute. + submission_tool_version: Optional version of the submission tool, + added as ``SUBMISSION_TOOL_VERSION`` project attribute. Returns: Root ```` element. @@ -342,7 +351,13 @@ def build_submission_xml( # PROJECT_SET project_set = ET.SubElement(webin, "PROJECT_SET") for study in studies: - _add_project_element(project_set, study, test=test) + _add_project_element( + project_set, study, + test=test, + center_name=center_name, + submission_tool=submission_tool, + submission_tool_version=submission_tool_version, + ) return webin @@ -350,6 +365,9 @@ def _add_project_element( project_set: ET.Element, study: dict[str, Any], test: bool = False, + center_name: str | None = None, + submission_tool: str | None = None, + submission_tool_version: str | None = None, ) -> None: """Append a ```` element to *project_set*.""" alias = study.get("alias", "") @@ -362,6 +380,8 @@ def _add_project_element( project = ET.SubElement(project_set, "PROJECT") project.set("alias", alias) + if center_name: + project.set("center_name", center_name) name_text = study.get("project_name", study.get("study_title", "")) if name_text: @@ -381,19 +401,25 @@ def _add_project_element( sp = ET.SubElement(project, "SUBMISSION_PROJECT") ET.SubElement(sp, "SEQUENCING_PROJECT") + + project_attributes: list[tuple[str, str]] = [] study_type = study.get("existing_study_type") if study_type: + project_attributes.append(("existing_study_type", study_type)) + new_type = study.get("new_study_type") + if new_type and study_type == "Other": + project_attributes.append(("new_study_type", new_type)) + if submission_tool: + project_attributes.append(("SUBMISSION_TOOL", submission_tool)) + if submission_tool_version: + project_attributes.append(("SUBMISSION_TOOL_VERSION", submission_tool_version)) + + if project_attributes: attrs = ET.SubElement( project, "PROJECT_ATTRIBUTES", ) - _add_project_attribute( - attrs, "existing_study_type", study_type, - ) - new_type = study.get("new_study_type") - if new_type and study_type == "Other": - _add_project_attribute( - attrs, "new_study_type", new_type, - ) + for tag_text, value_text in project_attributes: + _add_project_attribute(attrs, tag_text, value_text) def _add_project_attribute( @@ -559,6 +585,21 @@ def _do_submission( default=None, help="Path to write JSON accession results (default: stdout)", ) +@click.option( + "--center-name", + default=None, + help="Submitting center name, added as center_name to each study", +) +@click.option( + "--submission-tool", + default=None, + help="Name of the tool used for submission, added as SUBMISSION_TOOL study attribute", +) +@click.option( + "--submission-tool-version", + default=None, + help="Version of the submission tool, added as SUBMISSION_TOOL_VERSION study attribute", +) @click.option( "--validate", is_flag=True, default=False, @@ -569,6 +610,9 @@ def main( use_test: bool, hold_until: str | None, output: Path | None, + center_name: str | None, + submission_tool: str | None, + submission_tool_version: str | None, validate: bool, ) -> None: """Submit studies to ENA via the Webin REST API v2.""" @@ -606,6 +650,9 @@ def main( hold_until=hold_until, action="ADD", test=use_test, + center_name=center_name, + submission_tool=submission_tool, + submission_tool_version=submission_tool_version, ) xml_bytes = xml_to_bytes(xml_root) logger.info("XML document size: %d bytes", len(xml_bytes)) diff --git a/conf/modules.config b/conf/modules.config index c14d7f2..3a8bab8 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -188,6 +188,10 @@ process { ] } + withName: 'REGISTERSTUDY' { + ext.args = { "--submission-tool '${workflow.manifest.name}' --submission-tool-version '${workflow.manifest.version}'" } + } + withName: 'GENERATE_ASSEMBLY_MANIFEST' { errorStrategy = { task.exitStatus in (1 + (130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 3 diff --git a/conf/test.config b/conf/test.config index 9334767..eb95428 100644 --- a/conf/test.config +++ b/conf/test.config @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_assembly_complete_metadata.config b/conf/test_assembly_complete_metadata.config index 615e871..8d37797 100644 --- a/conf/test_assembly_complete_metadata.config +++ b/conf/test_assembly_complete_metadata.config @@ -29,7 +29,7 @@ params { mode = "metagenomic_assemblies" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/conf/test_assembly_complete_metadata_existing_study.config b/conf/test_assembly_complete_metadata_existing_study.config index f526e9f..e2a795e 100644 --- a/conf/test_assembly_complete_metadata_existing_study.config +++ b/conf/test_assembly_complete_metadata_existing_study.config @@ -28,7 +28,7 @@ params { mode = "metagenomic_assemblies" submission_study = "PRJEB98843" - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/conf/test_assembly_no_coverage_paired_reads.config b/conf/test_assembly_no_coverage_paired_reads.config index 4afb1d8..da90b50 100644 --- a/conf/test_assembly_no_coverage_paired_reads.config +++ b/conf/test_assembly_no_coverage_paired_reads.config @@ -29,7 +29,7 @@ params { mode = "metagenomic_assemblies" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/conf/test_assembly_no_coverage_single_reads.config b/conf/test_assembly_no_coverage_single_reads.config index de9e064..b8fc5eb 100644 --- a/conf/test_assembly_no_coverage_single_reads.config +++ b/conf/test_assembly_no_coverage_single_reads.config @@ -29,7 +29,7 @@ params { mode = "metagenomic_assemblies" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/conf/test_assembly_one_contig.config b/conf/test_assembly_one_contig.config index fcb7bc7..0f2cd80 100644 --- a/conf/test_assembly_one_contig.config +++ b/conf/test_assembly_one_contig.config @@ -29,7 +29,7 @@ params { mode = "metagenomic_assemblies" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/conf/test_full.config b/conf/test_full.config index b7278aa..7adf1d5 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -21,7 +21,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_complete_metadata.config b/conf/test_mag_complete_metadata.config index 4a1689e..7758fdd 100644 --- a/conf/test_mag_complete_metadata.config +++ b/conf/test_mag_complete_metadata.config @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_complete_metadata_existing_study.conf b/conf/test_mag_complete_metadata_existing_study.conf index edfba5a..9edd925 100644 --- a/conf/test_mag_complete_metadata_existing_study.conf +++ b/conf/test_mag_complete_metadata_existing_study.conf @@ -28,7 +28,7 @@ params { mode = "mags" submission_study = "PRJEB98843" - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_no_coverage_paired_reads.conf b/conf/test_mag_no_coverage_paired_reads.conf index 920e926..02f17ba 100644 --- a/conf/test_mag_no_coverage_paired_reads.conf +++ b/conf/test_mag_no_coverage_paired_reads.conf @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_no_coverage_single_reads.conf b/conf/test_mag_no_coverage_single_reads.conf index ebbc5ce..838e3d6 100644 --- a/conf/test_mag_no_coverage_single_reads.conf +++ b/conf/test_mag_no_coverage_single_reads.conf @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_no_quality.conf b/conf/test_mag_no_quality.conf index 4b8e12c..0570fa5 100644 --- a/conf/test_mag_no_quality.conf +++ b/conf/test_mag_no_quality.conf @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_no_rna_presence.conf b/conf/test_mag_no_rna_presence.conf index d9d2990..0b4ebde 100644 --- a/conf/test_mag_no_rna_presence.conf +++ b/conf/test_mag_no_rna_presence.conf @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_no_taxonomy.conf b/conf/test_mag_no_taxonomy.conf index 3fea804..6875ffa 100644 --- a/conf/test_mag_no_taxonomy.conf +++ b/conf/test_mag_no_taxonomy.conf @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_mag_one_contig.conf b/conf/test_mag_one_contig.conf index 06ec0ec..1ec44d7 100644 --- a/conf/test_mag_one_contig.conf +++ b/conf/test_mag_one_contig.conf @@ -29,7 +29,7 @@ params { mode = "mags" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true diff --git a/conf/test_reads_long_bam.config b/conf/test_reads_long_bam.config index a0dca38..1f8b1fe 100644 --- a/conf/test_reads_long_bam.config +++ b/conf/test_reads_long_bam.config @@ -30,7 +30,7 @@ params { webincli_mode = "submit" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/conf/test_reads_long_bam_validate.config b/conf/test_reads_long_bam_validate.config index 6d5ff0a..3b5a091 100644 --- a/conf/test_reads_long_bam_validate.config +++ b/conf/test_reads_long_bam_validate.config @@ -29,7 +29,7 @@ params { mode = "reads" webincli_mode = "validate" submission_study = "PRJEB98843" - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/conf/test_reads_paired.config b/conf/test_reads_paired.config index d4bbd08..94fac5d 100644 --- a/conf/test_reads_paired.config +++ b/conf/test_reads_paired.config @@ -29,7 +29,7 @@ params { mode = "reads" submission_study = null study_metadata = params.pipelines_testdata_base_path + 'seqsubmit/test_data/study_metadata/study_metadata.json' - centre_name = "TEST_CENTER" + center_name = "TEST_CENTER" test_upload = true } diff --git a/docs/usage.md b/docs/usage.md index a8ab3c5..25bbb84 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -354,7 +354,7 @@ In addition to the [common parameters](#running-the-pipeline): | Parameter | Required | Description | | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--upload_tpa` | No | Mark assemblies as [third party assemblies (TPA)](#third-party-assemblies-tpa) when required. Default: `false`. | +| `--upload_tpa` | No | Mark submission as [third party assemblies (TPA)](#third-party-assemblies-tpa) when required. Default: `false`. | | `--checkm2_db` | No | Path to a pre-downloaded CheckM2 database. If omitted, downloads the version set by `--checkm2_db_download_id`. Default: `14897628` (Zenodo accession). | | `--cat_db` | No | Path to a local CAT_pack database. If omitted, builds CAT_pack DB from NCBI non-redundant protein database (`nr`). | @@ -366,7 +366,7 @@ nextflow run nf-core/seqsubmit \ --mode mags \ --input samplesheet_genomes.csv \ --submission_study \ - --centre_name \ + --center_name \ --webincli_mode submit \ --test_upload \ --outdir mags_submission/ @@ -403,7 +403,7 @@ nextflow run nf-core/seqsubmit \ -profile \ --mode \ --input \ - --centre_name \ + --center_name \ --submission_study \ --outdir ``` @@ -416,7 +416,7 @@ Parameters common to all modes: | `--input` | Yes | Path to samplesheet describing the data to be submitted (supported formats: csv, tsv, yaml, yml, json). Columns/fields depend on the pipeline mode. See [usage docs](https://nf-co.re/seqsubmit/usage#samplesheet-input). | | `--outdir` | Yes | Path to the output directory for pipeline results. You have to use absolute paths to storage on Cloud infrastructure. | | `--submission_study` OR `--study_metadata` | Yes (one of) | ENA study accession (PRJ/ERP) to submit the data to OR metadata file in JSON/TSV/CSV format to register a new study. | -| `--centre_name` | Yes | Name of the submitter's organisation (mandatory for broker accounts). | +| `--center_name` | Yes | Name of the submitter's organisation (mandatory for broker accounts). | | `--test_upload` | No | Submit to the ENA TEST server instead of the LIVE server. Use that flag for development purposes or for validation of your submissions. Submission would be done to TEST ENA server instead of LIVE server. TEST server holds data 24h and removes afterwords. LIVE server does not have option to modify your submission, you can only suppress data and re-upload. Default: `true`. | | `--webincli_mode` | No | Webin-CLI mode for ENA interaction: `submit` uploads data, `validate` performs validation only. `validate` mode checks correctness of manifest files, data access and validity. `submit` mode does validation and push data to ENA server. Default: `submit`. | | `--is_private` | No | Use if you are referencing private data accessions in your submission. Set to true when the referenced project/reads/assembly are still private in ENA, so metadata is fetched via authenticated access. Does NOT affect the privacy of your own submission, use --release_date for that. Default: `false`. | diff --git a/main.nf b/main.nf index 1c9223a..98856ce 100644 --- a/main.nf +++ b/main.nf @@ -55,7 +55,7 @@ workflow NFCORE_SEQSUBMIT { params.checkm2_db, params.checkm2_db_download_id, params.cat_db, - params.centre_name, + params.center_name, params.upload_tpa, params.test_upload, params.webincli_mode, @@ -76,7 +76,8 @@ workflow NFCORE_SEQSUBMIT { params.test_upload, params.webincli_mode, params.is_private, - params.release_date ? channel.value(params.release_date): channel.value(false) + params.release_date ? channel.value(params.release_date): channel.value(false), + params.center_name ) ch_multiqc_report = ASSEMBLYSUBMIT.out.multiqc_report } else if (params.mode == "reads") { @@ -90,7 +91,8 @@ workflow NFCORE_SEQSUBMIT { params.study_metadata, params.test_upload, params.webincli_mode, - params.release_date ? channel.value(params.release_date): channel.value(false) + params.release_date ? channel.value(params.release_date): channel.value(false), + params.center_name ) ch_multiqc_report = READSUBMIT.out.multiqc_report } diff --git a/modules/local/genome_upload/main.nf b/modules/local/genome_upload/main.nf index a0abb62..13b485a 100644 --- a/modules/local/genome_upload/main.nf +++ b/modules/local/genome_upload/main.nf @@ -12,7 +12,7 @@ process GENOME_UPLOAD { path(table_for_upload) val(mags_or_bins_flag) val(submission_study) - val(centre_name) + val(center_name) val(is_tpa) val(test_upload) val(is_private) @@ -32,12 +32,13 @@ process GENOME_UPLOAD { def tpa = is_tpa ? "--tpa" : "" def mode = (!test_upload) ? "--live" : "" def is_private_flag = is_private ? "--private" : "" + def center_name_arg = center_name ? "--centre_name ${center_name}" : "" """ genome_upload \\ -u ${submission_study} \\ --genome_info ${table_for_upload} \\ - --centre_name "${centre_name}" \\ + ${center_name_arg} \\ --${mags_or_bins_flag} \\ ${tpa} \\ ${mode} \\ diff --git a/modules/local/genome_upload/meta.yml b/modules/local/genome_upload/meta.yml index 4364cf2..c3c1cea 100644 --- a/modules/local/genome_upload/meta.yml +++ b/modules/local/genome_upload/meta.yml @@ -27,9 +27,9 @@ input: - submission_study: type: value description: ENA study accession used for submission. - - centre_name: + - center_name: type: value - description: Submitting centre name required by ENA. + description: Submitting center name required by ENA. - is_tpa: type: value description: Whether genomes are submitted as TPA (Third Party Annotation). diff --git a/modules/local/genome_upload/tests/main.nf.test b/modules/local/genome_upload/tests/main.nf.test new file mode 100644 index 0000000..f91749f --- /dev/null +++ b/modules/local/genome_upload/tests/main.nf.test @@ -0,0 +1,136 @@ +def writeGenomeMetadataTsv = { String genomeName, String fastaName -> + def metadataDir = new File(System.getenv("NFT_WORKDIR") ?: ".nf-test", "tmp/genome_upload") + metadataDir.mkdirs() + def metadata = File.createTempFile("genomes_metadata_${genomeName}_", ".tsv", metadataDir) + def header = [ + "genome_name", "genome_path", "accessions", "assembly_software", "binning_software", + "binning_parameters", "stats_generation_software", "completeness", "contamination", + "genome_coverage", "metagenome", "co-assembly", "broad_environment", "local_environment", + "environmental_medium", "rRNA_presence", "NCBI_lineage" + ] + def row = [ + genomeName, fastaName, "SRR14332510", "spades_v3.15.5", "mags_v1", + "default", "CheckM2_v1.0.1", "92.81", "1.09", + "66.04", "sediment metagenome", "False", "marine", "cable bacteria", + "marine sediment", "False", "d__Bacteria;p__Bacillota_A;c__Clostridia;o__Lachnospirales;f__Lachnospiraceae;g__Lachnospira;s__Lachnospira eligens" + ] + metadata.text = [header, row].collect { it.join("\t") }.join("\n") + "\n" + return metadata.absolutePath +} + +nextflow_process { + name "Test Process GENOME_UPLOAD" + script "../main.nf" + config "./nextflow.config" + process "GENOME_UPLOAD" + + tag "modules" + tag "genome_upload" + + test("genome_upload - mags - ENA test server") { + def genomeMetadata = writeGenomeMetadataTsv("test_mag", "bin_lachnospira_eligens.fa.gz") + + when { + process { + """ + input[0] = file(params.pipelines_testdata_base_path + 'test_data/bins/bin_lachnospira_eligens.fa.gz', checkIfExists: true) + input[1] = file("${genomeMetadata}", checkIfExists: true) + input[2] = 'mags' + input[3] = 'PRJEB98843' + input[4] = 'TEST_CENTER' + input[5] = false // is_tpa + input[6] = true // test_upload + input[7] = false // is_private + """ + } + } + + then { + assert process.success + assertAll( + { assert process.out.manifests.size() == 1 }, + { assert path(process.out.manifests[0]).fileName.toString() ==~ /test_mag_\d+\.manifest/ }, + { + def lines = path(process.out.manifests[0]).readLines() + assert lines.contains("STUDY\tPRJEB98843") + assert lines.any { it ==~ /SAMPLE\tERS\d+/ } + assert lines.any { it ==~ /ASSEMBLYNAME\ttest_mag_\d+/ } + assert lines.contains("ASSEMBLY_TYPE\tMetagenome-Assembled Genome (MAG)") + assert lines.contains("COVERAGE\t66.04") + assert lines.contains("PROGRAM\tspades_v3.15.5") + assert lines.contains("RUN_REF\tSRR14332510") + assert lines.any { it.startsWith("FASTA\t") && it.endsWith("bin_lachnospira_eligens.fa.gz") } + }, + { assert path(process.out.upload_registered_mags[0]).fileName.toString() == "registered_MAGs_test.tsv" }, + { + def rows = path(process.out.upload_registered_mags[0]).readLines() + assert rows[0] == "alias\tsample" + assert rows.size() == 2 + assert rows[1] ==~ /test_mag_\d+\tERS\d+/ + }, + { assert path(process.out.upload_genome_samples[0]).exists() }, + { assert path(process.out.ena_upload_backup_json[0]).exists() } + ) + } + } + + test("genome_upload - bins - ENA test server") { + def genomeMetadata = writeGenomeMetadataTsv("test_bin", "bin_lachnospira_eligens.fa.gz") + + when { + process { + """ + input[0] = file(params.pipelines_testdata_base_path + 'test_data/bins/bin_lachnospira_eligens.fa.gz', checkIfExists: true) + input[1] = file("${genomeMetadata}", checkIfExists: true) + input[2] = 'bins' + input[3] = 'PRJEB98843' + input[4] = "TEST_CENTER" // center name + input[5] = false // is_tpa + input[6] = true // test_upload + input[7] = false // is_private + """ + } + } + + then { + assert process.success + assertAll( + { assert process.out.manifests.size() == 1 }, + { + def lines = path(process.out.manifests[0]).readLines() + assert lines.contains("STUDY\tPRJEB98843") + assert lines.any { it ==~ /SAMPLE\tERS\d+/ } + assert lines.contains("ASSEMBLY_TYPE\tbinned metagenome") + }, + { assert path(process.out.upload_registered_mags[0]).fileName.toString() == "registered_bins_test.tsv" } + ) + } + } + + test("genome_upload - stub") { + options "-stub" + def genomeMetadata = writeGenomeMetadataTsv("test_mag_stub", "bin_lachnospira_eligens.fa.gz") + + when { + process { + """ + input[0] = file(params.pipelines_testdata_base_path + 'test_data/bins/bin_lachnospira_eligens.fa.gz', checkIfExists: true) + input[1] = file("${genomeMetadata}", checkIfExists: true) + input[2] = 'mags' + input[3] = 'PRJEB98843' + input[4] = 'TEST_CENTER' + input[5] = false // is_tpa + input[6] = true // test_upload + input[7] = false // is_private + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/local/genome_upload/tests/main.nf.test.snap b/modules/local/genome_upload/tests/main.nf.test.snap new file mode 100644 index 0000000..e4d4c55 --- /dev/null +++ b/modules/local/genome_upload/tests/main.nf.test.snap @@ -0,0 +1,44 @@ +{ + "genome_upload - stub": { + "content": [ + { + "0": [ + "test_1.manifest:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "1": [ + "ENA_backup.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "2": [ + "genome_samples.xml:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "3": [ + "registered_MAGs_test.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "4": [ + [ + "GENOME_UPLOAD", + "genome_uploader", + "3.0.4" + ] + ], + "ena_upload_backup_json": [ + "ENA_backup.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "manifests": [ + "test_1.manifest:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "upload_genome_samples": [ + "genome_samples.xml:md5,d41d8cd98f00b204e9800998ecf8427e" + ], + "upload_registered_mags": [ + "registered_MAGs_test.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + } + ], + "timestamp": "2026-10-30T22:35:09.968164", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.10.4" + } + } +} \ No newline at end of file diff --git a/modules/local/genome_upload/tests/nextflow.config b/modules/local/genome_upload/tests/nextflow.config new file mode 100644 index 0000000..08a1ebf --- /dev/null +++ b/modules/local/genome_upload/tests/nextflow.config @@ -0,0 +1,14 @@ +// Test configuration for GENOME_UPLOAD module. +// Real submission tests register samples on the ENA dev server (discarded daily) +// and require maintainer Webin credentials set as Nextflow secrets. + +env { + ENA_WEBIN = secrets.ENA_WEBIN + ENA_WEBIN_PASSWORD = secrets.ENA_WEBIN_PASSWORD +} + +process { + withName: 'GENOME_UPLOAD' { + ext.args = "--force" // ensures that ENA metadata is re-downloaded even if cache exists + } +} diff --git a/modules/local/registerstudy/main.nf b/modules/local/registerstudy/main.nf index 0a20f5a..b2890b7 100644 --- a/modules/local/registerstudy/main.nf +++ b/modules/local/registerstudy/main.nf @@ -15,6 +15,7 @@ process REGISTERSTUDY { tuple val(meta), path(study_metadata) val(test_upload) val(release_date) + val(center_name) output: tuple val(meta), path("*_accessions.json"), emit: accessions @@ -28,6 +29,7 @@ process REGISTERSTUDY { def prefix = task.ext.prefix ?: "${meta.id}" def test_flag = test_upload ? "--test" : "" def hold_data_private_until = release_date ? "--hold-until ${release_date}" : "" + def center_name_arg = center_name ? "--center-name ${center_name}": "" """ submit_study.py \\ @@ -35,6 +37,7 @@ process REGISTERSTUDY { --output ${prefix}_accessions.json \\ ${test_flag} \\ ${hold_data_private_until} \\ + ${center_name_arg} \\ ${args} """ diff --git a/modules/local/registerstudy/tests/main.nf.test b/modules/local/registerstudy/tests/main.nf.test index a1c82ec..2a8d3e5 100644 --- a/modules/local/registerstudy/tests/main.nf.test +++ b/modules/local/registerstudy/tests/main.nf.test @@ -34,6 +34,7 @@ nextflow_process { ] input[1] = true input[2] = false + input[3] = false """ } } @@ -59,6 +60,7 @@ nextflow_process { ] input[1] = true input[2] = false + input[3] = 'TEST_CENTER' """ } } @@ -86,6 +88,7 @@ nextflow_process { ] input[1] = true input[2] = false + input[3] = false """ } } diff --git a/nextflow.config b/nextflow.config index dcfeb4c..2ed60a2 100644 --- a/nextflow.config +++ b/nextflow.config @@ -16,7 +16,7 @@ params { submission_study = null is_private = false release_date = null - centre_name = null + center_name = null upload_tpa = false test_upload = true webincli_mode = "submit" diff --git a/nextflow_schema.json b/nextflow_schema.json index bbd9f5d..e07a2ea 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -252,17 +252,17 @@ "title": "Pipeline flow control parameters", "type": "object", "description": "Use these parameters to control the flow of the pipeline execution.", - "required": ["centre_name", "mode"], + "required": ["center_name", "mode"], "properties": { - "centre_name": { + "center_name": { "type": "string", "description": "Name of the submitter's organisation (mandatory for broker accounts).", "help_text": "ena-webin-cli argument -centerName: the center name of the submitter (mandatory for broker accounts)." }, "upload_tpa": { "type": "boolean", - "description": "Mark the assemblies as a Third PArty (TPA)", - "help_text": "Set to true if the assembly was built from public sequence data (TPA) rather than original primary data. See NCBI TPA guidance: https://www.ncbi.nlm.nih.gov/genbank/tpa/", + "description": "Mark the submission as a Third PArty (TPA). Not applicable to `--mode reads`.", + "help_text": "Set to true if the assembly/MAG/bin was built from public sequence data (TPA) rather than original primary data. Only used with `--mode mags`, `bins` or `metagenomic_assemblies`; setting it with `--mode reads` is rejected. See NCBI TPA guidance: https://www.ncbi.nlm.nih.gov/genbank/tpa/", "default": false }, "mode": { @@ -310,7 +310,27 @@ "enum": ["submit", "validate"], "help_text": "Controls ENA Webin-CLI mode. `validate` mode checks correctness of manifest files, data access and validity. `submit` mode does validation and push data to ENA server. Default: submit." } - } + }, + "allOf": [ + { + "if": { + "properties": { + "mode": { + "const": "reads" + } + }, + "required": ["mode"] + }, + "then": { + "properties": { + "upload_tpa": { + "const": false, + "errorMessage": "--upload_tpa is not applicable to --mode reads (TPA applies only to mags, bins and metagenomic_assemblies)" + } + } + } + } + ] } }, "oneOf": [ diff --git a/workflows/assemblysubmit.nf b/workflows/assemblysubmit.nf index bb3fe00..a215795 100644 --- a/workflows/assemblysubmit.nf +++ b/workflows/assemblysubmit.nf @@ -42,6 +42,7 @@ workflow ASSEMBLYSUBMIT { webincli_mode // val: either 'validate' or 'submit' to specify WebinCLI mode of operation is_private // val: fetch metadata from private/public account release_date // val: keep submitted data private until given date + center_name // val: name of submitting institution main: @@ -139,7 +140,8 @@ workflow ASSEMBLYSUBMIT { // Only register a study when at least one assembly passed validation FASTA_VALIDATION.out.valid_fastas.first().map { _it -> [[id: "study"], file(study_metadata)] }, test_upload, - release_date + release_date, + center_name ) study_accession_ch = REGISTERSTUDY.out.accessions diff --git a/workflows/genomesubmit.nf b/workflows/genomesubmit.nf index 17edbf9..b4a8289 100644 --- a/workflows/genomesubmit.nf +++ b/workflows/genomesubmit.nf @@ -46,7 +46,7 @@ workflow GENOMESUBMIT { checkm2_db // val: path to CheckM2 database checkm2_db_download_id // val: CheckM2 database download ID cat_db // val: path to CAT database - centre_name // val: submission centre name + center_name // val: submission center name upload_tpa // val: upload as TPA (Third Party Annotation) test_upload // val: true for test upload mode webincli_mode // val: either 'validate' or 'submit' to specify WebinCLI mode of operation @@ -229,7 +229,8 @@ workflow GENOMESUBMIT { // Only register a study when at least one genome passed validation FASTA_VALIDATION.out.valid_fastas.first().map { _it -> [[id: "study"], file(study_metadata)] }, test_upload, - release_date + release_date, + center_name ) study_accession_ch = REGISTERSTUDY.out.accessions @@ -245,7 +246,7 @@ workflow GENOMESUBMIT { CONCAT_METADATA.out.file_out.map { _meta, file -> file }.first(), mags_or_bins_flag, // mags or bins study_accession_ch.first(), - centre_name, + center_name, upload_tpa, test_upload, is_private diff --git a/workflows/readsubmit.nf b/workflows/readsubmit.nf index 6e94adb..ee23c66 100644 --- a/workflows/readsubmit.nf +++ b/workflows/readsubmit.nf @@ -38,6 +38,7 @@ workflow READSUBMIT { test_upload // val: true for test upload mode webincli_mode // val: either 'validate' or 'submit' to specify WebinCLI mode of operation release_date // val: keep submitted data private until given date + center_name // val: name of submitting institution main: def ch_versions = channel.empty() @@ -68,7 +69,8 @@ workflow READSUBMIT { REGISTERSTUDY( channel.of([[id: "study"], file(study_metadata)]), test_upload, - release_date + release_date, + center_name ) study_accession_ch = REGISTERSTUDY.out.accessions