Skip to content

feat: PLAN32-entrypoint entrypoint の複数リポジトリ clone と workspace 生成 - #106

Merged
takemi-ohama merged 5 commits into
release/PLAN32from
feature/PLAN32-entrypoint
Aug 22, 2026
Merged

feat: PLAN32-entrypoint entrypoint の複数リポジトリ clone と workspace 生成#106
takemi-ohama merged 5 commits into
release/PLAN32from
feature/PLAN32-entrypoint

Conversation

@takemi-ohama

@takemi-ohamatakemi-ohama commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

コンテナ起動時のリポジトリ取得を 1 リポジトリ固定から複数リポジトリ対応へ変更します。

  • containers/base/entrypoint.sh
    • GIT_USER / GIT_REPO による単一 clone を廃止し、ホストから渡される clone プラン(DEVBASE_REPOS = base64 の US (0x1f) 区切りレコード列)を 1 行ずつ処理して /work 配下へ複数リポジトリを clone する
    • リポジトリごとに branch のチェックアウト、init.sh 実行の有無を切り替える
    • DEVBASE_PRIMARY_DIR のディレクトリへ最後に cd する(ログイン直後の作業場所)
    • DEVBASE_WORKSPACE / DEVBASE_WORKSPACE_B64 があれば multi-root workspace ファイルを書き出す
  • tests/containers/test_entrypoint_repos.py を追加

設計上の判断

  • clone / checkout / init.sh の失敗は warning に留めて次のリポジトリへ進む。1 つ落ちただけでコンテナが起動しないと、他リポジトリでの作業まで止まるため(従来の単一 clone も fail-soft だった挙動を踏襲)
  • workspace ファイルの中身はホスト側で組み立てて base64 で渡す。JSON のエスケープをシェルでやらない分、壊れにくく、生成ロジックをテストできる場所に置ける
  • フィールド区切りにタブではなく US (0x1f) を使う。タブは IFS の空白として扱われ連続する区切りが 1 つに畳まれるため、branch 未指定(空フィールド)の行で init の値がずれる。非空白の US なら IFS=$'\x1f' read -r url dir branch init がそのまま 4 列として読める
  • 行区切りは LF で末尾にも LF を付けるwhile read は EOF 直前の改行なし行を読み捨てる実装があるため、末尾 LF が無いと repo 1 件のときにその唯一の行が落ちる
  • 関数定義だけを source できるようにしたDEVBASE_ENTRYPOINT_LIB_ONLY=1)。ローカルの bare リポジトリを file:// で clone するテストにより、Docker にもネットワークにも依存せず検証できる

⚠ 適用にはベースイメージの再ビルドが必要

entrypoint はイメージに焼き込まれるため、devbase up では反映されません。検証・利用時は devbase build --no-cache が必要です。

Test plan

  • uv run pytest tests/containers/ — 16 passed / 1 skipped(全リポジトリの clone / branch チェックアウト / init.sh の実行可否 / clone 失敗時の継続 / checkout 失敗時の継続 / 既存 clone の保持 / プラン未設定 / 壊れたプラン / workspace 書き出し / primary への cd / 旧 GIT_REPO で clone しないこと / 実物の encode_repo_plan 出力を通す結合テスト)
    • 結合テストは lib/devbase/project/config.py(Task 1 / 別 PR)が入るまで importorskip で skip。release ブランチで両 Task が揃うと自動で有効化される
  • uv run pytest — 全 1260 件 green(+ skip 1)
  • bash -n containers/base/entrypoint.sh
  • 実機: devbase build --no-cache → 複数リポジトリのプロジェクトで devbase up/work に全リポジトリが clone され primary へ cd していること(release ブランチでの結合検証で実施)

PLAN32 Task 3。GIT_USER/GIT_REPO による単一 clone を廃し、ホストが渡す
clone プラン (DEVBASE_REPOS = base64 TSV) を 1 行ずつ処理して /work 配下へ
複数リポジトリを clone する。branch 指定の checkout、init.sh の実行可否、
primary ディレクトリへの cd、複数 repo 用 workspace ファイルの書き出しを
それぞれ関数に分けた。
clone / checkout / init.sh の失敗は warning に留めて次のリポジトリへ進む。
1 つ落ちただけで起動できないと、他リポジトリでの作業まで止まるため。
TSV の分解に `IFS=$'\t' read` は使っていない。タブは IFS の空白扱いで連続
する区切りが 1 つに畳まれ、branch 未指定の行で init がずれるため、パラメータ
展開で 1 フィールドずつ切り出している。
関数定義だけを source できるようにし (DEVBASE_ENTRYPOINT_LIB_ONLY)、
ローカルの bare リポジトリを clone 元にした単体テストを追加した。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@takemi-ohamatakemi-ohama left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | codex | REQUEST_CHANGES

