feat(plugin): 既存 plugins/ → repos/ マイグレーション (PLAN04 PR2)#30
feat(plugin): 既存 plugins/ → repos/ マイグレーション (PLAN04 PR2)#30takemi-ohama wants to merge 9 commits into
Conversation
PLAN04 PR2。PR1 (#29) で repos/ 永続クローン方式に切り替えたが、PR1 以前に plugins/<name>/ へファイルコピーされた既存インストールは移行されないため、その 移行ロジックを追加する。 - migrator.py (新規): - needs_migration / _is_legacy_plugin: legacy plugins/ インストールの検出 (linked は --link 専用として除外) - _dirs_differ: コピーとクローンの差分検出 (内容変更・追加ファイルを保守的に差分扱い) - migrate: 未クローン repo の永続クローン作成、InstalledPlugin.path の repos/ 書き換え、 差分なしは plugins/<name> 削除・差分ありは <name>.bak 保全、sync_projects 再実行、 --link/.bak/skip が無ければ plugins/ を .gitkeep のみに正規化 - plugin migrate サブコマンド (cli.py / commands/plugin.py) - install/update 初回実行時に _auto_migrate で自動移行 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | gemini | REQUEST_CHANGES
マイグレーション時のデータ損失リスクを回避するため、比較ロジックの厳密化とバックアップの保護が必要です。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | codex | REQUEST_CHANGES
データ保持を目的にした migration で、symlink 差分の見落としと、失敗時に registry だけ先行更新される経路があります。どちらも旧 plugins/ copy の退避・削除前後の整合性を保つよう修正してください。
cross-review round 1 の major 指摘 4 件 (codex 2 / gemini 2) に対応。 - _dirs_differ: regular file のみ比較していたため legacy copy のみに存在する symlink / 空ディレクトリ / 型不一致を差分として検知できず、後続の shutil.rmtree で silently 削除される恐れがあった。全エントリを対象に 型 + 内容 (file は byte, symlink は target) を比較するよう厳密化 - _unique_bak_path: 既存の <name>.bak を無条件に rmtree していたため、 前回 migration で保全した未整理バックアップが消失する恐れがあった。 存在時は .bak-2, .bak-3 ... と一意名に退避するよう変更 - migrate: filesystem の退避/削除が成功してから registry.add で plugins.yml を repos/ path に書き換えるよう順序を入れ替え。失敗時に registry だけ先行更新され retry も効かなくなる partial state を防止 - _cleanup_plugins_dir: .bak-N 形式も保全 .bak として検知するよう調整 - 上記挙動を網羅するテスト 6 件追加 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cross-review round 1 fix 対応サマリcommit:
対応した指摘 (全 4 thread / 独自再判定の結果すべて major で確定)
テストmigrator テスト 6 件追加 (symlink 追加 / 空ディレクトリ / symlink target 変更 / 型不一致 / 一致 symlink / 既存 .bak 非上書き)。全 249 件 pass。ruff ( deferred / rejected
CI本 PR は base が @reviewers 再レビューをお願いします。 |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | gemini | REQUEST_CHANGES
今回の修正で、migration 時の filesystem 操作の安全性や順序の整合性が向上しました。一方で、差分検知ロジックの厳格さによる UX への影響や、状態報告の不正確な箇所が見受けられます。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | codex | REQUEST_CHANGES
移行処理で再試行不能な状態を残すパスと、通常の upstream 追加をローカル変更扱いする差分判定は修正が必要です。新規 devbase plugin migrate コマンドの CLI リファレンスも同じPRで追加してください。
cross-review round 2 の指摘対応。 - _dirs_differ: upstream 専用追加 (clone にのみ存在) を差分扱いしないよう 変更。コピー側にのみ存在するエントリ・共通エントリの型/target/内容差分の みを preserved 判定に使い、通常の upstream 更新で不要な .bak 退避が発生 しないようにした (codex#91 / gemini#91 重複指摘)。 - _files_equal: read_bytes() の全読み込みを 64KB チャンクのストリーム比較に 置き換え、巨大ファイルでのメモリ枯渇リスクを排除 (gemini#105)。 - _ensure_repo_cloned: 前回 clone 失敗で残った partial dir (.git 無し / registry.yml 不正) を検知して削除・再 clone するよう修正。無限に parse 失敗を繰り返す経路を解消 (codex#132)。 - _cleanup_plugins_dir: .gitkeep でも .bak でもない想定外エントリが残る場合 は cleaned=True と報告せず False を返すよう修正 (gemini#176)。 - docs: devbase plugin migrate の CLI リファレンスを追加 (codex review body)。 テスト 4 件追加 (upstream 専用追加は差分なし / 同サイズ内容差 / partial clone 再 clone / cleanup の想定外エントリ保持)。全 252 件 pass。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cross-review round 2 fix 対応サマリcommit:
(実 thread 5 件 / うち line 91 は codex・gemini の重複指摘で実体 1 件) 対応した指摘
ドキュメント
テストmigrator テスト 4 件追加 (upstream 専用追加は差分なし / 同サイズ内容差 / partial clone 再 clone / cleanup の想定外エントリ保持)。既存の upstream-only 差分テストを新挙動に更新。全 252 件 pass。ruff ( deferred / rejected
CI本 PR は base が @reviewers 再レビューをお願いします。 |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | gemini | REQUEST_CHANGES
今回の変更により、旧形式のプラグイン管理から repos/ ベースへの移行が自動化されます。全体的に良くテストされていますが、移行処理の正確性とパフォーマンスの観点から以下の点を修正してください。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | codex | REQUEST_CHANGES
移行時の保全判定と clone 健全性確認に、ユーザー変更を失うケースと復旧不能な repos/ path を登録するケースが残っています。下記を修正してください。
cross-review round 3 の指摘に対応: - _cleanup_plugins_dir の `.bak` 判定を `'.bak' in name` から `<name>.bak[-N]` 末尾一致 (_is_bak_name) に修正。my.bakery 等の誤マッチを排除 - migrate ループ内の per-plugin `registry.add` を loop 末尾の単一 `registry.add_many` に集約し plugins.yml の保存頻発を解消 (各 plugin の fs 移動と entry 構築は同一 try 内のため失敗時の retry 性は維持) - _ensure_repo_cloned で local_path 設定済みでも .git/registry.yml を 検証 (_clone_is_healthy)。壊れた既存 dir は除去して再 clone - _files_equal で S_IMODE を比較。旧コピーの実行ビット変更を差分扱いし保全 - _auto_migrate の preserved/skipped 再通知を loud な per-plugin WARNING から 簡潔な INFO ヒント 1 行に抑制 (詳細は devbase plugin migrate 側で出力) migrator テスト 12 件追加 (.bak 末尾判定 / clone 健全性 / 実行ビット差分 / batched save / broken local_path 再 clone / 警告抑制)。全 264 件 pass。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cross-review round 3 fix 対応サマリcommit:
(対象 thread 5 件 / すべて妥当な指摘で修正対応) 対応した指摘
テストmigrator テスト 12 件追加 ( deferred / rejected
CI本 PR は base が @reviewers 再レビューをお願いします。 |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 4 | gemini | REQUEST_CHANGES
全体として移行ロジックの堅牢性が向上していますが、registry 保存時のデータ整合性やパーミッション比較の感度について改善の余地があります。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 4 | codex | REQUEST_CHANGES
既存の repos/ クローンを修復する経路で、ローカル変更を含む可能性がある作業ツリーを無条件削除しないようにしてください。
…PR2 round4) - registry.add_many: 引数内で名前が重複する場合 last-wins で一意化してから 反映し、plugins.yml に矛盾エントリが残らないようにした - _files_equal: 全権限ビット比較を exec ビット (+x) 限定に変更し、umask / group 設定差による誤った .bak 退避を防止 - _ensure_repo_cloned: local_path 記録済みだが unhealthy な既存 dir でも .git があれば未コミット/未 push のローカル変更を失わないよう rmtree せず PluginError を送出し、.git 欠落 (真に壊れている) 場合のみ再 clone する test: add_many 重複排除 / exec ビット限定 / .git 付き clone 保全の 6 件を追加 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cross-review round 4 fix 対応サマリcommit:
(対象 thread 3 件 / すべて round 3 修正への追従指摘で、いずれも妥当と判定し修正対応) 対応した指摘
テストmigrator/registry テスト 6 件追加 ( deferred / rejected
CI本 PR は base が @reviewers 再レビューをお願いします。 |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 5 | codex | REQUEST_CHANGES
移行処理に、失敗時の整合性崩れと既存 clone 削除のデータ保全リスクが残っています。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 5 | gemini | APPROVE
PLAN04 (repos/ ベースのプラグイン管理) への移行ロジックおよび、既存の plugins/ からの自動移行 (auto-migration) の実装を確認しました。移行時の不整合を防ぐための registry.add_many での重複排除や、umask 等の影響を排除した _files_equal (exec bit 限定比較) など、エッジケースへの配慮が行き届いており、テストも非常に網羅的です。
インラインで指摘した点は、手動でファイルを壊した場合などの極めて限定的な状況に関するものであり、全体として品質は非常に高いと判断します。
また、PR外の既存コードではありますが、lib/devbase/plugin/registry.py の _save メソッド (L49付近) において、tmp_path が未定義の状態で locals() を参照する可能性があります(mkstemp 自体が失敗した場合)。動作上は locals() チェックでガードされていますが、try の前に tmp_path = None と初期化しておく方がより安全で明快です。
…検知 (PR2 round5) cross-review round 5 で指摘された 4 件に対応: - derived clone 経路 (.git 保護): repo.local_path 未設定でも repos/<derived> に .git 付き既存 clone があり registry.yml だけ欠ける場合、無条件 rmtree で 未コミット/未 push のローカル変更を失っていた。_reclaim_or_protect_existing を新設し local_path 経路と同じく .git 有りは削除せず PluginError で復旧案内 する (freshly clone した分のみ破棄)。 - registry 先行永続化: 旧 plugins/ コピーの削除/.bak 退避 → add_many の順序を 逆転し、検証済み path rewrite を破壊的 fs 操作の前に 1 回保存する二相構成へ。 保存失敗時はコピー無傷で abort (次回 retry 可能)、phase2 の retire 失敗は registry が既に有効な repos/ clone を指すため lingering copy として _cleanup_plugins_dir が surface する (silent data loss を排除)。 - clone_dir がファイル/symlink で squat: clone_dir.is_dir() のみでは git_clone が失敗するため、ファイル/symlink は unlink して再 clone (git tree を持たない ため損失なし)。 - _entry_kind == 'other' (socket/pipe/device): 内容比較できず identical を 証明できないため diverged 扱いとし .bak 保全に倒す。 migrator テスト 5 件追加 (derived .git 保護 / clone_dir ファイル squat / registry 保存失敗でコピー無傷 / retire は保存後 / fifo は差分扱い)。 全 275 件 pass。ruff (E9,F63,F7,F82) / compileall pass。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cross-review round 5 fix 対応サマリcommit:
(対象 thread 4 件 / すべて round 3/4 修正への追従ハードニングで、いずれも妥当と判定し修正対応) 対応した指摘
テストmigrator テスト 5 件追加 (derived deferred / rejected
CI本 PR は base が @reviewers 再レビューをお願いします。 |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 6 | gemini | APPROVE
PR #30 の実装を詳細に確認しました。全体として、非常に堅牢で配慮の行き届いた設計(二相コミット形式の migration、.git ディレクトリの保護、SSH/HTTPS URL の重複検知など)であり、実環境でのデータ安全性が高く評価できます。
設計レベルでの重大な懸念事項は見当たりませんでした。以下に、パフォーマンスとエッジケースの正確性に関する軽微な改善提案を数点送ります。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 6 | codex | REQUEST_CHANGES
正常な既存 repos/ clone を再利用できず migration が skip される経路が残っています。
round 5 で derived 経路 (local_path 未設定) の `.git` 付き既存 dir を 無条件に保護 (PluginError) していたが過剰だった。`repos/<derived>` に .git + registry.yml が両方そろった健全 clone が残っている場合は PluginError で migration を skip せず、そのまま reuse して local_path を 永続化するよう修正。 - 健全 clone (.git + registry.yml) → reuse + local_path 永続化 - .git ありだが unhealthy (registry.yml 欠落) → 従来どおり保護 (PluginError) - .git 無し / file・symlink squat → reclaim して再 clone local_path 経路と derived 経路で挙動を揃え、fresh clone 後と healthy reuse 後の local_path 永続化を `_persist_repo_local_path` に共通化した。 健全 derived clone が reuse され migration が skip されないことを検証する テスト `test_derived_path_with_healthy_clone_is_reused` を追加。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cross-review round 6 fix 対応サマリcommit:
(OPEN thread 3 件 / 内訳: codex 1 件 修正, gemini 2 件 = deferred 1 + praise 1) 対応した指摘
deferred (1 件)
no-action (1 件)
テストmigrator テスト 1 件追加 ( rejected
CI本 PR は base が @reviewers gemini は round 6 で APPROVE 済み、codex の major 1 件を本コミットで修正しました。再レビューをお願いします。 |
_ensure_repo_cloned が clone のたびに add_repository で plugins.yml を 保存していたため、多数リポジトリ移行時に保存回数が repo 数に比例していた。 clone 済み repo 行を pending_repos に貯め、path rewrite と合わせて Phase2 (破壊的 cleanup) の直前に save_migration で 1 回だけ保存するよう変更。 二相アトミシティは維持: 旧 copy 削除より前に registry が必ず flush 済みで あること (clone を指す local_path / plugin path の両方) を不変条件として 保持。save_migration は repos + plugins を単一 load+save で upsert する。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cross-review deferred minor 追対応 (round 7)round 6 で deferred としていた minor 指摘 1 件 (thread 指摘: 対応: clone 済み repo 行を
二相アトミシティ維持: テスト: 多数 repo の fresh clone でも commit: 0c7549b |
|
ℹ️ レビューコメント履歴整理のため本 PR を一度 close し、同じブランチ |
Summary
PR1 (#29) で repos/ 永続クローン方式に切り替えたが、PR1 以前に
plugins/<name>/へファイルコピーされた既存インストールは移行されない。本 PR でその移行ロジックを追加する。
実装内容 (予定)
lib/devbase/plugin/migrator.py(新規): plugins/ → repos/ 移行ロジック.bak保全 + warningInstalledPlugin.pathの書き換え + sync_projects 再実行--linkが 0 件なら plugins/ を.gitkeepのみ残して削除lib/devbase/commands/plugin.py+cli.py:devbase plugin migrateサブコマンド追加tests/plugin/: マイグレーションテストTest plan
.bak保全--link残存時は plugins/ を維持 / 0 件なら .gitkeep 残して削除