mirror of https://github.com/docker/compose.git
Add status field in CLI metrics : success, failure, cancelled
Signed-off-by: Guillaume Tardif <guillaume.tardif@docker.com>
This commit is contained in:
parent
10372b7098
commit
3ccc603461
|
@ -21,6 +21,8 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/Azure/azure-sdk-for-go/profiles/preview/preview/subscription/mgmt/subscription"
|
||||
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-05-01/resources"
|
||||
|
@ -138,7 +140,7 @@ func (helper contextCreateACIHelper) chooseGroup(ctx context.Context, subscripti
|
|||
group, err := helper.selector.Select("Select a resource group", groupNames)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
os.Exit(0)
|
||||
return resources.Group{}, errdefs.Cancelled(err)
|
||||
}
|
||||
|
||||
return resources.Group{}, err
|
||||
|
|
|
@ -70,7 +70,7 @@ $ docker context create my-context --description "some description" --docker "ho
|
|||
Use: "create CONTEXT",
|
||||
Short: "Create new context",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(cmd.Root())
|
||||
return nil
|
||||
},
|
||||
Long: longHelp,
|
||||
|
|
|
@ -27,7 +27,7 @@ func inspectCommand() *cobra.Command {
|
|||
Use: "inspect",
|
||||
Short: "Display detailed information on one or more contexts",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(cmd.Root())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ func runList(cmd *cobra.Command, opts lsOpts) error {
|
|||
return err
|
||||
}
|
||||
if opts.format != "" {
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(cmd.Root())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ func runLogin(cmd *cobra.Command, args []string) error {
|
|||
backend := args[0]
|
||||
return errors.New("unknown backend type for cloud login: " + backend)
|
||||
}
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(cmd.Root())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,6 @@ func Command() *cobra.Command {
|
|||
}
|
||||
|
||||
func runLogout(cmd *cobra.Command, args []string) error {
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(cmd.Root())
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ func runVersion(cmd *cobra.Command, version string) error {
|
|||
// we don't want to fail on error, there is an error if the engine is not available but it displays client version info
|
||||
// Still, technically the [] byte versionResult could be nil, just let the original command display what it has to display
|
||||
if versionResult == nil {
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(cmd.Root())
|
||||
return nil
|
||||
}
|
||||
var s string = string(versionResult)
|
||||
|
|
35
cli/main.go
35
cli/main.go
|
@ -31,6 +31,8 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
dockererrdef "github.com/docker/docker/errdefs"
|
||||
|
||||
"github.com/docker/compose-cli/cli/cmd/compose"
|
||||
"github.com/docker/compose-cli/cli/cmd/logout"
|
||||
volume "github.com/docker/compose-cli/cli/cmd/volume"
|
||||
|
@ -102,7 +104,7 @@ func main() {
|
|||
SilenceUsage: true,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !isContextAgnosticCommand(cmd) {
|
||||
mobycli.ExecIfDefaultCtxType(cmd.Context())
|
||||
mobycli.ExecIfDefaultCtxType(cmd.Context(), cmd.Root())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
@ -136,7 +138,7 @@ func main() {
|
|||
helpFunc := root.HelpFunc()
|
||||
root.SetHelpFunc(func(cmd *cobra.Command, args []string) {
|
||||
if !isContextAgnosticCommand(cmd) {
|
||||
mobycli.ExecIfDefaultCtxType(cmd.Context())
|
||||
mobycli.ExecIfDefaultCtxType(cmd.Context(), cmd.Root())
|
||||
}
|
||||
helpFunc(cmd, args)
|
||||
})
|
||||
|
@ -158,7 +160,7 @@ func main() {
|
|||
|
||||
// --host and --version should immediately be forwarded to the original cli
|
||||
if opts.Host != "" || opts.Version {
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(root)
|
||||
}
|
||||
|
||||
if opts.Config == "" {
|
||||
|
@ -171,7 +173,7 @@ func main() {
|
|||
|
||||
s, err := store.New(configDir)
|
||||
if err != nil {
|
||||
mobycli.Exec()
|
||||
mobycli.Exec(root)
|
||||
}
|
||||
|
||||
ctype := store.DefaultContextType
|
||||
|
@ -185,41 +187,43 @@ func main() {
|
|||
root.AddCommand(volume.ACICommand())
|
||||
}
|
||||
|
||||
metrics.Track(ctype, os.Args[1:], root.PersistentFlags())
|
||||
|
||||
ctx = apicontext.WithCurrentContext(ctx, currentContext)
|
||||
ctx = store.WithContextStore(ctx, s)
|
||||
|
||||
if err = root.ExecuteContext(ctx); err != nil {
|
||||
// if user canceled request, simply exit without any error message
|
||||
if errors.Is(ctx.Err(), context.Canceled) {
|
||||
if dockererrdef.IsCancelled(err) || errors.Is(ctx.Err(), context.Canceled) {
|
||||
metrics.Track(ctype, os.Args[1:], root.PersistentFlags(), metrics.CancelledStatus)
|
||||
os.Exit(130)
|
||||
}
|
||||
if ctype == store.AwsContextType {
|
||||
exit(root, currentContext, errors.Errorf(`%q context type has been renamed. Recreate the context by running:
|
||||
$ docker context create %s <name>`, cc.Type(), store.EcsContextType))
|
||||
$ docker context create %s <name>`, cc.Type(), store.EcsContextType), ctype)
|
||||
}
|
||||
|
||||
// Context should always be handled by new CLI
|
||||
requiredCmd, _, _ := root.Find(os.Args[1:])
|
||||
if requiredCmd != nil && isContextAgnosticCommand(requiredCmd) {
|
||||
exit(root, currentContext, err)
|
||||
exit(root, currentContext, err, ctype)
|
||||
}
|
||||
mobycli.ExecIfDefaultCtxType(ctx)
|
||||
mobycli.ExecIfDefaultCtxType(ctx, root)
|
||||
|
||||
checkIfUnknownCommandExistInDefaultContext(err, currentContext)
|
||||
checkIfUnknownCommandExistInDefaultContext(err, currentContext, root)
|
||||
|
||||
exit(root, currentContext, err)
|
||||
exit(root, currentContext, err, ctype)
|
||||
}
|
||||
metrics.Track(ctype, os.Args[1:], root.PersistentFlags(), metrics.SuccessStatus)
|
||||
}
|
||||
|
||||
func exit(cmd *cobra.Command, ctx string, err error) {
|
||||
func exit(root *cobra.Command, ctx string, err error, ctype string) {
|
||||
metrics.Track(ctype, os.Args[1:], root.PersistentFlags(), metrics.FailureStatus)
|
||||
|
||||
if errors.Is(err, errdefs.ErrLoginRequired) {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(errdefs.ExitCodeLoginRequired)
|
||||
}
|
||||
if errors.Is(err, errdefs.ErrNotImplemented) {
|
||||
cmd, _, _ := cmd.Traverse(os.Args[1:])
|
||||
cmd, _, _ := root.Traverse(os.Args[1:])
|
||||
name := cmd.Name()
|
||||
parent := cmd.Parent()
|
||||
if parent != nil && parent.Parent() != nil {
|
||||
|
@ -237,13 +241,14 @@ func fatal(err error) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
func checkIfUnknownCommandExistInDefaultContext(err error, currentContext string) {
|
||||
func checkIfUnknownCommandExistInDefaultContext(err error, currentContext string, root *cobra.Command) {
|
||||
submatch := unknownCommandRegexp.FindSubmatch([]byte(err.Error()))
|
||||
if len(submatch) == 2 {
|
||||
dockerCommand := string(submatch[1])
|
||||
|
||||
if mobycli.IsDefaultContextCommand(dockerCommand) {
|
||||
fmt.Fprintf(os.Stderr, "Command %q not available in current context (%s), you can use the \"default\" context to run this command\n", dockerCommand, currentContext)
|
||||
metrics.Track(currentContext, os.Args[1:], root.PersistentFlags(), metrics.FailureStatus)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@ import (
|
|||
"os/signal"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose-cli/metrics"
|
||||
|
||||
apicontext "github.com/docker/compose-cli/context"
|
||||
"github.com/docker/compose-cli/context/store"
|
||||
)
|
||||
|
@ -33,8 +37,8 @@ var delegatedContextTypes = []string{store.DefaultContextType}
|
|||
// ComDockerCli name of the classic cli binary
|
||||
const ComDockerCli = "com.docker.cli"
|
||||
|
||||
// ExecIfDefaultCtxType delegates to com.docker.cli if on moby or AWS context (until there is an AWS backend)
|
||||
func ExecIfDefaultCtxType(ctx context.Context) {
|
||||
// ExecIfDefaultCtxType delegates to com.docker.cli if on moby context
|
||||
func ExecIfDefaultCtxType(ctx context.Context, root *cobra.Command) {
|
||||
currentContext := apicontext.CurrentContext(ctx)
|
||||
|
||||
s := store.ContextStore(ctx)
|
||||
|
@ -42,7 +46,7 @@ func ExecIfDefaultCtxType(ctx context.Context) {
|
|||
currentCtx, err := s.Get(currentContext)
|
||||
// Only run original docker command if the current context is not ours.
|
||||
if err != nil || mustDelegateToMoby(currentCtx.Type()) {
|
||||
Exec()
|
||||
Exec(root)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +60,7 @@ func mustDelegateToMoby(ctxType string) bool {
|
|||
}
|
||||
|
||||
// Exec delegates to com.docker.cli if on moby context
|
||||
func Exec() {
|
||||
func Exec(root *cobra.Command) {
|
||||
cmd := exec.Command(ComDockerCli, os.Args[1:]...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
|
@ -83,12 +87,16 @@ func Exec() {
|
|||
err := cmd.Run()
|
||||
childExit <- true
|
||||
if err != nil {
|
||||
metrics.Track(store.DefaultContextName, os.Args[1:], root.PersistentFlags(), metrics.FailureStatus)
|
||||
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
os.Exit(exiterr.ExitCode())
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
metrics.Track(store.DefaultContextName, os.Args[1:], root.PersistentFlags(), metrics.SuccessStatus)
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
|
@ -155,7 +157,7 @@ func (h contextCreateAWSHelper) chooseProfile(section map[string]ini.Section) (s
|
|||
selected, err := h.user.Select("Select AWS Profile", profiles)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
os.Exit(-1)
|
||||
return "", errdefs.Cancelled(err)
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ type Command struct {
|
|||
Command string `json:"command"`
|
||||
Context string `json:"context"`
|
||||
Source string `json:"source"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -40,6 +41,12 @@ const (
|
|||
CLISource = "cli"
|
||||
// APISource is sent for API metrics
|
||||
APISource = "api"
|
||||
// SuccessStatus is sent for API metrics
|
||||
SuccessStatus = "success"
|
||||
// FailureStatus is sent for API metrics
|
||||
FailureStatus = "failure"
|
||||
// CancelledStatus is sent for API metrics
|
||||
CancelledStatus = "cancelled"
|
||||
)
|
||||
|
||||
// Client sends metrics to Docker Desktopn
|
||||
|
@ -83,5 +90,4 @@ func (c *client) Send(command Command) {
|
|||
_, _ = c.httpClient.Post("http://localhost/usage", "application/json", bytes.NewBuffer(req))
|
||||
}()
|
||||
<-wasIn
|
||||
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ const (
|
|||
)
|
||||
|
||||
// Track sends the tracking analytics to Docker Desktop
|
||||
func Track(context string, args []string, flags *flag.FlagSet) {
|
||||
func Track(context string, args []string, flags *flag.FlagSet, status string) {
|
||||
command := getCommand(args, flags)
|
||||
if command != "" {
|
||||
c := NewClient()
|
||||
|
@ -85,6 +85,7 @@ func Track(context string, args []string, flags *flag.FlagSet) {
|
|||
Command: command,
|
||||
Context: context,
|
||||
Source: CLISource,
|
||||
Status: status,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue