Skip to content

Commit f52bbbc

Browse files
takemi-ohamaclaude
andcommitted
feat(install): devbase ワンライナー installer (curl | bash) を追加 (PLAN31_1)
clone (既存なら git pull --ff-only) して bin/devbase init を 1 回呼ぶ薄い installer を新設。uv 自動導入・PATH/補完登録・plugins.yml 生成・冪等性・ 旧版移行はすべて既存の init に委譲する。 - 前提チェック: git/curl 必須・docker は警告のみ - DEVBASE_INSTALL_DIR/_REPO/_REF で配置先・clone元・ref を上書き可能 - DEVBASE_INSTALL_REF はサニタイズ (オプション注入/メタ文字を拒否) - 既存ディレクトリが devbase 以外の非空なら誤上書きを避けて中止 - 非 TTY (curl|bash) で対話しない。env init は対話必須のため案内のみ - tests/cli/test_install_sh.py: clone/init/冪等pull/中止/git不在/不正REF を検証 - CI に install.sh の ShellCheck (severity=error) を追加 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 54b71a5 commit f52bbbc

7 files changed

Lines changed: 557 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ jobs:
4141
with:
4242
scandir: ./bin
4343
severity: error
44+
- name: Run ShellCheck on install.sh
45+
run: shellcheck --severity=error install.sh

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
## [Unreleased]
66

77
### Added
8+
- **ワンライナー installer (`install.sh`) を新設**しました (PLAN31_1)。
9+
`curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh | bash`
10+
`~/devbase` への clone(既存なら `git pull --ff-only`)と `devbase init` まで
11+
自動完了します(uv の自動導入・PATH/補完の登録・`plugins.yml` 生成を含む)。
12+
- 配置先 / clone 元 / ref を `DEVBASE_INSTALL_DIR` / `DEVBASE_INSTALL_REPO` /
13+
`DEVBASE_INSTALL_REF` で上書きできます。`DEVBASE_INSTALL_REF` は branch/tag 名
14+
として妥当な文字のみ許可し、オプション注入を防ぎます。
15+
- 非 TTY (`curl | bash`) で対話プロンプトを出しません。`env init` は対話必須のため
16+
実行せず、完了後に次の手順(`shell-rc` 再読み込み / `plugin install` / `env init`
17+
/ `build` / `up` / `login`)を案内します。
18+
- 配置先が devbase 以外の非空ディレクトリの場合は誤上書きを避けて中止します。
19+
- CI に `install.sh` の ShellCheck (`severity=error`) を追加しました。
820
- **`devbase list` の対話選択を TUI 化**しました。`questionary` 導入により、↑↓ の
921
矢印キーで行移動、文字入力でプロジェクト名のインクリメンタル絞り込みができます
1022
(全項目に通し番号を表示)。Enter で決定、Ctrl-C で中止します。

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,38 @@ devbaseは、Docker Composeを使った再現性の高い開発環境を提供
2020

2121
## クイックスタート
2222

