Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions cmd/compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ func RootCommand(dockerCli command.Cli, backendOptions *BackendOptions) *cobra.C
applyAnsiMode(dockerCli, ansi)

detached, _ := cmd.Flags().GetBool("detach")
ep, err := selectEventProcessor(dockerCli, opts.Progress, ansi, detached)
ep, err := selectEventProcessor(dockerCli, opts.Progress, ansi, detached, dryRun)
if err != nil {
return err
}
Expand Down Expand Up @@ -712,39 +712,43 @@ func stdinfo(dockerCli command.Cli) io.Writer {
// In auto mode we probe Err() (not Out()) because the renderer writes to stderr;
// probing stdout would force plain mode whenever stdout is redirected (e.g.
// `docker compose up | tee log`) while stderr is still a terminal.
func selectEventProcessor(dockerCli command.Cli, progress, ansi string, detached bool) (api.EventProcessor, error) {
func selectEventProcessor(dockerCli command.Cli, progress, ansi string, detached, dryRun bool) (api.EventProcessor, error) {
var termOpts []display.TermOption
if dryRun {
termOpts = append(termOpts, display.WithDryRun())
}
switch progress {
case "", display.ModeAuto:
switch {
case ansi == "never":
display.Mode = display.ModePlain
return display.Plain(dockerCli.Err()), nil
return display.Plain(dockerCli.Err(), dryRun), nil
case dockerCli.Err().IsTerminal():
display.Mode = display.ModeTTY
return display.Full(dockerCli.Err(), stdinfo(dockerCli), detached), nil
return display.Full(dockerCli.Err(), stdinfo(dockerCli), detached, termOpts...), nil
default:
display.Mode = display.ModePlain
return display.Plain(dockerCli.Err()), nil
return display.Plain(dockerCli.Err(), dryRun), nil
}
case display.ModeTTY:
if ansi == "never" {
return nil, errors.New("can't use --progress tty while ANSI support is disabled")
}
display.Mode = display.ModeTTY
return display.Full(dockerCli.Err(), stdinfo(dockerCli), detached), nil
return display.Full(dockerCli.Err(), stdinfo(dockerCli), detached, termOpts...), nil
case display.ModePlain:
if ansi == "always" {
return nil, errors.New("can't use --progress plain while ANSI support is forced")
}
display.Mode = display.ModePlain
return display.Plain(dockerCli.Err()), nil
return display.Plain(dockerCli.Err(), dryRun), nil
case display.ModeQuiet, "none":
display.Mode = display.ModeQuiet
return display.Quiet(), nil
case display.ModeJSON:
display.Mode = display.ModeJSON
logrus.SetFormatter(&logrus.JSONFormatter{})
return display.JSON(dockerCli.Err()), nil
return display.JSON(dockerCli.Err(), dryRun), nil
default:
return nil, fmt.Errorf("unsupported --progress value %q", progress)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/compose/compose_progress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func TestSelectEventProcessor_AutoMode(t *testing.T) {
saveGlobalState(t)
cli := newMockCli(t, newStream(t, tc.outIsTTY), newStream(t, tc.errIsTTY))

ep, err := selectEventProcessor(cli, "", tc.ansi, false)
ep, err := selectEventProcessor(cli, "", tc.ansi, false, false)
assert.NilError(t, err)
assert.Equal(t, fmt.Sprintf("%T", ep), tc.wantType)
// the global must hold the mode actually rendered, never ModeAuto
Expand Down Expand Up @@ -210,7 +210,7 @@ func TestSelectEventProcessor_ExplicitMode(t *testing.T) {
// Explicit modes don't probe IsTerminal; pipes are fine for both.
cli := newMockCli(t, newStream(t, false), newStream(t, false))

ep, err := selectEventProcessor(cli, tc.progress, tc.ansi, false)
ep, err := selectEventProcessor(cli, tc.progress, tc.ansi, false, false)
if tc.wantErrText != "" {
assert.ErrorContains(t, err, tc.wantErrText)
assert.Assert(t, ep == nil)
Expand Down
5 changes: 3 additions & 2 deletions cmd/display/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ import (
"github.com/docker/compose/v5/pkg/api"
)

func JSON(out io.Writer) api.EventProcessor {
func JSON(out io.Writer, dryRun bool) api.EventProcessor {
return &jsonWriter{
out: out,
out: out,
dryRun: dryRun,
}
}

Expand Down
11 changes: 11 additions & 0 deletions cmd/display/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,14 @@ func TestJsonWriter_Event(t *testing.T) {
}
assert.DeepEqual(t, expected, actual)
}

func TestJSON_DryRunWiring(t *testing.T) {
var out bytes.Buffer
ep := JSON(&out, true)
ep.On(api.Resource{ID: "service1", Text: api.StatusCreating})

var actual jsonMessage
err := json.Unmarshal(out.Bytes(), &actual)
assert.NilError(t, err)
assert.Equal(t, actual.DryRun, true)
}
5 changes: 3 additions & 2 deletions cmd/display/plain.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import (
"github.com/docker/compose/v5/pkg/api"
)

func Plain(out io.Writer) api.EventProcessor {
func Plain(out io.Writer, dryRun bool) api.EventProcessor {
return &plainWriter{
out: out,
out: out,
dryRun: dryRun,
}
}

Expand Down
43 changes: 43 additions & 0 deletions cmd/display/plain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright 2020 Docker Compose CLI authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package display

import (
"bytes"
"strings"
"testing"

"gotest.tools/v3/assert"

"github.com/docker/compose/v5/pkg/api"
)

func TestPlain_DryRun(t *testing.T) {
var out bytes.Buffer
ep := Plain(&out, true)
ep.On(api.Resource{ID: "service1", Text: api.StatusCreating})

assert.Assert(t, strings.Contains(out.String(), DRYRUN_PREFIX))
}

func TestPlain_NotDryRun(t *testing.T) {
var out bytes.Buffer
ep := Plain(&out, false)
ep.On(api.Resource{ID: "service1", Text: api.StatusCreating})

assert.Assert(t, !strings.Contains(out.String(), DRYRUN_PREFIX))
}
19 changes: 19 additions & 0 deletions cmd/display/tty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,22 @@ func TestTerm_VisualSnapshot(t *testing.T) {
assert.Equal(t, expected[i], strings.TrimRight(lines[i], " "), "line %d", i)
}
}

// TestTerm_DryRunPrefixesRows covers the wiring from the --dry-run flag down
// to the rendered rows: WithDryRun must reach the layout, which is what puts
// the marker on every task row.
func TestTerm_DryRunPrefixesRows(t *testing.T) {
var buf bytes.Buffer
ep := Full(&buf, &buf, false, WithDryRun())
w, ok := ep.(*termWriter)
assert.Assert(t, ok)

w.size = func() (int, int) { return 120, 40 }
w.now = testClock().Now
w.operation = "pull"
feed(w, api.Resource{ID: "svc", Text: "Pulling", Status: api.Working})
w.repaint()

assert.Assert(t, strings.Contains(stripAnsi(buf.String()), DRYRUN_PREFIX),
"rendered frame does not carry the dry-run marker: %q", stripAnsi(buf.String()))
}