Pārlūkot izejas kodu

dectect if piped run command and disable tty if so

Signed-off-by: Guillaume Lours <[email protected]>
Guillaume Lours 2 mēneši atpakaļ
vecāks
revīzija
d07c437ce8

+ 4 - 0
cmd/compose/run.go

@@ -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)

+ 56 - 0
pkg/e2e/compose_run_test.go

@@ -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",
+		})
+	})
 }

+ 9 - 0
pkg/e2e/fixtures/run-test/piped-test.yaml

@@ -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