devcontainerに非対話的なexecサブコマンドを追加
Rails開発環境をコンテナ化する devcontainer ツールに、TTYを必要としない exec サブコマンドが追加されました。これにより、自動化スクリプトやエージェントワークフローからコンテナ内のコマンドを実行できるようになります。
背景
これまで devcontainer ツールは、sh サブコマンドによる対話的なシェルセッションの開始のみをサポートしていました。-it フラグを使用した対話モードは、人間がターミナルで作業する場合には便利ですが、CI/CDパイプラインやスクリプトによる自動化には適していませんでした。
本PRの作者は、rdoc-to-mdスクリプトの改善にエージェントコーディングを活用する過程で、コンテナ外部からコマンドを実行する手段が必要になりました。この変更により、開発ツールの自動化やテストハーネスの構築が可能になります。
技術的な変更
tools/devcontainer スクリプトに新しい exec サブコマンドが追加されました。既存の sh サブコマンドとの主な違いは、TTYアロケーション(-it フラグ)の有無と、コマンド実行前の mise の有効化です。
変更内容:
when "exec"
service_id, _, _ = Open3.capture3("#{DOCKER} ps -q -f name=#{info[\"service\"]}")
cmd = ARGV[1..].join(" ")
env_args = info["containerEnv"].flat_map { |k, v| ["-e", "#{k}=#{v}"] }
system DOCKER, "exec", *env_args, "-w", working_dir, service_id.chomp, "/bin/bash", "-c", "eval \"$(~/.local/bin/mise activate bash)\" && #{cmd}"
実行時は以下のように使用します:
devcontainer exec "echo hi"
devcontainer exec "bundle exec rails test"
環境変数は info["containerEnv"] から取得され、-e フラグとして展開されます。作業ディレクトリも -w オプションで設定されるため、コンテナ内の正しい位置でコマンドが実行されます。
設計判断
mise の明示的な有効化 が実装の核心部分です。コマンド実行前に eval "$(~/.local/bin/mise activate bash)" を実行することで、rubyやbundleなどのツールがPATHに追加されます。
既存の sh サブコマンドは対話的なシェルを起動するのに対し、exec サブコマンドは非対話的に単一のコマンドを実行します。非対話的な実行環境では、exec で明示的に mise を有効化する処理が必要になりました。
コマンド文字列の構築には ARGV[1..] を使用し、引数を空白で結合する方式が採用されました。これにより、複数の引数を持つコマンドや、パイプやリダイレクトを含む複雑なコマンドラインも正しく処理されます。
まとめ
本PRは、対話的な sh サブコマンドと非対話的な exec サブコマンドを使い分けることで、手動作業と自動化の両方に対応した開発環境を提供します。mise の明示的な有効化により、コンテナ内の実行環境を一貫して維持しながら、エージェントワークフローやCI/CDパイプラインからのコマンド実行が可能になりました。