Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
## [Unreleased]

### Added
- **`devbase project` サブコマンド群を新設**しました (PLAN06)。CWD に依存せずプロジェクト名でコンテナ操作ができます。
- `devbase project up/down/ps/logs/scale [name]` で、任意のディレクトリから `$DEVBASE_ROOT/projects/<name>` を対象に操作できます。名前解決はラッパー (`bin/devbase`) が対象ディレクトリへ `cd` してから実行するため、シェル実装の `build` を含む全操作が名前指定で成立します(呼び出し元シェルの作業ディレクトリは変わりません)。存在しない名前はエラーになり候補が提示されます。
- `devbase project list [--interactive|-i]` で `$DEVBASE_ROOT/projects/` 配下を `NAME` / `PLUGIN` / `STATUS` の一覧表示します。`PLUGIN` 列はシンボリックリンク先から解決するため、PLAN04 の同名衝突 suffix(例 `carmo.takemi`)が付いていても正しいプラグイン名を表示します。`--interactive` では一覧から番号で選択して起動でき、非対話環境では番号入力にフォールバックします。
- トップレベルシノニム `devbase up/down/ps/scale [name]` / `devbase build [image]` / `devbase login [index]` / `devbase list` を整備しました(`logs` はシノニムを持たず `devbase project logs` のみ)。
- bash / zsh のシェル補完に `project` グループとプロジェクト名補完(`$DEVBASE_ROOT/projects/` 配下を列挙)を追加しました。
- 利用者向けドキュメント [`docs/user/cli-reference.md`](docs/user/cli-reference.md) / [`docs/user/container-operations.md`](docs/user/container-operations.md) を `project` 体系に更新しました。
- `devbase env export` / `devbase env import` で **S3 URI (`s3://bucket/key`) を入出力先として指定**できるようになりました (PLAN03-1 PR3)。
- 既定でオブジェクト単位の SSE (`aws:kms` または `AES256`) を強制し、export 時はバケット側のデフォルト暗号化も `GetBucketEncryption` で事前確認します。
- 暗号化が未設定のバケットへ export する場合は `--unsafe-allow-unencrypted-bucket` の明示が必要です (オブジェクト単位の SSE はこのフラグに関係なく常に付与されます)。
Expand All @@ -15,6 +21,7 @@
- README と環境変数ガイドからのリンクも追加しました。

### Changed
- **`devbase container` グループを非推奨化**しました (PLAN06)。`devbase container <sub>` は `devbase project <sub>` のエイリアスとして当面動作しますが、実行時に非推奨警告を表示します(移行期間後のリリースで削除予定)。`[name]` 指定や `list` などの新機能は `project` 側のみで提供されます。トップレベルショートカット (`devbase up` 等) の転送先も `container` から `project` へ変更しました。
- `gs://` (GCS) スキームは **PLAN03-1 PR4 廃案** により対応しません。指定すると明示的なエラーメッセージで失敗します (旧: "未実装")。
- `lib/devbase/env/` 配下の export / import モジュールをリファクタリングしました (PLAN03-1 PR5)。公開 API (`ExportOptions`, `ImportOptions`, `export`, `import_bundle`) に互換性のない変更はありません。
- export / import で重複していた passphrase 読み取り / 既定鍵 fallback / セキュアな bytes 書き込みを `io_common.py` に集約。
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ devbaseは、Docker Composeを使った再現性の高い開発環境を提供
- **Pluginベースのプロジェクト管理**: 外部リポジトリからプロジェクト設定をインストール・更新
- **コンテナ化された開発環境**: Docker Composeベースで再現性の高い環境を提供
- **豊富なツールセット**: Docker CLI、AWS CLI、gcloud SDK、Terraform、Node.js、AI CLIツールがプリインストール
- **複数コンテナの並行開発**: `devbase container scale`で既存コンテナを再起動せずにスケール可能
- **複数コンテナの並行開発**: `devbase project scale`で既存コンテナを再起動せずにスケール可能
- **データ永続化**: 名前付きボリュームでコンテナ再起動後もデータを保持
- **スナップショット管理**: `/home/ubuntu` 共通ボリュームの増分バックアップ・復元・世代管理
- **環境変数の自動収集**: `devbase env init`でAWS/Git/GCP認証情報を対話的に設定
Expand Down Expand Up @@ -75,12 +75,14 @@ devbaseのコマンドは4つのグループにまとめられています。

