From 9d2489c1d210620639369f35f0c9b1dc6bc988ea Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Thu, 7 Aug 2025 14:54:32 +1000 Subject: [PATCH 1/2] feat: support -f parameter for deployment target views command --- pkg/cmd/target/azure-web-app/view/view.go | 2 +- pkg/cmd/target/cloud-region/view/view.go | 2 +- pkg/cmd/target/kubernetes/view/view.go | 2 +- .../target/listening-tentacle/view/view.go | 2 +- pkg/cmd/target/polling-tentacle/view/view.go | 2 +- pkg/cmd/target/shared/view.go | 5 +- pkg/cmd/target/ssh/view/view.go | 2 +- pkg/cmd/target/view/view.go | 271 ++++++++++++++++-- 8 files changed, 262 insertions(+), 26 deletions(-) diff --git a/pkg/cmd/target/azure-web-app/view/view.go b/pkg/cmd/target/azure-web-app/view/view.go index c5c1968b..24f77058 100644 --- a/pkg/cmd/target/azure-web-app/view/view.go +++ b/pkg/cmd/target/azure-web-app/view/view.go @@ -28,7 +28,7 @@ func NewCmdView(f factory.Factory) *cobra.Command { $ %[1]s deployment-target azure-web-app view Machines-100 `, constants.ExecutableName), RunE: func(c *cobra.Command, args []string) error { - opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args) + opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c) return ViewRun(opts) }, } diff --git a/pkg/cmd/target/cloud-region/view/view.go b/pkg/cmd/target/cloud-region/view/view.go index 7ae62bbb..b0593ac1 100644 --- a/pkg/cmd/target/cloud-region/view/view.go +++ b/pkg/cmd/target/cloud-region/view/view.go @@ -23,7 +23,7 @@ func NewCmdView(f factory.Factory) *cobra.Command { $ %[1]s deployment-target cloud-region view Machines-100 `, constants.ExecutableName), RunE: func(c *cobra.Command, args []string) error { - opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args) + opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c) return ViewRun(opts) }, } diff --git a/pkg/cmd/target/kubernetes/view/view.go b/pkg/cmd/target/kubernetes/view/view.go index 2ca14271..ebccb5f2 100644 --- a/pkg/cmd/target/kubernetes/view/view.go +++ b/pkg/cmd/target/kubernetes/view/view.go @@ -24,7 +24,7 @@ func NewCmdView(f factory.Factory) *cobra.Command { $ %[1]s deployment-target kubernetes view 'target-name' `, constants.ExecutableName), RunE: func(c *cobra.Command, args []string) error { - opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args) + opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c) return ViewRun(opts) }, } diff --git a/pkg/cmd/target/listening-tentacle/view/view.go b/pkg/cmd/target/listening-tentacle/view/view.go index 4ff3b6d4..19b237a5 100644 --- a/pkg/cmd/target/listening-tentacle/view/view.go +++ b/pkg/cmd/target/listening-tentacle/view/view.go @@ -25,7 +25,7 @@ func NewCmdView(f factory.Factory) *cobra.Command { $ %[1]s deployment-target listening-tentacle view Machines-100 `, constants.ExecutableName), RunE: func(c *cobra.Command, args []string) error { - opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args) + opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c) return ViewRun(opts) }, } diff --git a/pkg/cmd/target/polling-tentacle/view/view.go b/pkg/cmd/target/polling-tentacle/view/view.go index 064fa029..e2fa3bd4 100644 --- a/pkg/cmd/target/polling-tentacle/view/view.go +++ b/pkg/cmd/target/polling-tentacle/view/view.go @@ -25,7 +25,7 @@ func NewCmdView(f factory.Factory) *cobra.Command { $ %[1]s deployment-target polling-tentacle view Machines-100 `, constants.ExecutableName), RunE: func(c *cobra.Command, args []string) error { - opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args) + opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c) return ViewRun(opts) }, } diff --git a/pkg/cmd/target/shared/view.go b/pkg/cmd/target/shared/view.go index 3d95de80..a535f967 100644 --- a/pkg/cmd/target/shared/view.go +++ b/pkg/cmd/target/shared/view.go @@ -7,6 +7,7 @@ import ( "github.com/OctopusDeploy/cli/pkg/output" "github.com/OctopusDeploy/cli/pkg/util" "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines" + "github.com/spf13/cobra" ) type ContributeEndpointCallback func(opts *ViewOptions, endpoint machines.IEndpoint) ([]*output.DataRow, error) @@ -19,6 +20,7 @@ type ViewOptions struct { *cmd.Dependencies IdOrName string *ViewFlags + Command *cobra.Command } func NewViewFlags() *ViewFlags { @@ -27,11 +29,12 @@ func NewViewFlags() *ViewFlags { } } -func NewViewOptions(viewFlags *ViewFlags, dependencies *cmd.Dependencies, args []string) *ViewOptions { +func NewViewOptions(viewFlags *ViewFlags, dependencies *cmd.Dependencies, args []string, command *cobra.Command) *ViewOptions { return &ViewOptions{ ViewFlags: viewFlags, Dependencies: dependencies, IdOrName: args[0], + Command: command, } } diff --git a/pkg/cmd/target/ssh/view/view.go b/pkg/cmd/target/ssh/view/view.go index 6c25ff32..722f02ae 100644 --- a/pkg/cmd/target/ssh/view/view.go +++ b/pkg/cmd/target/ssh/view/view.go @@ -25,7 +25,7 @@ func NewCmdView(f factory.Factory) *cobra.Command { $ %[1]s deployment-target ssh view Machines-100 `, constants.ExecutableName), RunE: func(c *cobra.Command, args []string) error { - opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args) + opts := shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c) return ViewRun(opts) }, } diff --git a/pkg/cmd/target/view/view.go b/pkg/cmd/target/view/view.go index 9dd7054a..212138fd 100644 --- a/pkg/cmd/target/view/view.go +++ b/pkg/cmd/target/view/view.go @@ -2,20 +2,18 @@ package view import ( "fmt" + "strings" "github.com/MakeNowJust/heredoc/v2" "github.com/OctopusDeploy/cli/pkg/cmd" - azureWebApp "github.com/OctopusDeploy/cli/pkg/cmd/target/azure-web-app/view" - cloudRegion "github.com/OctopusDeploy/cli/pkg/cmd/target/cloud-region/view" - k8s "github.com/OctopusDeploy/cli/pkg/cmd/target/kubernetes/view" - listeningTentacle "github.com/OctopusDeploy/cli/pkg/cmd/target/listening-tentacle/view" - pollingTentacle "github.com/OctopusDeploy/cli/pkg/cmd/target/polling-tentacle/view" "github.com/OctopusDeploy/cli/pkg/cmd/target/shared" - ssh "github.com/OctopusDeploy/cli/pkg/cmd/target/ssh/view" "github.com/OctopusDeploy/cli/pkg/constants" "github.com/OctopusDeploy/cli/pkg/factory" "github.com/OctopusDeploy/cli/pkg/machinescommon" + "github.com/OctopusDeploy/cli/pkg/output" "github.com/OctopusDeploy/cli/pkg/usage" + "github.com/OctopusDeploy/cli/pkg/util" + "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/machines" "github.com/spf13/cobra" ) @@ -31,7 +29,7 @@ func NewCmdView(f factory.Factory) *cobra.Command { $ %[1]s deployment-target view 'web-server' `, constants.ExecutableName), RunE: func(c *cobra.Command, args []string) error { - return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args)) + return ViewRun(shared.NewViewOptions(flags, cmd.NewDependencies(f, c), args, c)) }, } @@ -46,28 +44,263 @@ func ViewRun(opts *shared.ViewOptions) error { return err } - switch target.Endpoint.GetCommunicationStyle() { + // Use basic format as default for deployment target view when no -f flag is specified + if !opts.Command.Flags().Changed(constants.FlagOutputFormat) { + opts.Command.Flags().Set(constants.FlagOutputFormat, constants.OutputFormatBasic) + } + + return output.PrintResource(target, opts.Command, output.Mappers[*machines.DeploymentTarget]{ + Json: func(t *machines.DeploymentTarget) any { + return getDeploymentTargetAsJson(opts, t) + }, + Table: output.TableDefinition[*machines.DeploymentTarget]{ + Header: []string{"NAME", "TYPE", "HEALTH", "ENVIRONMENTS", "ROLES", "TENANTS", "TENANT TAGS", "ENDPOINT DETAILS"}, + Row: func(t *machines.DeploymentTarget) []string { + return getDeploymentTargetAsTableRow(opts, t) + }, + }, + Basic: func(t *machines.DeploymentTarget) string { + return getDeploymentTargetAsBasic(opts, t) + }, + }) +} + +type DeploymentTargetAsJson struct { + Id string `json:"Id"` + Name string `json:"Name"` + HealthStatus string `json:"HealthStatus"` + StatusSummary string `json:"StatusSummary"` + CommunicationStyle string `json:"CommunicationStyle"` + Environments []string `json:"Environments"` + Roles []string `json:"Roles"` + Tenants []string `json:"Tenants"` + TenantTags []string `json:"TenantTags"` + EndpointDetails map[string]string `json:"EndpointDetails"` + WebUrl string `json:"WebUrl"` +} + +func getDeploymentTargetAsJson(opts *shared.ViewOptions, target *machines.DeploymentTarget) DeploymentTargetAsJson { + environmentMap, _ := shared.GetEnvironmentMap(opts) + tenantMap, _ := shared.GetTenantMap(opts) + + environments := resolveValues(target.EnvironmentIDs, environmentMap) + tenants := resolveValues(target.TenantIDs, tenantMap) + + endpointDetails := getEndpointDetails(target) + + return DeploymentTargetAsJson{ + Id: target.GetID(), + Name: target.Name, + HealthStatus: target.HealthStatus, + StatusSummary: target.StatusSummary, + CommunicationStyle: target.Endpoint.GetCommunicationStyle(), + Environments: environments, + Roles: target.Roles, + Tenants: tenants, + TenantTags: target.TenantTags, + EndpointDetails: endpointDetails, + WebUrl: util.GenerateWebURL(opts.Host, target.SpaceID, fmt.Sprintf("infrastructure/machines/%s/settings", target.GetID())), + } +} + +func getDeploymentTargetAsTableRow(opts *shared.ViewOptions, target *machines.DeploymentTarget) []string { + environmentMap, _ := shared.GetEnvironmentMap(opts) + environments := resolveValues(target.EnvironmentIDs, environmentMap) + + healthStatus := getHealthStatusFormatted(target.HealthStatus) + targetType := getTargetTypeDisplayName(target.Endpoint.GetCommunicationStyle()) + + // Handle tenants + tenants := "None" + if !util.Empty(target.TenantIDs) { + tenantMap, _ := shared.GetTenantMap(opts) + tenantNames := resolveValues(target.TenantIDs, tenantMap) + tenants = strings.Join(tenantNames, ", ") + } + + // Handle tenant tags + tenantTags := "None" + if !util.Empty(target.TenantTags) { + tenantTags = strings.Join(target.TenantTags, ", ") + } + + // Handle endpoint details + endpointDetails := getEndpointDetails(target) + var endpointDetailsStr strings.Builder + first := true + for key, value := range endpointDetails { + if !first { + endpointDetailsStr.WriteString("; ") + } + endpointDetailsStr.WriteString(fmt.Sprintf("%s: %s", key, value)) + first = false + } + endpointDetailsString := endpointDetailsStr.String() + if endpointDetailsString == "" { + endpointDetailsString = "-" + } + + return []string{ + output.Bold(target.Name), + targetType, + healthStatus, + strings.Join(environments, ", "), + strings.Join(target.Roles, ", "), + tenants, + tenantTags, + endpointDetailsString, + } +} + +func getHealthStatusFormatted(status string) string { + switch status { + case "Healthy": + return output.Green(status) + case "Unhealthy": + return output.Red(status) + default: + return output.Yellow(status) + } +} + +func getTargetTypeDisplayName(communicationStyle string) string { + switch communicationStyle { case "None": - return cloudRegion.ViewRun(opts) + return "Cloud Region" case "TentaclePassive": - return listeningTentacle.ViewRun(opts) + return "Listening Tentacle" case "TentacleActive": - return pollingTentacle.ViewRun(opts) + return "Polling Tentacle" case "Ssh": - return ssh.ViewRun(opts) + return "SSH" case "OfflineDrop": - return shared.ViewRun(opts, nil, "Offline Drop Folder") + return "Offline Drop" case "AzureWebApp": - return azureWebApp.ViewRun(opts) + return "Azure Web App" case "AzureCloudService": - return shared.ViewRun(opts, nil, "Azure Cloud Service") + return "Azure Cloud Service" case "AzureServiceFabricCluster": - return shared.ViewRun(opts, nil, "Azure Service Fabric Cluster") + return "Azure Service Fabric" case "Kubernetes": - return k8s.ViewRun(opts) + return "Kubernetes" case "StepPackage": - return shared.ViewRun(opts, nil, "Step Package") + return "Step Package" + default: + return communicationStyle + } +} + +func getDeploymentTargetAsBasic(opts *shared.ViewOptions, target *machines.DeploymentTarget) string { + var result strings.Builder + + // Header + result.WriteString(fmt.Sprintf("%s %s\n", output.Bold(target.Name), output.Dimf("(%s)", target.GetID()))) + + // Health status + healthStatus := getHealthStatusFormatted(target.HealthStatus) + result.WriteString(fmt.Sprintf("Health status: %s\n", healthStatus)) + + // Current status + result.WriteString(fmt.Sprintf("Current status: %s\n", target.StatusSummary)) + + // Target type and endpoint details + targetType := getTargetTypeDisplayName(target.Endpoint.GetCommunicationStyle()) + result.WriteString(fmt.Sprintf("Type: %s\n", output.Cyan(targetType))) + + // Add endpoint-specific details + endpointDetails := getEndpointDetails(target) + for key, value := range endpointDetails { + result.WriteString(fmt.Sprintf("%s: %s\n", key, value)) + } + + // Environments + environmentMap, _ := shared.GetEnvironmentMap(opts) + environments := resolveValues(target.EnvironmentIDs, environmentMap) + result.WriteString(fmt.Sprintf("Environments: %s\n", output.FormatAsList(environments))) + + // Roles + result.WriteString(fmt.Sprintf("Roles: %s\n", output.FormatAsList(target.Roles))) + + // Tenants + if !util.Empty(target.TenantIDs) { + tenantMap, _ := shared.GetTenantMap(opts) + tenants := resolveValues(target.TenantIDs, tenantMap) + result.WriteString(fmt.Sprintf("Tenants: %s\n", output.FormatAsList(tenants))) + } else { + result.WriteString("Tenants: None\n") + } + + // Tenant Tags + if !util.Empty(target.TenantTags) { + result.WriteString(fmt.Sprintf("Tenant Tags: %s\n", output.FormatAsList(target.TenantTags))) + } else { + result.WriteString("Tenant Tags: None\n") + } + + // Web URL + url := util.GenerateWebURL(opts.Host, target.SpaceID, fmt.Sprintf("infrastructure/machines/%s/settings", target.GetID())) + result.WriteString(fmt.Sprintf("\nView this deployment target in Octopus Deploy: %s\n", output.Blue(url))) + + // Handle web flag + if opts.WebFlags != nil && opts.WebFlags.Web.Value { + machinescommon.DoWebForTargets(target, opts.Dependencies, opts.WebFlags, targetType) + } + + return result.String() +} + +func resolveValues(keys []string, lookup map[string]string) []string { + var values []string + for _, key := range keys { + if value, exists := lookup[key]; exists { + values = append(values, value) + } else { + values = append(values, key) + } } + return values +} - return fmt.Errorf("unsupported deployment target '%s'", target.Endpoint.GetCommunicationStyle()) +func getEndpointDetails(target *machines.DeploymentTarget) map[string]string { + details := make(map[string]string) + + switch target.Endpoint.GetCommunicationStyle() { + case "AzureWebApp": + if endpoint, ok := target.Endpoint.(*machines.AzureWebAppEndpoint); ok { + webApp := endpoint.WebAppName + if endpoint.WebAppSlotName != "" { + webApp = fmt.Sprintf("%s/%s", webApp, endpoint.WebAppSlotName) + } + details["Web App"] = webApp + } + case "Kubernetes": + if endpoint, ok := target.Endpoint.(*machines.KubernetesEndpoint); ok { + details["Authentication Type"] = endpoint.Authentication.GetAuthenticationType() + } + case "Ssh": + if endpoint, ok := target.Endpoint.(*machines.SSHEndpoint); ok { + details["URI"] = endpoint.URI.String() + runtime := "Mono" + if endpoint.DotNetCorePlatform != "" { + runtime = endpoint.DotNetCorePlatform + } + details["Runtime architecture"] = runtime + } + case "TentaclePassive": + if endpoint, ok := target.Endpoint.(*machines.ListeningTentacleEndpoint); ok { + details["URI"] = endpoint.URI.String() + details["Tentacle version"] = endpoint.TentacleVersionDetails.Version + } + case "TentacleActive": + if endpoint, ok := target.Endpoint.(*machines.PollingTentacleEndpoint); ok { + details["URI"] = endpoint.URI.String() + details["Tentacle version"] = endpoint.TentacleVersionDetails.Version + } + case "None": + // Cloud regions typically don't have additional endpoint details + case "OfflineDrop", "StepPackage", "AzureCloudService", "AzureServiceFabricCluster": + // These endpoints don't have specific details we can easily extract + } + + return details } From 2f7c05d2b161aa63daab45c3173755b0fbec6ac5 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Thu, 7 Aug 2025 18:07:29 +1000 Subject: [PATCH 2/2] tidy --- pkg/cmd/target/shared/view.go | 2 - pkg/cmd/target/view/view.go | 71 ++++++++++++++++------------------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/pkg/cmd/target/shared/view.go b/pkg/cmd/target/shared/view.go index a535f967..f1bbe3ca 100644 --- a/pkg/cmd/target/shared/view.go +++ b/pkg/cmd/target/shared/view.go @@ -96,8 +96,6 @@ func ViewRun(opts *ViewOptions, contributeEndpoint ContributeEndpointCallback, d fmt.Fprintf(opts.Out, "\n") machinescommon.DoWebForTargets(target, opts.Dependencies, opts.WebFlags, description) return nil - - return nil } func ContributeProxy(opts *ViewOptions, proxyID string) ([]*output.DataRow, error) { diff --git a/pkg/cmd/target/view/view.go b/pkg/cmd/target/view/view.go index 212138fd..c3e30725 100644 --- a/pkg/cmd/target/view/view.go +++ b/pkg/cmd/target/view/view.go @@ -44,11 +44,6 @@ func ViewRun(opts *shared.ViewOptions) error { return err } - // Use basic format as default for deployment target view when no -f flag is specified - if !opts.Command.Flags().Changed(constants.FlagOutputFormat) { - opts.Command.Flags().Set(constants.FlagOutputFormat, constants.OutputFormatBasic) - } - return output.PrintResource(target, opts.Command, output.Mappers[*machines.DeploymentTarget]{ Json: func(t *machines.DeploymentTarget) any { return getDeploymentTargetAsJson(opts, t) @@ -66,28 +61,28 @@ func ViewRun(opts *shared.ViewOptions) error { } type DeploymentTargetAsJson struct { - Id string `json:"Id"` - Name string `json:"Name"` - HealthStatus string `json:"HealthStatus"` - StatusSummary string `json:"StatusSummary"` - CommunicationStyle string `json:"CommunicationStyle"` - Environments []string `json:"Environments"` - Roles []string `json:"Roles"` - Tenants []string `json:"Tenants"` - TenantTags []string `json:"TenantTags"` - EndpointDetails map[string]string `json:"EndpointDetails"` - WebUrl string `json:"WebUrl"` + Id string `json:"Id"` + Name string `json:"Name"` + HealthStatus string `json:"HealthStatus"` + StatusSummary string `json:"StatusSummary"` + CommunicationStyle string `json:"CommunicationStyle"` + Environments []string `json:"Environments"` + Roles []string `json:"Roles"` + Tenants []string `json:"Tenants"` + TenantTags []string `json:"TenantTags"` + EndpointDetails map[string]string `json:"EndpointDetails"` + WebUrl string `json:"WebUrl"` } func getDeploymentTargetAsJson(opts *shared.ViewOptions, target *machines.DeploymentTarget) DeploymentTargetAsJson { environmentMap, _ := shared.GetEnvironmentMap(opts) tenantMap, _ := shared.GetTenantMap(opts) - + environments := resolveValues(target.EnvironmentIDs, environmentMap) tenants := resolveValues(target.TenantIDs, tenantMap) - + endpointDetails := getEndpointDetails(target) - + return DeploymentTargetAsJson{ Id: target.GetID(), Name: target.Name, @@ -106,10 +101,10 @@ func getDeploymentTargetAsJson(opts *shared.ViewOptions, target *machines.Deploy func getDeploymentTargetAsTableRow(opts *shared.ViewOptions, target *machines.DeploymentTarget) []string { environmentMap, _ := shared.GetEnvironmentMap(opts) environments := resolveValues(target.EnvironmentIDs, environmentMap) - + healthStatus := getHealthStatusFormatted(target.HealthStatus) targetType := getTargetTypeDisplayName(target.Endpoint.GetCommunicationStyle()) - + // Handle tenants tenants := "None" if !util.Empty(target.TenantIDs) { @@ -117,13 +112,13 @@ func getDeploymentTargetAsTableRow(opts *shared.ViewOptions, target *machines.De tenantNames := resolveValues(target.TenantIDs, tenantMap) tenants = strings.Join(tenantNames, ", ") } - + // Handle tenant tags tenantTags := "None" if !util.Empty(target.TenantTags) { tenantTags = strings.Join(target.TenantTags, ", ") } - + // Handle endpoint details endpointDetails := getEndpointDetails(target) var endpointDetailsStr strings.Builder @@ -139,7 +134,7 @@ func getDeploymentTargetAsTableRow(opts *shared.ViewOptions, target *machines.De if endpointDetailsString == "" { endpointDetailsString = "-" } - + return []string{ output.Bold(target.Name), targetType, @@ -192,35 +187,35 @@ func getTargetTypeDisplayName(communicationStyle string) string { func getDeploymentTargetAsBasic(opts *shared.ViewOptions, target *machines.DeploymentTarget) string { var result strings.Builder - + // Header result.WriteString(fmt.Sprintf("%s %s\n", output.Bold(target.Name), output.Dimf("(%s)", target.GetID()))) - + // Health status healthStatus := getHealthStatusFormatted(target.HealthStatus) result.WriteString(fmt.Sprintf("Health status: %s\n", healthStatus)) - + // Current status result.WriteString(fmt.Sprintf("Current status: %s\n", target.StatusSummary)) - + // Target type and endpoint details targetType := getTargetTypeDisplayName(target.Endpoint.GetCommunicationStyle()) result.WriteString(fmt.Sprintf("Type: %s\n", output.Cyan(targetType))) - + // Add endpoint-specific details endpointDetails := getEndpointDetails(target) for key, value := range endpointDetails { result.WriteString(fmt.Sprintf("%s: %s\n", key, value)) } - + // Environments environmentMap, _ := shared.GetEnvironmentMap(opts) environments := resolveValues(target.EnvironmentIDs, environmentMap) result.WriteString(fmt.Sprintf("Environments: %s\n", output.FormatAsList(environments))) - + // Roles result.WriteString(fmt.Sprintf("Roles: %s\n", output.FormatAsList(target.Roles))) - + // Tenants if !util.Empty(target.TenantIDs) { tenantMap, _ := shared.GetTenantMap(opts) @@ -229,23 +224,23 @@ func getDeploymentTargetAsBasic(opts *shared.ViewOptions, target *machines.Deplo } else { result.WriteString("Tenants: None\n") } - + // Tenant Tags if !util.Empty(target.TenantTags) { result.WriteString(fmt.Sprintf("Tenant Tags: %s\n", output.FormatAsList(target.TenantTags))) } else { result.WriteString("Tenant Tags: None\n") } - + // Web URL url := util.GenerateWebURL(opts.Host, target.SpaceID, fmt.Sprintf("infrastructure/machines/%s/settings", target.GetID())) result.WriteString(fmt.Sprintf("\nView this deployment target in Octopus Deploy: %s\n", output.Blue(url))) - + // Handle web flag if opts.WebFlags != nil && opts.WebFlags.Web.Value { machinescommon.DoWebForTargets(target, opts.Dependencies, opts.WebFlags, targetType) } - + return result.String() } @@ -263,7 +258,7 @@ func resolveValues(keys []string, lookup map[string]string) []string { func getEndpointDetails(target *machines.DeploymentTarget) map[string]string { details := make(map[string]string) - + switch target.Endpoint.GetCommunicationStyle() { case "AzureWebApp": if endpoint, ok := target.Endpoint.(*machines.AzureWebAppEndpoint); ok { @@ -301,6 +296,6 @@ func getEndpointDetails(target *machines.DeploymentTarget) map[string]string { case "OfflineDrop", "StepPackage", "AzureCloudService", "AzureServiceFabricCluster": // These endpoints don't have specific details we can easily extract } - + return details }