diff --git a/cli/cliui/prompt.go b/cli/cliui/prompt.go index 89e10f42232db..607274188aa5f 100644 --- a/cli/cliui/prompt.go +++ b/cli/cliui/prompt.go @@ -2,7 +2,9 @@ package cliui import ( "bufio" + "encoding/json" "fmt" + "io" "os" "os/signal" "strings" @@ -45,12 +47,22 @@ func Prompt(cmd *cobra.Command, opts PromptOptions) (string, error) { } else { reader := bufio.NewReader(cmd.InOrStdin()) line, err = reader.ReadString('\n') - // Multiline with single quotes! - if err == nil && strings.HasPrefix(line, "'") { - rest, err := reader.ReadString('\'') + + // Check if the first line beings with JSON object or array chars. + // This enables multiline JSON to be pasted into an input, and have + // it parse properly. + if err == nil && (strings.HasPrefix(line, "{") || strings.HasPrefix(line, "[")) { + pipeReader, pipeWriter := io.Pipe() + defer pipeWriter.Close() + defer pipeReader.Close() + go func() { + _, _ = pipeWriter.Write([]byte(line)) + _, _ = reader.WriteTo(pipeWriter) + }() + var rawMessage json.RawMessage + err := json.NewDecoder(pipeReader).Decode(&rawMessage) if err == nil { - line += rest - line = strings.Trim(line, "'") + line = string(rawMessage) } } } diff --git a/cli/cliui/prompt_test.go b/cli/cliui/prompt_test.go index ee43c70bc7740..c01c2d2e78dc5 100644 --- a/cli/cliui/prompt_test.go +++ b/cli/cliui/prompt_test.go @@ -2,7 +2,6 @@ package cliui_test import ( "context" - "runtime" "testing" "github.com/spf13/cobra" @@ -47,7 +46,7 @@ func TestPrompt(t *testing.T) { require.Equal(t, "yes", <-doneChan) }) - t.Run("Multiline", func(t *testing.T) { + t.Run("JSON", func(t *testing.T) { t.Parallel() ptty := ptytest.New(t) doneChan := make(chan string) @@ -59,13 +58,44 @@ func TestPrompt(t *testing.T) { doneChan <- resp }() ptty.ExpectMatch("Example") - ptty.WriteLine("'this is a") - ptty.WriteLine("test'") - newline := "\n" - if runtime.GOOS == "windows" { - newline = "\r\n" - } - require.Equal(t, "this is a"+newline+"test", <-doneChan) + ptty.WriteLine("{}") + require.Equal(t, "{}", <-doneChan) + }) + + t.Run("BadJSON", func(t *testing.T) { + t.Parallel() + ptty := ptytest.New(t) + doneChan := make(chan string) + go func() { + resp, err := newPrompt(ptty, cliui.PromptOptions{ + Text: "Example", + }) + require.NoError(t, err) + doneChan <- resp + }() + ptty.ExpectMatch("Example") + ptty.WriteLine("{a") + require.Equal(t, "{a", <-doneChan) + }) + + t.Run("MultilineJSON", func(t *testing.T) { + t.Parallel() + ptty := ptytest.New(t) + doneChan := make(chan string) + go func() { + resp, err := newPrompt(ptty, cliui.PromptOptions{ + Text: "Example", + }) + require.NoError(t, err) + doneChan <- resp + }() + ptty.ExpectMatch("Example") + ptty.WriteLine(`{ +"test": "wow" +}`) + require.Equal(t, `{ +"test": "wow" +}`, <-doneChan) }) } diff --git a/cli/workspacecreate_test.go b/cli/workspacecreate_test.go index 5dd85e0833c93..d076de8d8d6c6 100644 --- a/cli/workspacecreate_test.go +++ b/cli/workspacecreate_test.go @@ -3,10 +3,11 @@ package cli_test import ( "testing" + "github.com/stretchr/testify/require" + "github.com/coder/coder/cli/clitest" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/pty/ptytest" - "github.com/stretchr/testify/require" ) func TestWorkspaceCreate(t *testing.T) { diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 563fd4c63b2b1..89fcf0000ddea 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -9,10 +9,11 @@ import ( "sync" "time" - "github.com/coder/coder/cryptorand" "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "golang.org/x/xerrors" + + "github.com/coder/coder/cryptorand" ) // Required to prevent port collision during container creation.