Nx Migration 生成器
为 Nx 插件添加 Nx Migration。Migration 让 nx migrate 能够在你进行破坏性更改时自动更新由插件早期版本生成的项目——重命名的目标、更改的配置,或需要伴随代码更改的依赖升级。
该生成器会搭建 migration 脚手架,在插件的 migrations.json 中注册它,并将 nx-migrations 字段连接到插件的 package.json(如果它们尚不存在则创建)。
生成 Migration
Section titled “生成 Migration”pnpm nx g @aws/nx-plugin:ts#nx-migrationyarn nx g @aws/nx-plugin:ts#nx-migrationnpx nx g @aws/nx-plugin:ts#nx-migrationbunx nx g @aws/nx-plugin:ts#nx-migration- 安装 Nx Console VSCode Plugin 如果您尚未安装
- 在VSCode中打开Nx控制台
- 点击
Generate (UI)在"Common Nx Commands"部分 - 搜索
@aws/nx-plugin - ts#nx-migration - 填写必需参数
- 点击
Generate
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| project 必需 | string | - | 要添加迁移的 Nx Plugin 项目。我们建议使用 ts#nx-plugin 生成器来创建此项目。 |
| name 必需 | string | - | 迁移名称,使用 kebab-case 格式(例如 rename-foo-target) |
| description | string | - | 迁移功能的描述,由 nx migrate 显示 |
| kind | deterministic | agentic | hybrid | deterministic | 迁移的类型:deterministic(代码模组)、agentic(由 AI 应用的提示用于用户自有代码)或 hybrid(先执行机械部分的代码模组,然后交给代理) |
| preferInstallDependencies | boolean | true | 是否在生成器运行后优先安装依赖项。设置为 false 可在批量运行多个生成器时延迟安装(如果后续生成器需要计算 Nx 项目图,仍会运行安装);在最后统一安装一次。 |
三种 migration 类型
Section titled “三种 migration 类型”Migration 有三种形式,通过 migrations.json 条目携带的字段来区分。传递 --kind 来选择(默认为 deterministic):
- Deterministic(
implementation)— 具有精确前后状态的代码修改,也是首选方式。它无人值守运行,包括在 CI 和非交互式终端中,并对每个用户应用相同的修改。当更改具有可以在任何地方可靠匹配的形状时单独使用它,通过nextSteps报告任何跳过的内容。 - Hybrid(
implementation+prompt)— 一个更改的两个部分。当更改是破坏性的且无法完全机械应用时使用它:代码修改尽可能安全地匹配并返回agentContext描述它更改了什么以及跳过了什么;Nx 将该上下文传递给配对的prompt,后者指导 agent 处理其余部分。当剩余的编辑跨越太多形状而无法进行代码修改时,prompt 可以防止工作区处于损坏状态。 - Agentic(
prompt)— 由用户的本地编码 agent 通过 Nx 的 agenticnx migrate流程应用的 markdown 指令文件。当根本没有机械的前后状态时单独使用它,因为正确的编辑取决于用户构建的内容。当没有 agent 运行时(CI、未安装 agent、拒绝同意),Nx 将 prompt 作为手动说明呈现——因此将 prompt 编写为独立的、人类可操作的步骤。
生成器会在插件项目的源文件夹下创建以下文件,具体取决于选择的 kind:
文件夹src/migrations/latest/<name>/
- migration.ts 代码修改实现(deterministic 和 hybrid)
- migration.spec.ts migration 的测试(deterministic 和 hybrid)
- prompt.md Agent/人类指令(agentic 和 hybrid)
- migrations.json 创建或更新以注册你的 migration
- package.json 创建或更新以添加 “nx-migrations” 条目
新的 migration 位于 latest/ 中。按发布它们的版本对 migration 进行分组,可以在集合增长时一目了然地看到它们的顺序——当你分配版本时,将 migration 移动到 v<x.y.z>/ 文件夹中(并在 migrations.json 中更新其路径)。
它在 migrations.json 中注册 migration,包含其类型的字段但没有 version——请参阅下面的版本控制。注册的键以 migration 所在的文件夹为前缀(latest-<name>),因此为后续更改重用名称不会静默覆盖已发布的 migration。
实现 Migration
Section titled “实现 Migration”deterministic(或 hybrid)migration 是一个修改虚拟文件系统(Tree)的函数,返回 MigrationReturnObject。这是一个 hybrid 示例,它返回两者:
import { type MigrationReturnObject, type Tree } from '@nx/devkit';import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
export default async function migration( tree: Tree,): Promise<MigrationReturnObject> { const nextSteps: string[] = []; const agentContext: string[] = [];
// Read and update the files your generators produce here.
await formatFilesInSubtree(tree);
return { nextSteps, agentContext };}nextSteps—nx migrate运行后 Nx 为用户打印的后续操作。每个条目都应该是他们需要手动完成的事情:协调你跳过的文件(请参阅下面的防护措施),或完成 migration 无法触及的内容,例如安装以刷新锁文件。它们不是你更改内容的日志——当转换干净地应用时,不要添加任何内容,否则确实需要操作的条目会被掩埋。agentContext(仅限 hybrid)— 代码修改更改内容的摘要,当在 Nx 的 agentic 流程下运行时传递给配对的prompt,以便 agent 可以专注于用户拥有的部分。
有关可以在 migration 中执行的一些示例操作(生成文件、使用 GritQL 修改现有文件、读取和更新 JSON),请参阅 Nx Generator 指南。
Migration 针对你无法控制的工作区运行,因此建议遵守以下规则(脚手架骨架已内置这些规则):
- 使用 GritQL 转换源代码。 使用 GritQL 辅助函数(
applyGritQL、matchGritQL)来编辑源代码,而不是正则表达式或字符串替换。GritQL 匹配 AST,因此一个模式可以跨越用户副本可能偏离的格式、空格和引号,而文本匹配会悄悄地错过等效代码或损坏文件。对 JSON 使用updateJson,对其他结构化配置使用匹配的解析器。 - 写入前进行模式匹配。 如果目标文件已偏离生成器生成的形状,请跳过它并通过
nextSteps报告,或考虑 hybrid migration,而不是覆盖用户的更改。matchGritQL是进行该检查的便捷方式。 - 仅报告剩余要做的事情。
nextSteps用于用户必须接手的工作,而不是你所做编辑的记录——这些已经在他们的git diff中了。 - 幂等性。 重新运行 migration 必须是无操作的。使用
where { ... <: not contains ... }子句保护注入代码的 GritQL 重写,这样第二次运行不会追加重复项。 - 格式化你写入的内容。 以
formatFilesInSubtree(tree)结束,以便 migration 写入的文件格式正确。
测试你的 Migration
Section titled “测试你的 Migration”脚手架的 migration.spec.ts 使用 createTreeUsingTsSolutionSetup() 构建与我们的预设生成的形状匹配的虚拟工作区。测试 migration 将工作区从”之前”状态带到目标状态,跳过(并报告)它无法识别的代码,并且是幂等的:
import type { Tree } from '@nx/devkit';import { createTreeUsingTsSolutionSetup } from '@aws/nx-plugin/sdk/utils/test';import migration from './migration.js';
describe('my migration', () => { let tree: Tree;
beforeEach(() => { tree = createTreeUsingTsSolutionSetup(); });
it('should update the generated shape', async () => { // Set up a tree with the "before" state tree.write('project.json', JSON.stringify({ targets: { foo: {} } }));
// Run the migration await migration(tree);
// Check that the tree matches the target state const projectJson = JSON.parse(tree.read('project.json', 'utf-8')); expect(projectJson.targets).toHaveProperty('bar'); expect(projectJson.targets).not.toHaveProperty('foo'); });});单元测试只能证明 migration 执行了你编写的内容。还要针对由插件已发布版本生成的工作区测试它——用户升级的状态——并确认结果与你的生成器今天生成的内容匹配:检查差异,将相同的项目生成到新工作区中并进行比较,检查工作区是否仍然构建,然后重新运行 migration 以确认它没有更改任何内容。使用你首先自定义的工作区重复此操作,以检查 migration 是否保留你的编辑并报告它们。
当用户安装的插件版本低于 migration 的 version 时,Nx 会运行 migration。此生成器不写入 version 字段——在你发布包含 migration 的版本时分配它(或从发布流程中标记它),以便它为从早期版本升级的每个人运行。
一旦分配版本,注册每种类型的一个 migration 的 migrations.json 如下所示:
{ "$schema": "http://json-schema.org/schema", "name": "my-plugin", "generators": { "v2.0.0-rename-foo-target": { "version": "2.0.0", "description": "Rename the foo target to bar", "implementation": "./src/migrations/v2.0.0/rename-foo-target/migration" }, "v3.0.0-migrate-custom-handlers": { "version": "3.0.0", "description": "Update custom handlers for the new API", "prompt": "./src/migrations/v3.0.0/migrate-custom-handlers/prompt.md" }, "v4.0.0-upgrade-framework": { "version": "4.0.0", "description": "Upgrade the framework and reconcile call sites", "implementation": "./src/migrations/v4.0.0/upgrade-framework/migration", "prompt": "./src/migrations/v4.0.0/upgrade-framework/prompt.md" } }}运行 Migration
Section titled “运行 Migration”用户使用两步 nx migrate 流程应用插件的 migration——生成待处理的 migration,安装,然后运行它们:
pnpm nx migrate my-plugin@latestpnpm nx migrate --run-migrationsyarn nx migrate my-plugin@latestyarn nx migrate --run-migrationsnpx nx migrate my-plugin@latestnpx nx migrate --run-migrationsbunx nx migrate my-plugin@latestbunx nx migrate --run-migrations当有可用的本地编码 agent 时,agentic 和 hybrid migration 会在 nx migrate --run-migrations 期间由用户的本地编码 agent 应用。
有关从升级用户角度的完整流程——包括 deterministic 和 agentic migration 的示例输出——请参阅升级你的工作区。