enonic-content-migration について
Enonic XP のコンテンツ一括操作と移行を扱うスキルです。API とブランチコンテキストの選択、バッチ処理、長時間タスクの進捗や結果の確認を案内します。
主な機能
- 01Enonic XP プロジェクトとバージョンの検出
- 02API とコンテキスト選択の案内
- 03NoQL クエリと集計の作成
- 04コンテンツのバッチ処理
- 05長時間タスクの進捗報告
- 06移行と公開結果の検証
活用シーン
- 01外部データからコンテンツを一括作成
- 02条件に合うコンテンツの更新や削除
- 03パスや環境間でコンテンツを移行・変換
- 04コンテンツを検索し集計で要約
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ webmaxru/ enonic-agent-skills --skill enonic-content-migrationインストール後、Claude Code で/enonic-content-migrationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/bulk-update.template.tstask-migration.template.tsreferences/compatibility.mdexamples.mdmigration-reference.mdtroubleshooting.mdscripts/find-enonic-targets.mjs詳細
Enonic コンテンツ移行
手順
ステップ 1:Enonic XP プロジェクトと操作範囲を特定する
- ワークスペース内で Enonic XP プロジェクトを示す要素を確認します。
com.enonic.xp依存関係を含むbuild.gradle、src/main/resources/ディレクトリ構造、またはxpVersionを含むgradle.propertiesが該当します。 - Node ランタイムを利用できる場合は、
node scripts/find-enonic-targets.mjs .を実行して、Enonic XP プロジェクトを示す要素と既存のコンテンツ操作ファイルを検索します。 - Enonic XP プロジェクトが検出されない場合は、ここで終了し、このスキルは Enonic XP のコンテンツ操作のみを対象としていることを説明します。
gradle.propertiesまたはbuild.gradleから対象の XP バージョンを特定し、適切な API サーフェスを選択します。- 要求された操作を分類します。
- 一括作成:外部ソース(JSON、CSV、API)からコンテンツをインポートします。
- 一括更新:クエリ条件に一致する既存のコンテンツを変更します。
- 一括削除:クエリ条件に一致するコンテンツを削除します。
- 移行:パス、サイト、または環境間でコンテンツを移動または変換します。
- クエリ/集計:NoQL と集計を使用してコンテンツを取得、分析します。
- 長時間実行タスク:進捗報告が必要な、約 100 件を超えるアイテムを処理する操作です。
ステップ 2:API レイヤーとコンテキストを選択する
- クエリ DSL のパターン、バッチ処理の戦略、ブランチの処理ルールについては、
references/migration-reference.mdを読みます。 - CMS コンテンツを扱い、公開/非公開、コンテンツタイプの検証、コンテンツドメインの抽象化が必要な操作では、
lib-contentを選択します。 - 低レベルのノード操作、カスタムリポジトリ、または生データ移行でコンテンツタイプの検証を回避する必要がある操作では、
lib-nodeを選択します。 - 必要なコンテキストを特定します。
- 変更操作では
draftブランチ、公開済みコンテンツの読み取りではmasterブランチで操作を実行するために、lib-contextを使用します。 - 高い権限が必要な操作では、
role:system.adminプリンシパルを指定してlib-contextを使用します。
- 変更操作では
- 約 100 件を超えるアイテムを処理する操作は、
lib-taskを使用したタスクコントローラーでラップします。パターンについては、references/migration-reference.mdのタスクコントローラーのセクションを読みます。
ステップ 3:クエリを構築する
- 対象コンテンツに一致する NoQL クエリ文字列または DSL 式を構築します。
- コンテンツタイプでフィルタリングするには、
contentLib.query()のcontentTypesパラメーター、またはノードクエリのtypeプロパティ比較を使用します。 - 日付範囲クエリには、
instant()またはdateTime()関数と、range()クエリ関数を使用します。 - 全文検索には、適切なフィールドパスと演算子(
AND/OR)を指定してfulltext()を使用します。 - パスを限定した操作では、子孫に一致するよう
_path LIKE '/content/site-path/*'を使用します。注:NoQL クエリの_pathプロパティには内部の/content/プレフィックスが含まれますが、結果のhit._pathにはコンテンツドメインのパスが返され、プレフィックスは含まれません。結果のパスからクエリを構築する際は、必ず/content/を先頭に付けてください。 exists、notExists、hasValue、またはbooleanの組み合わせを使用して、クエリ後の絞り込みを効率化するfiltersを追加します。- グループ化された統計情報(用語の件数、日付ヒストグラム、数値範囲、統計情報)が必要な操作では、
aggregationsを追加します。 - クエリと集計の完全なパターンについては、
references/examples.mdを読みます。 ステップ 4:バッチ処理を実装する startパラメーターとcountパラメーターを使ってページネーションで取得し、すべての結果をメモリに読み込まないようにします。- アイテムごとの処理の複雑さに応じて、
countを 50~200 のバッチサイズに設定します。 result.hits.length === 0またはstart >= result.totalになるまでループし、反復ごとにstartをバッチサイズ分増やします。contentLib.create()を一括で実行する際は、アイテムごとのインデックス更新を避けるためにrefresh: falseを設定し、バッチ完了後に手動で更新します。contentLib.modify()では、各コンテンツアイテムを安全に変換するためにエディターコールバックパターンを使用します。contentLib.publish()では、大規模な公開セットでタイムアウトしないよう、キーを 50~100 件ずつのグループに分けて処理します。- レポート用に成功数と失敗数を記録します。
- 再利用可能なバッチ更新コントローラーテンプレートについては、
assets/bulk-update.template.tsを確認します。注:テンプレートでは TypeScript/ESM 構文(import、const、アロー関数)が使われています。.jsファイルとして XP ランタイムにデプロイする際は、CommonJS JavaScript(require()、var、function())に適合させてください。
ステップ 5:ブランチ操作と公開を処理する
- コンテンツの変更は
draftブランチのコンテキストで実行します。 - 変更が完了したら、
contentLib.publish()を使って変更したアイテムをmasterに公開します。XP < 7.12 の場合は、sourceBranch: 'draft'とtargetBranch: 'master'を渡します。XP 7.12 以降では、これらのパラメーターは無視されます(常に draft から master に公開されます)。 - 一括更新したアイテムを公開する際は、依存関係が意図せず公開されるのを避けるため、
includeDependencies: falseを設定します。 - draft と master の状態を比較する操作には、
lib-nodeのrepo.diff()を使用し、target: 'master'とincludeChildren: trueを指定します。
ステップ 6:時間のかかる操作をタスクコントローラーでラップする
- インラインのタスク関数には
taskLib.executeFunction()を、名前付きタスク記述子にはtaskLib.submitTask()を使用します。 - バッチ処理中は、一定の間隔で
taskLib.progress({ info, current, total })を使って進捗を報告します。 - 進捗報告に対応した再利用可能なタスクコントローラーテンプレートについては、
assets/task-migration.template.tsを確認します。 - 重複した操作を開始する前に、
taskLib.isRunning()で既存の実行中インスタンスを確認します。 - 操作による負荷が過剰な場合は、バッチ間のスロットリングに
taskLib.sleep()を使用します。 - XP 7.13 以降の名前付きタスクでは、
run関数の第 2 引数としてtaskIdが渡されます:exports.run = function(params, taskId) { ... }。
ステップ 7:結果を検証して報告する
- 操作の完了後、処理したアイテム数、作成・更新・削除したアイテム数、失敗したアイテム数、合計所要時間の概要をログに記録します。
- 移行操作では、移行先のパスをクエリして、移行先にコンテンツが存在することを確認します。
- 公開操作では、
masterブランチをクエリして、公開状態を確認します。 - エラーが発生した場合は、エラーの詳細(コンテンツパス、エラーメッセージ)を構造化レポートにまとめます。
エラー処理
scripts/find-enonic-targets.mjsで Enonic XP プロジェクトが見つからない場合は、ワークスペースに Enonic XP アプリケーションが含まれていないことを説明します。- コンテンツ操作で
contentAlreadyExistsエラーが発生した場合は、対象が存在するか確認し、更新するかスキップするかを判断します。重複の処理パターンについては、references/troubleshooting.mdを確認します。 - クエリ結果が 0 件の場合は、クエリ構文、ブランチのコンテキスト、プロパティのパスを確認します。NoQL の文字列形式の不一致(たとえば、日付比較で
instant()ラッパーがないこと)は、よくある原因です。 - タスクが失敗またはタイムアウトした場合は、
taskLib.get(taskId)で状態と進捗の詳細を確認します。タイムアウトや権限の問題については、references/troubleshooting.mdを確認します。 - 公開または変更時に
AccessDeniedExceptionが発生した場合は、lib-contextを介してコンテキストにrole:system.adminプリンシパルが含まれていることを確認します。
コメント
Markdown 対応