콘텐츠로 이동

Nx Migration 생성기

Nx 플러그인에 Nx Migration을 추가합니다. Migration을 사용하면 nx migrate가 플러그인의 이전 버전에서 생성된 프로젝트를 자동으로 업데이트할 수 있습니다. 이는 타겟 이름 변경, 제공된 설정 변경, 또는 코드 변경이 필요한 종속성 업데이트와 같은 주요 변경 사항이 있을 때 유용합니다.

이 생성기는 migration을 스캐폴딩하고, 플러그인의 migrations.json에 등록하며, 플러그인의 package.jsonnx-migrations 필드를 연결합니다(아직 존재하지 않는 경우 둘 다 생성합니다).

Terminal window
pnpm nx g @aws/nx-plugin:ts#nx-migration
어떤 파일이 변경될지 확인하기 위해 드라이 런을 수행할 수도 있습니다
Terminal window
pnpm nx g @aws/nx-plugin:ts#nx-migration --dry-run
매개변수타입기본값설명
project 필수string-마이그레이션을 추가할 Nx Plugin 프로젝트입니다. ts#nx-plugin 생성기를 사용하여 생성하는 것을 권장합니다.
name 필수string-마이그레이션 이름, kebab-case 형식으로 작성 (예: rename-foo-target)
description string-마이그레이션이 수행하는 작업에 대한 설명, nx migrate 명령어로 표시됨
kind deterministic | agentic | hybriddeterministic마이그레이션의 종류: deterministic (코드모드), agentic (사용자 소유 코드에 AI가 적용하는 프롬프트), 또는 hybrid (기계적인 부분을 처리한 후 에이전트에게 넘기는 코드모드)
preferInstallDependencies booleantrue생성기 실행 후 의존성 설치를 선호할지 여부입니다. 여러 생성기를 일괄 처리할 때 설치를 연기하려면 false로 설정하세요(후속 생성기가 Nx 프로젝트 그래프를 계산할 수 있도록 필요한 경우 설치는 여전히 실행됩니다). 마지막에 한 번만 설치하세요.

Migration은 세 가지 형태로 제공되며, migrations.json 항목이 포함하는 필드에 따라 구분됩니다. --kind를 전달하여 선택하세요(기본값 deterministic):

  • Deterministic (implementation) — 정확한 이전/이후 상태를 가진 코드모드이며, 가장 먼저 사용해야 하는 방식입니다. CI 및 비대화형 터미널을 포함하여 무인으로 실행되며, 모든 사용자에게 동일하게 적용됩니다. 변경 사항이 나타나는 모든 곳에서 안정적으로 일치시킬 수 있는 형태를 가질 때 단독으로 사용하며, 건너뛴 항목은 nextSteps를 통해 보고합니다.
  • Hybrid (implementation + prompt) — 하나의 변경 사항의 두 부분입니다. 변경 사항이 주요 변경이며 기계적으로 완전히 적용할 수 없을 때 사용합니다: 코드모드는 안전하게 일치시킬 수 있는 만큼 수행하고 변경한 내용과 건너뛴 내용을 설명하는 agentContext를 반환합니다; Nx는 해당 컨텍스트를 쌍을 이루는 prompt에 전달하여 나머지 부분을 처리합니다. 프롬프트는 남은 편집이 코드모드하기에는 너무 많은 형태에 걸쳐 있을 때 워크스페이스가 손상된 상태로 남는 것을 방지합니다.
  • Agentic (prompt) — Nx의 에이전트 기반 nx migrate 플로우를 통해 사용자의 로컬 코딩 에이전트가 적용하는 마크다운 지침 파일입니다. 올바른 편집이 사용자가 구축한 내용에 따라 달라지기 때문에 기계적인 이전/이후 상태가 전혀 유지되지 않을 때 단독으로 사용합니다. 에이전트가 실행되지 않을 때(CI, 에이전트 미설치, 동의 거부), Nx는 프롬프트를 수동 지침으로 표시하므로 프롬프트를 독립적이고 사람이 실행 가능한 단계로 작성하세요.

생성기는 선택한 kind에 따라 플러그인 프로젝트의 소스 폴더 아래에 다음 파일을 생성합니다:

  • 디렉터리src/migrations/latest/<name>/
    • migration.ts 코드모드 구현 (deterministic 및 hybrid)
    • migration.spec.ts migration을 위한 테스트 (deterministic 및 hybrid)
    • prompt.md 에이전트/사람 지침 (agentic 및 hybrid)
  • migrations.json migration을 등록하기 위해 생성 또는 업데이트됨
  • package.json “nx-migrations” 항목을 추가하기 위해 생성 또는 업데이트됨

새 migration은 latest/에 생성됩니다. migration을 제공하는 릴리스별로 그룹화하면 컬렉션이 증가함에 따라 순서를 한눈에 볼 수 있습니다 — 버전을 할당할 때 migration을 v<x.y.z>/ 폴더로 이동하고(그리고 migrations.json에서 경로를 업데이트하세요).

