NfcoreReportingOrchestrator
Orchestrated comprehensive reporting utilities for nf-core pipelines.
Overview
The NfcoreReportingOrchestrator utility provides high-level orchestration of reporting functionality by coordinating SoftwareVersionReport and NfcoreCitationUtils. Public extension functions remain stable, while the internal implementation now uses PipelineExecutionContext so report generation receives explicit workflow, manifest, and configuration metadata instead of reading global Nextflow session state.
Key Benefits
- Unified Interface: Single entry point for comprehensive pipeline reporting
- Explicit Context: Manifest and workflow metadata are passed through
PipelineExecutionContext, including data used by methods-description templates - Coordinated Processing: Ensures consistent handling of both versions and citations
- Error Resilience: Robust error handling with graceful degradation
- Performance Optimization: Efficient processing of large datasets
- Consistent Output: Standardized report formats across all functions
Available Functions
generateComprehensiveReport()
Description:
Generates a complete pipeline report including version information, tool citations, bibliography, and methods description. This is the primary function for full pipeline reporting that combines all available reporting capabilities.
Function Signature:
Map generateComprehensiveReport( List<List> topicVersions, List<String> legacyVersions = [], List<String> metaFilePaths = [], String mqcMethodsYamlPath = null)Parameters:
topicVersions(List- ): Version data from topic channels in
[process, name, version]formatlegacyVersions(List, optional): List of legacy YAML version strings metaFilePaths(List, optional): List of paths to module meta.yml files for citations mqcMethodsYamlPath(String, optional): Path to MultiQC methods description template
Returns:
Map: Comprehensive report containing:versions_yaml(String): Complete YAML with all version informationtool_citations(String): Formatted citation text for methods descriptionstool_bibliography(String): HTML bibliography for referencesmethods_description(String): Complete methods description with templates
Usage Example:
include { generateComprehensiveReport } from 'plugin/nf-core-utils'
workflow { // Collect versions from topic channels ch_versions = channel.empty()
FASTQC(samples) MULTIQC(reports)
ch_versions = ch_versions .mix(FASTQC.out.versions) .mix(MULTIQC.out.versions)
// Collect all data for comprehensive reporting def topicVersions = ch_versions.collect() def legacyVersions = ['legacy_versions.yml'] def metaFilePaths = [ 'modules/nf-core/fastqc/meta.yml', 'modules/nf-core/multiqc/meta.yml' ] def methodsTemplate = "${projectDir}/assets/methods_description_template.yml"
// Generate complete report def report = generateComprehensiveReport( topicVersions, legacyVersions, metaFilePaths, methodsTemplate )
// Write all report components file("${params.outdir}/pipeline_info/software_versions.yml").text = report.versions_yaml file("${params.outdir}/pipeline_info/citations.txt").text = report.tool_citations file("${params.outdir}/pipeline_info/bibliography.html").text = report.tool_bibliography file("${params.outdir}/pipeline_info/methods_description.html").text = report.methods_description
log.info "Generated comprehensive report with versions and citations"}Pipeline Integration:
workflow { // Standard processing PROCESS_SAMPLES(samples)
// Single function call for complete reporting def allVersions = ch_versions.collect() def citations = collectAllMetaFiles()
def completeReport = generateComprehensiveReport( allVersions, [], // No legacy versions citations, "${projectDir}/assets/methods_template.yml" )
// All reporting outputs ready for MultiQC publishReportFiles(completeReport)}generateVersionReport()
Description:
Generates a version-only report when citations are not needed or handled separately. This function focuses exclusively on version aggregation and formatting.
Function Signature:
Map generateVersionReport(List<List> topicVersions, List<String> legacyVersions = [])Parameters:
topicVersions(List- ): Version data from topic channels in
[process, name, version]formatlegacyVersions(List, optional): List of legacy YAML version strings
Returns:
Map: Version report containing:versions_yaml(String): Complete YAML with all version informationworkflow_version(String): Formatted workflow version string
Usage Example:
include { generateVersionReport } from 'plugin/nf-core-utils'
workflow { // Collect only version information def versions = ch_versions.collect() def legacyFiles = ['old_process/versions.yml']
def versionReport = generateVersionReport(versions, legacyFiles)
// Write version file for MultiQC file("${params.outdir}/pipeline_info/software_versions.yml").text = versionReport.versions_yaml
log.info "Pipeline version: ${versionReport.workflow_version}"}Specialized Use Cases:
// When you only need version trackingworkflow VERSION_TRACKING { // Process with version-aware modules ANALYSIS_MODULES(data)
// Generate version report without citations def versionData = ch_versions.collect() def report = generateVersionReport(versionData)
// Lightweight reporting for version tracking only Channel.value(report.versions_yaml) .collectFile(name: 'software_versions.yml', storeDir: "${params.outdir}/versions")}generateCitationReport()
Description:
Generates a citation-only report when versions are handled separately. This function focuses exclusively on citation extraction, processing, and methods description generation.
Function Signature:
Map generateCitationReport(List<String> metaFilePaths, String mqcMethodsYamlPath = null)Parameters:
metaFilePaths(List): List of paths to module meta.yml files mqcMethodsYamlPath(String, optional): Path to MultiQC methods description template
Returns:
Map: Citation report containing:tool_citations(String): Formatted citation text for methods descriptionstool_bibliography(String): HTML bibliography for referencesmethods_description(String): Methods description with citation integration (if template provided)
Usage Example:
include { generateCitationReport } from 'plugin/nf-core-utils'
workflow { // Collect citation sources def metaFiles = [ 'modules/nf-core/fastqc/meta.yml', 'modules/nf-core/multiqc/meta.yml', 'modules/local/custom_tool/meta.yml' ] def methodsTemplate = "${projectDir}/assets/methods_description_template.yml"
def citationReport = generateCitationReport(metaFiles, methodsTemplate)
// Write citation components file("${params.outdir}/pipeline_info/tool_citations.txt").text = citationReport.tool_citations file("${params.outdir}/pipeline_info/bibliography.html").text = citationReport.tool_bibliography file("${params.outdir}/pipeline_info/methods.html").text = citationReport.methods_description
log.info "Generated citations for ${metaFiles.size()} modules"}Publication-Ready Citations:
// Generate publication-ready citation materialsworkflow PUBLICATION_PREP { def citationSources = collectPublicationModules() def publicationTemplate = "${projectDir}/assets/publication_methods.yml"
def report = generateCitationReport(citationSources, publicationTemplate)
// Create publication materials file("${params.outdir}/publication/methods_section.html").text = report.methods_description file("${params.outdir}/publication/references.html").text = report.tool_bibliography file("${params.outdir}/publication/inline_citations.txt").text = report.tool_citations}Orchestration Benefits
Unified Processing
The orchestrator provides several advantages over calling individual utility functions:
// Instead of separate utility calls:// def versions = NfcoreVersionUtils.processMixedVersionSources(...)// def citations = NfcoreCitationUtils.collectCitationsFromFiles(...)// def methods = NfcoreCitationUtils.methodsDescriptionText(...)
// Single orchestrated call:def report = generateComprehensiveReport(topicVersions, legacyVersions, metaFiles, methodsTemplate)// Gets: versions_yaml, tool_citations, tool_bibliography, methods_descriptionError Handling Coordination
// Robust error handling across all reporting componentsworkflow { try { def report = generateComprehensiveReport(versions, [], citations, methods)
// All components generated successfully publishAllReports(report)
} catch (Exception e) { log.warn "Comprehensive reporting failed: ${e.message}"
// Fallback to basic reporting def basicReport = generateVersionReport(versions) file("${params.outdir}/software_versions.yml").text = basicReport.versions_yaml }}Performance Optimization
// Optimized processing for large datasetsworkflow LARGE_SCALE_ANALYSIS { // Process thousands of samples MASSIVELY_PARALLEL_ANALYSIS(samples)
// Efficient orchestrated reporting def versionData = ch_versions.collect() def citationData = ch_citations.collect()
// Single coordinated processing call def report = generateComprehensiveReport(versionData, [], citationData, methodsTemplate)
// Optimized output generation publishOptimizedReports(report)}Integration Examples
Complete Pipeline Integration
#!/usr/bin/env nextflow
include { generateComprehensiveReport } from 'plugin/nf-core-utils'
workflow { // Initialize reporting channels ch_versions = channel.empty() ch_multiqc_files = channel.empty()
// Main analysis pipeline PREPROCESSING(samples) QUALITY_CONTROL(PREPROCESSING.out.processed) ANALYSIS(QUALITY_CONTROL.out.passed)
// Collect versions ch_versions = ch_versions .mix(PREPROCESSING.out.versions) .mix(QUALITY_CONTROL.out.versions) .mix(ANALYSIS.out.versions)
// Collect MultiQC files ch_multiqc_files = ch_multiqc_files .mix(QUALITY_CONTROL.out.reports) .mix(ANALYSIS.out.reports)
// Orchestrated reporting def versionData = ch_versions.collect() def citationFiles = [ 'modules/nf-core/fastqc/meta.yml', 'modules/nf-core/multiqc/meta.yml', 'modules/local/analysis_tool/meta.yml' ] def methodsTemplate = "${projectDir}/assets/methods_description_template.yml"
// Generate complete report def comprehensiveReport = generateComprehensiveReport( versionData, [], citationFiles, methodsTemplate )
// Prepare MultiQC inputs def mqc_versions = Channel.value([ 'software_versions_mqc.yaml', comprehensiveReport.versions_yaml ])
def mqc_methods = Channel.value([ 'methods_description_mqc.yaml', comprehensiveReport.methods_description ])
// Run MultiQC with orchestrated reports MULTIQC( ch_multiqc_files .mix(mqc_versions) .mix(mqc_methods) .collect() )
// Publish comprehensive reports publishReportingOutputs(comprehensiveReport)}
def publishReportingOutputs(report) { file("${params.outdir}/pipeline_info/software_versions.yml").text = report.versions_yaml file("${params.outdir}/pipeline_info/citations.txt").text = report.tool_citations file("${params.outdir}/pipeline_info/bibliography.html").text = report.tool_bibliography file("${params.outdir}/pipeline_info/methods_description.html").text = report.methods_description}Migration from Individual Utilities
// Before: Multiple utility calls// include {// processMixedVersionSources;// collectCitationsFromFiles;// methodsDescriptionText// } from 'plugin/nf-core-utils'
// After: Orchestrated approachinclude { generateComprehensiveReport } from 'plugin/nf-core-utils'
workflow MIGRATED_REPORTING { // Same data collection def versions = ch_versions.collect() def citations = ['modules/tool/meta.yml'] def methods = "${projectDir}/methods.yml"
// Single orchestrated call replaces multiple utility calls def report = generateComprehensiveReport(versions, [], citations, methods)
// Same outputs, simplified generation publishUnifiedReports(report)}Conditional Reporting Strategies
workflow ADAPTIVE_REPORTING { // Collect available data def versions = ch_versions.collect() def citationFiles = findAvailableCitations() def methodsTemplate = findMethodsTemplate()
// Choose reporting strategy based on available data def report = null
if (citationFiles.size() > 0 && methodsTemplate) { // Full comprehensive reporting report = generateComprehensiveReport(versions, [], citationFiles, methodsTemplate) log.info "Generated comprehensive report with ${citationFiles.size()} citations"
} else if (citationFiles.size() > 0) { // Version + citations without methods report = generateComprehensiveReport(versions, [], citationFiles, null) log.info "Generated report with versions and citations"
} else { // Version-only reporting report = generateVersionReport(versions) log.info "Generated version-only report" }
// Publish available report components publishAvailableReports(report)}Best Practices
1. Choose Appropriate Reporting Function
// Use comprehensive reporting for full pipelinesdef fullReport = generateComprehensiveReport(versions, [], citations, methods)
// Use specialized reporting for focused needsdef versionOnly = generateVersionReport(versions) // Version tracking onlydef citationOnly = generateCitationReport(citations, methods) // Publication prep2. Error Handling Strategies
workflow ROBUST_REPORTING { try { // Attempt comprehensive reporting def report = generateComprehensiveReport(versions, [], citations, methods) publishCompleteReports(report)
} catch (Exception e) { log.warn "Comprehensive reporting failed, falling back to components: ${e.message}"
// Fallback strategy try { def versionReport = generateVersionReport(versions) publishVersionReport(versionReport)
def citationReport = generateCitationReport(citations) publishCitationReport(citationReport)
} catch (Exception fallbackError) { log.error "All reporting failed: ${fallbackError.message}" publishMinimalReport() } }}3. Performance Optimization for Large Datasets
// Optimize for large numbers of processesworkflow LARGE_SCALE_REPORTING { // Batch process versions efficiently def versionBatches = ch_versions .buffer(size: 100) .collect()
// Efficient citation collection def citationBatches = ch_citation_files .collate(50) .collect()
// Coordinated batch processing def reports = [] versionBatches.each { batch -> def batchReport = generateVersionReport(batch) reports.add(batchReport) }
// Merge batch reports def finalReport = mergeBatchReports(reports)}4. Testing Orchestrated Functions
test("Comprehensive reporting integration") { when { def versions = [ ['FASTQC', 'fastqc', '0.11.9'], ['MULTIQC', 'multiqc', '1.12'] ] def citations = ['modules/nf-core/fastqc/meta.yml'] def methods = 'test_methods_template.yml'
def report = generateComprehensiveReport(versions, [], citations, methods) }
then { assert report.containsKey('versions_yaml') assert report.containsKey('tool_citations') assert report.containsKey('tool_bibliography') assert report.containsKey('methods_description')
assert report.versions_yaml.contains('FASTQC') assert report.tool_citations.contains('fastqc') assert report.tool_bibliography.contains('<li>') }}
test("Graceful degradation with missing data") { when { def report = generateComprehensiveReport([], [], [], null) }
then { assert report.versions_yaml.contains('Workflow:') assert report.tool_citations == "No citations available." assert report.tool_bibliography.isEmpty() }}Common Issues and Solutions
Issue: Inconsistent Report Components
Problem: Different utility functions produce incompatible output formats
Solution:
// Use orchestrator for consistent formattingdef report = generateComprehensiveReport(versions, [], citations, methods)// All components guaranteed to be compatibleIssue: Memory Usage with Large Datasets
Problem: Large version/citation datasets cause memory issues
Solution:
// Process in chunksworkflow MEMORY_EFFICIENT { def versionChunks = ch_versions.collate(1000).collect() def citationChunks = ch_citations.collate(100).collect()
def reports = [] versionChunks.each { chunk -> def chunkReport = generateVersionReport(chunk) reports.add(chunkReport) }
// Merge efficiently def finalReport = mergeReports(reports)}Issue: Missing Template Variables
Problem: Methods description template has undefined variables
Solution:
// Validate template requirementsdef validateTemplate(templatePath, report) { def template = file(templatePath).text def requiredVars = ['tool_citations_text', 'tool_bibliography_text']
requiredVars.each { var -> if (!template.contains("\${${var}}")) { log.warn "Template missing variable: ${var}" } }}Performance Considerations
Orchestration Efficiency
- Reduced Function Calls: Single orchestrated call vs multiple utility calls
- Coordinated Processing: Optimized data flow between version and citation processing
- Memory Management: Efficient handling of large datasets through coordinated processing
- Error Recovery: Centralized error handling reduces redundant processing
Benchmarking Results
// Performance comparisonworkflow BENCHMARK_REPORTING { // Individual calls approach def start1 = System.currentTimeMillis() def versions = processVersions(versionData) def citations = processCitations(citationData) def methods = generateMethods(methodsTemplate, citations) def time1 = System.currentTimeMillis() - start1
// Orchestrated approach def start2 = System.currentTimeMillis() def report = generateComprehensiveReport(versionData, [], citationData, methodsTemplate) def time2 = System.currentTimeMillis() - start2
log.info "Individual calls: ${time1}ms, Orchestrated: ${time2}ms" // Typical result: 40-60% faster with orchestrated approach}For more information on orchestrated reporting and utility coordination, see the individual utility documentation and nf-core reporting best practices.