Skip to content

Commit 7c722c0

Browse files
committed
feat: standardize error for prompt
Signed-off-by: Alano Terblanche <[email protected]>
1 parent b8d5454 commit 7c722c0

29 files changed

+425
-165
lines changed

cli/command/builder/prune.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package builder
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"strings"
78

@@ -10,6 +11,7 @@ import (
1011
"github.com/docker/cli/cli/command/completion"
1112
"github.com/docker/cli/opts"
1213
"github.com/docker/docker/api/types"
14+
"github.com/docker/docker/errdefs"
1315
units "github.com/docker/go-units"
1416
"github.com/spf13/cobra"
1517
)
@@ -67,9 +69,13 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
6769
warning = allCacheWarning
6870
}
6971
if !options.force {
70-
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
72+
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning)
73+
if err != nil {
7174
return 0, "", err
7275
}
76+
if !r {
77+
return 0, "", errdefs.Cancelled(errors.New("`builder prune` has been cancelled"))
78+
}
7379
}
7480

7581
report, err := dockerCli.Client().BuildCachePrune(ctx, types.BuildCachePruneOptions{

cli/command/builder/prune_test.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ import (
55
"errors"
66
"testing"
77

8-
"github.com/docker/cli/cli/command"
98
"github.com/docker/cli/internal/test"
109
"github.com/docker/docker/api/types"
11-
"gotest.tools/v3/assert"
1210
)
1311

1412
func TestBuilderPromptTermination(t *testing.T) {
@@ -21,8 +19,5 @@ func TestBuilderPromptTermination(t *testing.T) {
2119
},
2220
})
2321
cmd := NewPruneCommand(cli)
24-
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
25-
t.Helper()
26-
assert.ErrorIs(t, err, command.ErrPromptTerminated)
27-
})
22+
test.TerminatePrompt(ctx, t, cmd, cli)
2823
}

cli/command/container/prune.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import (
88
"github.com/docker/cli/cli/command"
99
"github.com/docker/cli/cli/command/completion"
1010
"github.com/docker/cli/opts"
11+
"github.com/docker/docker/errdefs"
1112
units "github.com/docker/go-units"
13+
"github.com/pkg/errors"
1214
"github.com/spf13/cobra"
1315
)
1416

@@ -54,9 +56,13 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
5456
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
5557

5658
if !options.force {
57-
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
59+
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning)
60+
if err != nil {
5861
return 0, "", err
5962
}
63+
if !r {
64+
return 0, "", errdefs.Cancelled(errors.New("`container prune` has been cancelled"))
65+
}
6066
}
6167

6268
report, err := dockerCli.Client().ContainersPrune(ctx, pruneFilters)

cli/command/container/prune_test.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ import (
44
"context"
55
"testing"
66

7-
"github.com/docker/cli/cli/command"
87
"github.com/docker/cli/internal/test"
98
"github.com/docker/docker/api/types"
109
"github.com/docker/docker/api/types/filters"
1110
"github.com/pkg/errors"
12-
"gotest.tools/v3/assert"
1311
)
1412

1513
func TestContainerPrunePromptTermination(t *testing.T) {
@@ -22,8 +20,5 @@ func TestContainerPrunePromptTermination(t *testing.T) {
2220
},
2321
})
2422
cmd := NewPruneCommand(cli)
25-
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
26-
t.Helper()
27-
assert.ErrorIs(t, err, command.ErrPromptTerminated)
28-
})
23+
test.TerminatePrompt(ctx, t, cmd, cli)
2924
}

cli/command/image/prune.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import (
1010
"github.com/docker/cli/cli/command"
1111
"github.com/docker/cli/cli/command/completion"
1212
"github.com/docker/cli/opts"
13+
"github.com/docker/docker/errdefs"
1314
units "github.com/docker/go-units"
15+
"github.com/pkg/errors"
1416
"github.com/spf13/cobra"
1517
)
1618

@@ -68,9 +70,13 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
6870
warning = allImageWarning
6971
}
7072
if !options.force {
71-
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
73+
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning)
74+
if err != nil {
7275
return 0, "", err
7376
}
77+
if !r {
78+
return 0, "", errdefs.Cancelled(errors.New("`image prune` has been cancelled"))
79+
}
7480
}
7581

7682
report, err := dockerCli.Client().ImagesPrune(ctx, pruneFilters)