checkout 失敗時に誤った branch の初期化処理を実行しないよう、処理の打ち切りが必要です。

Comment threadcontainers/base/entrypoint.sh

@takemi-ohamatakemi-ohama left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | gemini | <REQUEST_CHANGES>

複数リポジトリの clone とワークスペース生成処理の実装方針・正確性は全体的に良好です。ただし、コンテナ再起動時における既存リポジトリへの git checkout 実行に関して重大な懸念があります。これを解消した上でのマージを推奨します。

Comment threadcontainers/base/entrypoint.sh
Comment threadtests/containers/test_entrypoint_repos.py Outdated
- checkout 失敗時に continue し、意図しない branch で init.sh が走らないようにする
- 既存 clone には checkout しない。コンテナ再起動のたびにユーザの作業ブランチから
設定 branch へ引き戻される問題を回避する
- テストの PATH ハードコードをやめ、実行環境を引き継ぐ (DEVBASE_*/GIT_* のみ除去)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@takemi-ohama

Copy link
Copy Markdown
ContributorAuthor

🔧 /ndf:fix サマリ (round 1)

対応件数: critical=0 / major=2 / minor=1 (合計 3 件)
deferred: 0 件 / rejected: 0 件
commit: 022f18b
CI: NONE (このブランチに紐づく workflow なし)

詳細

#指摘元箇所対応
1codex [major / 正確性]containers/base/entrypoint.shcheckout 失敗時に continue し、意図しない branch で init.sh を実行しないよう修正
2gemini [major / ユーザビリティ]containers/base/entrypoint.shcheckout を git clone 直後のみに限定。既存 clone ではユーザの作業ブランチを維持
3gemini [minor / テスト]tests/containers/test_entrypoint_repos.pyPATH ハードコードを廃止し os.environ を継承 (DEVBASE_* / GIT_* のみ除去してテストの独立性は担保)

指摘 1 と 2 は同じ checkout 処理に対するもので、cloned フラグを導入して一括で解決しています。

cloned=0
if [ -d"$target/.git" ];thenecho"Repository already exists: $dir"else
... git clone ... ||continue
cloned=1
fiif [ "$cloned"="1" ] && [ -n"$branch" ];thenif! git -C "$target" checkout "$branch";thenecho"Warning: Failed to checkout branch '$branch' in $dir (skipping)"continuefifi

追加した回帰テスト

  • test_a_failing_checkout_skips_the_init_script — checkout 失敗時に init.sh が走らない
  • test_existing_clone_keeps_the_branch_the_user_switched_to — 再起動しても作業ブランチに留まる

検証

  • uv run pytest1259 passed
  • uv run pytest tests/containers/15 passed
  • bash -n containers/base/entrypoint.sh → OK

entrypoint.sh はイメージへ焼き込まれるため、実機での動作確認は devbase build --no-cache が必要です。この PR では実施せず、release/PLAN32 での結合検証で行います。

@codex@gemini 再レビューをお願いします。

タブ区切りは IFS の空白扱いで連続する区切りが 1 つに畳まれるため、branch
未指定の行で init の値がずれる。非空白の US (0x1f) にすると bash の自然な
読み方 (IFS='�' read -r ...) がそのまま正しく動くので、パラメータ展開に
よる手動分解をやめて read に戻した。あわせて列数・init 値の検証を入れ、
壊れた行は警告に留めて次の行へ進む。
符号化側 (lib/devbase/project/config.py) と同じ契約に揃えている。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@takemi-ohamatakemi-ohama left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | codex | REQUEST_CHANGES

DEVBASE_REPOS の wire format を送受信側・PLAN32 仕様で統一し、実際の producer と entrypoint を通す結合テストを追加してください。

Comment threadcontainers/base/entrypoint.sh

@takemi-ohamatakemi-ohama left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | gemini |

コンテナ再起動時の git checkout による意図しないブランチ切り替え問題は適切に解消されています(clone 直後のみ実行されるよう修正済み)。
区切り文字の US (0x1f) への変更やバリデーションの追加により、空フィールドや不正フォーマットに対する堅牢性も向上しており、実装・テストともに十分な品質です。マージして問題ありません。

