diff --git a/cli/command/context/list.go b/cli/command/context/list.go index aaf0195a73..55173d51ed 100644 --- a/cli/command/context/list.go +++ b/cli/command/context/list.go @@ -66,6 +66,8 @@ func runList(dockerCli command.Cli, opts *listOptions) error { Name: rawMeta.Name, Current: isCurrent, Error: err.Error(), + + ContextType: getContextType(nil, opts.format), }) continue } @@ -80,6 +82,8 @@ func runList(dockerCli command.Cli, opts *listOptions) error { Description: meta.Description, DockerEndpoint: dockerEndpoint.Host, Error: errMsg, + + ContextType: getContextType(meta.AdditionalFields, opts.format), } contexts = append(contexts, &desc) } @@ -96,6 +100,8 @@ func runList(dockerCli command.Cli, opts *listOptions) error { Name: curContext, Current: true, Error: errMsg, + + ContextType: getContextType(nil, opts.format), }) } sort.Slice(contexts, func(i, j int) bool { @@ -111,6 +117,30 @@ func runList(dockerCli command.Cli, opts *listOptions) error { return nil } +// getContextType sets the LegacyContextType field for compatibility with +// Visual Studio, which depends on this field from the "cloud integration" +// wrapper. +// +// https://github.com/docker/compose-cli/blob/c156ce6da4c2b317174d42daf1b019efa87e9f92/api/context/store/contextmetadata.go#L28-L34 +// https://github.com/docker/compose-cli/blob/c156ce6da4c2b317174d42daf1b019efa87e9f92/api/context/store/store.go#L34-L51 +// +// TODO(thaJeztah): remove this and [ClientContext.ContextType] once Visual Studio is updated to no longer depend on this. +func getContextType(meta map[string]any, format string) string { + if format != formatter.JSONFormat && format != formatter.JSONFormatKey { + // We only need the ContextType field when formatting as JSON, + // which is the format-string used by Visual Studio to detect the + // context-type. + return "" + } + if ct, ok := meta["Type"]; ok { + // If the context on-disk has a context-type (ecs, aci), return it. + return ct.(string) + } + + // Use the default context-type. + return "moby" +} + func format(dockerCli command.Cli, opts *listOptions, contexts []*formatter.ClientContext) error { contextCtx := formatter.Context{ Output: dockerCli.Out(), diff --git a/cli/command/context/testdata/list-json.golden b/cli/command/context/testdata/list-json.golden index 6be551b6de..a55cf47f7c 100644 --- a/cli/command/context/testdata/list-json.golden +++ b/cli/command/context/testdata/list-json.golden @@ -1,5 +1,5 @@ -{"Current":false,"Description":"description of context1","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"context1"} -{"Current":false,"Description":"description of context2","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"context2"} -{"Current":false,"Description":"description of context3","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"context3"} -{"Current":true,"Description":"description of current","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"current"} -{"Current":false,"Description":"Current DOCKER_HOST based configuration","DockerEndpoint":"unix:///var/run/docker.sock","Error":"","Name":"default"} +{"Name":"context1","Description":"description of context1","DockerEndpoint":"https://someswarmserver.example.com","Current":false,"Error":"","ContextType":"aci"} +{"Name":"context2","Description":"description of context2","DockerEndpoint":"https://someswarmserver.example.com","Current":false,"Error":"","ContextType":"ecs"} +{"Name":"context3","Description":"description of context3","DockerEndpoint":"https://someswarmserver.example.com","Current":false,"Error":"","ContextType":"moby"} +{"Name":"current","Description":"description of current","DockerEndpoint":"https://someswarmserver.example.com","Current":true,"Error":"","ContextType":"moby"} +{"Name":"default","Description":"Current DOCKER_HOST based configuration","DockerEndpoint":"unix:///var/run/docker.sock","Current":false,"Error":"","ContextType":"moby"} diff --git a/cli/command/formatter/context.go b/cli/command/formatter/context.go index 985a6ff32e..293c84155a 100644 --- a/cli/command/formatter/context.go +++ b/cli/command/formatter/context.go @@ -1,5 +1,7 @@ package formatter +import "encoding/json" + const ( // ClientContextTableFormat is the default client context format. ClientContextTableFormat = "table {{.Name}}{{if .Current}} *{{end}}\t{{.Description}}\t{{.DockerEndpoint}}\t{{.Error}}" @@ -28,6 +30,13 @@ type ClientContext struct { DockerEndpoint string Current bool Error string + + // ContextType is a temporary field for compatibility with + // Visual Studio, which depends on this from the "cloud integration" + // wrapper. + // + // Deprecated: this type is only for backward-compatibility. Do not use. + ContextType string `json:"ContextType,omitempty"` } // ClientContextWrite writes formatted contexts using the Context @@ -60,6 +69,13 @@ func newClientContextContext() *clientContextContext { } func (c *clientContextContext) MarshalJSON() ([]byte, error) { + if c.c.ContextType != "" { + // We only have ContextType set for plain "json" or "{{json .}}" formatting, + // so we should be able to just use the default json.Marshal with no + // special handling. + return json.Marshal(c.c) + } + // FIXME(thaJeztah): why do we need a special marshal function here? return MarshalJSON(c) }