cli/command/image/prune_test.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import (
44
"context"
55
"fmt"
66
"io"
7+
"strings"
78
"testing"
89

9-
"github.com/docker/cli/cli/command"
10+
"github.com/docker/cli/cli/streams"
1011
"github.com/docker/cli/internal/test"
1112
"github.com/docker/docker/api/types"
1213
"github.com/docker/docker/api/types/filters"
@@ -94,13 +95,18 @@ func TestNewPruneCommandSuccess(t *testing.T) {
9495
},
9596
}
9697
for _, tc := range testCases {
97-
cli := test.NewFakeCli(&fakeClient{imagesPruneFunc: tc.imagesPruneFunc})
98-
cmd := NewPruneCommand(cli)
99-
cmd.SetOut(io.Discard)
100-
cmd.SetArgs(tc.args)
101-
err := cmd.Execute()
102-
assert.NilError(t, err)
103-
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("prune-command-success.%s.golden", tc.name))
98+
t.Run(tc.name, func(t *testing.T) {
99+
cli := test.NewFakeCli(&fakeClient{imagesPruneFunc: tc.imagesPruneFunc})
100+
// when prompted, answer "Y" to confirm the prune.
101+
// will not be prompted if --force is used.
102+
cli.SetIn(streams.NewIn(io.NopCloser(strings.NewReader("Y\n"))))
103+
cmd := NewPruneCommand(cli)
104+
cmd.SetOut(io.Discard)
105+
cmd.SetArgs(tc.args)
106+
err := cmd.Execute()
107+
assert.NilError(t, err)
108+
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("prune-command-success.%s.golden", tc.name))
109+
})
104110
}
105111
}
106112

@@ -114,8 +120,5 @@ func TestPrunePromptTermination(t *testing.T) {
114120
},
115121
})
116122
cmd := NewPruneCommand(cli)
117-
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
118-
t.Helper()
119-
assert.ErrorIs(t, err, command.ErrPromptTerminated)
120-
})
123+
test.TerminatePrompt(ctx, t, cmd, cli)
121124
}

cli/command/network/prune.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"github.com/docker/cli/cli"
88
"github.com/docker/cli/cli/command"
99
"github.com/docker/cli/opts"
10+
"github.com/docker/docker/errdefs"
11+
"github.com/pkg/errors"
1012
"github.com/spf13/cobra"
1113
)
1214

@@ -50,9 +52,13 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
5052
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
5153

5254
if !options.force {
53-
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil {
55+
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning)
56+
if err != nil {
5457
return "", err
5558
}
59+
if !r {
60+
return "", errdefs.Cancelled(errors.New("`network prune` cancelled has been cancelled"))
61+
}
5662
}
5763

5864
report, err := dockerCli.Client().NetworksPrune(ctx, pruneFilters)

cli/command/network/prune_test.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ import (
44
"context"
55
"testing"
66

7-
"github.com/docker/cli/cli/command"
87
"github.com/docker/cli/internal/test"
98
"github.com/docker/docker/api/types"
109
"github.com/docker/docker/api/types/filters"
1110
"github.com/pkg/errors"
12-
"gotest.tools/v3/assert"
1311
)
1412

1513
func TestNetworkPrunePromptTermination(t *testing.T) {
@@ -22,8 +20,5 @@ func TestNetworkPrunePromptTermination(t *testing.T) {
2220
},
2321
})
2422
cmd := NewPruneCommand(cli)
25-
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
26-
t.Helper()
27-
assert.ErrorIs(t, err, command.ErrPromptTerminated)
28-
})
23+
test.TerminatePrompt(ctx, t, cmd, cli)
2924
}

cli/command/network/remove_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"io"
66
"testing"
77

8-
"github.com/docker/cli/cli/command"
98
"github.com/docker/cli/internal/test"
109
"github.com/docker/docker/api/types"
1110
"github.com/docker/docker/errdefs"
@@ -115,8 +114,5 @@ func TestNetworkRemovePromptTermination(t *testing.T) {
115114
})
116115
cmd := newRemoveCommand(cli)
117116
cmd.SetArgs([]string{"existing-network"})
118-
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
119-
t.Helper()
120-
assert.ErrorIs(t, err, command.ErrPromptTerminated)
121-
})
117+
test.TerminatePrompt(ctx, t, cmd, cli)
122118
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
Upgrading plugin foo/bar from localhost:5000/foo/bar:v0.1.0 to localhost:5000/foo/bar:v1.0.0
2-
Plugin images do not match, are you sure? [y/N]
2+
Plugin images do not match, are you sure? [y/N]

cli/command/plugin/upgrade.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/distribution/reference"
99
"github.com/docker/cli/cli"
1010
"github.com/docker/cli/cli/command"
11+
"github.com/docker/docker/errdefs"
1112
"github.com/docker/docker/pkg/jsonmessage"
1213
"github.com/pkg/errors"
1314
"github.com/spf13/cobra"
@@ -63,11 +64,12 @@ func runUpgrade(ctx context.Context, dockerCli command.Cli, opts pluginOptions)
6364

6465
fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, reference.FamiliarString(old), reference.FamiliarString(remote))
6566
if !opts.skipRemoteCheck && remote.String() != old.String() {
66-
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), "Plugin images do not match, are you sure?"); !r || err != nil {
67-
if err != nil {
68-
return errors.Wrap(err, "canceling upgrade request")
69-
}
70-
return errors.New("canceling upgrade request")
67+
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), "Plugin images do not match, are you sure?")
68+
if err != nil {
69+
return err
70+
}
71+
if !r {
72+
return errdefs.Cancelled(errors.New("`plugin upgrade` has been cancelled"))
7173
}
7274
}
7375

