From 8e45e826ff675579dd5981504ee47c949321e165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=C5=81uszczek?= Date: Sun, 22 Mar 2026 14:09:33 +0100 Subject: [PATCH] Add --run flag to console command for running a specific command --run CMD wraps the command in the shell: /bin/sh -c CMD, keeping TTY mode so interactive commands like 'rails c' or 'bash' work correctly. Co-Authored-By: Claude Sonnet 4.6 --- lib/portainer_cli.rb | 1 + lib/portainer_cli/commands/console.rb | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/portainer_cli.rb b/lib/portainer_cli.rb index b395a81..08f2ae2 100644 --- a/lib/portainer_cli.rb +++ b/lib/portainer_cli.rb @@ -32,6 +32,7 @@ module PortainerCli portainer-cli create container --endpoint ID --image IMAGE [--name NAME] [--port h:c] [--env K=V] portainer-cli console [container] Open interactive shell (resolves endpoint automatically) --shell SHELL Shell to use (default: /bin/sh) + --run CMD Run command instead of a bare shell portainer-cli exec Open interactive shell (manual endpoint) --shell SHELL Shell to use (default: /bin/sh) diff --git a/lib/portainer_cli/commands/console.rb b/lib/portainer_cli/commands/console.rb index 6078bc5..61a4ebd 100644 --- a/lib/portainer_cli/commands/console.rb +++ b/lib/portainer_cli/commands/console.rb @@ -22,10 +22,11 @@ module PortainerCli def run(args) opts = { shell: '/bin/sh' } OptionParser.new do |o| - o.on('--shell SHELL', 'Shell to use (default: /bin/sh)') { |v| opts[:shell] = v } + o.on('--shell SHELL', 'Shell to use (default: /bin/sh)') { |v| opts[:shell] = v } + o.on('--run CMD', 'Run command instead of a bare shell') { |v| opts[:run] = v } end.parse!(args) - stack_name = args.shift or error("Usage: portainer-cli console [container] [--shell /bin/bash]") + stack_name = args.shift or error("Usage: portainer-cli console [container] [--run CMD] [--shell /bin/bash]") container_name = args.shift || stack_name stack = resolve_stack(stack_name) @@ -37,7 +38,7 @@ module PortainerCli $stderr.puts dim("Connecting to #{container_name} (#{container_id[0, 12]})...") - exec_id = create_exec(endpoint_id, container_id, opts[:shell]) + exec_id = create_exec(endpoint_id, container_id, opts[:shell], opts[:run]) ws_url = exec_websocket_url(exec_id, endpoint_id) send_resize(endpoint_id, exec_id) if $stdout.tty? @@ -123,7 +124,8 @@ module PortainerCli error("Container '#{name_or_id}' not found. Available:\n#{available}") end - def create_exec(endpoint_id, container_id, shell) + def create_exec(endpoint_id, container_id, shell, run_cmd = nil) + cmd = run_cmd ? [shell, '-c', run_cmd] : [shell] result = @client.post( "/api/endpoints/#{endpoint_id}/docker/containers/#{container_id}/exec", { @@ -131,7 +133,7 @@ module PortainerCli 'AttachStdout' => true, 'AttachStderr' => true, 'Tty' => true, - 'Cmd' => [shell] + 'Cmd' => cmd } ) result['Id']