| グループ | 略記 | 説明 |
|---------|------|------|
| `container` | `ct` | コンテナ管理(up / down / login / ps / logs / scale / build) |
| `project` | | プロジェクト管理(up / down / login / ps / logs / scale / build / list) |
| `env` | — | 環境変数管理(init / sync / list / set / get / delete / edit / project / export / import) |
| `plugin` | `pl` | プラグイン管理(list / install / uninstall / update / info / sync / repo) |
| `snapshot` | `ss` | スナップショット管理(create / list / restore / copy / delete / rotate) |

- **ショートカット**: `up`, `down`, `login`, `build`, `ps` はトップレベルから直接使用可能
> **`container`(略記 `ct`)グループは非推奨です。** `devbase project <sub>` のエイリアスとして当面動作しますが、非推奨警告を表示します。新しいコマンドは `project` を使用してください。

- **ショートカット**: `up [name]`, `down [name]`, `login [index]`, `build [image]`, `ps [name]`, `scale [name] <num>`, `list` はトップレベルから直接使用可能(`project` グループへ自動転送。`logs` はシノニムを持ちません)。ただし `build` のみ例外で、`project` グループ(Python 実装)ではなく `bin/devbase` のシェル実装 `cmd_build` へ直接委譲されます(詳細は [CLI リファレンス](docs/user/cli-reference.md#ショートカットコマンド))
- **プレフィックス略記**: `devbase p l` → `devbase plugin list`
- **トップレベルコマンド**: `init`, `status`, `shell-rc`

Expand Down
114 changes: 108 additions & 6 deletions bin/devbase
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,72 @@ run_python() {
# Resolve abbreviated command to full command name via unique prefix matching
resolve_command() {
local input="$1"
local commands="init status shell-rc container ct env plugin pl snapshot ss up down login build ps scale help"
local commands="init status shell-rc project container ct env plugin pl snapshot ss up down login build ps scale list help"
local matches=()
for cmd in $commands; do
[[ "$cmd" == "$input"* ]] && matches+=("$cmd")
done
if [ ${#matches[@]} -eq 1 ]; then
echo "${matches[0]}"
else
echo "$input" # no match or ambiguous -> return as-is
return
fi
# ambiguous の場合の後方互換 preference。`list` 追加で `l` が login/list の
# 両方にマッチするようになったため、既存の `devbase l` → `login` を維持する。
# cli.py の TOP_PREFIX_PREFERENCES と同期させること。
if [ ${#matches[@]} -gt 1 ]; then
local preferred=""
case "$input" in
l) preferred="login" ;;
esac
if [ -n "$preferred" ]; then
for m in "${matches[@]}"; do
[ "$m" = "$preferred" ] && { echo "$preferred"; return; }
done
fi
fi
echo "$input" # no match or ambiguous -> return as-is
}

# ===================================================================
# Project name resolution (PLAN06 Task 2)
# ===================================================================
# `devbase project <sub> <name>` および同義のトップレベルシノニム
# `devbase <sub> <name>` の <name> が $DEVBASE_ROOT/projects/<name> に実在する
# 場合、そのディレクトリへ cd し COMPOSE_PROJECT_NAME / env を再設定する。
# これにより任意の CWD からプロジェクトを指定してコンテナ操作できる。
#
# 重要: `build` は shell 実装 (cmd_build) が CWD で動くため、この wrapper cd
# だけが build の name 解決手段になる (PLAN06 方針 A の核心)。Python 側 chdir
# フォールバックでは build を救えない。
#
# <name> 判定は projects/ 配下の実在性で行う。これにより `login <index>` /
# `build <image>` / `scale <N>` の既存 positional と曖昧にならない: 実在する
# プロジェクト名のときだけ name として解釈し cd + strip する。実在しなければ
# 引数はそのまま下流 (Python パーサ) へ渡し、Python 側で index/image/scale
# あるいは「存在しない name」エラーとして扱わせる。

# name 候補を受け取り projects/ 配下に実在すれば cd + env 再設定して 0 を返す。
maybe_cd_project() {
local name="${1:-}"
case "$name" in -*|"") return 1 ;; esac # フラグ・空は name ではない
local target="${DEVBASE_ROOT}/projects/${name}"
[ -d "$target" ] || return 1
cd "$target" || return 1
export COMPOSE_PROJECT_NAME="$name"
# cd 後にプロジェクトの env を再 source (初期 CWD で読んだ値を上書き)。
# project の .env (dotfile) は CRLF / 特殊文字対策で意図的に source しない
# 方針を踏襲する (冒頭コメント参照)。
#
# 注意: env は環境変数定義のみを想定したファイルであり subshell ではなく
# 現プロセスで source する。これは wrapper 冒頭 L23-24 の env 読み込みと同一
# 意図 — set -a で export した変数を後続の run_python / cmd_build へ引き継ぐ
# ため、変数が親プロセスに残らない subshell 化はできない。代償として env 内に
# `exit` 等があると wrapper ごと終了するが、env は (a) プロジェクト所有者が
# 管理する信頼境界内のファイルで (b) 元々 L24 で初期 CWD でも source される
# ため、ここで新たなリスクが増えるわけではない。万一 exit を含む env を読んで
# も「該当プロジェクトの操作が中断する」だけで他プロジェクトへ波及しない。
[ -f "env" ] && set -a && source ./env && set +a
return 0
}

# Resolve the command (skip flags like --version, -V, -h, --help)
Expand All @@ -187,14 +243,60 @@ case "$_resolved_cmd" in
*) _resolved_cmd="$(resolve_command "$_resolved_cmd")" ;;
esac

# name 解決: 実在するプロジェクト名を検出したら cd し、その token を argv から
# 取り除いた配列 _DEVBASE_ARGS を組み立てる。検出しなければ素通し。
# name 候補の位置:
# project|container <sub> <name> -> $3 (サブコマンドは保持)
# トップレベルシノニム <sub> <name> -> $2
#
# 重要 (PLAN06 codex 指摘対応): `project`/`container` グループでは parser が
# `name` positional を持つサブコマンド (`up`/`down`/`ps`/`logs`/`scale`) に限定
# して $3 を name 解決する。`project login` / `project build` は単一 positional が
# index / image (旧 container 互換) であり parser が name を受け付けない
# (cli.py の _add_login_subparser / _add_build_subparser 参照)。これらで $3 を
# name strip すると、`project build web` の image=web や `project login web` の
# index 引数が実在プロジェクト名と一致した瞬間に消えて別操作へ化けるため除外する。
#
# トップレベルシノニム (`build`/`login` を含む) は従来どおり「実在 project なら
# cd」方針を維持する: トップレベル `build`/`login` は Python parser を経由せず
# shell cmd_build / wrapper cd だけが name 指定の手段であり、`build carmo` /
# `login carmo` を「そのプロジェクトを操作」と解釈する設計 (存在性ベース判定)。
_DEVBASE_ARGS=("${@:2}")
# 同期注意 (メンテナンス性): 下記 2 リストは cli.py の parser 定義に対応する。
# _PROJECT_NAME_SUBCOMMANDS = `project`/`container` で `name` positional を
# 受け付けるサブコマンド集合。cli.py の _add_project_parser で
# `add_argument('name', ...)` を持つもの (up/down/ps/logs/scale) と一致させる。
# login/build は index/image 互換のため意図的に除外 (上のコメント参照)。
# _NAME_RESOLVABLE_SHORTCUTS = トップレベルシノニムのうち「実在 project なら cd」
# を許すもの。cli.py の SHORTCUTS 経由で project サブコマンドへ写像される
# 集合 + shell 実装の build を含む。
# cli.py 側でサブコマンドを追加/削除した際は両リストの更新漏れに注意すること
# (cli.py の _add_project_parser / SHORTCUTS にも対の注記あり)。
_PROJECT_NAME_SUBCOMMANDS=" up down ps logs scale "
_NAME_RESOLVABLE_SHORTCUTS=" up down ps scale login build "
case "$_resolved_cmd" in
project|container)
if [[ "$_PROJECT_NAME_SUBCOMMANDS" == *" ${2:-} "* ]] \
&& maybe_cd_project "${3:-}"; then
_DEVBASE_ARGS=("${2:-}" "${@:4}")
fi
;;
*)
if [[ "$_NAME_RESOLVABLE_SHORTCUTS" == *" $_resolved_cmd "* ]] \
&& maybe_cd_project "${2:-}"; then
_DEVBASE_ARGS=("${@:3}")
fi
;;
esac

case "$_resolved_cmd" in
# Python-implemented commands
--version|-V)
run_python "$@" ;;
init|status|shell-rc|container|ct|env|plugin|pl|snapshot|ss|up|down|login|ps|scale)
run_python "${_resolved_cmd}" "${@:2}" ;;
init|status|shell-rc|project|container|ct|env|plugin|pl|snapshot|ss|up|down|login|ps|scale|list)
run_python "${_resolved_cmd}" "${_DEVBASE_ARGS[@]}" ;;
# Shell-implemented commands
build) shift; cmd_build "$@" ;;
build) cmd_build "${_DEVBASE_ARGS[@]}" ;;
# Help and unknown
-h|--help|help|"") run_python "--help" ;;
*) echo "Error: unknown command '$1'" >&2; exit 1 ;;
Expand Down
Loading
Loading