cli/command/plugin/upgrade_test.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ import (
55
"io"
66
"testing"
77

8-
"github.com/docker/cli/cli/command"
98
"github.com/docker/cli/internal/test"
109
"github.com/docker/docker/api/types"
1110
"github.com/pkg/errors"
12-
"gotest.tools/v3/assert"
1311
"gotest.tools/v3/golden"
1412
)
1513

@@ -34,9 +32,6 @@ func TestUpgradePromptTermination(t *testing.T) {
3432
// need to set a remote address that does not match the plugin
3533
// reference sent by the `pluginInspectFunc`
3634
cmd.SetArgs([]string{"foo/bar", "localhost:5000/foo/bar:v1.0.0"})
37-
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
38-
t.Helper()
39-
assert.ErrorIs(t, err, command.ErrPromptTerminated)
40-
})
35+
test.TerminatePrompt(ctx, t, cmd, cli)
4136
golden.Assert(t, cli.OutBuffer().String(), "plugin-upgrade-terminate.golden")
4237
}

cli/command/system/prune.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import (
1717
"github.com/docker/cli/cli/command/volume"
1818
"github.com/docker/cli/opts"
1919
"github.com/docker/docker/api/types/versions"
20+
"github.com/docker/docker/errdefs"
2021
"github.com/docker/go-units"
2122
"github.com/fvbommel/sortorder"
23+
"github.com/pkg/errors"
2224
"github.com/spf13/cobra"
2325
)
2426

@@ -75,9 +77,13 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
7577
return fmt.Errorf(`ERROR: The "until" filter is not supported with "--volumes"`)
7678
}
7779
if !options.force {
78-
if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), confirmationMessage(dockerCli, options)); !r || err != nil {
80+
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), confirmationMessage(dockerCli, options))
81+
if err != nil {
7982
return err
8083
}
84+
if !r {
85+
return errdefs.Cancelled(errors.New("`system prune` has been cancelled"))
86+
}
8187
}
8288
pruneFuncs := []func(ctx context.Context, dockerCli command.Cli, all bool, filter opts.FilterOpt) (uint64, string, error){
8389
container.RunPrune,

cli/command/system/prune_test.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"testing"
66

7-
"github.com/docker/cli/cli/command"
87
"github.com/docker/cli/cli/config/configfile"
98
"github.com/docker/cli/internal/test"
109
"github.com/docker/docker/api/types"
@@ -18,7 +17,7 @@ func TestPrunePromptPre131DoesNotIncludeBuildCache(t *testing.T) {
1817
cli := test.NewFakeCli(&fakeClient{version: "1.30"})
1918
cmd := newPruneCommand(cli)
2019
cmd.SetArgs([]string{})
21-
assert.NilError(t, cmd.Execute())
20+
assert.ErrorContains(t, cmd.Execute(), "`system prune` has been cancelled")
2221
expected := `WARNING! This will remove:
2322
- all stopped containers
2423
- all networks not used by at least one container
@@ -36,7 +35,7 @@ func TestPrunePromptFilters(t *testing.T) {
3635
cmd := newPruneCommand(cli)
3736
cmd.SetArgs([]string{"--filter", "until=24h", "--filter", "label=hello-world", "--filter", "label!=foo=bar", "--filter", "label=bar=baz"})
3837

39-
assert.NilError(t, cmd.Execute())
38+
assert.ErrorContains(t, cmd.Execute(), "`system prune` has been cancelled")
4039
expected := `WARNING! This will remove:
4140
- all stopped containers
4241
- all networks not used by at least one container
@@ -69,8 +68,5 @@ func TestSystemPrunePromptTermination(t *testing.T) {
6968
})
7069

7170
cmd := newPruneCommand(cli)
72-
test.TerminatePrompt(ctx, t, cmd, cli, func(t *testing.T, err error) {
73-
t.Helper()
74-
assert.ErrorIs(t, err, command.ErrPromptTerminated)
75-
})
71+
test.TerminatePrompt(ctx, t, cmd, cli)
7672
}

cli/command/trust/revoke.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/docker/cli/cli/command"
99
"github.com/docker/cli/cli/command/image"
1010
"github.com/docker/cli/cli/trust"
11+
"github.com/docker/docker/errdefs"
1112
"github.com/pkg/errors"
1213
"github.com/spf13/cobra"
1314
"github.com/theupdateframework/notary/client"
@@ -45,12 +46,10 @@ func revokeTrust(ctx context.Context, dockerCLI command.Cli, remote string, opti
4546
if imgRefAndAuth.Tag() == "" && !options.forceYes {
4647
deleteRemote, err := command.PromptForConfirmation(ctx, dockerCLI.In(), dockerCLI.Out(), fmt.Sprintf("Please confirm you would like to delete all signature data for %s?", remote))
4748
if err != nil {
48-
fmt.Fprintf(dockerCLI.Out(), "\nAborting action.\n")
49-
return errors.Wrap(err, "aborting action")
49+
return err
5050
}
5151
if !deleteRemote {
52-
fmt.Fprintf(dockerCLI.Out(), "\nAborting action.\n")
53-
return nil
52+
return errdefs.Cancelled(errors.New("`trust revoke` has been cancelled"))
5453
}
5554
}
5655

0 commit comments

Comments
 (0)