env-init を flake パッケージとして追加し devbox 開発環境を整備#1
Conversation
汎用 dev ツールの第一弾として env-init を Nix flake で配布する形に移植し、 devbox で Nix の test/lint を含む開発環境を整備した。 - pkgs/env-init: 生スクリプトを verbatim 移植し makeWrapper で PATH のみ wrap - flake.nix: packages / checks (shellcheck・bats・statix・deadnix・nixfmt) / formatter - devbox.json: dev ツール + path:.#env-init の dogfood + init_hook + scripts - ルート .env.template: 書式の参照例(本 repo の dogfood でも使用) - CI: check.yml(nix flake check) と release.yml(タグ駆動の Release 自動生成) - README/CLAUDE.md: 構成・開発・バージョニング(SemVer)を追記 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Linux の hermetic な nix ビルドサンドボックスには /usr/bin/env が無く、 生スクリプトの `#!/usr/bin/env bash` が bad interpreter で落ちて CI が失敗していた。 インストールした libexec のコピーのみ shebang を bashNonInteractive の絶対パスへ 置換する(リポジトリ上の原本は #!/usr/bin/env bash のまま=非 Nix 利用者向けに可搬)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
この PR は、汎用 dev ツール集約リポジトリの初期整備として env-init を flake package として追加し、devbox ベースでの開発環境(テスト/リンター含む)と CI(check/release)を一式整えるものです。
Changes:
env-init本体スクリプトと bats テストを追加し、worktree ごとの.env生成を実装- Nix flake の
packages/checks/formatterを追加し、nix flake checkで test/lint を集約 - devbox 設定・CI workflows・README/CLAUDE.md を追加して開発/リリース手順を整備
Reviewed changes
Copilot reviewed 10 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| README.md | リポジトリ構成・開発手順・バージョニング・env-init 利用方法を追加 |
| pkgs/env-init/tests/env-init.bats | env-init の bats フルセットテストを追加 |
| pkgs/env-init/package.nix | env-init を makeWrapper で wrap する Nix 派生を追加 |
| pkgs/env-init/env-init | .env.template から .env を生成するエンジン本体を追加 |
| flake.nix | packages/checks/formatter を公開し nix flake check を定義 |
| flake.lock | nixpkgs 入力の lock を追加 |
| devbox.lock | devbox 依存パッケージの lock を追加 |
| devbox.json | 開発環境(lint/test)と dogfooding を追加 |
| CLAUDE.md | リポジトリの前提/開発方針を追記(※一部記述に不整合あり) |
| .gitignore | ローカルツール/Claude Code ローカル状態の ignore を追加 |
| .github/workflows/release.yml | SemVer タグ push で release 作成する workflow を追加 |
| .github/workflows/check.yml | push/PR で nix flake check を回す workflow を追加 |
| .env.template | env-init 用テンプレートの書式例を追加 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - パッケージは `pkgs/<name>/` に `package.nix`(`writeShellApplication` 派生)と生スクリプトを同居させる。生スクリプトは | ||
| `#!/usr/bin/env bash` 始まりで単体実行可能なまま保ち、wrap は外側に被せるだけで中身を書き換えない。 | ||
| - test / lint の真実は `flake.nix` の `checks`(bats・statix・deadnix・nixfmt、および writeShellApplication build 内包の | ||
| shellcheck)に一元化する。`devbox.json` の scripts はそれへの薄い委譲。 |
There was a problem hiding this comment.
ご指摘のとおりです。実装は runCommand + makeWrapper(shellcheck は独立 check)なのに CLAUDE.md が writeShellApplication 前提のままでした。f961ae6 で実態に合わせて修正し、writeShellApplication は本文前にプリアンブルを差し込み $0 依存(env-init の --help)を壊しうるため避ける旨も明記しました。
writeShellApplication 前提の記述だったが、実装は runCommand + makeWrapper で shellcheck も独立 check。将来のパッケージ作成者を誤導しないよう実態に合わせて 一般化した(Copilot レビュー指摘)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| "nixfmt@latest", | ||
| "bats@latest", | ||
| "path:.#env-init" |
There was a problem hiding this comment.
ご指摘のとおりです。cfadb4e で devbox.json の packages に openssl@3 を追加しました(devbox.lock も更新)。これでルートの .env.template の openssl rand が dogfood 環境で常に解決でき、SESSION_SECRET の空生成(silent failure)を防げます。利用側 repo が openssl を供給する設計の、本 repo 版でもあります。
| # bin/env-init --force # 既存 .env を上書き (N は WORKTREE_N から復元) | ||
| # bin/env-init -n 3 # worktree 番号 N を手動指定 | ||
| # | ||
| # devbox タスク経由: `task env:init` (引数は `-- --force` のように渡す) |
There was a problem hiding this comment.
ご指摘のとおりです。cfadb4e で --help ヘッダを本リポジトリの実態に更新しました(存在しない task env:init を削除し、コマンド名を env-init・起動例を devbox init_hook の [ -f .env ] || env-init に)。移行後は本リポジトリが正典(移行元の実体は削除される方針)のため、生スクリプトの記述を実態へ合わせました。
- env-init の --help ヘッダを本リポジトリの実態に合わせて更新(存在しない `task env:init` を削除し、コマンド名を `env-init`・起動は devbox init_hook に)。 移行後は本リポジトリが正典のため生スクリプトの記述を実態へ更新。 - devbox.json に openssl@3 を追加。ルート .env.template が `openssl rand` を使うため、 dogfood が環境非依存で SESSION_SECRET を生成できるようにする(空生成の silent failure を防止)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
意図しないメジャーアップグレードで破壊的変更を取り込むのを防ぐため、 shellcheck@0 / statix@0 / deadnix@1 / nixfmt@1 / bats@1 にピン。 解決されるバージョンは従来と同一で、devbox update 時の major 跳ねを抑止する。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| PRIMARY_PATH=$(git worktree list --porcelain | awk '/^worktree / { sub(/^worktree /, ""); print; exit }') | ||
| if [ -z "$PRIMARY_PATH" ]; then | ||
| echo "error: could not determine primary worktree path" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ "$REPO_ROOT" = "$PRIMARY_PATH" ]; then | ||
| N=0 | ||
| else | ||
| # 他の worktree (自分自身と primary を除く) の .env から WORKTREE_N を読み、 | ||
| # 使用済み N を集めて {1..99} の最小未使用値を割り当てる。 | ||
| USED_NS="" | ||
| # プロセス置換で直接読む (while を current shell で回し USED_NS を親に残す。 | ||
| # bash 必須だが本スクリプトは元から bash 前提)。 | ||
| while IFS= read -r line; do | ||
| case "$line" in | ||
| "worktree "*) | ||
| wt_path=${line#worktree } | ||
| if [ "$wt_path" = "$REPO_ROOT" ] || [ "$wt_path" = "$PRIMARY_PATH" ]; then | ||
| continue | ||
| fi | ||
| wt_env="$wt_path/.env" |
There was a problem hiding this comment.
ご指摘のとおりです。妥当なエッジケース(symlink 跨ぎで --force 時に N がズレ得る)として修正しました。canonicalize_dir(cd … && pwd -P)を追加し、REPO_ROOT / PRIMARY_PATH / 各 worktree パスを物理パスに正規化してから比較するようにしています。あわせて bats は BATS_TEST_TMPDIR(macOS では /var→/private/var の symlink を含む)を正規化せず使い、symlink 跨ぎの primary 判定・sibling 除外を実地で検証するようにしました。
| # - それ以外 (if/echo/exit/関数定義などの評価専用ロジック) → .env に出力しない | ||
| # (素通しするとシェル構文が .env に混入し、`. ./.env` や dotenv パーサを壊す) | ||
| while IFS= read -r line || [ -n "$line" ]; do | ||
| if [[ $line =~ ^([A-Za-z_][A-Za-z0-9_]*)= ]]; then |
There was a problem hiding this comment.
これはあえての設計です。テンプレートは bash として source 評価されるため、if/for/関数本体などのロジックブロック内の代入(通常インデントされる)まで抽出対象にすると、その分岐が実行されていなくても抽出フェーズの ${!name} が空値を返し、条件付き変数を誤って空のまま .env に固定してしまいます。そのため「列 0 のトップレベル宣言のみ .env に出力/インデント=評価専用ロジックは非出力」という区別にしています(スクリプト冒頭コメントの『それ以外 (if/echo/exit/関数定義などの評価専用ロジック) → .env に出力しない』方針)。インデントしたトップレベル宣言を出力したい場合はテンプレート側で列 0 に置く運用とします。
git rev-parse --show-toplevel と git worktree list --porcelain のパス表現が symlink でズレる環境(macOS の /var → /private/var 等)で、primary 判定や sibling 除外を誤り --force 時に worktree N がズレ得るのを修正。canonicalize_dir で REPO_ROOT / PRIMARY_PATH / 各 worktree パスを pwd -P 正規化してから比較する。 bats も BATS_TEST_TMPDIR を正規化せず使い、symlink 跨ぎの判定を実地検証する。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| # リポジトリルート (このスクリプトを呼んだ worktree のルート) | ||
| REPO_ROOT=$(canonicalize_dir "$(git rev-parse --show-toplevel)") | ||
| ENV_PATH="$REPO_ROOT/.env" | ||
| TEMPLATE_PATH="$REPO_ROOT/.env.template" |
There was a problem hiding this comment.
ご指摘のとおりです。git rev-parse --show-toplevel の失敗を明示的にハンドルし、git の生エラーは抑止して error: not inside a git worktree. Run env-init from within a git repository. を出して exit 1 するようにしました。あわせて bats に git 管理外で実行するケースを追加しています。
(補足: 直前の canonicalize_dir 変更が git 失敗時の set -e 即時終了を握り潰し、的外れな「.env.template not found」を出す退行も生んでいたため、本修正で併せて解消しました。)
git 管理外で実行された場合に git の生 fatal だけが出ていた問題を修正し、 「git worktree 内で実行する」旨のメッセージで exit 1 する。あわせて、直前の canonicalize_dir 変更が git 失敗時の set -e 即時終了を握り潰して的外れな 「.env.template not found」を出していた退行も解消。bats に git 管理外ケースを追加。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LGTM ✅汎用 dev ツール集約リポジトリの第一弾として 主な内容
レビュー対応
follow-up(依存の定期更新 / メジャー移動タグ)は #2 で別 PR 対応。 |
ユーザー指示の要点
汎用 dev ツールの第一弾として
env-initを追加する。devbox で Nix のテスト/リンターを含む開発環境をセットアップしたうえで、移植元からenv-initを移植する。変更の概要
pkgs/env-init/env-init: 移植元を verbatim コピー(無改変)。pkgs/env-init/package.nix:makeWrapperで生スクリプトに PATH のみ被せて wrap(中身は無改変)。flake.nix:packages/checks(shellcheck・bats・statix・deadnix・nixfmt)/formatter(nixfmt-tree)。defaultは設けず利用側は#<tool>を明示。devbox.json: dev ツール一式 +path:.#env-initの dogfood + init_hook +check/build/fmtscripts。.env.template(ルート):N算術・変数展開・乱数生成を含む書式の参照例。本 repo の dogfood でも使用。pkgs/env-init/tests/env-init.bats: フルセット(引数/help/冪等性/算術・変数展開/権限600/worktree の N 最小未使用割当・再利用)。check.yml(push/PR でnix flake check)、release.yml(v*タグ駆動で GitHub Release 自動生成)。Action は SHA ピン、最小権限。レビューのポイント
makeWrapper採用:writeShellApplicationだとプリアンブルで--helpが読む先頭ヘッダコメントが押し下げられ usage が空になる回帰が出たため。$0が生スクリプトを指すよう makeWrapper にし、shellcheck は flake check に明示追加。bashOptions = [ errexit nounset ]: 元のset -euに忠実化し、pipefail 由来の挙動変化を回避。nixを入れない:nix@latestが古い nix を導入し現行 nixpkgs を評価できなかったため、ホストの nix を使用。検証方法
devbox run check(=nix flake check)が all checks passed(bats 8件・shellcheck・statix・deadnix・nixfmt・build)。.env生成を確認(WORKTREE_N=0/PORT_APP=3000/APP_URL・DATABASE_URLの変数展開 / 乱数 secret / 権限 600 /.envは ignore)。check.yml)で x86_64-linux 含めて再現。🤖 Generated with Claude Code