dectect if piped run command and disable tty if so

Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
This commit is contained in:
Guillaume Lours 2025-09-18 17:37:04 +02:00
parent da72230c39
commit d07c437ce8
3 changed files with 69 additions and 0 deletions

View File

@ -183,7 +183,11 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
} else {
options.noTty = !ttyFlag
}
} else if !cmd.Flags().Changed("no-TTY") && !cmd.Flags().Changed("interactive") && !dockerCli.In().IsTerminal() {
// Check if the command was piped or not, if so, force noTty to tru
options.noTty = true
}
if options.quiet {
progress.Mode = progress.ModeQuiet
devnull, err := os.Open(os.DevNull)

View File

@ -222,4 +222,60 @@ func TestLocalComposeRun(t *testing.T) {
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "build", "echo", "hello world")
res.Assert(t, icmd.Expected{Out: "hello world"})
})
t.Run("compose run with piped input detection", func(t *testing.T) {
if composeStandaloneMode {
t.Skip("Skipping test compose with piped input detection in standalone mode")
}
// Test that piped input is properly detected and TTY is automatically disabled
// This tests the logic added in run.go that checks dockerCli.In().IsTerminal()
cmd := c.NewCmd("sh", "-c", "echo 'piped-content' | docker compose -f ./fixtures/run-test/piped-test.yaml run --rm piped-test")
res := icmd.RunCmd(cmd)
res.Assert(t, icmd.Expected{Out: "piped-content"})
res.Assert(t, icmd.Success)
})
t.Run("compose run piped input should not allocate TTY", func(t *testing.T) {
if composeStandaloneMode {
t.Skip("Skipping test compose with piped input detection in standalone mode")
}
// Test that when stdin is piped, the container correctly detects no TTY
// This verifies that the automatic noTty=true setting works correctly
cmd := c.NewCmd("sh", "-c", "echo '' | docker compose -f ./fixtures/run-test/piped-test.yaml run --rm tty-test")
res := icmd.RunCmd(cmd)
res.Assert(t, icmd.Expected{Out: "No TTY detected"})
res.Assert(t, icmd.Success)
})
t.Run("compose run piped input with explicit --tty should fail", func(t *testing.T) {
if composeStandaloneMode {
t.Skip("Skipping test compose with piped input detection in standalone mode")
}
// Test that explicitly requesting TTY with piped input fails with proper error message
// This should trigger the "input device is not a TTY" error
cmd := c.NewCmd("sh", "-c", "echo 'test' | docker compose -f ./fixtures/run-test/piped-test.yaml run --rm --tty piped-test")
res := icmd.RunCmd(cmd)
res.Assert(t, icmd.Expected{
ExitCode: 1,
Err: "the input device is not a TTY",
})
})
t.Run("compose run piped input with --no-TTY=false should fail", func(t *testing.T) {
if composeStandaloneMode {
t.Skip("Skipping test compose with piped input detection in standalone mode")
}
// Test that explicitly disabling --no-TTY (i.e., requesting TTY) with piped input fails
// This should also trigger the "input device is not a TTY" error
cmd := c.NewCmd("sh", "-c", "echo 'test' | docker compose -f ./fixtures/run-test/piped-test.yaml run --rm --no-TTY=false piped-test")
res := icmd.RunCmd(cmd)
res.Assert(t, icmd.Expected{
ExitCode: 1,
Err: "the input device is not a TTY",
})
})
}

View File

@ -0,0 +1,9 @@
services:
piped-test:
image: alpine
command: cat
# Service that will receive piped input and echo it back
tty-test:
image: alpine
command: sh -c "if [ -t 0 ]; then echo 'TTY detected'; else echo 'No TTY detected'; fi"
# Service to test TTY detection