이는 해당 종류의 필드와 version 없이 migrations.json에 migration을 등록합니다 — 아래 버전 관리를 참조하세요. 등록된 키는 migration이 있는 폴더로 접두사가 붙습니다(latest-<name>), 따라서 나중에 변경할 때 이름을 재사용해도 이미 제공된 migration을 자동으로 덮어쓰지 않습니다.

deterministic(또는 hybrid) migration은 가상 파일시스템(Tree)을 변경하고 MigrationReturnObject를 반환하는 함수입니다. 다음은 둘 다 반환하는 hybrid migration입니다:

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 };
}
  • nextStepsnx migrate 실행 후 Nx가 사용자에게 출력하는 후속 작업입니다. 모든 항목은 사용자가 수동으로 수행해야 하는 작업이어야 합니다: 건너뛴 파일 조정(아래 가드레일 참조), 또는 잠금 파일을 새로 고치기 위한 설치와 같이 migration의 범위를 벗어난 작업 완료. 변경한 내용의 로그가 아닙니다 — 변환이 깔끔하게 적용되면 아무것도 추가하지 마세요. 그렇지 않으면 실제로 조치가 필요한 항목이 묻힙니다.
  • agentContext (hybrid만 해당) — 코드모드가 변경한 내용의 요약으로, Nx의 에이전트 기반 플로우에서 실행될 때 쌍을 이루는 prompt에 전달되어 에이전트가 사용자 소유 부분에 집중할 수 있도록 합니다.

migration에서 수행할 수 있는 몇 가지 예제 작업(파일 생성, GritQL을 사용한 기존 파일 수정, JSON 읽기 및 업데이트)은 Nx Generator 가이드를 참조하세요.

Migration은 제어할 수 없는 워크스페이스에 대해 실행되므로 다음을 준수하는 것이 권장됩니다(스캐폴딩된 스켈레톤에 이러한 내용이 포함되어 있습니다):

  • GritQL로 소스 코드 변환. 정규식이나 문자열 교체 대신 GritQL 헬퍼(applyGritQL, matchGritQL)를 사용하여 소스를 편집하세요. GritQL은 AST를 일치시키므로 사용자의 복사본이 변경되었을 수 있는 형식, 공백 및 따옴표에 관계없이 하나의 패턴이 유지되며, 텍스트 일치는 동등한 코드를 조용히 놓치거나 파일을 손상시킵니다. JSON에는 updateJson을 사용하고 다른 구조화된 설정에는 일치하는 파서를 사용하세요.
  • 쓰기 전에 패턴 일치. 대상 파일이 생성기가 생성하는 형태에서 벗어난 경우, 사용자의 변경 사항을 덮어쓰는 대신 건너뛰고 nextSteps를 통해 보고하거나 hybrid migration을 고려하세요. matchGritQL은 해당 확인을 수행하는 편리한 방법입니다.
  • 남은 작업만 보고. nextSteps는 사용자가 처리해야 하는 작업을 위한 것이지, 수행한 편집의 기록이 아닙니다 — 그것들은 이미 git diff에 있습니다.
  • 멱등성. migration을 다시 실행하면 아무 작업도 수행하지 않아야 합니다. 코드를 삽입하는 GritQL 재작성을 where { ... <: not contains ... } 절로 보호하여 두 번째 실행이 중복을 추가하지 않도록 하세요.
  • 작성한 내용 포맷. formatFilesInSubtree(tree)로 마무리하여 migration이 작성한 파일이 올바르게 포맷되도록 하세요.

스캐폴딩된 migration.spec.tscreateTreeUsingTsSolutionSetup()을 사용하여 프리셋이 생성하는 형태와 일치하는 가상 워크스페이스를 구축합니다. 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이 작성한 대로 수행한다는 것만 증명합니다. 플러그인의 게시된 버전(사용자가 업그레이드하는 상태)에서 생성된 워크스페이스에 대해서도 테스트하고 결과가 현재 생성기가 생성하는 것과 일치하는지 확인하세요: diff를 검사하고, 새 워크스페이스에 동일한 프로젝트를 생성하여 비교하고, 워크스페이스가 여전히 빌드되는지 확인한 다음, migration을 다시 실행하여 아무것도 변경하지 않는지 확인하세요. 먼저 사용자 정의한 워크스페이스로 반복하여 migration이 편집 내용을 그대로 두고 대신 보고하는지 확인하세요.

Nx는 사용자가 설치한 플러그인 버전이 migration의 version보다 낮을 때 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"
}
}
}

사용자는 두 단계의 nx migrate 플로우로 플러그인의 migration을 적용합니다 — 대기 중인 migration을 생성하고, 설치한 다음, 실행합니다:

Terminal window
pnpm nx migrate my-plugin@latest
pnpm nx migrate --run-migrations

Agentic 및 hybrid migration은 사용 가능한 경우 nx migrate --run-migrations 중에 사용자의 로컬 코딩 에이전트에 의해 적용됩니다.

업그레이드하는 사용자의 관점에서 전체 플로우(deterministic 및 agentic migration의 예제 출력 포함)는 워크스페이스 업그레이드를 참조하세요.