Skip to content
Merged
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
2 changes: 2 additions & 0 deletions containers/base/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ AI_SETTINGS=(
".gemini"
".serena"
".ssh"
".kiro"
"share"
)

# Ensure /persistent/ai directory exists
Expand Down
3 changes: 2 additions & 1 deletion docs/user/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,15 @@ devbase はホストマシンの認証情報を自動収集し、コンテナ内

## `devbase up` 後のエディタ自動オープン

`devbase up` 完了後、dev コンテナへ接続した VS Code を自動で開けます(VS Code の「Attach to Running Container」を CLI から起動)。`/work/$GIT_REPO` をワークスペースとして開きます
`devbase up` 完了後、dev コンテナへ接続した VS Code を自動で開けます(VS Code の「Attach to Running Container」を CLI から起動)。既定では `/work/$GIT_REPO` フォルダを開きます(`--folder-uri`)。`DEVBASE_WORKSPACE` を指定するとフォルダの代わりに `*.code-workspace` ワークスペースファイルを開きます(`--file-uri`)

これらは `devbase env init` の収集対象外で、プロジェクトの `env` か `$DEVBASE_ROOT/.env` に手書きする devbase 動作設定です。

| キー | 説明 |
|------|------|
| `DEVBASE_OPEN_EDITOR` | 真(`1`/`true`/`yes`/`on`)で `up` 後にエディタを開く(既定: OFF) |
| `DEVBASE_EDITOR` | 起動コマンド(既定: `code`)。`cursor` / `code-insiders` 等も可 |
| `DEVBASE_WORKSPACE` | 開く `*.code-workspace` ファイルの**コンテナ内絶対パス**(例 `/home/ubuntu/share/work/uttarov2-doc.workspace`)。指定時はフォルダではなくワークスペースを開く。未設定なら従来どおり `/work/$GIT_REPO` フォルダ。共有マウント `/home/ubuntu/share` 配下に置けば全コンテナで共用可 |
| `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`) |
Expand Down
32 changes: 29 additions & 3 deletions lib/devbase/editor/opener.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,26 @@ def resolve_workdir(environ=None, project_name: Optional[str] = None) -> str:
return f"/work/{repo}" if repo else "/work"


def resolve_workspace(environ=None) -> Optional[str]:
"""開く VS Code ワークスペースファイル (``*.code-workspace``) のコンテナ内パス。
``DEVBASE_WORKSPACE`` env にコンテナ内の絶対パス (例
``/home/ubuntu/share/work/uttarov2-doc.workspace``) が指定されていればそれを返す。
未設定・空文字なら None を返し、呼び出し側 (:func:`open_editor`) は従来どおり
:func:`resolve_workdir` のフォルダを ``--folder-uri`` で開く。
ワークスペースファイルはコンテナ内に実在するパスを指す前提 (attach 先は
コンテナ authority のため)。``/home/ubuntu/share`` 等の共有マウント配下に置けば
全コンテナで共用できる。env 名はホスト CI が設定し得る汎用 ``WORKSPACE`` との
衝突を避けるため ``DEVBASE_*`` 接頭辞付きにしている。
"""
env = os.environ if environ is None else environ
value = env.get("DEVBASE_WORKSPACE")
if value is None:
return None
return value.strip() or None


