From 39cdbfe430213551f8f6ebdef9093449bb586d2d Mon Sep 17 00:00:00 2001 From: Alex Lubbock Date: Wed, 22 Apr 2026 23:25:22 +0100 Subject: [PATCH 1/7] fix(kubernetes): add output format handling to nodepool instance delete --- .../kubernetes_nodepool_instance_delete.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/kubernetes/kubernetes_nodepool_instance_delete.go b/cmd/kubernetes/kubernetes_nodepool_instance_delete.go index 1e9dba0b..a3a62b86 100644 --- a/cmd/kubernetes/kubernetes_nodepool_instance_delete.go +++ b/cmd/kubernetes/kubernetes_nodepool_instance_delete.go @@ -63,7 +63,20 @@ var kubernetesNodePoolInstanceDeleteCmd = &cobra.Command{ os.Exit(1) } - fmt.Printf("Instance %s has been deleted from node pool %s in cluster %s\n", instanceID, nodePoolID, kubernetesFindCluster.Name) + ow := utility.NewOutputWriter() + ow.StartLine() + ow.AppendDataWithLabel("instance_id", instanceID, "Instance ID") + ow.AppendDataWithLabel("node_pool_id", nodePoolID, "Node Pool ID") + ow.AppendDataWithLabel("cluster_name", kubernetesFindCluster.Name, "Cluster Name") + + switch common.OutputFormat { + case "json": + ow.WriteSingleObjectJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + fmt.Printf("Instance %s has been deleted from node pool %s in cluster %s\n", instanceID, nodePoolID, kubernetesFindCluster.Name) + } } else { fmt.Println("Operation aborted.") } From d23935e3ed8d36ebcc35d65ca95f517c8b5245d6 Mon Sep 17 00:00:00 2001 From: Alex Lubbock Date: Wed, 22 Apr 2026 23:26:51 +0100 Subject: [PATCH 2/7] fix(kubernetes): move WriteCustomOutput to correct case in cluster remove switch --- cmd/kubernetes/kubernetes_remove.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/kubernetes/kubernetes_remove.go b/cmd/kubernetes/kubernetes_remove.go index d680d312..ffef9929 100644 --- a/cmd/kubernetes/kubernetes_remove.go +++ b/cmd/kubernetes/kubernetes_remove.go @@ -118,6 +118,7 @@ var kubernetesRemoveCmd = &cobra.Command{ } else { ow.WriteMultipleObjectsJSON(common.PrettySet) } + case "custom": ow.WriteCustomOutput(common.OutputFields) default: fmt.Printf("The Kubernetes %s (%s) %s been deleted\n", From a92fcd3e68d63ccfb649716f29d480f1802f7928 Mon Sep 17 00:00:00 2001 From: Alex Lubbock Date: Wed, 22 Apr 2026 23:26:55 +0100 Subject: [PATCH 3/7] fix(apikey): add output format handling to apikey remove --- cmd/apikey/apikey_remove.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cmd/apikey/apikey_remove.go b/cmd/apikey/apikey_remove.go index 29abbb6d..afd0ea51 100644 --- a/cmd/apikey/apikey_remove.go +++ b/cmd/apikey/apikey_remove.go @@ -41,7 +41,18 @@ var apikeyRemoveCmd = &cobra.Command{ config.SaveConfig() if numKeys > len(config.Current.APIKeys) { - fmt.Printf("Removed the API Key %s\n", utility.Green(index)) + ow := utility.NewOutputWriter() + ow.StartLine() + ow.AppendDataWithLabel("name", index, "Name") + + switch common.OutputFormat { + case "json": + ow.WriteSingleObjectJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + fmt.Printf("Removed the API Key %s\n", utility.Green(index)) + } } else { utility.Error("The API Key %q couldn't be found", args[0]) os.Exit(1) From fd7e392169e178c7b6d13c49ee8a99982cb6bcc8 Mon Sep 17 00:00:00 2001 From: Alex Lubbock Date: Wed, 22 Apr 2026 23:38:01 +0100 Subject: [PATCH 4/7] fix(apikey): add output format handling to apikey set --- cmd/apikey/apikey_current.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/apikey/apikey_current.go b/cmd/apikey/apikey_current.go index 6e545f88..460200af 100644 --- a/cmd/apikey/apikey_current.go +++ b/cmd/apikey/apikey_current.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/civo/cli/common" "github.com/civo/cli/config" "github.com/civo/cli/utility" "github.com/spf13/cobra" @@ -24,7 +25,19 @@ var apikeyCurrentCmd = &cobra.Command{ if index != "" { config.Current.Meta.CurrentAPIKey = index config.SaveConfig() - fmt.Printf("Set the default API Key to be %s\n", utility.Green(index)) + + ow := utility.NewOutputWriter() + ow.StartLine() + ow.AppendDataWithLabel("name", index, "Name") + + switch common.OutputFormat { + case "json": + ow.WriteSingleObjectJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + fmt.Printf("Set the default API Key to be %s\n", utility.Green(index)) + } } }, From dd62518afc1ccced192694ebf756ffe448e08812 Mon Sep 17 00:00:00 2001 From: Alex Lubbock Date: Wed, 22 Apr 2026 23:38:05 +0100 Subject: [PATCH 5/7] fix(instance): add output format handling to public-ip and recovery commands --- cmd/instance/instance_ip.go | 21 +++++++++++++++++---- cmd/instance/instance_recovery.go | 23 +++++++++++++++++------ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/cmd/instance/instance_ip.go b/cmd/instance/instance_ip.go index 58be013a..bbd21578 100644 --- a/cmd/instance/instance_ip.go +++ b/cmd/instance/instance_ip.go @@ -51,10 +51,23 @@ var instancePublicIPCmd = &cobra.Command{ utility.Error("%s", err) } - if args[0] == "disable" { - fmt.Printf("Instance %s has been updated to NOT have a Public IP\n", utility.Green(instance.Hostname)) - } else { - fmt.Printf("Instance %s has been updated to have a Public IP. IP addressed will be assigned shortly.\n", utility.Green(instance.Hostname)) + ow := utility.NewOutputWriter() + ow.StartLine() + ow.AppendDataWithLabel("id", instance.ID, "ID") + ow.AppendDataWithLabel("hostname", instance.Hostname, "Hostname") + ow.AppendDataWithLabel("public_ip", args[0], "Public IP") + + switch common.OutputFormat { + case "json": + ow.WriteSingleObjectJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + if args[0] == "disable" { + fmt.Printf("Instance %s has been updated to NOT have a Public IP\n", utility.Green(instance.Hostname)) + } else { + fmt.Printf("Instance %s has been updated to have a Public IP. IP addressed will be assigned shortly.\n", utility.Green(instance.Hostname)) + } } }, } diff --git a/cmd/instance/instance_recovery.go b/cmd/instance/instance_recovery.go index 24ca5341..a9a885f3 100644 --- a/cmd/instance/instance_recovery.go +++ b/cmd/instance/instance_recovery.go @@ -47,8 +47,6 @@ Example: utility.Error("%s", err) os.Exit(1) } - fmt.Println("Instance ID is: ", instance.ID) - if args[0] == "enable" { _, err := client.EnableRecoveryMode(instance.ID) if err != nil { @@ -63,10 +61,23 @@ Example: } } - if args[0] == "enable" { - fmt.Printf("Recovery mode has been enabled for instance %s\n", utility.Green(instance.Hostname)) - } else { - fmt.Printf("Recovery mode has been disabled for instance %s\n", utility.Green(instance.Hostname)) + ow := utility.NewOutputWriter() + ow.StartLine() + ow.AppendDataWithLabel("id", instance.ID, "ID") + ow.AppendDataWithLabel("hostname", instance.Hostname, "Hostname") + ow.AppendDataWithLabel("recovery_mode", args[0], "Recovery Mode") + + switch common.OutputFormat { + case "json": + ow.WriteSingleObjectJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + if args[0] == "enable" { + fmt.Printf("Recovery mode has been enabled for instance %s\n", utility.Green(instance.Hostname)) + } else { + fmt.Printf("Recovery mode has been disabled for instance %s\n", utility.Green(instance.Hostname)) + } } }, } From 5913c20d9c4685cb7d1efb3cdb39945cb53580eb Mon Sep 17 00:00:00 2001 From: Alex Lubbock Date: Wed, 22 Apr 2026 23:38:08 +0100 Subject: [PATCH 6/7] fix(kubernetes,network): add output format handling to update-kubeconfig and network show --- .../kubernetes_update_kubeconfig.go | 14 +++- cmd/network/network_show.go | 76 ++++++++++++------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/cmd/kubernetes/kubernetes_update_kubeconfig.go b/cmd/kubernetes/kubernetes_update_kubeconfig.go index ab5e547c..289a63af 100644 --- a/cmd/kubernetes/kubernetes_update_kubeconfig.go +++ b/cmd/kubernetes/kubernetes_update_kubeconfig.go @@ -39,6 +39,18 @@ var kubernetesUpdateKubeconfigCmd = &cobra.Command{ os.Exit(1) } - fmt.Printf("Updated kubeconfig with cluster %s configuration\n", utility.Green(cluster.Name)) + ow := utility.NewOutputWriter() + ow.StartLine() + ow.AppendDataWithLabel("id", cluster.ID, "ID") + ow.AppendDataWithLabel("name", cluster.Name, "Name") + + switch common.OutputFormat { + case "json": + ow.WriteSingleObjectJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + fmt.Printf("Updated kubeconfig with cluster %s configuration\n", utility.Green(cluster.Name)) + } }, } diff --git a/cmd/network/network_show.go b/cmd/network/network_show.go index 5a80ee80..43f2d38f 100644 --- a/cmd/network/network_show.go +++ b/cmd/network/network_show.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/civo/cli/common" "github.com/civo/cli/config" "github.com/civo/cli/utility" "github.com/spf13/cobra" @@ -29,36 +30,57 @@ var networkShowCmd = &cobra.Command{ os.Exit(1) } - // Display Core Network Details - fmt.Println("Network Details:") - fmt.Printf("ID: %s\n", network.ID) - fmt.Printf("Name: %s\n", network.Name) - fmt.Printf("Default: %s\n", utility.BoolToYesNo(network.Default)) - fmt.Printf("CIDR: %s\n", network.CIDR) - fmt.Printf("Status: %s\n", network.Status) - fmt.Printf("IPv4 Enabled: %s\n", utility.BoolToYesNo(network.IPv4Enabled)) - fmt.Printf("IPv6 Enabled: %s\n", utility.BoolToYesNo(network.IPv6Enabled)) + ow := utility.NewOutputWriter() + ow.StartLine() + ow.AppendDataWithLabel("id", network.ID, "ID") + ow.AppendDataWithLabel("name", network.Name, "Name") + ow.AppendDataWithLabel("default", utility.BoolToYesNo(network.Default), "Default") + ow.AppendDataWithLabel("cidr", network.CIDR, "CIDR") + ow.AppendDataWithLabel("status", network.Status, "Status") + ow.AppendDataWithLabel("ipv4_enabled", utility.BoolToYesNo(network.IPv4Enabled), "IPv4 Enabled") + ow.AppendDataWithLabel("ipv6_enabled", utility.BoolToYesNo(network.IPv6Enabled), "IPv6 Enabled") + ow.AppendDataWithLabel("vlan_id", fmt.Sprintf("%d", network.VlanID), "VLAN ID") + ow.AppendDataWithLabel("physical_interface", network.PhysicalInterface, "Hardware Address") + ow.AppendDataWithLabel("gateway_ipv4", network.GatewayIPv4, "Gateway IPv4") + ow.AppendDataWithLabel("allocation_pool_v4_start", network.AllocationPoolV4Start, "Allocation Pool IPv4 Start") + ow.AppendDataWithLabel("allocation_pool_v4_end", network.AllocationPoolV4End, "Allocation Pool IPv4 End") + ow.AppendDataWithLabel("nameservers_v4", utility.SliceToString(network.NameserversV4), "Nameservers IPv4") + ow.AppendDataWithLabel("nameservers_v6", utility.SliceToString(network.NameserversV6), "Nameservers IPv6") - // Conditional VLAN Details - if network.VlanID != 0 { - fmt.Println("\nVLAN Details:") - fmt.Printf("VLAN ID: %d\n", network.VlanID) - fmt.Printf("Hardware Address: %s\n", network.PhysicalInterface) - fmt.Printf("Gateway IPv4: %s\n", network.GatewayIPv4) - fmt.Printf("Allocation Pool IPv4 Start: %s\n", network.AllocationPoolV4Start) - fmt.Printf("Allocation Pool IPv4 End: %s\n", network.AllocationPoolV4End) - } else { - fmt.Println("\nNo VLAN Configuration") - } + switch common.OutputFormat { + case "json": + ow.WriteSingleObjectJSON(common.PrettySet) + case "custom": + ow.WriteCustomOutput(common.OutputFields) + default: + fmt.Println("Network Details:") + fmt.Printf("ID: %s\n", network.ID) + fmt.Printf("Name: %s\n", network.Name) + fmt.Printf("Default: %s\n", utility.BoolToYesNo(network.Default)) + fmt.Printf("CIDR: %s\n", network.CIDR) + fmt.Printf("Status: %s\n", network.Status) + fmt.Printf("IPv4 Enabled: %s\n", utility.BoolToYesNo(network.IPv4Enabled)) + fmt.Printf("IPv6 Enabled: %s\n", utility.BoolToYesNo(network.IPv6Enabled)) - // Nameserver Details - if len(network.NameserversV4) > 0 || len(network.NameserversV6) > 0 { - fmt.Println("\nNameserver Details:") - if len(network.NameserversV4) > 0 { - fmt.Printf("Nameservers IPv4: %s\n", utility.SliceToString(network.NameserversV4)) + if network.VlanID != 0 { + fmt.Println("\nVLAN Details:") + fmt.Printf("VLAN ID: %d\n", network.VlanID) + fmt.Printf("Hardware Address: %s\n", network.PhysicalInterface) + fmt.Printf("Gateway IPv4: %s\n", network.GatewayIPv4) + fmt.Printf("Allocation Pool IPv4 Start: %s\n", network.AllocationPoolV4Start) + fmt.Printf("Allocation Pool IPv4 End: %s\n", network.AllocationPoolV4End) + } else { + fmt.Println("\nNo VLAN Configuration") } - if len(network.NameserversV6) > 0 { - fmt.Printf("Nameservers IPv6: %s\n", utility.SliceToString(network.NameserversV6)) + + if len(network.NameserversV4) > 0 || len(network.NameserversV6) > 0 { + fmt.Println("\nNameserver Details:") + if len(network.NameserversV4) > 0 { + fmt.Printf("Nameservers IPv4: %s\n", utility.SliceToString(network.NameserversV4)) + } + if len(network.NameserversV6) > 0 { + fmt.Printf("Nameservers IPv6: %s\n", utility.SliceToString(network.NameserversV6)) + } } } }, From fa2de32a033f76ed0c900a26d05d772ed4a0e1c1 Mon Sep 17 00:00:00 2001 From: Alex Lubbock Date: Sun, 24 May 2026 15:01:53 +0100 Subject: [PATCH 7/7] fix(network,instance): address PR review feedback network show: guard VLAN-specific fields (vlan_id, physical_interface, allocation_pool_v4_start, allocation_pool_v4_end) behind VlanID \!= 0 so they are omitted from JSON/custom output on non-VLAN networks. Use strconv.Itoa for VlanID, consistent with network list. Move gateway_ipv4 outside the VLAN guard -- it is relevant to all networks. instance recovery: restore instance UUID in human output, shown in parentheses after the hostname. --- cmd/instance/instance_recovery.go | 4 ++-- cmd/network/network_show.go | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cmd/instance/instance_recovery.go b/cmd/instance/instance_recovery.go index a9a885f3..20d9a9ae 100644 --- a/cmd/instance/instance_recovery.go +++ b/cmd/instance/instance_recovery.go @@ -74,9 +74,9 @@ Example: ow.WriteCustomOutput(common.OutputFields) default: if args[0] == "enable" { - fmt.Printf("Recovery mode has been enabled for instance %s\n", utility.Green(instance.Hostname)) + fmt.Printf("Recovery mode has been enabled for instance %s (%s)\n", utility.Green(instance.Hostname), instance.ID) } else { - fmt.Printf("Recovery mode has been disabled for instance %s\n", utility.Green(instance.Hostname)) + fmt.Printf("Recovery mode has been disabled for instance %s (%s)\n", utility.Green(instance.Hostname), instance.ID) } } }, diff --git a/cmd/network/network_show.go b/cmd/network/network_show.go index 43f2d38f..caf30291 100644 --- a/cmd/network/network_show.go +++ b/cmd/network/network_show.go @@ -3,6 +3,7 @@ package network import ( "fmt" "os" + "strconv" "github.com/civo/cli/common" "github.com/civo/cli/config" @@ -39,11 +40,13 @@ var networkShowCmd = &cobra.Command{ ow.AppendDataWithLabel("status", network.Status, "Status") ow.AppendDataWithLabel("ipv4_enabled", utility.BoolToYesNo(network.IPv4Enabled), "IPv4 Enabled") ow.AppendDataWithLabel("ipv6_enabled", utility.BoolToYesNo(network.IPv6Enabled), "IPv6 Enabled") - ow.AppendDataWithLabel("vlan_id", fmt.Sprintf("%d", network.VlanID), "VLAN ID") - ow.AppendDataWithLabel("physical_interface", network.PhysicalInterface, "Hardware Address") ow.AppendDataWithLabel("gateway_ipv4", network.GatewayIPv4, "Gateway IPv4") - ow.AppendDataWithLabel("allocation_pool_v4_start", network.AllocationPoolV4Start, "Allocation Pool IPv4 Start") - ow.AppendDataWithLabel("allocation_pool_v4_end", network.AllocationPoolV4End, "Allocation Pool IPv4 End") + if network.VlanID != 0 { + ow.AppendDataWithLabel("vlan_id", strconv.Itoa(network.VlanID), "VLAN ID") + ow.AppendDataWithLabel("physical_interface", network.PhysicalInterface, "Hardware Address") + ow.AppendDataWithLabel("allocation_pool_v4_start", network.AllocationPoolV4Start, "Allocation Pool IPv4 Start") + ow.AppendDataWithLabel("allocation_pool_v4_end", network.AllocationPoolV4End, "Allocation Pool IPv4 End") + } ow.AppendDataWithLabel("nameservers_v4", utility.SliceToString(network.NameserversV4), "Nameservers IPv4") ow.AppendDataWithLabel("nameservers_v6", utility.SliceToString(network.NameserversV6), "Nameservers IPv6") @@ -61,12 +64,12 @@ var networkShowCmd = &cobra.Command{ fmt.Printf("Status: %s\n", network.Status) fmt.Printf("IPv4 Enabled: %s\n", utility.BoolToYesNo(network.IPv4Enabled)) fmt.Printf("IPv6 Enabled: %s\n", utility.BoolToYesNo(network.IPv6Enabled)) + fmt.Printf("Gateway IPv4: %s\n", network.GatewayIPv4) if network.VlanID != 0 { fmt.Println("\nVLAN Details:") fmt.Printf("VLAN ID: %d\n", network.VlanID) fmt.Printf("Hardware Address: %s\n", network.PhysicalInterface) - fmt.Printf("Gateway IPv4: %s\n", network.GatewayIPv4) fmt.Printf("Allocation Pool IPv4 Start: %s\n", network.AllocationPoolV4Start) fmt.Printf("Allocation Pool IPv4 End: %s\n", network.AllocationPoolV4End) } else {