Nx Migration ジェネレーター
Nx Plugin に Nx Migration を追加します。Migration を使用すると、破壊的変更(ターゲットの名前変更、提供される設定の変更、またはコード変更を伴う依存関係のバージョンアップなど)を行った際に、nx migrate がプラグインの以前のバージョンで生成されたプロジェクトを自動的に更新できるようになります。
このジェネレーターは、migration のスキャフォールディングを行い、プラグインの migrations.json に登録し、プラグインの package.json に nx-migrations フィールドを配線します(存在しない場合は両方とも作成します)。
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変更されるファイルを確認するためにドライランを実行することもできます
pnpm nx g @aws/nx-plugin:ts#nx-migration --dry-runyarn nx g @aws/nx-plugin:ts#nx-migration --dry-runnpx nx g @aws/nx-plugin:ts#nx-migration --dry-runbunx nx g @aws/nx-plugin:ts#nx-migration --dry-run- インストール 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プロジェクトグラフを計算できるよう、必要に応じてインストールは実行されます)。最後に一度だけインストールします。 |
3 種類の migration
Section titled “3 種類の migration”Migration には 3 つの形式があり、migrations.json エントリが持つフィールドによって区別されます。--kind を渡して選択します(デフォルトは deterministic):
- Deterministic(
implementation)— 正確な変更前/変更後を持つコードモッドで、最初に使用すべきものです。CI や非対話型ターミナルを含む無人環境で実行され、すべてのユーザーに対して同じように適用されます。変更が現れるすべての場所で確実に一致できる形状を持つ場合に単独で使用し、スキップしたものはnextSteps経由で報告します。 - Hybrid(
implementation+prompt)— 1 つの変更の両方の部分です。変更が破壊的で機械的に完全に適用できない場合に使用します:コードモッドは安全に一致できる限りのことを行い、変更した内容とスキップした内容を記述するagentContextを返します。Nx はそのコンテキストをペアのpromptに渡し、残りの部分をエージェントに指示します。プロンプトは、残りの編集がコードモッドするには形状が多すぎる場合に、ワークスペースが壊れた状態で放置されるのを防ぎます。 - Agentic(
prompt)— Nx のエージェント型nx migrateフローを介してユーザーのローカルコーディングエージェントによって適用される markdown 指示ファイルです。正しい編集がユーザーが構築したものに依存するため、機械的な変更前/変更後がまったく成立しない場合に単独で使用します。エージェントが実行されない場合(CI、エージェントがインストールされていない、同意が拒否された)、Nx はプロンプトを手動の指示として表示します。そのため、プロンプトは自己完結型で人間が実行可能な手順として記述してください。
ジェネレーターの出力
Section titled “ジェネレーターの出力”ジェネレーターは、選択した kind に応じて、プラグインプロジェクトのソースフォルダー配下に以下のファイルを作成します:
Directorysrc/migrations/latest/<name>/
- migration.ts Codemod implementation (deterministic and hybrid)
- migration.spec.ts Tests for your migration (deterministic and hybrid)
- prompt.md Agent/human instructions (agentic and hybrid)
- migrations.json Created or updated to register your migration
- package.json Created or updated to add an “nx-migrations” entry
新しい migration は latest/ に配置されます。migration をリリースごとにグループ化することで、コレクションが増えるにつれて順序が一目でわかるようになります。バージョンを割り当てる際には、migration を v<x.y.z>/ フォルダーに移動し(migrations.json でそのパスを更新)します。
migration は、その種類のフィールドを持ち、version なしで migrations.json に登録されます。詳細は以下のバージョニングを参照してください。登録されるキーには、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 のエージェント型フローで実行される際にペアのpromptに渡され、エージェントがユーザー所有の部分に集中できるようにします。
migration で実行できる操作の例(ファイルの生成、GritQL を使用した既存ファイルの変更、JSON の読み取りと更新)については、Nx Generator ガイドを参照してください。
ガードレール
Section titled “ガードレール”Migration は制御できないワークスペースに対して実行されるため、以下に従うことをお勧めします(スキャフォールディングされたスケルトンにはこれらが組み込まれています):
- GritQL でソースコードを変換する。 正規表現や文字列置換ではなく、GritQL ヘルパー(
applyGritQL、matchGritQL)を使用してソースを編集します。GritQL は AST に一致するため、ユーザーのコピーが変化したフォーマット、空白、引用符にかかわらず、1 つのパターンが保持されます。テキストマッチングでは、同等のコードを静かに見逃したり、ファイルを破損したりします。JSON にはupdateJsonを使用し、他の構造化された設定には一致するパーサーを使用します。 - 書き込む前にパターンマッチする。 ターゲットファイルがジェネレーターが生成する形状から逸脱している場合は、ユーザーの変更を上書きするのではなく、スキップして
nextSteps経由で報告するか、hybrid migration を検討してください。matchGritQLはそのチェックを行う便利な方法です。 - 残っていることだけを報告する。
nextStepsはユーザーが引き継ぐ必要がある作業用であり、行った編集の記録ではありません。それらはすでにgit diffにあります。 - 冪等性。 migration を再実行しても何も起こらないようにする必要があります。コードを挿入する GritQL の書き換えを
where { ... <: not contains ... }句でガードし、2 回目の実行で重複が追加されないようにします。 - 書き込んだものをフォーマットする。
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 が編集を残し、代わりに報告することを確認します。
バージョニング
Section titled “バージョニング”Nx は、ユーザーがインストールしたプラグインのバージョンが migration の version より小さい場合に migration を実行します。このジェネレーターは version フィールドを書き込みません。migration を出荷するリリースをカットする際に割り当て(またはリリースプロセスからスタンプ)して、以前のバージョンからアップグレードするすべてのユーザーに対して実行されるようにします。
バージョンを割り当てると、各種類の migration を 1 つずつ登録する 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 の実行”ユーザーは、2 ステップの 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-migrationsAgentic および hybrid migration は、利用可能な場合、nx migrate --run-migrations 中にユーザーのローカルコーディングエージェントによって適用されます。
アップグレードするユーザーの視点からの完全なフロー(deterministic および agentic migration の出力例を含む)については、ワークスペースのアップグレードを参照してください。