23+
### ワンライナーインストール(推奨)
24+
25+
```bash
26+
curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh | bash
27+
```
28+
29+
`~/devbase` に clone(既存なら更新)し、`devbase init` まで自動実行します(uv の自動導入・PATH/補完の登録・`plugins.yml` 生成を含む)。完了後に表示される手順に従い、`source "$(~/devbase/bin/devbase shell-rc)"` でシェルを再読み込みしてください。`env init` は対話が必要なため案内のみで、自動実行はしません。
30+
31+
環境変数で挙動を上書きできます。
32+
33+
| 変数 | 既定値 | 用途 |
34+
|------|--------|------|
35+
| `DEVBASE_INSTALL_DIR` | `$HOME/devbase` | 配置先ディレクトリ |
36+
| `DEVBASE_INSTALL_REPO` | `https://github.com/devbasex/devbase.git` | clone 元(fork / テスト用) |
37+
| `DEVBASE_INSTALL_REF` | `main` | チェックアウトする branch / tag |
38+
39+
```bash
40+
# 例: 別ディレクトリへ特定タグを入れる(パイプではなく保存実行でも env は同様に効きます)
41+
DEVBASE_INSTALL_DIR=~/work/devbase DEVBASE_INSTALL_REF=v1.2.3 \
42+
bash -c "$(curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh)"
43+
```
44+
45+
> **`curl | bash` を実行する前に**: 中身を確認したい場合は、いったん保存してから実行してください。
46+
>
47+
> ```bash
48+
> curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh -o install.sh
49+
> less install.sh # 内容を確認
50+
> bash install.sh
51+
> ```
52+
53+
### 手動セットアップ
54+
2355
```bash
2456
# 1. クローンと初期化
2557
git clone https://github.com/devbasex/devbase.git

docs/user/getting-started.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,42 @@ devbase を利用するには、以下のソフトウェアがホストマシン
1717

1818
> **Note:** Docker Desktop を使用している場合、Docker Engine と Docker Compose の両方が含まれています。Linux では Docker Engine を直接インストールし、Docker Compose プラグインを追加してください。
1919
20+
## クイックインストール(ワンライナー)
21+
22+
手順 1〜2(クローンと初期化)を 1 コマンドで自動化できます。`git``curl` があれば実行できます。
23+
24+
```bash
25+
curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh | bash
26+
```
27+
28+
このスクリプトは次を行います。
29+
30+
1. `~/devbase` に devbase を clone します(既に devbase が clone 済みなら `git pull --ff-only` で更新)。
31+
2. clone 先で `devbase init` を 1 回実行します(uv の自動導入・PATH/補完の登録・`plugins.yml` 生成を含む)。
32+
3. 完了後、シェル再読み込み(手順 3)以降の次の手順を表示します。
33+
34+
`env init`(手順 7)は対話が必要なため、ワンライナーでは**実行せず案内のみ**です。完了後に手動で実行してください。
35+
36+
環境変数で挙動を上書きできます。
37+
38+
| 変数 | 既定値 | 用途 |
39+
|------|--------|------|
40+
| `DEVBASE_INSTALL_DIR` | `$HOME/devbase` | 配置先ディレクトリ |
41+
| `DEVBASE_INSTALL_REPO` | `https://github.com/devbasex/devbase.git` | clone 元(fork / テスト用) |
42+
| `DEVBASE_INSTALL_REF` | `main` | チェックアウトする branch / tag |
43+
44+
> **既存ディレクトリの扱い**: 配置先が devbase 以外の非空ディレクトリだった場合、誤上書きを避けるためスクリプトは中止します。別の場所に入れるには `DEVBASE_INSTALL_DIR=/path/to/dir` を指定してください。
45+
46+
> **`curl | bash` を実行する前に**: 信頼できないスクリプトをそのままパイプ実行するのが不安な場合は、保存して内容を確認してから実行してください。
47+
>
48+
> ```bash
49+
> curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh -o install.sh
50+
> less install.sh # 内容を確認
51+
> bash install.sh
52+
> ```
53+
54+
ワンライナーを使わず手動で進める場合は、以下の手順に従ってください。
55+
2056
## セットアップ手順
2157
2258
### 1. リポジトリのクローン

