nf-core-utils 迁移
将 nf-core 管道从自带的工具代码迁移到 nf-core-utils 插件(并直接调用 nf-schema),一次一个插件版本,不破坏使用额外配置启动管道的运行。
从模块 meta.yml 构建的工具引用(citationsOnTheFly、publication 块)将在下面的“引用”部分作为迁移后的单独 PR 处理。nf-test 基础设施(tests/lib、快照辅助函数、nft-utils)不在本迁移范围内:如果你看到它,将其作为后续任务提及,不要合并在迁移 PR 中。
开始前值得阅读的参考迁移:nf-core/rnavar#233(首次移除自带的子工作流)、nf-core/rnavar#252(基因组和版本辅助函数)、nf-core/seqinspector#241 和 nf-core/rnaseq#1977(完整替换)。使用 gh pr diff <n> -R nf-core/<repo> 获取它们。
1. 盘点已迁移的内容
迁移分阶段进行:每个插件版本会吸收更多辅助函数,因此一个“已经使用了 nf-core-utils”的管道通常仍保留着让插件函数失效的本地副本。不要假设用户描述的起始状态是最新的。检查:
ls subworkflows/nf-core/ | grep '^utils_' # 仍存在的自带子工作流
grep -n '"utils_' modules.json # 它们在 modules.json 中的条目
grep -rn "from 'plugin/" main.nf workflows subworkflows/local # 已从插件导入的内容
grep -n "^def " main.nf workflows/*.nf subworkflows/local/utils_*/main.nf # 本地辅助函数定义
grep -n "id '" nextflow.config # 当前插件引脚版本
将每个本地 def 与目标插件版本导出的函数(第 2 步)进行对比。与插件导出同名的本地定义是待删除的候选。保留包含管道特定逻辑的定义(自定义验证、工具列表、管道特定的摘要文本)。
2. 读取要引用的插件版本的签名
不同版本的插件 API 会变化,其他管道的差异可能针对不同版本。从缓存的插件中读取真实签名,而不是凭记忆:
nextflow plugin install nf-core-utils@<ver> # 或运行管道一次;插件存放在 ~/.nextflow/plugins/
P=~/.nextflow/plugins/nf-core-utils-<ver>
grep Plugin-Requires $P/classes/META-INF/MANIFEST.MF # 最低 Nextflow 版本
python3 -c "import json;[print(x['spec']['name'],[p['type'] for p in x['spec']['parameters']]) for x in json.load(open('$P/classes/META-INF/spec.json'))['definitions'] if x['type']=='Function']"
javap -cp $P/classes nfcore.plugin.NfUtilsExtension | grep <function>
javap -cp ~/.nextflow/plugins/nf-schema-<ver>/classes nextflow.validation.ValidationExtension | grep <function>
如果 Plugin-Requires 高于 manifest.nextflowVersion,请在同一个 PR 中升级 manifest.nextflowVersion、.github/workflows/nf-test.yml 中的最低 NXF_VER 以及 README 徽章。
如果出于某种原因你故意保留较旧的引脚版本(例如 nf-schema 2.x,因为 3.x 去掉了 paramsSummaryLog(Map, WorkflowMetadata)),请在 PR 描述中列出在下一个大版本中会损坏的调用点,以便后续可见。
3. 替换辅助函数
使用 references/function-map.md 对每个自带的子工作流和本地辅助函数进行逐个替换。在 nextflow.config 中固定插件版本:
plugins {
id 'nf-core-utils@<ver>' // nf-core-utils 是 Nextflow 管道的实用工具集合
id 'nf-schema@<ver>' // 验证管道参数并根据样本表创建输入通道
}
然后删除 subworkflows/nf-core/utils_nextflow_pipeline、utils_nfcore_pipeline 和 utils_nfschema_plugin(包括它们的 tests/ 目录)以及它们在 modules.json 中的条目。优先使用 nf-core subworkflows remove <name> 以保持 modules.json 的一致性;如果必须手动编辑 modules.json,之后运行 npx -y prettier@3 --write modules.json,因为 JSON 转储会破坏 installed_by 数组。
4. 在每个不是 nextflow.config 的配置中固定插件
启动时配置(Seqera Platform 中的 nextflow_config,即 .github/workflows/awsfulltest.yml / awstest.yml、Tower 配置、机构 -c 配置)中的 plugins {} 块会替换管道自身的 plugins {} 块而不是合并。任何管道使用 include { ... } from 'plugin/<name>' 导入但未在该块中固定的插件都会解析到最新版本,一旦新主版本发布就会损坏。
在这些块中重复 nextflow.config 中的完全相同版本,再加上该块为自己添加的任何插件:
nextflow_config: |
plugins {
id 'nf-core-utils@<与 nextflow.config 相同>'
id 'nf-schema@<与 nextflow.config 相同>'
id '[email protected]'
}
检查引脚版本是否一致:
grep -rhoE "id '(nf-core-utils|nf-schema)@[^']+'" nextflow.config .github/workflows/ | sort | uniq -c
每个插件应只出现一个版本。
5. 根据证据诊断插件故障
Missing process or function X(...) -- Did you mean 'X' instead? 表示存在名为 X 的函数,但没有重载匹配参数。将其理解为插件版本不匹配,而不是拼写错误:找到实际加载的版本,然后将其签名(第 2 步)与调用点对比。
在更改任何内容之前确认加载的版本:
- 大型测试 / Platform 运行:
gh run list -R nf-core/<pipeline> -w "nf-core AWS full size tests"和gh run view <id> --log,或 nf-slack 发布的 Slack 消息,或 Platform 运行日志。查找Downloading plugin <name>@<ver>/Starting plugin <name>@<ver>。 - 本地重现配置覆盖:使用仅包含外部
plugins {}块的配置运行,并检查日志。
printf "plugins {\n id '[email protected]'\n}\n" > /tmp/override.config
nextflow run . -profile test,docker --outdir /tmp/out -c /tmp/override.config 2>&1 | head -40
grep -E "plugin (nf-schema|nf-core-utils)@" .nextflow.log
仅在这些来源都为空时才要求用户提供日志。
6. 验证
在报告之前,将你自己造成的失败与 dev 上已有的失败分开:在干净的工作树上重新运行失败的测试或检查。
git worktree add /tmp/dev-baseline origin/dev
(cd /tmp/dev-baseline && <相同的测试或检查命令>)
git worktree remove --force /tmp/dev-baseline
至少运行:
nextflow lint main.nf workflows subworkflows/local(严格语法)nf-core pipelines lint- 管道 nf-test,设置
NXF_VER为管道的最低 Nextflow 版本 nextflow run . --help、--help_full和--version,因为这些路径会提前退出,并且当内联UTILS_NFSCHEMA_PLUGIN/UTILS_NEXTFLOW_PIPELINE时容易损坏
引用(单独 PR)
一旦辅助函数来自插件,MultiQC 方法描述可以引用实际运行的工具,使用 citationsOnTheFly(nf-core-utils 0.7.0 或更高版本)和每个模块 meta.yml 中的 tools: 条目。将此保留在迁移 PR 之外:它会涉及许多模块文件,更改整个管道的快照,并涉及用户应做出的归属决策。
开始前阅读 references/citations.md。简而言之:
- 将
channel.topic("versions").collect(flat: false)连接到citationsOnTheFly,并在收集之后将运行的工具(MultiQC)作为额外参数传递。 - 预测哪些工具会记录
No citation metadata found并破坏快照;逐个精确引用真实工具,忽略通用实用程序。 - 与用户商定引用元数据的位置:上游 nf-core/modules、模块补丁或本地覆盖文件。
- 每个 DOI、作者列表和标题都来自 Crossref / PubMed,绝不能凭记忆,并在替换模块引用的论文之前询问。
- 将模块补丁限制在
meta.yml中,并从测试运行中读取渲染的Tools used文本。
注意事项
- 快照:来自插件的
softwareVersionsToYAML将元组版本保留为带引号的字符串,因此之前包含数字版本的快照(1.21而不是"1.21")会在许多文件中发生变化。这是预期的;检查是否只有引用发生了变化。 - 收集版本以使元组和空流得以存活:rnaseq#1977 使用
.toList()收集,并通过entry instanceof Path ? entry.text : entry读取旧的versions.yml输出,以便远程工作目录继续正常工作。 - 如果自带的
UTILS_NFSCHEMA_PLUGIN调用依赖它,则保留validateParameters(cast_cli_params: false);在内联之前检查旧的调用。 getWorkflowVersion()读取 manifest;如果管道之前打印了 git 后缀,则传递workflow.manifest.version, workflow.commitId。- 来自插件的
methodsDescriptionText接受String路径,因此传递file.toString(),而不是Path。 - nf-core YAML 文件有时会引用键(
- "gatk4":)。使用正则表达式进行批量编辑必须匹配引用和未引用的键,然后统计编辑的文件数量是否与预期列表一致。 - 如果必须修补模块,
nf-core modules patch会区分modules/nf-core/<m>/tests/下的被 gitignore 的文件,因此首先将它们重置到固定的 SHA(git -C ~/.config/nfcore/nf-core/modules show <git_sha>:modules/nf-core/<m>/<file>),并检查每个.diff只包含你打算更改的文件。
PR
- 先创建 PR,然后再使用真实的 PR 编号编写 CHANGELOG 条目。猜测下一个编号会与其他贡献者冲突。
- CHANGELOG:
Changed下的一条条目、如果 PR 修复了插件引脚则在Fixed下的条目,以及一个包含新旧版本的Dependencies - Nextflow plugins表。 - PR 描述:插件版本前后对比、你固定的每个外部
plugins {}块、哪些辅助函数已迁移到插件以及哪些保留在本地(并说明原因)、后续任务(下一个主要版本的调用点、引用、测试基础设施)。