diff --git a/CHANGELOG.md b/CHANGELOG.md index b131b03..58ab1e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,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 db45c53..aec5443 100644 --- a/docs/plugin-dev/quickstart.md +++ b/docs/plugin-dev/quickstart.md @@ -170,19 +170,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 0fdb27c..0dbfad4 100644 --- a/docs/user/project-yml.md +++ b/docs/user/project-yml.md @@ -147,6 +147,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` でベースイメージを > 再ビルドしないと反映されません。 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..120e519 --- /dev/null +++ b/tests/commands/test_hook_env.py @@ -0,0 +1,87 @@ +"""ライフサイクルフックへ渡す環境変数 (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) + monkeypatch.delenv("DEVBASE_WORK_DIR", raising=False) + (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) + # 実行環境に同名の変数が居ても判定がぶれないよう、事前状態を固定する + monkeypatch.delenv("DEVBASE_WORK_DIR", raising=False) + (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"