def _detect_ssh_host_from_dirs(server_dirs) -> Optional[str]:
"""複数の VS Code 系サーバーディレクトリの File History を横断して ssh-remote
authority ラベルを推測する。
Expand Down Expand Up @@ -493,7 +513,13 @@ def open_editor(*, project_name: str, dev_service_name: str, workdir: str,
ssh_host = (resolve_editor_ssh_host(env, auto_detect=ctx.in_vscode)
if ctx.is_ssh else None)
docker_context = resolve_docker_context(env) if ssh_host else None
uri = build_attach_uri(container, workdir,
# DEVBASE_WORKSPACE があれば *.code-workspace をワークスペースとして開く。VS Code は
# `--file-uri` に渡したパスが .code-workspace 拡張子なら multi-root ワークスペースとして
# 開くため、フォルダを開く `--folder-uri` と URI ターゲット・フラグの両方を切り替える。
workspace = resolve_workspace(env)
open_target = workspace or workdir
uri_flag = "--file-uri" if workspace else "--folder-uri"
uri = build_attach_uri(container, open_target,
ssh_host=ssh_host, docker_context=docker_context)

if plan.action == "print_command":
Expand All @@ -505,12 +531,12 @@ def open_editor(*, project_name: str, dev_service_name: str, workdir: str,
"手元の VS Code で次を実行するか、VS Code の Remote-SSH 統合ターミナルから "
"`devbase up` を実行すると自動で開きます:"
)
logger.info(" %s --folder-uri '%s'", quoted, uri)
logger.info(" %s %s '%s'", quoted, uri_flag, uri)
return "print_command"

quoted = " ".join(shlex.quote(c) for c in editor)
logger.info("[editor] %s を起動します (%s)", quoted, plan.reason)
cmd = [*editor, "--folder-uri", uri]
cmd = [*editor, uri_flag, uri]
try:
(launcher or _launch)(cmd, dict(env))
except Exception as e: # noqa: BLE001 - 起動失敗で up を倒さない
Expand Down
51 changes: 51 additions & 0 deletions tests/editor/test_opener.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,20 @@ def test_resolve_workdir_fallback_project_name():
assert opener.resolve_workdir({}, "proj") == "/work/proj"


def test_resolve_workspace_none_when_unset():
assert opener.resolve_workspace({}) is None


def test_resolve_workspace_blank_is_none():
assert opener.resolve_workspace({"DEVBASE_WORKSPACE": " "}) is None


def test_resolve_workspace_returns_path():
env = {"DEVBASE_WORKSPACE": "/home/ubuntu/share/work/uttarov2-doc.workspace"}
assert opener.resolve_workspace(env) == \
"/home/ubuntu/share/work/uttarov2-doc.workspace"


# ---------------------------------------------------------------------------
# decide_action (§2.4 マトリクス全分岐)
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -472,6 +486,43 @@ def test_open_editor_launch_invokes_launcher(monkeypatch):
assert cmd[2].endswith("/work/carmo")


def test_open_editor_launch_uses_file_uri_for_workspace(monkeypatch):
"""DEVBASE_WORKSPACE 指定時は --file-uri でワークスペースファイルを開く。"""
monkeypatch.setattr(opener.shutil, "which", lambda c: "/usr/bin/code")
calls = []
result = opener.open_editor(
project_name="uttarov2-doc", dev_service_name="dev",
workdir="/work/uttarov2-doc",
environ={"DEVBASE_WORKSPACE":
"/home/ubuntu/share/work/uttarov2-doc.workspace"},
isatty=True, launcher=lambda cmd, env: calls.append(cmd),
)
assert result == "launch"
cmd = calls[0]
assert cmd[1] == "--file-uri"
assert cmd[2].startswith("vscode-remote://attached-container+")
assert cmd[2].endswith("/home/ubuntu/share/work/uttarov2-doc.workspace")


def test_open_editor_print_command_file_uri_for_workspace(monkeypatch, caplog):
"""plain SSH の提示コマンドも DEVBASE_WORKSPACE 指定時は --file-uri になる。"""
import logging
monkeypatch.setattr(opener.shutil, "which", lambda c: "/usr/bin/code")
with caplog.at_level(logging.INFO):
result = opener.open_editor(
project_name="uttarov2-doc", dev_service_name="dev",
workdir="/work/uttarov2-doc",
environ={"SSH_CONNECTION": "1.2.3.4 5 6.7.8.9 22",
"DEVBASE_WORKSPACE":
"/home/ubuntu/share/work/uttarov2-doc.workspace"},
isatty=True, launcher=lambda cmd, env: None,
)
assert result == "print_command"
text = "\n".join(r.getMessage() for r in caplog.records)
assert "code --file-uri" in text
assert "uttarov2-doc.workspace" in text


def test_open_editor_launch_nested_uri_under_remote_ssh(monkeypatch):
"""Remote-SSH (in_vscode + ssh) かつ DEVBASE_EDITOR_SSH_HOST 設定時はネスト URI で launch。"""
monkeypatch.setattr(opener.shutil, "which", lambda c: "/usr/bin/code")
Expand Down
Loading