install.sh

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env bash
2+
#
3+
# devbase ワンライナー installer (PLAN31_1)
4+
#
5+
# curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh | bash
6+
#
7+
# clone (または pull) して `bin/devbase init` を 1 回呼ぶだけの薄い導入スクリプト。
8+
# uv の自動導入・rc 追記・補完登録・plugins.yml 生成・冪等性・旧版移行はすべて
9+
# `devbase init` 側の既存処理に委譲する。env init は対話必須のため案内のみ。
10+
#
11+
# 環境変数で上書き可能:
12+
# DEVBASE_INSTALL_DIR 配置先 (既定: $HOME/devbase)
13+
# DEVBASE_INSTALL_REPO clone 元 URL (既定: https://github.com/devbasex/devbase.git)
14+
# DEVBASE_INSTALL_REF branch / tag (既定: main)
15+
#
16+
set -euo pipefail
17+
18+
INSTALL_DIR="${DEVBASE_INSTALL_DIR:-$HOME/devbase}"
19+
REPO="${DEVBASE_INSTALL_REPO:-https://github.com/devbasex/devbase.git}"
20+
REF="${DEVBASE_INSTALL_REF:-main}"
21+
22+
# --- 出力ヘルパ --------------------------------------------------------------
23+
info() { printf '==> %s\n' "$*"; }
24+
warn() { printf 'warning: %s\n' "$*" >&2; }
25+
err() { printf 'error: %s\n' "$*" >&2; }
26+
die() { err "$*"; exit 1; }
27+
28+
# --- 前提チェック ------------------------------------------------------------
29+
require_commands() {
30+
local missing=()
31+
local cmd
32+
for cmd in "$@"; do
33+
command -v "$cmd" >/dev/null 2>&1 || missing+=("$cmd")
34+
done
35+
if [ "${#missing[@]}" -gt 0 ]; then
36+
err "required command(s) not found: ${missing[*]}"
37+
die "git と curl をインストールしてから再実行してください。"
38+
fi
39+
}
40+
41+
# --- REF サニタイズ ----------------------------------------------------------
42+
# REF は `git clone --branch` に渡るため、オプション注入 (先頭 '-') やシェル
43+
# メタ文字混入を防ぐ。branch/tag 名として妥当な文字 (英数 . _ - /) のみ許可。
44+
validate_ref() {
45+
local ref="$1"
46+
case "$ref" in
47+
""|-*) die "invalid DEVBASE_INSTALL_REF: ${ref:-<empty>}" ;;
48+
esac
49+
if [[ ! "$ref" =~ ^[A-Za-z0-9._/-]+$ ]]; then
50+
die "invalid DEVBASE_INSTALL_REF: ${ref}"
51+
fi
52+
}
53+
54+
# --- 配置先判定 --------------------------------------------------------------
55+
# 既存ディレクトリが devbase repo か (bin/devbase を持つ git work tree か) 判定。
56+
is_devbase_repo() {
57+
local dir="$1"
58+
[ -f "$dir/bin/devbase" ] \
59+
&& git -C "$dir" rev-parse --is-inside-work-tree >/dev/null 2>&1
60+
}
61+
62+
dir_is_empty() {
63+
local dir="$1"
64+
local entry
65+
for entry in "$dir"/* "$dir"/.*; do
66+
[ -e "$entry" ] || continue
67+
case "${entry##*/}" in .|..) continue ;; esac
68+
return 1
69+
done
70+
return 0
71+
}
72+
73+
# --- 完了案内 ----------------------------------------------------------------
74+
print_next_steps() {
75+
cat <<EOF
76+
77+
============================================================
78+
devbase のインストールが完了しました
79+
配置先: ${INSTALL_DIR}
80+
------------------------------------------------------------
81+
次の手順:
82+
1. シェルを再読み込み:
83+
source "\$("${INSTALL_DIR}/bin/devbase" shell-rc)"
84+
2. plugin を導入:
85+
devbase plugin install <name>
86+
3. プロジェクトへ移動して env を初期化 (対話):
87+
cd "${INSTALL_DIR}/projects/<project>"
88+
devbase env init
89+
4. ビルドして起動:
90+
devbase build && devbase up && devbase login
91+
============================================================
92+
EOF
93+
}
94+
95+
main() {
96+
info "devbase installer"
97+
98+
require_commands git curl
99+
command -v docker >/dev/null 2>&1 \
100+
|| warn "docker が見つかりません。build/up 実行時に Docker と Compose が必要です。"
101+
validate_ref "$REF"
102+
103+
if [ -e "$INSTALL_DIR" ] && ! dir_is_empty "$INSTALL_DIR"; then
104+
if is_devbase_repo "$INSTALL_DIR"; then
105+
info "既存の devbase を更新します (git pull --ff-only): ${INSTALL_DIR}"
106+
git -C "$INSTALL_DIR" pull --ff-only
107+
else
108+
err "配置先が devbase ではない既存ディレクトリです: ${INSTALL_DIR}"
109+
err "誤上書きを避けるため中止します。別の配置先を指定してください:"
110+
die " DEVBASE_INSTALL_DIR=/path/to/dir で再実行してください。"
111+
fi
112+
else
113+
info "devbase を clone します: ${REPO} (${REF}) -> ${INSTALL_DIR}"
114+
git clone --branch "$REF" -- "$REPO" "$INSTALL_DIR"
115+
fi
116+
117+
info "初期化を実行します (uv 自動導入 / rc / 補完 / plugins)..."
118+
cd "$INSTALL_DIR"
119+
"$INSTALL_DIR/bin/devbase" init
120+
121+
print_next_steps
122+
}
123+
124+
main "$@"
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# PLAN31_1: devbase ワンライナー installer (`curl | bash`)
2+
3+
> 元 issue: `issues/i31.md` 第1項
4+
> ステータス: 着手可(設計確定 2026-06-09・既存コード精読済み)
5+
> 関連 skill: `/ndf:issue-plan-strategy`, `/ndf:implementation-plan`
6+
7+
## 1. 背景と目的
8+
9+
現状の導入は手動多段階(`docs/user/getting-started.md` の手順 1〜9)。ゴールは
10+
Claude CLI の `curl -fsSL https://claude.ai/install.sh | bash` 相当で
11+
**`devbase init` 相当まで自動完了**させること。env init は対話必須のため案内のみ。
12+
13+
```text
14+
curl -fsSL https://raw.githubusercontent.com/devbasex/devbase/main/install.sh | bash
15+
```
16+
17+
## 2. 確定した設計判断(2026-06-09 ユーザー確認済み)
18+
19+
| 項目 | 決定 |
20+
|---|---|
21+
| 配置先 (DEVBASE_ROOT) | **`~/devbase`** に clone(`DEVBASE_INSTALL_DIR` で上書き可) |
22+
| env init の扱い | install では実行せず、完了後に手順を案内 |
23+
| TUI 範囲 | 本 plan 対象外(→ `PLAN31_2`|
24+
25+
## 3. 既存コード調査結果(installer 実装の前提)
26+
27+
| 事実 | 出典 | installer への含意 |
28+
|---|---|---|
29+
| `bin/devbase``BASH_SOURCE` から symlink 解決して **DEVBASE_ROOT を自己解決** | `bin/devbase:6-13` | clone 後に `~/devbase/bin/devbase` を呼ぶだけで DEVBASE_ROOT は自動確定。env 設定不要 |
30+
| `ensure_uv()`**uv を自動導入** (`astral.sh/uv/install.sh`) し `~/.local/bin` を PATH 追加 | `bin/devbase:180-191` | installer 側で uv を入れる必要なし。`run_python``uv run --project "$DEVBASE_ROOT"` (`bin/devbase:194-197`) |
31+
| `init` は Python 実装で wrapper 経由実行 (`run_python init`) | `bin/devbase:358-359` | installer は `bin/devbase init` を 1 回呼ぶだけ |
32+
| `cmd_init` は rc 追記に **marker `# devbase` + check_string `export DEVBASE_ROOT=`** で冪等 | `init.py:298-306` | 再実行しても二重追記しない。installer の冪等性は init に委譲できる |
33+
| 補完登録も **marker `# devbase completion`** で冪等、zsh/bash 自動判定 | `init.py:215-247`, `237-242` | 同上 |
34+
| `_setup_plugins_config``~/.devbase/config.yml` / `plugins/` / `projects/` / `plugins.yml` を作成。official repo 取得は**ネットワーク失敗時に空構造へ graceful fallback** | `init.py:84-134` | オフライン/失敗でも init は成功する。installer はネットワーク前提にしなくてよい |
35+
| 旧 rc ブロック (`DEVBASE_PARENT_ROOT` 等) は **自動マイグレーション** | `init.py:138-212` | 旧版からの移行も init 任せ |
36+
| `pyproject.toml``package = false`・deps=pyyaml/pyrage/boto3/questionary・`requires-python>=3.10``uv.lock` 同梱 | `pyproject.toml` | PyPI 配布なし。clone 必須。deps は `uv run --project` が解決 |
37+
| 前提ソフト: Docker/Compose/Bash4+/Python3.10+/Git(uv 以外) | `getting-started.md:11-16` | installer は git/curl を必須チェック、docker は利用時に必要な旨を案内 |
38+
39+
**結論**: installer の本質は `clone(または pull)→ ~/devbase/bin/devbase init` の 2 手。
40+
uv 導入・rc 追記・補完・plugins.yml・冪等性・旧版移行はすべて既存資産が担う。
41+
42+
## 4. 要件
43+
44+
### 4.1 機能要件
45+
46+
- `install.sh` をリポジトリ root に置き、`raw.githubusercontent.com/devbasex/devbase/main/install.sh` で配布する。
47+
- 前提チェック: `git` / `curl` の存在。無ければ案内して `exit 1``docker` は警告のみ(install は通す)。
48+
- 配置先解決: `INSTALL_DIR="${DEVBASE_INSTALL_DIR:-$HOME/devbase}"`
49+
- clone 元: `REPO="${DEVBASE_INSTALL_REPO:-https://github.com/devbasex/devbase.git}"`(fork/テスト用に上書き可)。
50+
- バージョン: `REF="${DEVBASE_INSTALL_REF:-main}"`(branch/tag)。
51+
- 既存 `INSTALL_DIR` の扱い:
52+
- `$INSTALL_DIR/bin/devbase` が存在し devbase git repo → `git -C "$INSTALL_DIR" pull`(更新)。
53+
- 存在するが devbase でない → **中止**して別ディレクトリ指定を案内(誤上書き防止)。
54+
- 無し → `git clone --branch "$REF" "$REPO" "$INSTALL_DIR"`
55+
- `"$INSTALL_DIR/bin/devbase" init` を実行(uv 自動導入+rc/補完/plugins 初期化)。
56+
- 完了メッセージ(実パス埋め込み):
57+
`source "$("$INSTALL_DIR/bin/devbase" shell-rc)"``devbase plugin install <name>`
58+
`cd "$INSTALL_DIR/projects/<x>"``devbase env init``build``up``login`
59+
60+
### 4.2 非機能要件
61+
62+
- **非 TTY 安全**: `curl | bash` では stdin がスクリプト本体。対話プロンプトを出さない
63+
(確認が要る分岐は env 既定値で回避、どうしても要るなら `< /dev/tty`)。
64+
- `#!/usr/bin/env bash` + `set -euo pipefail`。失敗時に途中状態を残さない。
65+
- shellcheck 通過を CI 条件に含める。
66+
- 配置先 / clone 元 / REF はサニタイズ(任意コマンド混入防止。特に `REF`)。
67+
68+
## 5. インストールフロー
69+
70+
```mermaid
71+
flowchart TD
72+
A["curl | bash 実行"] --> B{git / curl あり?}
73+
B -- no --> Z["案内して exit 1"]
74+
B -- yes --> C{"INSTALL_DIR 存在?"}
75+
C -- no --> D["git clone --branch REF REPO INSTALL_DIR"]
76+
C -- devbase repo --> E["git -C INSTALL_DIR pull"]
77+
C -- 別物 --> Z2["中止: DEVBASE_INSTALL_DIR 指定を案内"]
78+
D --> F["INSTALL_DIR/bin/devbase init<br/>(uv自動導入 + rc/補完/plugins)"]
79+
E --> F
80+
F --> G["次手順を表示<br/>source shell-rc / env init / build / up"]
81+
G --> H["exit 0"]
82+
```
83+
84+
## 6. PR 分割計画
85+
86+
installer 本体(スクリプト + テスト)とドキュメントで関心が分かれるため 2 PR。
87+
PR1 が小さく収束すれば PR2 を畳む判断も可(着手時に再評価)。
88+
89+
| PR # | branch 名 | 概要 | 主な変更ファイル | 依存 |
90+
|---|---|---|---|---|
91+
| 1 | `feature/PLAN31_1-install-script` | `install.sh`(前提チェック / 配置先・REF 解決 / clone・pull / 既存判定 / `bin/devbase init` 起動 / 完了案内 / 冪等)+ サンドボックステスト + shellcheck CI | `install.sh`(新規), `tests/test_install_sh.py`(新規), `.github/workflows/*` | なし |
92+
| 2 | `feature/PLAN31_1-docs` | README/getting-started のワンライナー化・`DEVBASE_INSTALL_DIR`/`_REF`/`_REPO` 説明・CHANGELOG | `README.md`, `docs/user/getting-started.md`, `CHANGELOG.md` | PR1 |
93+
94+
```text
95+
release branch: release/PLAN31_1
96+
base branch: main
97+
```
98+
99+
## 7. テスト計画
100+
101+
- **PR1(ネットワーク非依存)**: `DEVBASE_INSTALL_REPO` をローカル bare repo
102+
(`git init --bare` + 雛形 push) に向け、一時 `HOME` / 一時 `DEVBASE_INSTALL_DIR`
103+
`install.sh` を実行し以下を検証:
104+
1. 新規 clone → `$INSTALL_DIR/bin/devbase` が存在し実行可能。
105+
2. 2 回目実行で pull 経路に入り **冪等**(rc に `# devbase` ブロックが 1 つだけ)。
106+
3. 既存の非 devbase ディレクトリ指定で **中止**(exit 非0・上書きしない)。
107+
4. `git` 不在を `PATH` 細工で再現しエラー終了。
108+
- `bin/devbase init` 呼び出しは uv/network を伴うため、テストでは `init` をスタブ
109+
`PATH` 先頭に偽 `devbase` を置く / `--dry-run` 相当の env で skip)して
110+
スクリプトの分岐ロジックのみを検証する方針。
111+
- **結合(release)**: 実 `~/devbase` 相当へ通し、`init` 後に
112+
`source "$(bin/devbase shell-rc)"``devbase --help` が PATH 経由で解決すること、
113+
および 2 回目 install が冪等であることを確認。
114+
115+
## 8. 留意点 / 未決事項
116+
117+
- `install.sh` の正規ホスティング(raw main 固定 か releases 資産化)はドキュメントで最終確定。
118+
- `bin/devbase init` はテストでスタブするため、installer 単体テストは「init を正しい
119+
引数・CWD で 1 回呼ぶ」ことの検証に留める(init 自体の挙動は既存テストの責務)。
120+
- `curl | bash` 警告として「実行前にスクリプトを確認する」代替手順
121+
`curl -fsSL … -o install.sh` → 確認 → `bash install.sh`)を README に併記。

0 commit comments

Comments
 (0)