plan と PR 本文が base64 TSV を契約としていた一方、entrypoint と符号化側
(encode_repo_plan) は US (0x1f) 区切りへ移行済みで、契約と実装が食い違っていた。
タブは IFS の空白として扱われ連続する区切りが 1 つに畳まれるため、branch 未指定
(空フィールド) の行で init の値がずれる。非空白の US なら IFS=$'\x1f' read が
そのまま 4 列として読める。実装は既に正しいので、契約側 (plan) を US へ揃える。
- issues/PLAN32_multi-repo-project.md: スキーマ節の wire format を US 区切り
(行区切り LF / 末尾 LF あり) の記述へ更新。代替案表にタブ区切りを不採用案として
理由付きで追加
- containers/base/entrypoint.sh: 行区切りと末尾 LF、符号化側の所在をコメントに明記
- tests/containers/test_entrypoint_repos.py: 実物の encode_repo_plan の出力を
entrypoint に通す結合テストを追加 (config.py は Task 1 の別 PR なので
importorskip で未導入ブランチでは skip)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@takemi-ohama

Copy link
Copy Markdown
ContributorAuthor

🔧 /ndf:fix サマリ (round 2)

対応件数: critical=0 / major=1 / minor=0 (合計 1 件)
deferred: 0 件 / rejected: 0 件
commit: 73536cb
CI: NONE (このブランチに紐づく workflow なし)

詳細

#指摘元箇所対応
1codex [major / 後方互換性]containers/base/entrypoint.sh:12wire format の契約 (plan / PR 本文) を US (0x1f) 区切りへ統一し、実装との食い違いを解消

指摘は妥当でした。ただし直す方向は entrypoint を TSV へ戻すのではなく、契約側を US へ揃えるとしています。

  • タブは IFS の空白として扱われ連続する区切りが 1 つに畳まれるため、branch 未指定 (空フィールド) の行で init の値がずれる。非空白の US なら IFS=$'\x1f' read -r url dir branch init がそのまま 4 列として読める
  • 符号化側 (feat: PLAN32-config-loader project.yml ローダと wire format #104encode_repo_plan) も同じラウンドで US 区切り + 末尾 LF へ変更済みで、producer と consumer は既に揃っている。ずれていたのはドキュメントだけだった

変更内容

ファイル変更
issues/PLAN32_multi-repo-project.md「スキーマ」節の wire format を US 区切り / 行区切り LF / 末尾 LF ありへ更新。「代替案と採否」表にタブ区切りを不採用案として理由付きで追加。grep -n TSV → 0 件
PR 本文同様に「base64 TSV」の記述を更新
containers/base/entrypoint.sh行区切りと末尾 LF、符号化側の所在 (lib/devbase/project/config.pyencode_repo_plan) をヘッダコメントに明記
tests/containers/test_entrypoint_repos.py結合テストを追加

コードの実害のある不整合は見つからなかったため、entrypoint.sh のロジック変更はありません。

追加した結合テスト

test_the_real_encoder_output_is_consumed_as_is — 実物の encode_repo_plan の出力 (url だけローカル bare repo へ差し替え) を devbase_clone_repos に通し、branch 未指定の行が畳まれず後続 repo もずれないことを確認します。

lib/devbase/project/config.py は Task 1 の別 PR (#104) なのでこのブランチでは pytest.importorskip で skip されますが、base の release/PLAN32 で両 Task が揃うと自動で有効になります。config.py を持ち込んだ状態で実行し 1 passed を確認済みです。

検証

  • uv run pytest1260 passed / 1 skipped
  • uv run pytest tests/containers/16 passed / 1 skipped
  • bash -n containers/base/entrypoint.sh → OK
  • git ls-remote origin feature/PLAN32-entrypoint73536cb (ローカル HEAD と一致)

@codex@gemini 再レビューをお願いします。

@takemi-ohamatakemi-ohama left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 3 | codex | APPROVE

修正が必要な指摘はありません。

@takemi-ohamatakemi-ohama left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 3 | gemini | APPROVE

clone プランの wire format 契約を US (0x1f) 区切りへ統一したことで、bash IFS の空白文字扱いに起因する空フィールド脱落問題が本質的に解消されています。実エンコーダとの結合テストも追加され、仕様と実装の整合性が担保されたため堅牢性が一層向上しました。全体として十分な品質です。

@takemi-ohama
takemi-ohama marked this pull request as ready for review August 22, 2026 16:00
@takemi-ohama
takemi-ohama merged commit 9f8c810 into release/PLAN32Aug 22, 2026
@takemi-ohama
takemi-ohama deleted the feature/PLAN32-entrypoint branch August 22, 2026 16:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@takemi-ohama