Merge pull request #1680 from cquon/plugin_error_handling

Fix issue where plugin command error exit code is printed out
This commit is contained in:
Sebastiaan van Stijn 2019-03-05 09:22:47 +01:00 committed by GitHub
commit 79e1cabf17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 2 deletions

View File

@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"github.com/docker/cli/cli-plugins/manager" "github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli-plugins/plugin" "github.com/docker/cli/cli-plugins/plugin"
@ -33,6 +34,16 @@ func main() {
}, },
} }
exitStatus2 := &cobra.Command{
Use: "exitstatus2",
Short: "Exit with status 2",
RunE: func(_ *cobra.Command, _ []string) error {
fmt.Fprintln(dockerCli.Err(), "Exiting with error status 2")
os.Exit(2)
return nil
},
}
var who string var who string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "helloworld", Use: "helloworld",
@ -54,10 +65,11 @@ func main() {
return dockerCli.ConfigFile().Save() return dockerCli.ConfigFile().Save()
}, },
} }
flags := cmd.Flags() flags := cmd.Flags()
flags.StringVar(&who, "who", "", "Who are we addressing?") flags.StringVar(&who, "who", "", "Who are we addressing?")
cmd.AddCommand(goodbye, apiversion) cmd.AddCommand(goodbye, apiversion, exitStatus2)
return cmd return cmd
}, },
manager.Metadata{ manager.Metadata{

View File

@ -4,7 +4,9 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"os/exec"
"strings" "strings"
"syscall"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
pluginmanager "github.com/docker/cli/cli-plugins/manager" pluginmanager "github.com/docker/cli/cli-plugins/manager"
@ -55,7 +57,21 @@ func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
return err return err
} }
return plugincmd.Run() err = plugincmd.Run()
if err != nil {
statusCode := 1
exitErr, ok := err.(*exec.ExitError)
if !ok {
return err
}
if ws, ok := exitErr.Sys().(syscall.WaitStatus); ok {
statusCode = ws.ExitStatus()
}
return cli.StatusError{
StatusCode: statusCode,
}
}
return nil
}, },
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// flags must be the top-level command flags, not cmd.Flags() // flags must be the top-level command flags, not cmd.Flags()

View File

@ -194,3 +194,16 @@ func TestCliInitialized(t *testing.T) {
assert.Assert(t, res.Stdout() != "") assert.Assert(t, res.Stdout() != "")
assert.Assert(t, is.Equal(res.Stderr(), "")) assert.Assert(t, is.Equal(res.Stderr(), ""))
} }
// TestPluginErrorCode tests when the plugin return with a given exit status.
// We want to verify that the exit status does not get output to stdout and also that we return the exit code.
func TestPluginErrorCode(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("helloworld", "exitstatus2"))
res.Assert(t, icmd.Expected{
ExitCode: 2,
Err: "Exiting with error status 2",
})
assert.Assert(t, is.Equal(res.Stdout(), ""))
}

View File

@ -8,6 +8,7 @@ Options:
Commands: Commands:
apiversion Print the API version of the server apiversion Print the API version of the server
exitstatus2 Exit with status 2
goodbye Say Goodbye instead of Hello goodbye Say Goodbye instead of Hello
Run 'docker helloworld COMMAND --help' for more information on a command. Run 'docker helloworld COMMAND --help' for more information on a command.