From 1b5f45d339f3732b64fbb27e0a2ebe23b0f2d0ac Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 01:35:54 +0900 Subject: [PATCH 1/8] =?UTF-8?q?docs:=20project.yml=20=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E3=81=AE=E3=83=89=E3=82=AD=E3=83=A5=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=82=92=E6=95=B4=E5=82=99=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PLAN32 Task 5。複数リポジトリ構成と project.yml への移行に合わせて利用者向け ドキュメントを更新した。 - docs/user/project-yml.md を新設: スキーマ、複数リポジトリの例、検証される 内容、env との使い分け、旧 env からの移行表、コンテナへの渡り方 - 環境変数ガイド / コンテナ操作ガイド / CLI リファレンス / プラグイン開発の 各所から旧キー (GIT_USER / GIT_REPO / WORK_DIR / CONTAINER_SCALE) の説明を 外し、project.yml とその参照へ置き換え - CLI リファレンスに devbase project migrate-config を追記 - アーキテクチャ解説に project/ モジュールの節を追加 - CHANGELOG に破壊的変更と再ビルドの注意を追記 過去リリース分の CHANGELOG 記述は履歴なので書き換えていない。 Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 25 ++++ README.md | 1 + docs/README.md | 3 + docs/developer/architecture.md | 20 ++++ docs/plugin-dev/compose-yml-guidelines.md | 28 +++-- docs/plugin-dev/quickstart.md | 66 ++++++++--- docs/plugin-dev/repo-backed-projects.md | 36 +++--- docs/user/cli-reference/02-project.md | 34 +++++- docs/user/container-operations.md | 15 ++- docs/user/environment-variables.md | 24 ++-- docs/user/project-yml.md | 138 ++++++++++++++++++++++ 11 files changed, 326 insertions(+), 64 deletions(-) create mode 100644 docs/user/project-yml.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d401fd..c8080fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,32 @@ ## [Unreleased] +### Changed +- **1 プロジェクト = 1 コンテナ = 複数リポジトリ**に対応しました。プロジェクトが開発対象と + するリポジトリは `projects//project.yml` の `repos` 配列で指定し、すべてが同じ + コンテナの `/work` 配下へ clone されます。リポジトリごとに Git ホスト・オーナー・ + ブランチ・clone 先ディレクトリ名・`init.sh` の実行有無を指定できます。関連する複数 + リポジトリ (本体・ドキュメント・インフラ等) を 1 つの開発環境で横断的に扱えます。 + リポジトリが 2 件以上あるときは、全リポジトリを含む multi-root ワークスペース + `/work/<プロジェクト名>.code-workspace` を生成してエディタで開きます。 + 詳細は [project.yml リファレンス](docs/user/project-yml.md) を参照してください。 +- **プロジェクト設定を `env` から `project.yml` へ移しました (破壊的変更)。** + `GIT_USER` / `GIT_REPO` / `GIT_HOST` / `WORK_DIR` / `CONTAINER_SCALE` / + `DEVBASE_OPEN_EDITOR` は `project.yml` の `repos` / `work_dir` / `scale` / + `open_editor` に移行しました。`env` は「コンテナへ渡す環境変数」だけを持ちます。 + 配列を表現できない環境変数では複数リポジトリを書けないためです。 + `project.yml` を持たないプロジェクトは `devbase up` が移行手順を案内して停止します + (旧形式へ暗黙にフォールバックすると、移行漏れを検出できないため)。 + `devbase project scale N` の書き込み先も `project.yml` の `scale` になります。 + +> **Note:** リポジトリの clone は `entrypoint.sh` で行われ、これはイメージに焼き込まれます。 +> 適用には `devbase build --no-cache` によるベースイメージの再ビルドが必要です。 + ### Added +- **`devbase project migrate-config`** を追加しました。旧 `env` 形式のプロジェクト定義を + `project.yml` へ機械的に変換します。`--dry-run` で変換結果を確認でき、既存の + `project.yml` は上書きしないため何度実行しても同じ状態に収束します。 + 変換対象は上記 6 キーのみで、`ENABLE_SSH` などそれ以外は `env` に残ります。 - **tmux 内では `VSCODE_IPC_HOOK_CLI` が古くても VS Code を自動で開く**ようにしました。 tmux サーバーはセッション作成時の環境変数を保持し続けますが、`update-environment` に 登録した変数は attach のたびに更新されるため、**ペインのシェルは古い値・tmux の diff --git a/README.md b/README.md index c995ce0..d0d486f 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ devbaseのコマンドは4つのグループにまとめられています。 | [はじめに](docs/user/getting-started.md) | 前提条件、初回セットアップ、日常ワークフロー | | [CLIリファレンス](docs/user/cli-reference/README.md) | 全コマンドの構文・オプション・使用例(コマンドグループ別) | | [プラグインレジストリ](docs/user/plugin-registries.md) | 公開・社内レジストリの一覧と追加方法 | +| [project.yml リファレンス](docs/user/project-yml.md) | プロジェクト設定(複数リポジトリ・scale・エディタ) | | [環境変数ガイド](docs/user/environment-variables.md) | 3レベル構造、コレクター、ソース同期 | | [環境変数の export/import ガイド](docs/user/env-export-import.md) | バンドル形式・age 暗号化・S3 連携・merge/replace の運用 | | [コンテナ操作ガイド](docs/user/container-operations.md) | ライフサイクル、並行開発、ボリューム構造 | diff --git a/docs/README.md b/docs/README.md index b108925..2cf4ce5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -45,6 +45,7 @@ graph TD | [はじめに](user/getting-started.md) | 前提条件、初回セットアップ、日常ワークフロー | | [CLI リファレンス](user/cli-reference/README.md) | 全コマンドの構文・オプション・使用例 | | [プラグインレジストリ](user/plugin-registries.md) | 公開・社内レジストリの一覧と追加方法 | +| [project.yml リファレンス](user/project-yml.md) | プロジェクト設定(複数リポジトリ・scale・エディタ) | | [環境変数ガイド](user/environment-variables.md) | 3レベル構造、コレクター、ソース同期 | | [環境変数の暗号化](user/env-encryption.md) | 認証情報を暗号化して保存する / 鍵とチーム共有 / 平文へ戻す | | [コンテナ操作ガイド](user/container-operations.md) | ライフサイクル、並行開発、ボリューム構造 | @@ -101,6 +102,7 @@ docs/ │ │ ├── 04-plugin.md ← plugin グループ │ │ └── 05-snapshot.md ← snapshot グループ │ ├── plugin-registries.md ← プラグインレジストリ +│ ├── project-yml.md ← project.yml リファレンス │ ├── environment-variables.md ← 環境変数ガイド │ ├── env-encryption.md ← 環境変数の暗号化 │ ├── container-operations.md ← コンテナ操作ガイド @@ -128,6 +130,7 @@ docs/ | 環境変数を設定する | [環境変数ガイド](user/environment-variables.md#環境変数の操作) | | 認証情報を暗号化して保存する | [環境変数の暗号化](user/env-encryption.md) | | 複数コンテナで並行開発する | [コンテナ操作ガイド](user/container-operations.md#並行開発) | +| 1 つのコンテナで複数リポジトリを扱う | [project.yml リファレンス](user/project-yml.md#複数リポジトリ) | | データをバックアップ・復元する | [スナップショットガイド](user/snapshot-guide.md) | | エラーが発生した | [トラブルシューティング](user/troubleshooting.md) | | 旧 Orca 接続から移行する | [Orca 削除の移行ガイド](user/orca-removal-migration.md) | diff --git a/docs/developer/architecture.md b/docs/developer/architecture.md index 4e1ef27..963f3bb 100644 --- a/docs/developer/architecture.md +++ b/docs/developer/architecture.md @@ -139,6 +139,26 @@ flowchart LR `snapshot/manager.py` の `SnapshotManager` クラスが全機能を提供する。差分バックアップとフルバックアップに対応し、zstd 圧縮を使用する。 +### project/ -- プロジェクト設定 (project.yml) + +`projects//project.yml` を読み、コンテナとエディタが使える形へ変換する層。 +YAML の解釈をホスト側の Python に閉じ込めることで、コンテナ側 (`entrypoint.sh`) は +復号して 1 行ずつ clone するだけで済み、イメージへ YAML パーサ依存を持ち込まない。 + +| モジュール | 役割 | +|-----------|------| +| `config.py` | `project.yml` の読み込み・`defaults` 継承・検証・正規化 (`ProjectConfig` / `RepoSpec`)。clone プランの符号化 (`encode_repo_plan`) | +| `runtime.py` | コンテナへ渡す環境変数の組み立て (`DEVBASE_REPOS` / `DEVBASE_PRIMARY_DIR` / `DEVBASE_WORKSPACE*`)、multi-root ワークスペース JSON の生成、`scale` の読み書き | +| `migrate.py` | 旧 `env` 形式 (`GIT_USER` / `GIT_REPO` 等) から `project.yml` への変換 | + +```mermaid +flowchart LR + Y["project.yml"] --> C["config.py
検証・正規化"] + C --> R["runtime.py
環境変数へ"] + R --> Compose[".docker-compose.scale.yml
dev サービス"] + Compose --> E["entrypoint.sh
復号して clone"] +``` + ### その他 | ディレクトリ | 役割 | diff --git a/docs/plugin-dev/compose-yml-guidelines.md b/docs/plugin-dev/compose-yml-guidelines.md index 977b92a..4aa7065 100644 --- a/docs/plugin-dev/compose-yml-guidelines.md +++ b/docs/plugin-dev/compose-yml-guidelines.md @@ -71,10 +71,9 @@ flowchart TB G1["共通APIキー"] G2["共有設定値"] end - subgraph level2["レベル2: プロジェクト設定(env)"] - P1["GIT_USER / GIT_REPO"] - P2["WORK_DIR"] - P3["CONTAINER_SCALE"] + subgraph level2["レベル2: プロジェクト環境変数(env)"] + P1["ENABLE_SSH など"] + P2["アプリが読む変数"] end subgraph level3["レベル3: プロジェクト機密(.env)"] S1["プロジェクト固有のAPIキー"] @@ -90,7 +89,7 @@ flowchart TB | レベル | ファイル | Git管理 | 用途 | 例 | |--------|---------|---------|------|-----| | 1 | `${DEVBASE_ROOT}/.env` | No | 全プロジェクト共通の設定 | 共通APIキー | -| 2 | `env` | Yes | プロジェクト固有の設定 | `GIT_REPO`, `CONTAINER_SCALE` | +| 2 | `env` | Yes | コンテナへ渡すプロジェクト固有の環境変数 | `ENABLE_SSH` | | 3 | `.env` | No | プロジェクト固有の機密 | DB接続文字列、秘密鍵 | --- @@ -204,9 +203,9 @@ ports: 例: `CONTAINER_INDEX=1` の場合は `13000:3000`、`CONTAINER_INDEX=2` の場合は `23000:3000` -### 5.3 CONTAINER_SCALE の設定 +### 5.3 コンテナ数(scale)の設定 -`env` ファイルで `CONTAINER_SCALE` を設定すると、`devbase up` 実行時に `.docker-compose.scale.yml` が自動生成され、指定された数のコンテナが起動します。 +`project.yml` の `scale` を設定すると、`devbase up` 実行時に `.docker-compose.scale.yml` が自動生成され、指定された数のコンテナが起動します(既定: 2)。詳細は [project.yml リファレンス](../user/project-yml.md) を参照してください。 --- @@ -241,15 +240,18 @@ networks: external: true ``` -対応する `env` ファイル: +対応する `project.yml`: -```bash -GIT_USER=your-org -GIT_REPO=my-webapp -WORK_DIR=/work/$GIT_REPO -CONTAINER_SCALE=1 +```yaml +version: 1 +scale: 1 +repos: + - owner: your-org + repo: my-webapp ``` +`env` にはコンテナへ渡す環境変数だけを書きます(無くてもファイル自体は残します。`env_file` が参照するため)。 + ### 6.2 データベースを含む構成 基本構成に `db` サービスを追加し、`depends_on` で依存関係を定義します。 diff --git a/docs/plugin-dev/quickstart.md b/docs/plugin-dev/quickstart.md index e607daa..7084ee2 100644 --- a/docs/plugin-dev/quickstart.md +++ b/docs/plugin-dev/quickstart.md @@ -93,26 +93,56 @@ networks: > **補足:** compose.yml の記述ルール詳細は [compose.yml ガイドライン](compose-yml-guidelines.md) を参照してください。 -### 2.3 env ファイルの作成 +### 2.3 project.yml の作成 -`projects/my-project/env` を作成します。このファイルはGit管理対象です。 +`projects/my-project/project.yml` を作成します。このファイルはGit管理対象で、**プロジェクト設定の正**です。 -```bash -GIT_USER=your-github-user -GIT_REPO=my-repo -WORK_DIR=/work/$GIT_REPO -CONTAINER_SCALE=1 -# GitLab等GitHub以外のホストを使う場合: -# GIT_HOST=gitlab.com +```yaml +version: 1 +scale: 1 +repos: + - owner: your-github-user + repo: my-repo ``` -| 変数 | 説明 | +複数のリポジトリを 1 つのコンテナへチェックアウトできます。 + +```yaml +version: 1 +scale: 1 +defaults: + owner: your-github-user +repos: + - repo: my-app # 先頭が primary(ログイン直後の作業ディレクトリ) + - repo: my-app-docs + - repo: my-app-infra + host: gitlab.com # リポジトリごとに Git ホストを変えられる + owner: another-org + dir: infra # /work 配下の clone 先名(既定: repo 名) + branch: develop # clone 後にチェックアウトするブランチ + init: false # clone 後の ./init.sh を実行しない +``` + +主なキーは以下のとおりです。全項目は [project.yml リファレンス](../user/project-yml.md) を参照してください。 + +| キー | 説明 | |------|------| -| `GIT_USER` | Gitホストのユーザー名またはOrganization名 | -| `GIT_REPO` | リポジトリ名 | -| `GIT_HOST` | Gitホスト名(デフォルト: `github.com`)。GitLabの場合は `gitlab.com` を指定 | -| `WORK_DIR` | コンテナ内の作業ディレクトリ | -| `CONTAINER_SCALE` | 起動するコンテナ数(デフォルト: 2) | +| `version` | スキーマ版。現在は `1` | +| `repos[].owner` / `repos[].repo` | Git ホストのユーザー名(Organization 名)とリポジトリ名 | +| `repos[].host` | Git ホスト名(既定: `github.com`)。GitLab なら `gitlab.com` | +| `repos[].dir` / `branch` / `init` / `primary` | clone 先ディレクトリ名 / チェックアウトするブランチ / `init.sh` の実行有無 / 既定の作業リポジトリ | +| `scale` | 起動するコンテナ数(既定: 2) | +| `open_editor` | `devbase up` 後に VS Code を自動で開くか | + +### 2.3.1 env ファイル(任意) + +`projects/my-project/env` には、**コンテナへ渡す環境変数**だけを書きます(`ENABLE_SSH` など)。devbase 自身の設定は `project.yml` にあります。 + +```bash +ENABLE_SSH=true +``` + +`compose.yml` が `env_file: - env` で参照するため、**中身が無くてもファイルは残してください**(実在しないと compose が起動時に落ちます)。 ### 2.4 .env ファイル(任意) @@ -137,12 +167,10 @@ MY_SECRET_API_KEY=sk-xxxxxxxxxxxx # projects/my-project/pre-up set -e -# env から GIT_USER / GIT_REPO を取得 -source ./env - # build context に使うリポジトリが無ければ clone +# (pre-up はホスト側で動くフックなので、clone 先も URL もここに直接書く) if [ ! -d "./repo" ]; then - git clone "https://github.com/${GIT_USER}/${GIT_REPO}.git" repo + git clone "https://github.com/your-github-user/my-repo.git" repo fi ``` diff --git a/docs/plugin-dev/repo-backed-projects.md b/docs/plugin-dev/repo-backed-projects.md index ae1c61a..f5dd0d7 100644 --- a/docs/plugin-dev/repo-backed-projects.md +++ b/docs/plugin-dev/repo-backed-projects.md @@ -4,7 +4,7 @@ リファレンス実装は Laravel Sail ベースの `carmo-system-console` プラグインです。**このリポジトリには含まれません** — 社内向けの private プラグインレジストリで配布されており、`devbase plugin install` 後に `projects/carmo-system-console/`(`projects/` は `.gitignore` 対象)へ展開されます。アクセス権が無い場合でも、本書のコード断片と [チェックリスト](#7-チェックリスト新規に-repo-連携プロジェクトを作るとき) だけでパターンを再現できます。 -> **前提:** ライフサイクルフック自体の基本は [プラグイン開発クイックスタート](quickstart.md#25-ライフサイクルフック任意) を、共有ボリュームや `CONTAINER_SCALE` の一般論は [compose.yml ガイドライン](compose-yml-guidelines.md) と [コンテナ操作ガイド](../user/container-operations.md#並行開発) を参照してください。本書はそれらを組み合わせた「repo 連携」パターンに絞って説明します。 +> **前提:** ライフサイクルフック自体の基本は [プラグイン開発クイックスタート](quickstart.md#25-ライフサイクルフック任意) を、共有ボリュームや `scale` の一般論は [compose.yml ガイドライン](compose-yml-guidelines.md) と [コンテナ操作ガイド](../user/container-operations.md#並行開発) を参照してください。本書はそれらを組み合わせた「repo 連携」パターンに絞って説明します。 --- @@ -28,7 +28,7 @@ graph TD S["リモート git リポジトリ
(volareinc/app 等)"] -->|"pre-up ① clone/pull"| R["ホスト ./repo
(app のビルドコンテキスト)"] S3["S3
env/<env>.env"] -->|"pre-up ② 取得"| E["ホスト ./.env
(compose 変数展開用)"] - R -->|"pre-up ③ populate"| V["共有 work ボリューム
/work/<GIT_REPO>"] + R -->|"pre-up ③ populate"| V["共有 work ボリューム
/work/<リポジトリ名>"] E -->|"pre-up ④ 配置"| V V --> A["app コンテナ /work"] V --> N["nginx コンテナ /work:ro"] @@ -64,9 +64,9 @@ volumes: > **Note:** `pre-up` は子プロセスのため `export DEVBASE_WORK_VOLUME` しても後続の `docker compose up` へは伝播しません。`compose.yml` 側は `${DEVBASE_WORK_VOLUME:-devbase_work_${DEVBASE_INSTANCE_INDEX:-1}}` のフォールバック式で解決し、加えて `pre-up` が同じ値を `.env` に書き出すことで整合を取ります。 -### スケール前提: `CONTAINER_SCALE=1` +### スケール前提: `scale: 1` -**このパターンは scale=1(1 プロジェクト = 1 work ボリューム)を前提としています。** devbase の既定は `CONTAINER_SCALE=2` なので、プロジェクトの `env` に `CONTAINER_SCALE=1` を明示してください。 +**このパターンは scale=1(1 プロジェクト = 1 work ボリューム)を前提としています。** devbase の既定は `2` なので、プロジェクトの [`project.yml`](../user/project-yml.md) に `scale: 1` を明示してください。 現行実装では、scale>1 にすると「全コンテナが同一のソースツリーを共有する」という本パターンの前提が次の 2 点で崩れます。 @@ -78,7 +78,7 @@ volumes: - **`DEVBASE_WORK_VOLUME` で名前を分ける。** scale 生成は dev サービスの `/work` を `devbase_work_`(scale=1 なら常に `devbase_work_1`)へ無条件に差し替えます(`compose.yml` に `/work` マウントを書いていなくても追加されます)。`DEVBASE_WORK_VOLUME` が効くのは app / nginx など非 dev サービスだけなので、既定名以外を指定すると dev だけが別ボリュームを見る分裂状態になります。 - **プロジェクトディレクトリごと複製する。** work ボリュームは `COMPOSE_PROJECT_NAME` の接頭辞が付かない[グローバルな external ボリューム](#クリーンに作り直す再-populate)なので、複製先も同じ `devbase_work_1` を共有します。分離になりません。 -同一リポジトリを同時に複数環境で動かす必要がある場合は、Docker ホスト(`docker context`)そのものを分けてください。なお **別リポジトリ**の repo 連携プロジェクト同士は、populate 先が `/work/` とサブディレクトリで分かれるため、同じ work ボリュームを共有したまま共存できます。 +同一リポジトリを同時に複数環境で動かす必要がある場合は、Docker ホスト(`docker context`)そのものを分けてください。なお **別リポジトリ**の repo 連携プロジェクト同士は、populate 先が `/work/<リポジトリ名>` とサブディレクトリで分かれるため、同じ work ボリュームを共有したまま共存できます。 --- @@ -90,8 +90,8 @@ volumes: |---|------|------| | ① | `repo/` の clone / pull | 無ければ `git clone`、あれば `git pull --ff-only`(app ビルドコンテキストの最新化) | | ② | `.env` の取得 | S3 等から取得してホスト `./.env` に配置(`docker compose` の変数展開前に必要) | -| ③ | work ボリュームへ populate | `repo/` の内容を `/work/` へコピー | -| ④ | `.env` を work ボリュームへ配置 | Laravel 等のランタイムが `/work//.env` を参照するため | +| ③ | work ボリュームへ populate | `repo/` の内容を `/work/<リポジトリ名>` へコピー | +| ④ | `.env` を work ボリュームへ配置 | Laravel 等のランタイムが `/work/<リポジトリ名>/.env` を参照するため | ② を `deploy`(`up` 後フック)ではなく `pre-up` で行うのは、`compose.yml` の `MYSQL_DATABASE: ${DB_DATABASE:-...}` のような変数展開が `docker compose` パース時(= MySQL コンテナ初回起動前)に `.env` を要求するためです。`deploy` 段階では間に合わず、DB がデフォルト名で初期化されてしまいます。 @@ -101,7 +101,7 @@ volumes: **このパターンの肝は「初回だけ populate し、2 回目以降はコンテナ側に触れない」ことです。** -`pre-up` は work ボリューム上に `/work//.git` が存在するかどうかで populate 済みを判定し、済みの場合は ②③④ をスキップします。 +`pre-up` は work ボリューム上に `/work/<リポジトリ名>/.git` が存在するかどうかで populate 済みを判定し、済みの場合は ②③④ をスキップします。 | # | 処理 | 未populate(初回) | populate 済み(2回目以降) | |---|------|:---:|:---:| @@ -130,20 +130,20 @@ populate 済み以降、更新経路は次のように分かれます。 | 対象 | 場所 | 更新方法 | |------|------|---------| | ビルドコンテキスト | ホスト `./repo` | `pre-up` が毎回 `git pull`(自動) | -| 実行時ソース | work ボリューム `/work/` | **コンテナ内で手動 `git pull`** | -| 実行時 `.env` | work ボリューム `/work//.env` | コンテナ内で手動編集 | +| 実行時ソース | work ボリューム `/work/<リポジトリ名>` | **コンテナ内で手動 `git pull`** | +| 実行時 `.env` | work ボリューム `/work/<リポジトリ名>/.env` | コンテナ内で手動編集 | ```bash # 実行時ソースの更新(dev コンテナ内) -cd /work/ +cd /work/<リポジトリ名> git pull origin main ``` ### クリーンに作り直す(再 populate) -`.env` やソースを S3 / `repo/` の内容からやり直したい場合は、populate 済み判定に使われる `/work/` を消して、次回 `up` で populate を再実行させます。 +`.env` やソースを S3 / `repo/` の内容からやり直したい場合は、populate 済み判定に使われる `/work/<リポジトリ名>` を消して、次回 `up` で populate を再実行させます。 -> **Warning:** work ボリューム(既定 `devbase_work_1`)は `COMPOSE_PROJECT_NAME` の接頭辞が付かない **グローバルな external ボリューム**で、同じインスタンス index を使う **すべての devbase プロジェクトが共有**します。`docker volume rm` でボリュームごと消すと、停止中の別プロジェクトのソースや生成物まで巻き添えで失われます。プロジェクトの分離単位はボリュームではなく `/work/` サブディレクトリなので、**通常はサブディレクトリだけを削除**してください。 +> **Warning:** work ボリューム(既定 `devbase_work_1`)は `COMPOSE_PROJECT_NAME` の接頭辞が付かない **グローバルな external ボリューム**で、同じインスタンス index を使う **すべての devbase プロジェクトが共有**します。`docker volume rm` でボリュームごと消すと、停止中の別プロジェクトのソースや生成物まで巻き添えで失われます。プロジェクトの分離単位はボリュームではなく `/work/<リポジトリ名>` サブディレクトリなので、**通常はサブディレクトリだけを削除**してください。 **推奨: このプロジェクトのサブディレクトリだけを削除する** @@ -153,8 +153,8 @@ devbase down # 何が入っているか(=他プロジェクトが同居していないか)を確認 docker run --rm -v devbase_work_1:/work alpine ls -la /work -# このプロジェクトのソースだけを削除( は env の値) -docker run --rm -v devbase_work_1:/work alpine rm -rf /work/ +# このプロジェクトのソースだけを削除(<リポジトリ名> は project.yml の repos[].dir) +docker run --rm -v devbase_work_1:/work alpine rm -rf /work/<リポジトリ名> devbase up # pre-up が ②③④ を再実行 ``` @@ -191,12 +191,12 @@ devbase up ## 7. チェックリスト(新規に repo 連携プロジェクトを作るとき) -- [ ] `env` に `GIT_USER` / `GIT_REPO` を定義した -- [ ] `env` に `CONTAINER_SCALE=1` を明記した(既定は `2`。[スケール前提](#スケール前提-container_scale1) を参照) +- [ ] `project.yml` に `repos`(`owner` / `repo`)を定義した +- [ ] `project.yml` に `scale: 1` を明記した(既定は `2`。[スケール前提](#スケール前提-scale-1) を参照) - [ ] `compose.yml` で work ボリュームを `external: true` + `name: ${DEVBASE_WORK_VOLUME:-devbase_work_${DEVBASE_INSTANCE_INDEX:-1}}` で宣言した - [ ] app サービスの `build.context` をホスト `./repo` にした - [ ] `pre-up` で ①clone/pull → ②`.env`取得 → ③populate → ④`.env`配置 を実装した -- [ ] `pre-up` が `/work//.git` の有無で populate 済みを判定し、②③④ をスキップする +- [ ] `pre-up` が `/work/<リポジトリ名>/.git` の有無で populate 済みを判定し、②③④ をスキップする - [ ] populate 時の owner を `1000:1000`(コンテナ内ユーザー)に設定した - [ ] `storage/` / `vendor/` / `node_modules/` 等、初回のみ生成され上書きしたくないパスの扱いを決めた - [ ] README にソース・`.env` の更新運用(手動 pull / 再 populate)を記載した diff --git a/docs/user/cli-reference/02-project.md b/docs/user/cli-reference/02-project.md index 1f2ae9e..505edf8 100644 --- a/docs/user/cli-reference/02-project.md +++ b/docs/user/cli-reference/02-project.md @@ -52,7 +52,8 @@ devbase up [name] - 起動時にスナップショットを自動作成(新世代 or 差分追加) - 直近のスナップショット取得から既定 60 分以内のときはスキップします - 間隔は `DEVBASE_SNAPSHOT_MIN_INTERVAL_MINUTES` 環境変数で上書き可能(既定 60、`0` で無効化=毎回取得、不正値は警告して既定値) -- `CONTAINER_SCALE` の値に基づいてコンテナ数を決定 +- `project.yml` の `scale` に基づいてコンテナ数を決定(既定: 2) +- `project.yml` の `repos` を clone プランへ正規化してコンテナへ渡す(コンテナ内で `/work` 配下へ clone される) - イメージの自動準備(`devbase up` は `devbase rebuild`=`devbase build --expires=7` 相当を実行): - `build:` 定義あり、イメージ未存在 → `devbase build` を自動実行 - `build:` 定義あり、イメージ存在 → プロジェクトイメージの作成日で再ビルドの要否を判定: @@ -157,6 +158,37 @@ devbase project scale 3 devbase project scale adminer 3 ``` +新しい値は `project.yml` の `scale` に書き戻されるため、次回の `devbase up` にも引き継がれます。 + +## `devbase project migrate-config` + +旧 `env` 形式(`GIT_USER` / `GIT_REPO` / `GIT_HOST` / `WORK_DIR` / `CONTAINER_SCALE` / +`DEVBASE_OPEN_EDITOR`)のプロジェクト定義を [`project.yml`](../project-yml.md) へ変換します。 + +``` +devbase project migrate-config [NAME ...] [--dry-run] [--projects-dir DIR] +``` + +| パラメータ | 必須 | 説明 | +|-----------|------|------| +| `NAME` | いいえ | 対象プロジェクト名(省略時は `projects/` 配下すべて) | +| `--dry-run` | いいえ | 生成される `project.yml` を表示するだけで書き換えない | +| `--projects-dir` | いいえ | 対象ディレクトリ(既定: `$DEVBASE_ROOT/projects`)。devbase へリンクしていないプラグインリポジトリ内の `projects/` を直接変換する場合に使う | + +```bash +# まず変換結果を確認する +devbase project migrate-config --dry-run + +# 変換を適用する +devbase project migrate-config +``` + +- 変換対象は上記キーのみで、`ENABLE_SSH` などそれ以外は `env` に残ります +- 既存の `project.yml` は上書きしません(手で複数リポジトリ構成へ整えたものを壊さないため)。 + `env` に残った旧キーの掃除だけを行うため、何度実行しても同じ状態になります +- `projects/` はプラグインリポジトリへのシンボリックリンクです。書き換わるのはリンク先の + 実体(=定義の正)で、出力には実際に触れたパスが表示されます + ## `devbase project build` コンテナイメージをビルドします。キャッシュの扱いは 3 モードあります。 diff --git a/docs/user/container-operations.md b/docs/user/container-operations.md index efe84d0..b66c269 100644 --- a/docs/user/container-operations.md +++ b/docs/user/container-operations.md @@ -69,11 +69,14 @@ devbase は複数のコンテナを同時に起動し、並行開発を行うこ ### コンテナ数の設定 -プロジェクトの `env` ファイルで `CONTAINER_SCALE` を設定します。デフォルト値は `2` です。 - -```bash -# env ファイルで設定 -CONTAINER_SCALE=2 +プロジェクトの [`project.yml`](project-yml.md) で `scale` を設定します。デフォルト値は `2` です。 + +```yaml +version: 1 +scale: 2 +repos: + - owner: your-org + repo: my-repo ``` ### 動的スケーリング @@ -295,7 +298,7 @@ devbase status ## ベストプラクティス 1. **プロジェクト固有のファイルは `/work` に配置する** -- `/persistent/ai`(`~/.claude` 等の symlink 先・`~/share`)は全コンテナで共有されるため -2. **`CONTAINER_SCALE` は必要最小限に設定する** -- リソース消費を抑制 +2. **`scale` は必要最小限に設定する** -- リソース消費を抑制 3. **作業終了後は `devbase down` を実行する** -- 自動ローテーションでディスク容量を管理 4. **`devbase ps` で状態を確認してからログインする** -- 異常終了したコンテナへのログイン試行を避ける 5. **イメージのビルドは初回と更新時のみ** -- 変更がない場合はキャッシュが利用される diff --git a/docs/user/environment-variables.md b/docs/user/environment-variables.md index e0cd444..1308049 100644 --- a/docs/user/environment-variables.md +++ b/docs/user/environment-variables.md @@ -34,14 +34,19 @@ graph TD **プロジェクト設定 `env`(`projects/*/env`)** -プロジェクト固有の設定値を格納します。Git 管理対象のため、機密情報は含めないでください。 +コンテナへ渡すプロジェクト固有の環境変数を格納します。Git 管理対象のため、機密情報は含めないでください。 ```bash # env ファイルの例 -REPO_NAME=my-project -CONTAINER_SCALE=2 +ENABLE_SSH=true ``` +devbase 自身の設定(どのリポジトリを clone するか、コンテナ数、エディタの自動オープン)は +環境変数ではなく [`projects/*/project.yml`](project-yml.md) に書きます。`env` に +`GIT_USER` / `GIT_REPO` / `WORK_DIR` / `CONTAINER_SCALE` を書いても効果はありません。 + +`compose.yml` が `env_file: - env` で参照するため、中身が無くてもファイル自体は残してください。 + **プロジェクト機密 `.env`(`projects/*/.env`)** プロジェクト固有の機密情報を格納します。gitignore 対象のため、チームメンバーは個別に設定する必要があります。 @@ -140,15 +145,20 @@ devbase はホストマシンの認証情報を自動収集し、コンテナ内 ## `devbase up` 後のエディタ自動オープン -`devbase up` 完了後、dev コンテナへ接続した VS Code を自動で開けます(VS Code の「Attach to Running Container」を CLI から起動)。既定では `/work/$GIT_REPO` フォルダを開きます(`--folder-uri`)。`DEVBASE_WORKSPACE` を指定するとフォルダの代わりに `*.code-workspace` ワークスペースファイルを開きます(`--file-uri`)。 +`devbase up` 完了後、dev コンテナへ接続した VS Code を自動で開けます(VS Code の「Attach to Running Container」を CLI から起動)。 + +開く対象は [`project.yml`](project-yml.md) から決まります。 + +- リポジトリが 1 件: primary リポジトリのフォルダ(`--folder-uri`) +- リポジトリが 2 件以上: 全リポジトリを含む multi-root ワークスペース `/work/<プロジェクト名>.code-workspace`(`--file-uri`) -これらは `devbase env init` の収集対象外で、プロジェクトの `env` か `$DEVBASE_ROOT/.env` に手書きする devbase 動作設定です。 +自動オープンの有無は `project.yml` の `open_editor` が最優先で、未指定なら以下の env に従います。これらは `devbase env init` の収集対象外で、`$DEVBASE_ROOT/.env` かプロジェクトの `env` に手書きする devbase 動作設定です。 | キー | 説明 | |------|------| -| `DEVBASE_OPEN_EDITOR` | 真(`1`/`true`/`yes`/`on`)で `up` 後にエディタを開く(既定: OFF) | +| `DEVBASE_OPEN_EDITOR` | 真(`1`/`true`/`yes`/`on`)で `up` 後にエディタを開く(既定: OFF)。`project.yml` の `open_editor` が指定されていればそちらが優先 | | `DEVBASE_EDITOR` | 起動コマンド(既定: `code`)。`cursor` / `code-insiders` 等も可 | -| `DEVBASE_WORKSPACE` | 開く `*.code-workspace` ファイルの**コンテナ内絶対パス**(例 `/home/ubuntu/share/work/uttarov2-doc.workspace`)。指定時はフォルダではなくワークスペースを開く。未設定なら従来どおり `/work/$GIT_REPO` フォルダ。`~/share`(= 全コンテナ共有ボリューム `/persistent/ai/share` への symlink)配下に置けば全コンテナで共用可 | +| `DEVBASE_WORKSPACE` | 開く `*.code-workspace` ファイルの**コンテナ内絶対パス**を明示指定する(例 `/home/ubuntu/share/work/uttarov2-doc.workspace`)。複数リポジトリ構成では devbase が自動生成するため通常は不要。`~/share`(= 全コンテナ共有ボリューム `/persistent/ai/share` への symlink)配下に置けば全コンテナで共用可 | | `DEVBASE_OPEN_INDEX` | scale 時に開く dev インスタンス番号(既定: `1`) | | `DEVBASE_EDITOR_SSH_HOST` | Remote-SSH 跨ホスト構成での ssh-remote ホスト名(例 `mac2`)。**通常は `~/.vscode-server` から自動検出**され不要。検出が外れる場合のみ明示。下記「跨ホスト」参照 | | `DEVBASE_EDITOR_DOCKER_CONTEXT` | 跨ホスト時に ssh 先で使う docker context(既定: ホストの `docker context show`) | diff --git a/docs/user/project-yml.md b/docs/user/project-yml.md new file mode 100644 index 0000000..0677385 --- /dev/null +++ b/docs/user/project-yml.md @@ -0,0 +1,138 @@ +# project.yml リファレンス + +`projects//project.yml` は、1 つのプロジェクト(= 1 つの dev コンテナ群)が +**どのリポジトリを開発対象にするか**と、devbase 自身のふるまいを定義するファイルです。 +Git 管理対象で、プロジェクト設定の正です。 + +1 プロジェクトに複数のリポジトリを登録でき、すべてが同じコンテナの `/work` 配下へ +clone されます。関連する複数リポジトリ(本体・ドキュメント・インフラなど)を 1 つの +開発環境で横断的に扱うための仕組みです。 + +## 最小構成 + +```yaml +version: 1 +repos: + - owner: volareinc + repo: carmo +``` + +`devbase up` すると、コンテナ内の `/work/carmo` にリポジトリが clone され、 +ログイン直後の作業ディレクトリもそこになります。 + +## 複数リポジトリ + +```yaml +version: 1 +scale: 1 +open_editor: true + +defaults: + owner: uttaro-dev2 + +repos: + - repo: uttarov2 # 先頭が primary + host: gitlab.com # リポジトリごとにホストを変えられる + owner: uttaro_dev + dir: system # /work/system へ clone する + - repo: uttarov2-doc + - repo: uttarov2migration + branch: develop + init: false +``` + +リポジトリが 2 件以上あるとき、`devbase up` は全リポジトリを含む +**multi-root ワークスペース** `/work/<プロジェクト名>.code-workspace` を生成し、 +エディタはそれを開きます(1 件のときは primary リポジトリのフォルダを開きます)。 + +## キー一覧 + +### 最上位 + +| キー | 必須 | 既定値 | 説明 | +|------|------|--------|------| +| `version` | はい | -- | スキーマ版。現在は `1` | +| `repos` | はい | -- | clone するリポジトリの配列(1 件以上) | +| `defaults` | いいえ | -- | `repos` の各要素へ継承させる既定値(`host` / `owner` / `branch` / `init`) | +| `scale` | いいえ | `2` | 起動するコンテナ数。`devbase project scale N` はこの値を書き換える | +| `open_editor` | いいえ | -- | `devbase up` 後に VS Code を自動で開くか。未指定なら env `DEVBASE_OPEN_EDITOR` に従う | +| `work_dir` | いいえ | primary の `/work/` | エディタが開く既定フォルダを明示指定する | + +### `repos[]` + +| キー | 必須 | 既定値 | 説明 | +|------|------|--------|------| +| `owner` | はい | `defaults.owner` | Git ホストのユーザー名または Organization 名 | +| `repo` | はい | -- | リポジトリ名 | +| `host` | いいえ | `github.com` | Git ホスト名(例 `gitlab.com`) | +| `dir` | いいえ | `repo` と同じ | `/work` 直下の clone 先ディレクトリ名 | +| `branch` | いいえ | リポジトリの既定ブランチ | clone 直後にチェックアウトするブランチ | +| `init` | いいえ | `true` | clone 後にリポジトリ直下の `./init.sh` を実行するか | +| `primary` | いいえ | 先頭要素が `true` | ログイン直後の作業ディレクトリになるリポジトリ(1 件だけ指定可) | + +clone URL は `https:////.git` で組み立てられます。認証は +コンテナに渡された既存の Git 資格情報の仕組みに委ねます(`project.yml` に +資格情報は書きません)。 + +## 検証されること + +設定ミスを黙って無視せず、`devbase up` の時点でエラーにします。 + +- `owner` / `repo` が無い、`repos` が空 +- `dir` の重複(同じ `/work/` を 2 つのリポジトリが奪い合う) +- `primary: true` が 2 件以上 +- 未知のキー(`brunch: main` のような打ち間違いが「書いたのに効かない」形で表れないため) +- 値に空白・制御文字が混ざっている、`dir` が `/work` 直下から外れている + +## `env` との使い分け + +| 書く場所 | 内容 | 例 | +|---------|------|-----| +| `project.yml` | devbase 自身の設定 | リポジトリ、コンテナ数、エディタの自動オープン | +| `env` | コンテナへ渡す環境変数 | `ENABLE_SSH`、アプリが読む設定値 | +| `.env` | プロジェクト固有の機密 | API キー、DB 接続情報 | + +`compose.yml` が `env_file: - env` で参照するため、`env` は中身が無くても +ファイル自体を残してください(実在しないと compose が起動時に落ちます)。 + +## 旧 `env` 形式からの移行 + +`GIT_USER` / `GIT_REPO` / `GIT_HOST` / `WORK_DIR` / `CONTAINER_SCALE` / +`DEVBASE_OPEN_EDITOR` を `env` に書く旧形式は廃止されました。`project.yml` の無い +プロジェクトは `devbase up` が移行手順を案内して停止します。 + +変換は [`devbase project migrate-config`](cli-reference/02-project.md#devbase-project-migrate-config) +で行います。 + +```bash +devbase project migrate-config --dry-run # 変換結果を確認 +devbase project migrate-config # 適用 +``` + +| 旧 `env` のキー | 移行先 | +|----------------|--------| +| `GIT_USER` | `repos[].owner` | +| `GIT_REPO` | `repos[].repo` | +| `GIT_HOST` | `repos[].host` | +| `WORK_DIR` | `work_dir`(既定値と同じ場合は書きません) | +| `CONTAINER_SCALE` | `scale` | +| `DEVBASE_OPEN_EDITOR` | `open_editor` | + +## コンテナへの渡り方 + +`project.yml` を編集する人が意識する必要はありませんが、仕組みを知っておくと +トラブルシュートに役立ちます。 + +```mermaid +flowchart LR + Y["project.yml
(人が編集する正)"] -->|"devbase up がホスト側で正規化"| P["clone プラン
DEVBASE_REPOS (base64)"] + P -->|"compose の dev サービスへ"| C["コンテナ"] + C -->|"entrypoint が復号して clone"| W["/work/<dir> ×N"] +``` + +YAML の解釈はホスト側の Python に閉じています。コンテナ側は復号して 1 行ずつ +clone するだけなので、イメージへ YAML パーサを持ち込みません。 + +> **Note:** `entrypoint.sh` はイメージに焼き込まれます。devbase 本体を更新して +> clone のふるまいが変わった場合は、`devbase build --no-cache` でベースイメージを +> 再ビルドしないと反映されません。 From efb6a3a3b241fc610753ecc947724bc4fb948220 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 01:43:32 +0900 Subject: [PATCH 2/8] =?UTF-8?q?docs:=20=E3=83=AC=E3=83=93=E3=83=A5?= =?UTF-8?q?=E3=83=BC=E6=8C=87=E6=91=98=E5=AF=BE=E5=BF=9C=20=E2=80=94=20?= =?UTF-8?q?=E3=82=A2=E3=83=B3=E3=82=AB=E3=83=BC=E5=88=87=E3=82=8C=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E3=81=A8=20env=20=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB?= =?UTF-8?q?=E5=BF=85=E9=A0=88=E3=81=AE=E6=98=8E=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - repo-backed-projects.md: 見出し変更で切れた `#スケール前提-container_scale1` 参照 2 箇所を `#スケール前提-scale-1` に修正 - quickstart.md: `env` はファイル自体が必須(中身は任意)と見出しから分かるよう変更し、 最小構成のディレクトリツリーへ `project.yml` を追加 - project-yml.md: `env` ファイルが必須である旨を同じ表現に揃える Co-Authored-By: Claude Opus 5 (1M context) --- docs/plugin-dev/quickstart.md | 11 ++++++++--- docs/plugin-dev/repo-backed-projects.md | 4 ++-- docs/user/project-yml.md | 5 +++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/plugin-dev/quickstart.md b/docs/plugin-dev/quickstart.md index 7084ee2..951f8ff 100644 --- a/docs/plugin-dev/quickstart.md +++ b/docs/plugin-dev/quickstart.md @@ -53,7 +53,8 @@ my-plugin/ └── projects/ └── my-project/ ├── compose.yml - └── env + ├── project.yml + └── env # 中身は任意だが、ファイルは必須 ``` ### 2.2 compose.yml の作成 @@ -134,7 +135,7 @@ repos: | `scale` | 起動するコンテナ数(既定: 2) | | `open_editor` | `devbase up` 後に VS Code を自動で開くか | -### 2.3.1 env ファイル(任意) +### 2.3.1 env ファイル(ファイルは必須・中身は任意) `projects/my-project/env` には、**コンテナへ渡す環境変数**だけを書きます(`ENABLE_SSH` など)。devbase 自身の設定は `project.yml` にあります。 @@ -142,7 +143,11 @@ repos: ENABLE_SSH=true ``` -`compose.yml` が `env_file: - env` で参照するため、**中身が無くてもファイルは残してください**(実在しないと compose が起動時に落ちます)。 +2.2 の `compose.yml` が `env_file: - env` で参照するため、**ファイルは必ず作成してください**(実在しないと `devbase up` が compose の起動時に失敗します)。渡したい環境変数が無ければ空ファイルで構いません。 + +```bash +touch projects/my-project/env +``` ### 2.4 .env ファイル(任意) diff --git a/docs/plugin-dev/repo-backed-projects.md b/docs/plugin-dev/repo-backed-projects.md index f5dd0d7..6a979db 100644 --- a/docs/plugin-dev/repo-backed-projects.md +++ b/docs/plugin-dev/repo-backed-projects.md @@ -182,8 +182,8 @@ devbase up |------|------|------| | `DEVBASE_REPO_PULL` | `1` | `0` にすると ①(`repo/` の `git pull`)を抑止。オフラインや意図的にビルドコンテキストを固定したいとき | | `DEVBASE_ENV_OVERWRITE` | `backup` | 未 populate 時の既存ホスト `.env` の扱い。`backup`(`.env.bak.` に退避して上書き)/ `skip`(既存があれば S3 取得しない)/ `force`(退避せず上書き) | -| `DEVBASE_WORK_VOLUME` | `devbase_work_` | `compose.yml` が参照する共有 work ボリューム名の明示指定。未指定なら `DEVBASE_INSTANCE_INDEX` から解決。ただし効くのは **app / nginx など非 dev サービスだけ**で、dev サービスの `/work` は scale 生成時に `devbase_work_` へ無条件に差し替えられます。dev から実行時ソースを触る本パターンでは **既定名のまま**にしてください([スケール前提](#スケール前提-container_scale1) を参照) | -| `DEVBASE_INSTANCE_INDEX` | `1` | work ボリューム名のインデックス。**devbase 本体が渡すのは `deploy` フックに対してのみ**で、`pre-up` や `docker compose` のプロセス環境には渡りません。`compose.yml` の `${DEVBASE_INSTANCE_INDEX:-1}` は `.env` に書かれた値、無ければ `1` に解決されます([スケール前提](#スケール前提-container_scale1) を参照) | +| `DEVBASE_WORK_VOLUME` | `devbase_work_` | `compose.yml` が参照する共有 work ボリューム名の明示指定。未指定なら `DEVBASE_INSTANCE_INDEX` から解決。ただし効くのは **app / nginx など非 dev サービスだけ**で、dev サービスの `/work` は scale 生成時に `devbase_work_` へ無条件に差し替えられます。dev から実行時ソースを触る本パターンでは **既定名のまま**にしてください([スケール前提](#スケール前提-scale-1) を参照) | +| `DEVBASE_INSTANCE_INDEX` | `1` | work ボリューム名のインデックス。**devbase 本体が渡すのは `deploy` フックに対してのみ**で、`pre-up` や `docker compose` のプロセス環境には渡りません。`compose.yml` の `${DEVBASE_INSTANCE_INDEX:-1}` は `.env` に書かれた値、無ければ `1` に解決されます([スケール前提](#スケール前提-scale-1) を参照) | > **Note:** `.env` の環境選択(例: `s3://.../env/local.env` の `local` 部分)など、S3 パスやプロファイルはプロジェクト固有の変数(例: `CARMO_ENV`)で制御することがあります。プロジェクトの `pre-up` 冒頭コメントを参照してください。 diff --git a/docs/user/project-yml.md b/docs/user/project-yml.md index 0677385..de5327e 100644 --- a/docs/user/project-yml.md +++ b/docs/user/project-yml.md @@ -92,8 +92,9 @@ clone URL は `https:////.git` で組み立てられます。 | `env` | コンテナへ渡す環境変数 | `ENABLE_SSH`、アプリが読む設定値 | | `.env` | プロジェクト固有の機密 | API キー、DB 接続情報 | -`compose.yml` が `env_file: - env` で参照するため、`env` は中身が無くても -ファイル自体を残してください(実在しないと compose が起動時に落ちます)。 +`compose.yml` が `env_file: - env` で参照するため、`env` は**ファイル自体が必須**です。 +渡したい環境変数が無ければ空ファイルで構いませんが、削除すると `devbase up` が +compose の起動時に失敗します。 ## 旧 `env` 形式からの移行 From 4e2b76e5b42f023ca2b8d5f6b2b57aeb1371eeef Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 01:53:40 +0900 Subject: [PATCH 3/8] =?UTF-8?q?docs:=20DEVBASE=5FOPEN=5FEDITOR=20=E3=81=AF?= =?UTF-8?q?=20env=20init=20=E3=81=AE=E5=8F=8E=E9=9B=86=E5=AF=BE=E8=B1=A1?= =?UTF-8?q?=E3=81=A7=E3=81=82=E3=82=8B=E3=81=93=E3=81=A8=E3=82=92=E6=98=8E?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `devbase env init` の editor コレクター (lib/devbase/env/collectors/editor.py) が `DEVBASE_OPEN_EDITOR` を対話収集し、対話の既定は `1` (有効) である。 「収集対象外」「既定: OFF」という記述は実装と矛盾していたため、収集対象で あることと、OFF に倒れるのはキー自体が未設定のときだけである旨へ修正した。 Co-Authored-By: Claude Opus 5 (1M context) --- docs/user/environment-variables.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user/environment-variables.md b/docs/user/environment-variables.md index 1308049..9438133 100644 --- a/docs/user/environment-variables.md +++ b/docs/user/environment-variables.md @@ -152,11 +152,11 @@ devbase はホストマシンの認証情報を自動収集し、コンテナ内 - リポジトリが 1 件: primary リポジトリのフォルダ(`--folder-uri`) - リポジトリが 2 件以上: 全リポジトリを含む multi-root ワークスペース `/work/<プロジェクト名>.code-workspace`(`--file-uri`) -自動オープンの有無は `project.yml` の `open_editor` が最優先で、未指定なら以下の env に従います。これらは `devbase env init` の収集対象外で、`$DEVBASE_ROOT/.env` かプロジェクトの `env` に手書きする devbase 動作設定です。 +自動オープンの有無は `project.yml` の `open_editor` が最優先で、未指定なら以下の env に従います。このうち `DEVBASE_OPEN_EDITOR` だけは `devbase env init` の editor コレクターが対話収集し(対話の既定は `1` = 有効)、`$DEVBASE_ROOT/.env` に書き込まれます。残りは収集対象外で、`$DEVBASE_ROOT/.env` かプロジェクトの `env` に手書きする devbase 動作設定です。 | キー | 説明 | |------|------| -| `DEVBASE_OPEN_EDITOR` | 真(`1`/`true`/`yes`/`on`)で `up` 後にエディタを開く(既定: OFF)。`project.yml` の `open_editor` が指定されていればそちらが優先 | +| `DEVBASE_OPEN_EDITOR` | 真(`1`/`true`/`yes`/`on`)で `up` 後にエディタを開く。`devbase env init` の対話既定は `1`(有効)なので、init 済みの環境では通常 ON。キー自体が未設定のときのみ OFF に倒れる。`project.yml` の `open_editor` が指定されていればそちらが優先 | | `DEVBASE_EDITOR` | 起動コマンド(既定: `code`)。`cursor` / `code-insiders` 等も可 | | `DEVBASE_WORKSPACE` | 開く `*.code-workspace` ファイルの**コンテナ内絶対パス**を明示指定する(例 `/home/ubuntu/share/work/uttarov2-doc.workspace`)。複数リポジトリ構成では devbase が自動生成するため通常は不要。`~/share`(= 全コンテナ共有ボリューム `/persistent/ai/share` への symlink)配下に置けば全コンテナで共用可 | | `DEVBASE_OPEN_INDEX` | scale 時に開く dev インスタンス番号(既定: `1`) | From 5dbe870f0035bb0802b49ce17e774b07b28dd3b1 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 02:03:37 +0900 Subject: [PATCH 4/8] =?UTF-8?q?docs:=20init.sh=20=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E9=A0=BB=E5=BA=A6=E3=81=A8=20DEVBASE=5FWORKSPACE=20?= =?UTF-8?q?=E3=81=AE=E6=9C=89=E5=8A=B9=E7=AF=84=E5=9B=B2=E3=82=92=E5=AE=9F?= =?UTF-8?q?=E8=A3=85=E3=81=AB=E5=90=88=E3=82=8F=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - project.yml リファレンス: `init` は clone 直後だけでなくコンテナ起動の たびに `./init.sh` を実行することを明記し、`branch` (clone 直後のみ) との タイミング差の表と冪等性の注意を追加 - 環境変数: `DEVBASE_WORKSPACE` が効くのはリポジトリ 1 件の構成だけで、 2 件以上では自動生成した workspace を直接開くため上書きできない旨を明記 - container-operations / plugin-dev quickstart の関連記述も同じ挙動へ揃える Co-Authored-By: Claude Opus 5 (1M context) --- docs/plugin-dev/quickstart.md | 4 ++-- docs/user/container-operations.md | 2 +- docs/user/environment-variables.md | 2 +- docs/user/project-yml.md | 14 +++++++++++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/plugin-dev/quickstart.md b/docs/plugin-dev/quickstart.md index 951f8ff..52c102a 100644 --- a/docs/plugin-dev/quickstart.md +++ b/docs/plugin-dev/quickstart.md @@ -121,7 +121,7 @@ repos: owner: another-org dir: infra # /work 配下の clone 先名(既定: repo 名) branch: develop # clone 後にチェックアウトするブランチ - init: false # clone 後の ./init.sh を実行しない + init: false # 起動のたびの ./init.sh 実行を無効化する ``` 主なキーは以下のとおりです。全項目は [project.yml リファレンス](../user/project-yml.md) を参照してください。 @@ -131,7 +131,7 @@ repos: | `version` | スキーマ版。現在は `1` | | `repos[].owner` / `repos[].repo` | Git ホストのユーザー名(Organization 名)とリポジトリ名 | | `repos[].host` | Git ホスト名(既定: `github.com`)。GitLab なら `gitlab.com` | -| `repos[].dir` / `branch` / `init` / `primary` | clone 先ディレクトリ名 / チェックアウトするブランチ / `init.sh` の実行有無 / 既定の作業リポジトリ | +| `repos[].dir` / `branch` / `init` / `primary` | clone 先ディレクトリ名 / チェックアウトするブランチ(clone 直後のみ) / `init.sh` の実行有無(起動のたびに実行。冪等に書くこと) / 既定の作業リポジトリ | | `scale` | 起動するコンテナ数(既定: 2) | | `open_editor` | `devbase up` 後に VS Code を自動で開くか | diff --git a/docs/user/container-operations.md b/docs/user/container-operations.md index b66c269..b140ec5 100644 --- a/docs/user/container-operations.md +++ b/docs/user/container-operations.md @@ -183,7 +183,7 @@ AI CLI ツールの設定や認証情報は、コンテナを再生成しても - `/persistent/ai` は全コンテナ共通の `devbase_home_ubuntu` ボリュームなので、**どのコンテナからも同じ実体**を参照します(例: `~/share` は全コンテナで共有)。 - symlink **対象外**のホーム配下ファイル(シェル履歴など)はコンテナ層に置かれ、再生成で失われます。永続化したいものは `/persistent/ai` 配下(= 上記 symlink 先)か `/work` に置いてください。 -- `share` 配下に置いた VS Code ワークスペースファイルは `DEVBASE_WORKSPACE` で開けます([環境変数](environment-variables.md) 参照)。 +- `share` 配下に置いた VS Code ワークスペースファイルは `DEVBASE_WORKSPACE` で開けます(リポジトリ 1 件の構成のみ。[環境変数](environment-variables.md) 参照)。 > **Note:** symlink 対象は entrypoint にビルド時 `COPY` で焼き込まれます。エントリを増減した場合は > イメージの再ビルドが必要です(`devbase up` 単体では反映されない場合があります。[CLI リファレンス: project グループ](cli-reference/02-project.md#devbase-project-up) の `devbase project up` の注記参照)。 diff --git a/docs/user/environment-variables.md b/docs/user/environment-variables.md index 9438133..769dba2 100644 --- a/docs/user/environment-variables.md +++ b/docs/user/environment-variables.md @@ -158,7 +158,7 @@ devbase はホストマシンの認証情報を自動収集し、コンテナ内 |------|------| | `DEVBASE_OPEN_EDITOR` | 真(`1`/`true`/`yes`/`on`)で `up` 後にエディタを開く。`devbase env init` の対話既定は `1`(有効)なので、init 済みの環境では通常 ON。キー自体が未設定のときのみ OFF に倒れる。`project.yml` の `open_editor` が指定されていればそちらが優先 | | `DEVBASE_EDITOR` | 起動コマンド(既定: `code`)。`cursor` / `code-insiders` 等も可 | -| `DEVBASE_WORKSPACE` | 開く `*.code-workspace` ファイルの**コンテナ内絶対パス**を明示指定する(例 `/home/ubuntu/share/work/uttarov2-doc.workspace`)。複数リポジトリ構成では devbase が自動生成するため通常は不要。`~/share`(= 全コンテナ共有ボリューム `/persistent/ai/share` への symlink)配下に置けば全コンテナで共用可 | +| `DEVBASE_WORKSPACE` | 開く `*.code-workspace` ファイルの**コンテナ内絶対パス**を明示指定する(例 `/home/ubuntu/share/work/uttarov2-doc.workspace`)。**効くのはリポジトリ 1 件の構成だけ**です。2 件以上の構成では `devbase up` が自動生成した `/work/<プロジェクト名>.code-workspace` を直接開くため、この env を設定しても上書きできません。`~/share`(= 全コンテナ共有ボリューム `/persistent/ai/share` への symlink)配下に置けば全コンテナで共用可 | | `DEVBASE_OPEN_INDEX` | scale 時に開く dev インスタンス番号(既定: `1`) | | `DEVBASE_EDITOR_SSH_HOST` | Remote-SSH 跨ホスト構成での ssh-remote ホスト名(例 `mac2`)。**通常は `~/.vscode-server` から自動検出**され不要。検出が外れる場合のみ明示。下記「跨ホスト」参照 | | `DEVBASE_EDITOR_DOCKER_CONTEXT` | 跨ホスト時に ssh 先で使う docker context(既定: ホストの `docker context show`) | diff --git a/docs/user/project-yml.md b/docs/user/project-yml.md index de5327e..f91bcc9 100644 --- a/docs/user/project-yml.md +++ b/docs/user/project-yml.md @@ -67,13 +67,25 @@ repos: | `host` | いいえ | `github.com` | Git ホスト名(例 `gitlab.com`) | | `dir` | いいえ | `repo` と同じ | `/work` 直下の clone 先ディレクトリ名 | | `branch` | いいえ | リポジトリの既定ブランチ | clone 直後にチェックアウトするブランチ | -| `init` | いいえ | `true` | clone 後にリポジトリ直下の `./init.sh` を実行するか | +| `init` | いいえ | `true` | リポジトリ直下の `./init.sh` を実行するか。clone 直後だけでなく**コンテナ起動のたび**(既存 clone があっても)実行されます | | `primary` | いいえ | 先頭要素が `true` | ログイン直後の作業ディレクトリになるリポジトリ(1 件だけ指定可) | clone URL は `https:////.git` で組み立てられます。認証は コンテナに渡された既存の Git 資格情報の仕組みに委ねます(`project.yml` に 資格情報は書きません)。 +`branch` と `init` は実行タイミングが異なります。 + +| キー | 実行タイミング | 理由 | +|------|--------------|------| +| `branch` | **clone 直後の 1 回だけ** | 既存 clone にも毎回適用すると、コンテナ内で作業ブランチへ切り替えた状態が再起動のたびに引き戻されるため | +| `init` | **コンテナ起動のたび**(既存 clone があっても毎回) | 依存パッケージの再取得など、コンテナ再生成後にも必要な処理を置く場所のため | + +`init.sh` は毎回走るので、**何度実行しても同じ結果になる(冪等な)内容にしてください**。 +`git clone` や追記のような繰り返すと壊れる処理を書く場合は、スクリプト側で実行済みかを +判定してください。実行が重い・1 回だけでよい場合は `init: false` にして手動実行に切り替えます。 +なお `init.sh` の失敗は警告に留まり、他リポジトリの処理とコンテナ起動は続行されます。 + ## 検証されること 設定ミスを黙って無視せず、`devbase up` の時点でエラーにします。 From 04fa02129211165b10dc25f8acab4426007f5abc Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 02:08:41 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat(hooks):=20pre-up=20/=20deploy=20?= =?UTF-8?q?=E3=81=B8=20clone=20=E5=85=88=E3=81=A8=E3=83=AA=E3=83=9D?= =?UTF-8?q?=E3=82=B8=E3=83=88=E3=83=AA=20URL=20=E3=82=92=E6=B8=A1=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PLAN32 で GIT_REPO / WORK_DIR が env から project.yml へ移った結果、それらを `source ./env` で読んでいたライフサイクルフックが値を取れなくなる。実際に plugin リポジトリの pre-up / deploy が壊れることを結合検証で確認した。 フックはホスト側で動くため、devbase 側から明示的に環境変数として渡す: - DEVBASE_PRIMARY_DIR: primary repo の /work 配下ディレクトリ名 - DEVBASE_PRIMARY_URL: primary repo の clone URL - DEVBASE_WORK_DIR: コンテナ内の既定の作業ディレクトリ - DEVBASE_REPO_DIRS: 全 repo のディレクトリ名 (空白区切り、宣言順) env を経由せず devbase が渡すことで、複数リポジトリ構成でもフックが clone 先を 一意に知れる。渡した値は子プロセス限定で、親の os.environ は汚さない。 Co-Authored-By: Claude Opus 5 (1M context) --- lib/devbase/commands/container.py | 31 ++++++--- lib/devbase/project/runtime.py | 22 ++++++ tests/commands/test_container_up_order.py | 2 +- tests/commands/test_hook_env.py | 84 +++++++++++++++++++++++ tests/project/test_runtime.py | 25 +++++++ 5 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 tests/commands/test_hook_env.py diff --git a/lib/devbase/commands/container.py b/lib/devbase/commands/container.py index cfd760b..197df26 100644 --- a/lib/devbase/commands/container.py +++ b/lib/devbase/commands/container.py @@ -146,11 +146,17 @@ def _compose_run(subcommand: str, *extra_args: str) -> int: return subprocess.run(cmd).returncode -def _run_deploy_script_for_instances(deploy_script: Path, indices) -> None: - """デプロイスクリプトをスケールされた各インスタンスに対して実行する""" +def _run_deploy_script_for_instances(deploy_script: Path, indices, + config=None) -> None: + """デプロイスクリプトをスケールされた各インスタンスに対して実行する。 + + ``config`` (``project.yml``) を渡すと、clone 先やリポジトリ URL をフックへ + 環境変数で伝える (:func:`devbase.project.runtime.hook_env`)。 + """ + hook_vars = project_runtime.hook_env(config) if config is not None else {} for i in indices: logger.info("[Bonus] Running deploy script for instance %d...", i) - env = {**os.environ, 'DEVBASE_INSTANCE_INDEX': str(i)} + env = {**os.environ, **hook_vars, 'DEVBASE_INSTANCE_INDEX': str(i)} try: subprocess.run(['bash', str(deploy_script)], check=True, env=env) logger.info("Deploy script completed for instance %d", i) @@ -158,12 +164,17 @@ def _run_deploy_script_for_instances(deploy_script: Path, indices) -> None: logger.warning("Deploy script failed for instance %d (exit code %d)", i, e.returncode) -def _run_pre_up_hook() -> bool: +def _run_pre_up_hook(config=None) -> bool: """`./pre-up` フックがあればコンテナ起動前に実行する。 ビルドコンテキスト用のリポジトリ clone など、`docker compose up` より前に 完了しておく必要のある準備処理をプロジェクト側で記述するためのフック。 + ``config`` (``project.yml``) を渡すと、clone 先やリポジトリ URL をフックへ + 環境変数で伝える (:func:`devbase.project.runtime.hook_env`)。フックは以前 + ``source ./env`` で ``GIT_REPO`` / ``WORK_DIR`` を読んでいたが、これらは + ``project.yml`` へ移ったため devbase 側から明示的に渡す。 + Returns: True: フックが存在しなかった、または成功した False: フックが失敗した(呼び出し側で `cmd_up` を中断する) @@ -173,8 +184,10 @@ def _run_pre_up_hook() -> bool: return True logger.info("Running pre-up hook: %s", pre_up_script) + hook_vars = project_runtime.hook_env(config) if config is not None else {} try: - subprocess.run(['bash', str(pre_up_script)], check=True, env=os.environ.copy()) + subprocess.run(['bash', str(pre_up_script)], check=True, + env={**os.environ, **hook_vars}) return True except subprocess.CalledProcessError as e: logger.error("pre-up hook failed (exit code %d)", e.returncode) @@ -644,7 +657,7 @@ def cmd_up(project_name: str = None, scale: int = None, return 1 # Pre-step: Run ./pre-up hook (e.g. clone source repos used as build contexts) - if not _run_pre_up_hook(): + if not _run_pre_up_hook(config): return 1 # Pre-check 2: Ensure container images exist @@ -693,7 +706,8 @@ def cmd_up(project_name: str = None, scale: int = None, # Run project-specific deploy script for each scaled instance deploy_script = Path('./deploy') if deploy_script.exists() and deploy_script.is_file(): - _run_deploy_script_for_instances(deploy_script, range(1, scale + 1)) + _run_deploy_script_for_instances(deploy_script, range(1, scale + 1), + config) _maybe_open_editor(project_name, open_editor, open_index, scale, config, compose_file=override_file) @@ -840,7 +854,8 @@ def cmd_scale(new_scale: int, project_name: str = None) -> int: # Run project-specific deploy script for newly added instances deploy_script = Path('./deploy') if deploy_script.exists() and deploy_script.is_file(): - _run_deploy_script_for_instances(deploy_script, range(current_scale + 1, new_scale + 1)) + _run_deploy_script_for_instances( + deploy_script, range(current_scale + 1, new_scale + 1), config) logger.info("=== Scale completed successfully ===") logger.info("Container scale: %d -> %d", current_scale, new_scale) diff --git a/lib/devbase/project/runtime.py b/lib/devbase/project/runtime.py index ac97007..62270db 100644 --- a/lib/devbase/project/runtime.py +++ b/lib/devbase/project/runtime.py @@ -65,6 +65,27 @@ def container_env(config: ProjectConfig, project_name: str) -> Dict[str, str]: return env +def hook_env(config: ProjectConfig) -> Dict[str, str]: + """``pre-up`` / ``deploy`` フックへ渡す環境変数を組み立てる。 + + フックはホスト側で動き、clone 先のパスやリポジトリ URL を必要とすることが + ある (共有ボリュームへの populate、Laravel の ``.env`` 配置など)。以前は + ``env`` の ``GIT_REPO`` / ``WORK_DIR`` を ``source ./env`` で読んでいたが、 + それらは ``project.yml`` へ移ったため devbase 側から明示的に渡す。 + + - ``DEVBASE_PRIMARY_DIR`` : primary repo の ``/work`` 配下ディレクトリ名 + - ``DEVBASE_PRIMARY_URL`` : primary repo の clone URL + - ``DEVBASE_WORK_DIR`` : コンテナ内の既定の作業ディレクトリ + - ``DEVBASE_REPO_DIRS`` : 全 repo のディレクトリ名 (空白区切り、宣言順) + """ + return { + "DEVBASE_PRIMARY_DIR": config.primary.dir, + "DEVBASE_PRIMARY_URL": config.primary.url, + "DEVBASE_WORK_DIR": config.resolved_work_dir(), + "DEVBASE_REPO_DIRS": " ".join(repo.dir for repo in config.repos), + } + + # --------------------------------------------------------------------------- # scale (旧 CONTAINER_SCALE) # --------------------------------------------------------------------------- @@ -136,6 +157,7 @@ def current_project_config(project_dir: Path = None) -> ProjectConfig: "build_workspace_document", "container_env", "current_project_config", + "hook_env", "read_scale", "workspace_path", "write_scale", diff --git a/tests/commands/test_container_up_order.py b/tests/commands/test_container_up_order.py index fac04d3..f5df914 100644 --- a/tests/commands/test_container_up_order.py +++ b/tests/commands/test_container_up_order.py @@ -35,7 +35,7 @@ def up_harness(tmp_path, monkeypatch): monkeypatch.setattr(container, 'get_project_name', lambda: 'proj') monkeypatch.setattr(container, 'get_dev_service_name', lambda: 'dev') monkeypatch.setattr(container, '_ensure_env_files', lambda: True) - monkeypatch.setattr(container, '_run_pre_up_hook', lambda: True) + monkeypatch.setattr(container, '_run_pre_up_hook', lambda config=None: True) monkeypatch.setattr(container, '_ensure_images', lambda: True) monkeypatch.setattr(container, '_auto_snapshot', lambda: None) monkeypatch.setattr(container, 'ensure_volumes', lambda *a, **k: None) diff --git a/tests/commands/test_hook_env.py b/tests/commands/test_hook_env.py new file mode 100644 index 0000000..689563b --- /dev/null +++ b/tests/commands/test_hook_env.py @@ -0,0 +1,84 @@ +"""ライフサイクルフックへ渡す環境変数 (PLAN32) + +``pre-up`` / ``deploy`` はホスト側で動き、clone 先のパスを必要とすることがある。 +旧構成では ``source ./env`` で ``GIT_REPO`` / ``WORK_DIR`` を読んでいたが、これらは +``project.yml`` へ移ったため devbase 側から明示的に渡す。 +""" + +from __future__ import annotations + +import os +from pathlib import Path + +import pytest + +from devbase.commands import container +from devbase.project.config import parse_project_config + +DUMP_SCRIPT = '''#!/bin/bash +{ + echo "DEVBASE_PRIMARY_DIR=$DEVBASE_PRIMARY_DIR" + echo "DEVBASE_PRIMARY_URL=$DEVBASE_PRIMARY_URL" + echo "DEVBASE_WORK_DIR=$DEVBASE_WORK_DIR" + echo "DEVBASE_REPO_DIRS=$DEVBASE_REPO_DIRS" + echo "DEVBASE_INSTANCE_INDEX=$DEVBASE_INSTANCE_INDEX" +} > dump.txt +''' + + +@pytest.fixture +def config(): + return parse_project_config({ + "version": 1, + "defaults": {"owner": "volareinc"}, + "repos": [{"repo": "carmo"}, {"repo": "carmo-batch"}], + }, source="project.yml") + + +def dumped(tmp_path: Path) -> dict: + lines = (tmp_path / "dump.txt").read_text().splitlines() + return dict(line.split("=", 1) for line in lines) + + +def test_pre_up_hook_receives_the_repo_layout(tmp_path, monkeypatch, config): + monkeypatch.chdir(tmp_path) + (tmp_path / "pre-up").write_text(DUMP_SCRIPT) + + assert container._run_pre_up_hook(config) is True + + values = dumped(tmp_path) + assert values["DEVBASE_PRIMARY_DIR"] == "carmo" + assert values["DEVBASE_PRIMARY_URL"] == "https://github.com/volareinc/carmo.git" + assert values["DEVBASE_WORK_DIR"] == "/work/carmo" + assert values["DEVBASE_REPO_DIRS"] == "carmo carmo-batch" + + +def test_deploy_hook_receives_the_repo_layout_and_index(tmp_path, monkeypatch, config): + monkeypatch.chdir(tmp_path) + deploy = tmp_path / "deploy" + deploy.write_text(DUMP_SCRIPT) + + container._run_deploy_script_for_instances(deploy, [2], config) + + values = dumped(tmp_path) + assert values["DEVBASE_WORK_DIR"] == "/work/carmo" + assert values["DEVBASE_INSTANCE_INDEX"] == "2" + + +def test_hooks_still_run_without_a_config(tmp_path, monkeypatch): + """設定を渡さない呼び出し (旧 scale 経路) でもフック自体は動く""" + monkeypatch.chdir(tmp_path) + (tmp_path / "pre-up").write_text(DUMP_SCRIPT) + + assert container._run_pre_up_hook() is True + + assert dumped(tmp_path)["DEVBASE_WORK_DIR"] == "" + + +def test_hook_env_does_not_leak_into_the_parent_process(tmp_path, monkeypatch, config): + monkeypatch.chdir(tmp_path) + (tmp_path / "pre-up").write_text(DUMP_SCRIPT) + + container._run_pre_up_hook(config) + + assert "DEVBASE_WORK_DIR" not in os.environ diff --git a/tests/project/test_runtime.py b/tests/project/test_runtime.py index d08f8af..da8588c 100644 --- a/tests/project/test_runtime.py +++ b/tests/project/test_runtime.py @@ -12,6 +12,7 @@ from devbase.project.runtime import ( build_workspace_document, container_env, + hook_env, read_scale, workspace_path, write_scale, @@ -146,3 +147,27 @@ def test_write_scale_rejects_a_broken_result(tmp_path): with pytest.raises(ConfigError, match="scale"): write_scale(tmp_path, 0) assert "scale" not in (tmp_path / "project.yml").read_text() + + +# --------------------------------------------------------------------------- +# ライフサイクルフックへ渡す環境変数 +# --------------------------------------------------------------------------- + +def test_hook_env_exposes_the_primary_repo_and_work_dir(): + """`pre-up` / `deploy` は clone 先を知る必要がある (旧 WORK_DIR / GIT_REPO の代替)""" + env = hook_env(config_of("carmo", "carmo-batch")) + + assert env["DEVBASE_PRIMARY_DIR"] == "carmo" + assert env["DEVBASE_PRIMARY_URL"] == "https://github.com/volareinc/carmo.git" + assert env["DEVBASE_WORK_DIR"] == "/work/carmo" + assert env["DEVBASE_REPO_DIRS"] == "carmo carmo-batch" + + +def test_hook_env_follows_explicit_work_dir_and_primary(): + config = config_of({"repo": "carmo-doc"}, {"repo": "carmo", "primary": True}, + work_dir="/work/carmo/app") + + env = hook_env(config) + + assert env["DEVBASE_PRIMARY_DIR"] == "carmo" + assert env["DEVBASE_WORK_DIR"] == "/work/carmo/app" From c48c3259b51e6d5afbf9ce127c5ef58fa582e887 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 02:15:15 +0900 Subject: [PATCH 6/8] =?UTF-8?q?docs:=20=E8=AA=AD=E3=81=BF=E8=BE=BC?= =?UTF-8?q?=E3=81=BF=E9=A0=86=E5=BA=8F=E3=81=AE=E8=A1=A8=E3=81=8B=E3=82=89?= =?UTF-8?q?=E3=82=82=20env=20=E3=81=AE=E6=97=A7=E7=94=A8=E9=80=94=E3=82=92?= =?UTF-8?q?=E5=A4=96=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit env の役割を「コンテナへ渡す環境変数」と書き換えたのに、直上の表だけ 「リポジトリ名・コンテナ数等」と旧仕様のままで矛盾していた。 Co-Authored-By: Claude Opus 5 (1M context) --- docs/user/environment-variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/environment-variables.md b/docs/user/environment-variables.md index 769dba2..cbe4a04 100644 --- a/docs/user/environment-variables.md +++ b/docs/user/environment-variables.md @@ -21,7 +21,7 @@ graph TD | 優先度 | レベル | ファイル | 用途 | Git 管理 | |-------|-------|---------|------|---------| | 1(低) | グローバル | `devbase/.env` | 共通 API キー・認証情報 | gitignore | -| 2 | プロジェクト設定 | `projects/*/env` | リポジトリ名・コンテナ数等 | 管理対象 | +| 2 | プロジェクト環境変数 | `projects/*/env` | コンテナへ渡すプロジェクト固有の環境変数(`ENABLE_SSH` 等) | 管理対象 | | 3(高) | プロジェクト機密 | `projects/*/.env` | プロジェクト固有の API キー | gitignore | > **Note:** 同じキーが複数のレベルに存在する場合、優先度が高いレベルの値が使用されます。例えば、グローバルの `AWS_PROFILE` をプロジェクトの `.env` で上書きすることで、プロジェクトごとに異なる AWS プロファイルを使用できます。 From f79d9453982becf60fc0aec852c95ae3fa340876 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 02:20:03 +0900 Subject: [PATCH 7/8] =?UTF-8?q?docs:=20=E3=83=95=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=81=B8=E6=B8=A1=E3=82=8B=E7=92=B0=E5=A2=83=E5=A4=89=E6=95=B0?= =?UTF-8?q?=E3=82=92=E5=85=AC=E5=BC=8F=E3=82=AC=E3=82=A4=E3=83=89=E3=81=B8?= =?UTF-8?q?=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pre-up / deploy へ渡す DEVBASE_PRIMARY_DIR / DEVBASE_PRIMARY_URL / DEVBASE_WORK_DIR / DEVBASE_REPO_DIRS は公開契約だが、ガイドは移行前の GIT_REPO / WORK_DIR を案内したままだった。フック作者がこの契約を使って 移行できないため、次を追記する。 - quickstart: 「フックへ渡る環境変数」表 (pre-up / deploy の別と DEVBASE_INSTANCE_INDEX が pre-up に渡らないことを含む) と、 DEVBASE_PRIMARY_URL を使う pre-up サンプル - repo-backed-projects: clone 先 / URL の受け取り方と pre-up 骨子、 関連環境変数節への追記、チェックリスト項目 - project.yml リファレンス: project.yml の各キーとの対応表 - CHANGELOG: Unreleased / Added へ本機能を記載 Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 9 +++++ docs/plugin-dev/quickstart.md | 32 +++++++++++++++-- docs/plugin-dev/repo-backed-projects.md | 46 +++++++++++++++++++++++-- docs/user/project-yml.md | 18 ++++++++++ 4 files changed, 99 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8080fc..ccc9c8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,15 @@ > 適用には `devbase build --no-cache` によるベースイメージの再ビルドが必要です。 ### Added +- **ライフサイクルフックへ `project.yml` の値を環境変数で渡す**ようにしました。`pre-up` / + `deploy` に `DEVBASE_PRIMARY_DIR` (primary の clone 先ディレクトリ名) / + `DEVBASE_PRIMARY_URL` (primary の clone URL) / `DEVBASE_WORK_DIR` (コンテナ内の既定の + 作業ディレクトリ) / `DEVBASE_REPO_DIRS` (全リポジトリのディレクトリ名・宣言順の空白 + 区切り) が渡ります。フックはホスト側で動くため `env` を読み込めず、`GIT_REPO` / + `WORK_DIR` の `project.yml` 移行によって `source ./env` に依存していたフックが値を + 取れなくなるためです。値は子プロセス限定で、親プロセスの環境は汚しません。 + 詳細は [フックへ渡る環境変数](docs/plugin-dev/quickstart.md#フックへ渡る環境変数) + を参照してください。 - **`devbase project migrate-config`** を追加しました。旧 `env` 形式のプロジェクト定義を `project.yml` へ機械的に変換します。`--dry-run` で変換結果を確認でき、既存の `project.yml` は上書きしないため何度実行しても同じ状態に収束します。 diff --git a/docs/plugin-dev/quickstart.md b/docs/plugin-dev/quickstart.md index 52c102a..16f313c 100644 --- a/docs/plugin-dev/quickstart.md +++ b/docs/plugin-dev/quickstart.md @@ -167,19 +167,45 @@ MY_SECRET_API_KEY=sk-xxxxxxxxxxxx | `pre-up` | `devbase up` 開始直後(`docker compose up` の前) | `build.context` 用ソースリポジトリの clone、設定ファイルの生成など、イメージビルド前に完了させたい準備 | | `deploy` | コンテナ起動完了後、各スケールインスタンスごとに実行 | S3 からの `.env` 取得、コンテナ起動後に必要な外部リソースの初期化など | +#### フックへ渡る環境変数 + +フックは**ホスト側**で動くため、コンテナへ渡る `env` / `.env` は読み込まれません。フックが必要とする `project.yml` の値は、devbase が環境変数として明示的に渡します。 + +| 変数 | 内容 | `pre-up` | `deploy` | +|------|------|:---:|:---:| +| `DEVBASE_PRIMARY_DIR` | primary リポジトリの `/work` 配下ディレクトリ名(`repos[].dir`。未指定ならリポジトリ名) | ✓ | ✓ | +| `DEVBASE_PRIMARY_URL` | primary リポジトリの clone URL(`https:////.git`) | ✓ | ✓ | +| `DEVBASE_WORK_DIR` | コンテナ内の既定の作業ディレクトリ(`work_dir`。未指定なら `/work/$DEVBASE_PRIMARY_DIR`) | ✓ | ✓ | +| `DEVBASE_REPO_DIRS` | 全リポジトリのディレクトリ名を `project.yml` の宣言順に空白区切りで並べたもの | ✓ | ✓ | +| `DEVBASE_INSTANCE_INDEX` | 実行対象のインスタンス番号(1 始まり)。`pre-up` はインスタンスごとに実行されないため渡りません | -- | ✓ | + +primary は `repos` の先頭(または `primary: true` を付けた 1 件)で、常にちょうど 1 件です。primary 以外も含めて全リポジトリを回したい場合は `DEVBASE_REPO_DIRS` を使います。 + +```bash +for dir in $DEVBASE_REPO_DIRS; do + echo "populate /work/$dir" +done +``` + +> **Note:** これらは**子プロセスにだけ**渡ります。フック内で `export` しても、後続の `docker compose up` や別プロジェクトの実行へは伝播しません。 + +#### `pre-up` の例 + ```bash #!/bin/bash # projects/my-project/pre-up set -e # build context に使うリポジトリが無ければ clone -# (pre-up はホスト側で動くフックなので、clone 先も URL もここに直接書く) +# (clone 先も URL も devbase が project.yml から渡してくれる) if [ ! -d "./repo" ]; then - git clone "https://github.com/your-github-user/my-repo.git" repo + git clone "$DEVBASE_PRIMARY_URL" repo fi + +echo "コンテナ内の作業ディレクトリ: $DEVBASE_WORK_DIR" # 例: /work/my-repo ``` -> **Note:** どちらのフックも `bash` で実行されます。`chmod +x` で実行可能ビットを立てておいてください。`pre-up` が非ゼロ終了すると `devbase up` は中断します。`deploy` は各インスタンスに対して `DEVBASE_INSTANCE_INDEX` を環境変数として渡しますが、失敗してもデプロイは続行されます。 +> **Note:** どちらのフックも `bash` で実行されます。`chmod +x` で実行可能ビットを立てておいてください。`pre-up` が非ゼロ終了すると `devbase up` は中断します。`deploy` は失敗してもデプロイは続行されます。 > **応用:** 外部リポジトリを共有 work ボリュームへ取り込み、app / nginx / db など複数コンテナで動かすプロジェクトでは、`pre-up` で clone/pull と work ボリュームへの populate を行い、2 回目以降はコンテナ側を上書きしないよう冪等にスキップするのが定石です。詳細は [repo 連携プロジェクトと pre-up populate パターン](repo-backed-projects.md) を参照してください。 diff --git a/docs/plugin-dev/repo-backed-projects.md b/docs/plugin-dev/repo-backed-projects.md index 6a979db..f30c6a5 100644 --- a/docs/plugin-dev/repo-backed-projects.md +++ b/docs/plugin-dev/repo-backed-projects.md @@ -88,10 +88,40 @@ volumes: | # | 処理 | 内容 | |---|------|------| -| ① | `repo/` の clone / pull | 無ければ `git clone`、あれば `git pull --ff-only`(app ビルドコンテキストの最新化) | +| ① | `repo/` の clone / pull | 無ければ `git clone "$DEVBASE_PRIMARY_URL"`、あれば `git pull --ff-only`(app ビルドコンテキストの最新化) | | ② | `.env` の取得 | S3 等から取得してホスト `./.env` に配置(`docker compose` の変数展開前に必要) | -| ③ | work ボリュームへ populate | `repo/` の内容を `/work/<リポジトリ名>` へコピー | -| ④ | `.env` を work ボリュームへ配置 | Laravel 等のランタイムが `/work/<リポジトリ名>/.env` を参照するため | +| ③ | work ボリュームへ populate | `repo/` の内容を `/work/$DEVBASE_PRIMARY_DIR` へコピー | +| ④ | `.env` を work ボリュームへ配置 | Laravel 等のランタイムが `/work/$DEVBASE_PRIMARY_DIR/.env` を参照するため | + +### clone 先と URL の受け取り方 + +`pre-up` はホスト側で動くフックなので、コンテナへ渡る `env` は読み込まれません。populate 先のディレクトリ名と clone URL は、devbase が `project.yml` から解決して環境変数で渡します。 + +```bash +#!/bin/bash +# projects//pre-up +set -e + +REPO_DIR="$DEVBASE_PRIMARY_DIR" # 例: carmo-system-console +WORK_VOLUME="${DEVBASE_WORK_VOLUME:-devbase_work_1}" + +# ① ビルドコンテキストの clone / pull +if [ ! -d "./repo/.git" ]; then + git clone "$DEVBASE_PRIMARY_URL" repo +elif [ "${DEVBASE_REPO_PULL:-1}" = "1" ]; then + git -C repo pull --ff-only +fi + +# populate 済み判定は work ボリューム上の /work/$REPO_DIR/.git で行う +if docker run --rm -v "$WORK_VOLUME:/work" alpine test -d "/work/$REPO_DIR/.git"; then + echo "populate 済みのためスキップ" + exit 0 +fi + +# ②③④ (.env 取得 / populate / .env 配置) は /work/$REPO_DIR を対象に行う +``` + +変数の一覧と `deploy` への渡り方は [クイックスタート「フックへ渡る環境変数」](quickstart.md#フックへ渡る環境変数) を参照してください。`project.yml` に複数リポジトリを書いている場合は、`DEVBASE_REPO_DIRS`(宣言順・空白区切り)で全 clone 先を回せます。 ② を `deploy`(`up` 後フック)ではなく `pre-up` で行うのは、`compose.yml` の `MYSQL_DATABASE: ${DB_DATABASE:-...}` のような変数展開が `docker compose` パース時(= MySQL コンテナ初回起動前)に `.env` を要求するためです。`deploy` 段階では間に合わず、DB がデフォルト名で初期化されてしまいます。 @@ -185,6 +215,15 @@ devbase up | `DEVBASE_WORK_VOLUME` | `devbase_work_` | `compose.yml` が参照する共有 work ボリューム名の明示指定。未指定なら `DEVBASE_INSTANCE_INDEX` から解決。ただし効くのは **app / nginx など非 dev サービスだけ**で、dev サービスの `/work` は scale 生成時に `devbase_work_` へ無条件に差し替えられます。dev から実行時ソースを触る本パターンでは **既定名のまま**にしてください([スケール前提](#スケール前提-scale-1) を参照) | | `DEVBASE_INSTANCE_INDEX` | `1` | work ボリューム名のインデックス。**devbase 本体が渡すのは `deploy` フックに対してのみ**で、`pre-up` や `docker compose` のプロセス環境には渡りません。`compose.yml` の `${DEVBASE_INSTANCE_INDEX:-1}` は `.env` に書かれた値、無ければ `1` に解決されます([スケール前提](#スケール前提-scale-1) を参照) | +上記はプロジェクト側が設定する変数です。これに対し、次の 4 つは **devbase が `project.yml` から解決して `pre-up` / `deploy` の両方へ渡す**読み取り専用の値です(詳細は [クイックスタート「フックへ渡る環境変数」](quickstart.md#フックへ渡る環境変数))。 + +| 変数 | 内容 | +|------|------| +| `DEVBASE_PRIMARY_DIR` | primary リポジトリの `/work` 配下ディレクトリ名(populate 先) | +| `DEVBASE_PRIMARY_URL` | primary リポジトリの clone URL | +| `DEVBASE_WORK_DIR` | コンテナ内の既定の作業ディレクトリ | +| `DEVBASE_REPO_DIRS` | 全リポジトリのディレクトリ名(宣言順・空白区切り) | + > **Note:** `.env` の環境選択(例: `s3://.../env/local.env` の `local` 部分)など、S3 パスやプロファイルはプロジェクト固有の変数(例: `CARMO_ENV`)で制御することがあります。プロジェクトの `pre-up` 冒頭コメントを参照してください。 --- @@ -196,6 +235,7 @@ devbase up - [ ] `compose.yml` で work ボリュームを `external: true` + `name: ${DEVBASE_WORK_VOLUME:-devbase_work_${DEVBASE_INSTANCE_INDEX:-1}}` で宣言した - [ ] app サービスの `build.context` をホスト `./repo` にした - [ ] `pre-up` で ①clone/pull → ②`.env`取得 → ③populate → ④`.env`配置 を実装した +- [ ] `pre-up` が clone 先・URL を `DEVBASE_PRIMARY_DIR` / `DEVBASE_PRIMARY_URL` から受け取っている(`source ./env` でも値を直書きでもなく) - [ ] `pre-up` が `/work/<リポジトリ名>/.git` の有無で populate 済みを判定し、②③④ をスキップする - [ ] populate 時の owner を `1000:1000`(コンテナ内ユーザー)に設定した - [ ] `storage/` / `vendor/` / `node_modules/` 等、初回のみ生成され上書きしたくないパスの扱いを決めた diff --git a/docs/user/project-yml.md b/docs/user/project-yml.md index f91bcc9..7a6f4c9 100644 --- a/docs/user/project-yml.md +++ b/docs/user/project-yml.md @@ -146,6 +146,24 @@ flowchart LR YAML の解釈はホスト側の Python に閉じています。コンテナ側は復号して 1 行ずつ clone するだけなので、イメージへ YAML パーサを持ち込みません。 +## ライフサイクルフックへの渡り方 + +プロジェクトに `pre-up` / `deploy` フックを置いている場合、それらは**ホスト側**で +動くため `env` を読み込めません。フックがよく必要とする値は、devbase が +`project.yml` から解決して環境変数として渡します。 + +| 環境変数 | `project.yml` の由来 | +|---------|---------------------| +| `DEVBASE_PRIMARY_DIR` | primary リポジトリの `repos[].dir`(未指定ならリポジトリ名) | +| `DEVBASE_PRIMARY_URL` | primary リポジトリの `host` / `owner` / `repo` から組み立てた clone URL | +| `DEVBASE_WORK_DIR` | `work_dir`(未指定なら `/work/`) | +| `DEVBASE_REPO_DIRS` | `repos[].dir` を宣言順に空白区切りで並べたもの | + +旧 `env` 形式のフックが `source ./env` で読んでいた `GIT_REPO` / `WORK_DIR` は、 +それぞれ `DEVBASE_PRIMARY_DIR` / `DEVBASE_WORK_DIR` に置き換えてください。詳細は +[プラグイン開発クイックスタート「フックへ渡る環境変数」](../plugin-dev/quickstart.md#フックへ渡る環境変数) +を参照してください。 + > **Note:** `entrypoint.sh` はイメージに焼き込まれます。devbase 本体を更新して > clone のふるまいが変わった場合は、`devbase build --no-cache` でベースイメージを > 再ビルドしないと反映されません。 From 59506e76d8c151575cf9738bc6576af8e59b0c0f Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sun, 23 Aug 2026 02:27:20 +0900 Subject: [PATCH 8/8] =?UTF-8?q?test:=20=E3=83=95=E3=83=83=E3=82=AF?= =?UTF-8?q?=E7=92=B0=E5=A2=83=E5=A4=89=E6=95=B0=E3=81=AE=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=81=8C=E5=AE=9F=E8=A1=8C=E7=92=B0=E5=A2=83=E3=81=AB?= =?UTF-8?q?=E5=BD=B1=E9=9F=BF=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 親プロセスへ漏れないことを確かめるテストは、実行環境に同名の変数が居ると 偽陰性/偽陽性になる。事前に unset して初期状態を固定した。 Co-Authored-By: Claude Opus 5 (1M context) --- tests/commands/test_hook_env.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/commands/test_hook_env.py b/tests/commands/test_hook_env.py index 689563b..120e519 100644 --- a/tests/commands/test_hook_env.py +++ b/tests/commands/test_hook_env.py @@ -68,6 +68,7 @@ def test_deploy_hook_receives_the_repo_layout_and_index(tmp_path, monkeypatch, c def test_hooks_still_run_without_a_config(tmp_path, monkeypatch): """設定を渡さない呼び出し (旧 scale 経路) でもフック自体は動く""" monkeypatch.chdir(tmp_path) + monkeypatch.delenv("DEVBASE_WORK_DIR", raising=False) (tmp_path / "pre-up").write_text(DUMP_SCRIPT) assert container._run_pre_up_hook() is True @@ -77,6 +78,8 @@ def test_hooks_still_run_without_a_config(tmp_path, monkeypatch): def test_hook_env_does_not_leak_into_the_parent_process(tmp_path, monkeypatch, config): monkeypatch.chdir(tmp_path) + # 実行環境に同名の変数が居ても判定がぶれないよう、事前状態を固定する + monkeypatch.delenv("DEVBASE_WORK_DIR", raising=False) (tmp_path / "pre-up").write_text(DUMP_SCRIPT) container._run_pre_up_hook(config)