Merge pull request #6340 from thaJeztah/28.x_backport_cleanup_plugins

[28.x backport] cli/command/plugin: fix linting issues, and assorted cleanups
This commit is contained in:
Sebastiaan van Stijn
2025-08-22 11:31:06 +02:00
committed by GitHub
16 changed files with 124 additions and 105 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ func validateConfig(path string) error {
return err
}
// validateContextDir validates the given dir and returns abs path on success.
// validateContextDir validates the given dir and returns its absolute path on success.
func validateContextDir(contextDir string) (string, error) {
absContextDir, err := filepath.Abs(contextDir)
if err != nil {
+9 -13
View File
@@ -1,7 +1,6 @@
package plugin
import (
"context"
"fmt"
"github.com/docker/cli/cli"
@@ -10,27 +9,24 @@ import (
"github.com/spf13/cobra"
)
func newDisableCommand(dockerCli command.Cli) *cobra.Command {
var force bool
func newDisableCommand(dockerCLI command.Cli) *cobra.Command {
var opts types.PluginDisableOptions
cmd := &cobra.Command{
Use: "disable [OPTIONS] PLUGIN",
Short: "Disable a plugin",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runDisable(cmd.Context(), dockerCli, args[0], force)
name := args[0]
if err := dockerCLI.Client().PluginDisable(cmd.Context(), name, opts); err != nil {
return err
}
_, _ = fmt.Fprintln(dockerCLI.Out(), name)
return nil
},
}
flags := cmd.Flags()
flags.BoolVarP(&force, "force", "f", false, "Force the disable of an active plugin")
flags.BoolVarP(&opts.Force, "force", "f", false, "Force the disable of an active plugin")
return cmd
}
func runDisable(ctx context.Context, dockerCli command.Cli, name string, force bool) error {
if err := dockerCli.Client().PluginDisable(ctx, name, types.PluginDisableOptions{Force: force}); err != nil {
return err
}
fmt.Fprintln(dockerCli.Out(), name)
return nil
}
+12 -19
View File
@@ -11,38 +11,31 @@ import (
"github.com/spf13/cobra"
)
type enableOpts struct {
timeout int
name string
}
func newEnableCommand(dockerCli command.Cli) *cobra.Command {
var opts enableOpts
var opts types.PluginEnableOptions
cmd := &cobra.Command{
Use: "enable [OPTIONS] PLUGIN",
Short: "Enable a plugin",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.name = args[0]
return runEnable(cmd.Context(), dockerCli, &opts)
name := args[0]
if err := runEnable(cmd.Context(), dockerCli, name, opts); err != nil {
return err
}
_, _ = fmt.Fprintln(dockerCli.Out(), name)
return nil
},
}
flags := cmd.Flags()
flags.IntVar(&opts.timeout, "timeout", 30, "HTTP client timeout (in seconds)")
flags.IntVar(&opts.Timeout, "timeout", 30, "HTTP client timeout (in seconds)")
return cmd
}
func runEnable(ctx context.Context, dockerCli command.Cli, opts *enableOpts) error {
name := opts.name
if opts.timeout < 0 {
return errors.Errorf("negative timeout %d is invalid", opts.timeout)
func runEnable(ctx context.Context, dockerCli command.Cli, name string, opts types.PluginEnableOptions) error {
if opts.Timeout < 0 {
return errors.Errorf("negative timeout %d is invalid", opts.Timeout)
}
if err := dockerCli.Client().PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: opts.timeout}); err != nil {
return err
}
fmt.Fprintln(dockerCli.Out(), name)
return nil
return dockerCli.Client().PluginEnable(ctx, name, opts)
}
+1 -1
View File
@@ -48,7 +48,7 @@ func TestPluginEnableErrors(t *testing.T) {
}))
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
assert.NilError(t, cmd.Flags().Set(key, value))
}
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
+7 -1
View File
@@ -12,6 +12,12 @@ const (
enabledHeader = "ENABLED"
pluginIDHeader = "ID"
rawFormat = `plugin_id: {{.ID}}
name: {{.Name}}
description: {{.Description}}
enabled: {{.Enabled}}
`
)
// NewFormat returns a Format for rendering using a plugin Context
@@ -26,7 +32,7 @@ func NewFormat(source string, quiet bool) formatter.Format {
if quiet {
return `plugin_id: {{.ID}}`
}
return `plugin_id: {{.ID}}\nname: {{.Name}}\ndescription: {{.Description}}\nenabled: {{.Enabled}}\n`
return rawFormat
}
return formatter.Format(source)
}
+69 -47
View File
@@ -19,85 +19,106 @@ import (
func TestPluginContext(t *testing.T) {
pluginID := test.RandomID()
var ctx pluginContext
cases := []struct {
var pCtx pluginContext
tests := []struct {
pluginCtx pluginContext
expValue string
call func() string
}{
{pluginContext{
p: types.Plugin{ID: pluginID},
trunc: false,
}, pluginID, ctx.ID},
{pluginContext{
p: types.Plugin{ID: pluginID},
trunc: true,
}, formatter.TruncateID(pluginID), ctx.ID},
{pluginContext{
p: types.Plugin{Name: "plugin_name"},
}, "plugin_name", ctx.Name},
{pluginContext{
p: types.Plugin{Config: types.PluginConfig{Description: "plugin_description"}},
}, "plugin_description", ctx.Description},
{
pluginCtx: pluginContext{
p: types.Plugin{ID: pluginID},
trunc: false,
},
expValue: pluginID,
call: pCtx.ID,
},
{
pluginCtx: pluginContext{
p: types.Plugin{ID: pluginID},
trunc: true,
},
expValue: formatter.TruncateID(pluginID),
call: pCtx.ID,
},
{
pluginCtx: pluginContext{
p: types.Plugin{Name: "plugin_name"},
},
expValue: "plugin_name",
call: pCtx.Name,
},
{
pluginCtx: pluginContext{
p: types.Plugin{Config: types.PluginConfig{Description: "plugin_description"}},
},
expValue: "plugin_description",
call: pCtx.Description,
},
}
for _, c := range cases {
ctx = c.pluginCtx
v := c.call()
for _, tc := range tests {
pCtx = tc.pluginCtx
v := tc.call()
if strings.Contains(v, ",") {
test.CompareMultipleValues(t, v, c.expValue)
} else if v != c.expValue {
t.Fatalf("Expected %s, was %s\n", c.expValue, v)
test.CompareMultipleValues(t, v, tc.expValue)
} else if v != tc.expValue {
t.Fatalf("Expected %s, was %s\n", tc.expValue, v)
}
}
}
func TestPluginContextWrite(t *testing.T) {
cases := []struct {
tests := []struct {
doc string
context formatter.Context
expected string
}{
// Errors
{
formatter.Context{Format: "{{InvalidFunction}}"},
`template parsing error: template: :1: function "InvalidFunction" not defined`,
doc: "invalid function",
context: formatter.Context{Format: "{{InvalidFunction}}"},
expected: `template parsing error: template: :1: function "InvalidFunction" not defined`,
},
{
formatter.Context{Format: "{{nil}}"},
`template parsing error: template: :1:2: executing "" at <nil>: nil is not a command`,
doc: "nil template",
context: formatter.Context{Format: "{{nil}}"},
expected: `template parsing error: template: :1:2: executing "" at <nil>: nil is not a command`,
},
// Table format
{
formatter.Context{Format: NewFormat("table", false)},
`ID NAME DESCRIPTION ENABLED
doc: "table format",
context: formatter.Context{Format: NewFormat("table", false)},
expected: `ID NAME DESCRIPTION ENABLED
pluginID1 foobar_baz description 1 true
pluginID2 foobar_bar description 2 false
`,
},
{
formatter.Context{Format: NewFormat("table", true)},
`pluginID1
doc: "table format, quiet",
context: formatter.Context{Format: NewFormat("table", true)},
expected: `pluginID1
pluginID2
`,
},
{
formatter.Context{Format: NewFormat("table {{.Name}}", false)},
`NAME
doc: "table format name col",
context: formatter.Context{Format: NewFormat("table {{.Name}}", false)},
expected: `NAME
foobar_baz
foobar_bar
`,
},
{
formatter.Context{Format: NewFormat("table {{.Name}}", true)},
`NAME
doc: "table format name col, quiet",
context: formatter.Context{Format: NewFormat("table {{.Name}}", true)},
expected: `NAME
foobar_baz
foobar_bar
`,
},
// Raw Format
{
formatter.Context{Format: NewFormat("raw", false)},
`plugin_id: pluginID1
doc: "raw format",
context: formatter.Context{Format: NewFormat("raw", false)},
expected: `plugin_id: pluginID1
name: foobar_baz
description: description 1
enabled: true
@@ -110,15 +131,16 @@ enabled: false
`,
},
{
formatter.Context{Format: NewFormat("raw", true)},
`plugin_id: pluginID1
doc: "raw format, quiet",
context: formatter.Context{Format: NewFormat("raw", true)},
expected: `plugin_id: pluginID1
plugin_id: pluginID2
`,
},
// Custom Format
{
formatter.Context{Format: NewFormat("{{.Name}}", false)},
`foobar_baz
doc: "custom format",
context: formatter.Context{Format: NewFormat("{{.Name}}", false)},
expected: `foobar_baz
foobar_bar
`,
},
@@ -129,8 +151,8 @@ foobar_bar
{ID: "pluginID2", Name: "foobar_bar", Config: types.PluginConfig{Description: "description 2"}, Enabled: false},
}
for _, tc := range cases {
t.Run(string(tc.context.Format), func(t *testing.T) {
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
var out bytes.Buffer
tc.context.Output = &out
+5 -7
View File
@@ -36,11 +36,9 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
client := dockerCli.Client()
getRef := func(ref string) (any, []byte, error) {
return client.PluginInspectWithRaw(ctx, ref)
}
return inspect.Inspect(dockerCli.Out(), opts.pluginNames, opts.format, getRef)
func runInspect(ctx context.Context, dockerCLI command.Cli, opts inspectOptions) error {
apiClient := dockerCLI.Client()
return inspect.Inspect(dockerCLI.Out(), opts.pluginNames, opts.format, func(ref string) (any, []byte, error) {
return apiClient.PluginInspectWithRaw(ctx, ref)
})
}
+4 -4
View File
@@ -21,14 +21,14 @@ var pluginFoo = &types.Plugin{
Documentation: "plugin foo documentation",
Entrypoint: []string{"/foo"},
Interface: types.PluginConfigInterface{
Socket: "pluginfoo.sock",
Socket: "plugin-foo.sock",
},
Linux: types.PluginConfigLinux{
Capabilities: []string{"CAP_SYS_ADMIN"},
},
WorkDir: "workdir-foo",
Rootfs: &types.PluginConfigRootfs{
DiffIds: []string{"sha256:8603eedd4ea52cebb2f22b45405a3dc8f78ba3e31bf18f27b4547a9ff930e0bd"},
DiffIds: []string{"sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"},
Type: "layers",
},
},
@@ -71,7 +71,7 @@ func TestInspectErrors(t *testing.T) {
cmd := newInspectCommand(cli)
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
assert.NilError(t, cmd.Flags().Set(key, value))
}
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
@@ -142,7 +142,7 @@ func TestInspect(t *testing.T) {
cmd := newInspectCommand(cli)
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
assert.NilError(t, cmd.Flags().Set(key, value))
}
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), tc.golden)
+3 -1
View File
@@ -125,7 +125,9 @@ func runInstall(ctx context.Context, dockerCLI command.Cli, opts pluginOptions)
}
return err
}
defer responseBody.Close()
defer func() {
_ = responseBody.Close()
}()
if err := jsonstream.Display(ctx, responseBody, dockerCLI.Out()); err != nil {
return err
}
+1 -1
View File
@@ -32,7 +32,7 @@ func TestInstallErrors(t *testing.T) {
},
{
description: "invalid plugin name",
args: []string{"UPPERCASE_REPONAME"},
args: []string{"UPPERCASE_REPO_NAME"},
expectedError: "invalid",
},
{
+2 -2
View File
@@ -51,7 +51,7 @@ func TestListErrors(t *testing.T) {
cmd := newListCommand(cli)
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
assert.NilError(t, cmd.Flags().Set(key, value))
}
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
@@ -170,7 +170,7 @@ func TestList(t *testing.T) {
cmd := newListCommand(cli)
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
assert.NilError(t, cmd.Flags().Set(key, value))
}
assert.NilError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), tc.golden)
+3 -1
View File
@@ -60,7 +60,9 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error
if err != nil {
return err
}
defer responseBody.Close()
defer func() {
_ = responseBody.Close()
}()
if !opts.untrusted {
repoInfo := &trust.RepositoryInfo{
+1 -1
View File
@@ -64,7 +64,7 @@ func TestRemoveWithForceOption(t *testing.T) {
})
cmd := newRemoveCommand(cli)
cmd.SetArgs([]string{"plugin-foo"})
cmd.Flags().Set("force", "true")
assert.NilError(t, cmd.Flags().Set("force", "true"))
assert.NilError(t, cmd.Execute())
assert.Check(t, force)
assert.Check(t, is.Equal("plugin-foo\n", cli.OutBuffer().String()))
+1 -3
View File
@@ -7,7 +7,7 @@ import (
)
func newSetCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
return &cobra.Command{
Use: "set PLUGIN KEY=VALUE [KEY=VALUE...]",
Short: "Change settings for a plugin",
Args: cli.RequiresMinArgs(2),
@@ -15,6 +15,4 @@ func newSetCommand(dockerCli command.Cli) *cobra.Command {
return dockerCli.Client().PluginSet(cmd.Context(), args[0], args[1:])
},
}
return cmd
}
@@ -15,7 +15,7 @@
],
"Env": null,
"Interface": {
"Socket": "pluginfoo.sock",
"Socket": "plugin-foo.sock",
"Types": null
},
"IpcHost": false,
@@ -36,7 +36,7 @@
"WorkDir": "workdir-foo",
"rootfs": {
"diff_ids": [
"sha256:8603eedd4ea52cebb2f22b45405a3dc8f78ba3e31bf18f27b4547a9ff930e0bd"
"sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
],
"type": "layers"
}
+3 -1
View File
@@ -85,7 +85,9 @@ func runUpgrade(ctx context.Context, dockerCLI command.Cli, opts pluginOptions)
}
return err
}
defer responseBody.Close()
defer func() {
_ = responseBody.Close()
}()
if err := jsonstream.Display(ctx, responseBody, dockerCLI.Out()); err != nil {
return err
}