From 604ebfab9b84dfc8a346145b280fa0304ffa117e Mon Sep 17 00:00:00 2001
From: Vishal Anarse <vishal@civo.com>
Date: Sat, 28 Oct 2023 17:46:18 +0530
Subject: [PATCH 1/3] Support manual backup

Signed-off-by: Vishal Anarse <vishal@civo.com>
---
 cmd/database/database_backup.go        |  3 +-
 cmd/database/database_backup_create.go | 89 +++++++++++++++-----------
 cmd/database/database_backup_list.go   | 59 ++++++++++++-----
 cmd/database/database_backup_update.go |  2 +-
 4 files changed, 98 insertions(+), 55 deletions(-)

diff --git a/cmd/database/database_backup.go b/cmd/database/database_backup.go
index 3035dac1..9950393a 100644
--- a/cmd/database/database_backup.go
+++ b/cmd/database/database_backup.go
@@ -8,6 +8,7 @@ import (
 
 var name, schedule string
 var count int
+var manual bool
 
 // dbBackupCmd is the root command for the db backup subcommand
 var dbBackupCmd = &cobra.Command{
@@ -33,9 +34,9 @@ func init() {
 	dbBackupCreateCmd.Flags().StringVarP(&name, "name", "n", "", "name of the database backup")
 	dbBackupCreateCmd.Flags().StringVarP(&schedule, "schedule", "s", "", "schedule of the database backup in the form of cronjob")
 	dbBackupCreateCmd.Flags().IntVarP(&count, "count", "c", 1, "number of backups to keep")
+	dbBackupCreateCmd.Flags().BoolVarP(&manual, "manual", "m", false, "set only if backup is manual/instant")
 
 	dbBackupCreateCmd.MarkFlagRequired("name")
-	dbBackupCreateCmd.MarkFlagRequired("schedule")
 
 	// Update cmd options
 	dbBackupUpdateCmd.Flags().StringVarP(&name, "name", "n", "", "name of the database backup")
diff --git a/cmd/database/database_backup_create.go b/cmd/database/database_backup_create.go
index c01bd96f..a3c0f0d8 100644
--- a/cmd/database/database_backup_create.go
+++ b/cmd/database/database_backup_create.go
@@ -15,9 +15,10 @@ import (
 var dbBackupCreateCmd = &cobra.Command{
 	Use:     "create",
 	Aliases: []string{"new", "add"},
-	Example: "civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --schedule <SCHEDULE> --count <COUNT>",
-	Short:   "Create a new database backup",
-	Args:    cobra.MinimumNArgs(1),
+	Example: `Scheduled: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --schedule <SCHEDULE> --count <COUNT>\n
+	Manual: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --manual`,
+	Short: "Create a new database backup",
+	Args:  cobra.MinimumNArgs(1),
 	Run: func(cmd *cobra.Command, args []string) {
 		utility.EnsureCurrentRegion()
 
@@ -38,53 +39,69 @@ var dbBackupCreateCmd = &cobra.Command{
 			os.Exit(1)
 		}
 
-		if common.RegionSet != "" {
-			client.Region = common.RegionSet
-		}
-
-		if count <= 0 {
-			utility.Error("Count must be greater than zero, you have given: %d", count)
-			os.Exit(1)
-		}
-
-		if schedule == "" {
-			utility.Error("Schedule must be specified")
-			os.Exit(1)
-		}
-
-		gron := gronx.New()
-		if !gron.IsValid(schedule) {
-			utility.Error("Invalid schedule, you have given: %s", schedule)
-			os.Exit(1)
-		}
-
 		db, err := client.FindDatabase(args[0])
 		if err != nil {
 			utility.Error("Database %s", err)
 			os.Exit(1)
 		}
 
-		backupCreateConfig := civogo.DatabaseBackupCreateRequest{
-			Name:     name,
-			Schedule: schedule,
-			Count:    int32(count),
-			Region:   client.Region,
+		backupCreateConfig := civogo.DatabaseBackupCreateRequest{}
+		if !manual {
+			if common.RegionSet != "" {
+				client.Region = common.RegionSet
+			}
+
+			if count <= 0 {
+				utility.Error("Count must be greater than zero, you have given: %d", count)
+				os.Exit(1)
+			}
+
+			if schedule == "" {
+				utility.Error("Schedule must be specified")
+				os.Exit(1)
+			}
+
+			gron := gronx.New()
+			if !gron.IsValid(schedule) {
+				utility.Error("Invalid schedule, you have given: %s", schedule)
+				os.Exit(1)
+			}
+
+			backupCreateConfig.Name = name
+			backupCreateConfig.Schedule = schedule
+			backupCreateConfig.Count = int32(count)
+
+		} else {
+			backupCreateConfig.Name = name
+			backupCreateConfig.IsManual = manual
 		}
 
+		backupCreateConfig.Region = client.Region
 		bk, err := client.CreateDatabaseBackup(db.ID, &backupCreateConfig)
 		if err != nil {
 			utility.Error("Error creating database %s", err)
 			os.Exit(1)
 		}
 
-		ow := utility.NewOutputWriterWithMap(map[string]string{
-			"database_id":   bk.DatabaseID,
-			"database_name": bk.DatabaseName,
-			"software":      bk.Software,
-			"name":          bk.Scheduled.Name,
-			"schedule":      bk.Scheduled.Schedule,
-			"count":         fmt.Sprintf("%d", count),
-		})
+		ow := &utility.OutputWriter{}
+		if !manual {
+			ow = utility.NewOutputWriterWithMap(map[string]string{
+				"database_id":   bk.DatabaseID,
+				"database_name": bk.DatabaseName,
+				"software":      bk.Software,
+				"name":          bk.Scheduled.Name,
+				"schedule":      bk.Scheduled.Schedule,
+				"count":         fmt.Sprintf("%d", count),
+			})
+		} else {
+			ow = utility.NewOutputWriterWithMap(map[string]string{
+				"database_id":   bk.DatabaseID,
+				"database_name": bk.DatabaseName,
+				"software":      bk.Software,
+				"name":          bk.Scheduled.Name,
+			})
+		}
+
 		switch common.OutputFormat {
 		case "json":
 			ow.WriteSingleObjectJSON(common.PrettySet)
diff --git a/cmd/database/database_backup_list.go b/cmd/database/database_backup_list.go
index 4f1b96db..c4670c3e 100644
--- a/cmd/database/database_backup_list.go
+++ b/cmd/database/database_backup_list.go
@@ -3,6 +3,7 @@ package database
 import (
 	"fmt"
 	"os"
+	"strings"
 
 	"github.com/civo/cli/common"
 	"github.com/civo/cli/config"
@@ -45,34 +46,58 @@ var dbBackupListCmd = &cobra.Command{
 			return
 		}
 
-		ow := utility.NewOutputWriter()
-		ow.StartLine()
-		ow.AppendDataWithLabel("database_id", utility.TrimID(backups.DatabaseID), "Database ID")
-		ow.AppendDataWithLabel("database_name", backups.DatabaseName, "Database Name")
-		ow.AppendDataWithLabel("name", backups.Scheduled.Name, "Backup Name")
-		ow.AppendDataWithLabel("schedule", backups.Scheduled.Schedule, "Schedule")
-		ow.AppendDataWithLabel("count", fmt.Sprintf("%d", backups.Scheduled.Count), "Count")
+		odb := utility.NewOutputWriter()
+		ombk := utility.NewOutputWriter()
+		osbk := utility.NewOutputWriter()
+		mbk := ""
+		sbk := ""
 
-		bk := ""
-		for i, backup := range backups.Scheduled.Backups {
-			bk += backup
-			if i < len(backups.Scheduled.Backups)-1 {
-				bk += "\n"
+		odb.StartLine()
+		odb.AppendDataWithLabel("database_id", utility.TrimID(backups.DatabaseID), "Database ID")
+		odb.AppendDataWithLabel("database_name", backups.DatabaseName, "Database Name")
+		odb.AppendDataWithLabel("software", backups.Software, "Software")
+
+		if backups.Scheduled.Schedule != "" {
+			osbk.AppendDataWithLabel("name", backups.Scheduled.Name, "Backup Name")
+			osbk.AppendDataWithLabel("schedule", backups.Scheduled.Schedule, "Schedule")
+			osbk.AppendDataWithLabel("count", fmt.Sprintf("%d", backups.Scheduled.Count), "Count")
+
+			sbk = strings.TrimSuffix(strings.Join(backups.Scheduled.Backups, ","), ",")
+			osbk.AppendDataWithLabel("backups", sbk, "Backups")
+		}
+
+		if backups.Manual != nil {
+			for i, m := range backups.Manual {
+				if i < len(backups.Manual)-1 {
+					mbk += m.Backup + ", "
+				} else {
+					mbk += m.Backup
+				}
 			}
+			ombk.AppendDataWithLabel("backups", mbk, "Backups")
 		}
-		ow.AppendDataWithLabel("backups", bk, "Backups")
 
 		if common.OutputFormat == "json" || common.OutputFormat == "custom" {
-			ow.AppendDataWithLabel("software", backups.Software, "Software")
+			odb.AppendDataWithLabel("database_id", utility.TrimID(backups.DatabaseID), "Database ID")
+			odb.AppendDataWithLabel("database_name", backups.DatabaseName, "Database Name")
+			odb.AppendDataWithLabel("software", backups.Software, "Software")
+			odb.AppendDataWithLabel("schedule_backup_name", backups.Scheduled.Name, "Schedule Backup Name")
+			odb.AppendDataWithLabel("schedule", backups.Scheduled.Schedule, "Schedule")
+			odb.AppendDataWithLabel("count", fmt.Sprintf("%d", backups.Scheduled.Count), "Count")
+			odb.AppendDataWithLabel("scheduled_backups", sbk, "Schedule Backups")
+			odb.AppendDataWithLabel("manual_backups", mbk, "Manual Backups")
 		}
 
 		switch common.OutputFormat {
 		case "json":
-			ow.WriteMultipleObjectsJSON(common.PrettySet)
+			odb.WriteMultipleObjectsJSON(common.PrettySet)
 		case "custom":
-			ow.WriteCustomOutput(common.OutputFields)
+			odb.WriteCustomOutput(common.OutputFields)
 		default:
-			ow.WriteTable()
+			fmt.Println("Scheduled Backups:")
+			osbk.WriteTable()
+			fmt.Println("Manual Backups:")
+			ombk.WriteTable()
 		}
 	},
 }
diff --git a/cmd/database/database_backup_update.go b/cmd/database/database_backup_update.go
index 1281efc4..b0fe60b3 100644
--- a/cmd/database/database_backup_update.go
+++ b/cmd/database/database_backup_update.go
@@ -14,7 +14,7 @@ import (
 var dbBackupUpdateCmd = &cobra.Command{
 	Use:     "update",
 	Aliases: []string{"modify", "change"},
-	Short:   "Update a database backup",
+	Short:   "Update a scheduled database backup",
 	Example: "civo database backup update <DATABASE-NAME/ID> --name <NEW_BACKUP-NAME> --schedule <SCHEDULE> --count <COUNT>",
 	Args:    cobra.MinimumNArgs(1),
 	Run: func(cmd *cobra.Command, args []string) {

From 07721895e244544037aac40cac682778380110d0 Mon Sep 17 00:00:00 2001
From: Vishal Anarse <vishal@civo.com>
Date: Mon, 6 Nov 2023 17:28:30 +0530
Subject: [PATCH 2/3] Fix field issue

Signed-off-by: Vishal Anarse <vishal@civo.com>
---
 cmd/database/database_backup.go        |  5 ++---
 cmd/database/database_backup_create.go | 12 ++++++------
 cmd/database/database_backup_list.go   | 14 +++++++++++---
 go.mod                                 |  2 +-
 go.sum                                 |  4 ++--
 5 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/cmd/database/database_backup.go b/cmd/database/database_backup.go
index 9950393a..70bda3a9 100644
--- a/cmd/database/database_backup.go
+++ b/cmd/database/database_backup.go
@@ -6,9 +6,8 @@ import (
 	"github.com/spf13/cobra"
 )
 
-var name, schedule string
+var name, schedule, backupType string
 var count int
-var manual bool
 
 // dbBackupCmd is the root command for the db backup subcommand
 var dbBackupCmd = &cobra.Command{
@@ -34,7 +33,7 @@ func init() {
 	dbBackupCreateCmd.Flags().StringVarP(&name, "name", "n", "", "name of the database backup")
 	dbBackupCreateCmd.Flags().StringVarP(&schedule, "schedule", "s", "", "schedule of the database backup in the form of cronjob")
 	dbBackupCreateCmd.Flags().IntVarP(&count, "count", "c", 1, "number of backups to keep")
-	dbBackupCreateCmd.Flags().BoolVarP(&manual, "manual", "m", false, "set only if backup is manual/instant")
+	dbBackupCreateCmd.Flags().StringVarP(&backupType, "type", "t", "scheduled", "set the type of database backup manul/scheduled")
 
 	dbBackupCreateCmd.MarkFlagRequired("name")
 
diff --git a/cmd/database/database_backup_create.go b/cmd/database/database_backup_create.go
index a3c0f0d8..723608ba 100644
--- a/cmd/database/database_backup_create.go
+++ b/cmd/database/database_backup_create.go
@@ -16,7 +16,7 @@ var dbBackupCreateCmd = &cobra.Command{
 	Use:     "create",
 	Aliases: []string{"new", "add"},
 	Example: `Scheduled: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --schedule <SCHEDULE> --count <COUNT>\n
-	Manual: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --manual`,
+	Manual: civo database backup create <DATABASE-NAME/ID> --name <BACKUP_NAME> --type manual`,
 	Short: "Create a new database backup",
 	Args:  cobra.MinimumNArgs(1),
 	Run: func(cmd *cobra.Command, args []string) {
@@ -46,7 +46,7 @@ var dbBackupCreateCmd = &cobra.Command{
 		}
 
 		backupCreateConfig := civogo.DatabaseBackupCreateRequest{}
-		if !manual {
+		if backupType != "manual" {
 			if common.RegionSet != "" {
 				client.Region = common.RegionSet
 			}
@@ -73,7 +73,7 @@ var dbBackupCreateCmd = &cobra.Command{
 
 		} else {
 			backupCreateConfig.Name = name
-			backupCreateConfig.IsManual = manual
+			backupCreateConfig.Type = backupType
 		}
 
 		backupCreateConfig.Region = client.Region
@@ -84,7 +84,7 @@ var dbBackupCreateCmd = &cobra.Command{
 		}
 
 		ow := &utility.OutputWriter{}
-		if !manual {
+		if backupType != "manual" {
 			ow = utility.NewOutputWriterWithMap(map[string]string{
 				"database_id":   bk.DatabaseID,
 				"database_name": bk.DatabaseName,
@@ -98,7 +98,7 @@ var dbBackupCreateCmd = &cobra.Command{
 				"database_id":   bk.DatabaseID,
 				"database_name": bk.DatabaseName,
 				"software":      bk.Software,
-				"name":          bk.Scheduled.Name,
+				"name":          name,
 			})
 		}
 
@@ -108,7 +108,7 @@ var dbBackupCreateCmd = &cobra.Command{
 		case "custom":
 			ow.WriteCustomOutput(common.OutputFields)
 		default:
-			fmt.Printf("Database backup (%s) for database %s has been created\n", utility.Green(bk.Scheduled.Name), utility.Green(bk.DatabaseName))
+			fmt.Printf("Database backup (%s) for database %s has been created\n", utility.Green(name), utility.Green(bk.DatabaseName))
 		}
 	},
 }
diff --git a/cmd/database/database_backup_list.go b/cmd/database/database_backup_list.go
index c4670c3e..e4ed7202 100644
--- a/cmd/database/database_backup_list.go
+++ b/cmd/database/database_backup_list.go
@@ -51,13 +51,16 @@ var dbBackupListCmd = &cobra.Command{
 		osbk := utility.NewOutputWriter()
 		mbk := ""
 		sbk := ""
+		isConfiguredScheduled := false
+		isConfiguredManual := false
 
 		odb.StartLine()
 		odb.AppendDataWithLabel("database_id", utility.TrimID(backups.DatabaseID), "Database ID")
 		odb.AppendDataWithLabel("database_name", backups.DatabaseName, "Database Name")
 		odb.AppendDataWithLabel("software", backups.Software, "Software")
 
-		if backups.Scheduled.Schedule != "" {
+		if backups.Scheduled != nil {
+			isConfiguredScheduled = true
 			osbk.AppendDataWithLabel("name", backups.Scheduled.Name, "Backup Name")
 			osbk.AppendDataWithLabel("schedule", backups.Scheduled.Schedule, "Schedule")
 			osbk.AppendDataWithLabel("count", fmt.Sprintf("%d", backups.Scheduled.Count), "Count")
@@ -67,6 +70,7 @@ var dbBackupListCmd = &cobra.Command{
 		}
 
 		if backups.Manual != nil {
+			isConfiguredManual = true
 			for i, m := range backups.Manual {
 				if i < len(backups.Manual)-1 {
 					mbk += m.Backup + ", "
@@ -94,9 +98,13 @@ var dbBackupListCmd = &cobra.Command{
 		case "custom":
 			odb.WriteCustomOutput(common.OutputFields)
 		default:
-			fmt.Println("Scheduled Backups:")
+			if isConfiguredScheduled {
+				fmt.Println("Scheduled Backups:")
+			}
 			osbk.WriteTable()
-			fmt.Println("Manual Backups:")
+			if isConfiguredManual {
+				fmt.Println("Manual Backups:")
+			}
 			ombk.WriteTable()
 		}
 	},
diff --git a/go.mod b/go.mod
index 6cd59120..bc626fb7 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
 	github.com/briandowns/spinner v1.11.1
 	github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c // indirect
-	github.com/civo/civogo v0.3.52
+	github.com/civo/civogo v0.3.53
 	github.com/dsnet/compress v0.0.1 // indirect
 	github.com/fatih/color v1.13.0 // indirect
 	github.com/google/go-github v17.0.0+incompatible
diff --git a/go.sum b/go.sum
index d3b4b373..2431f852 100644
--- a/go.sum
+++ b/go.sum
@@ -61,8 +61,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/civo/civogo v0.3.52 h1:x300yiN6N8cK3kd79RMxLCzsKCWnm4Nxv8+Nn8hjAEI=
-github.com/civo/civogo v0.3.52/go.mod h1:54lv/FOf7gh6wE9ZwVdw4yBehk8V1CvU9aWa4v6dvW0=
+github.com/civo/civogo v0.3.53 h1:PYqwTwt9YmeBRKMzfuTXBSPtE0WIsbLzhxD3V36bVlo=
+github.com/civo/civogo v0.3.53/go.mod h1:54lv/FOf7gh6wE9ZwVdw4yBehk8V1CvU9aWa4v6dvW0=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=

From ebc54d7b63d848e053cd30b9d321b540341caff4 Mon Sep 17 00:00:00 2001
From: Vishal Anarse <vishal@civo.com>
Date: Mon, 6 Nov 2023 17:52:17 +0530
Subject: [PATCH 3/3] Addressed comments

Signed-off-by: Vishal Anarse <vishal@civo.com>
---
 cmd/database/database_backup.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cmd/database/database_backup.go b/cmd/database/database_backup.go
index 70bda3a9..a2ee72ef 100644
--- a/cmd/database/database_backup.go
+++ b/cmd/database/database_backup.go
@@ -33,7 +33,7 @@ func init() {
 	dbBackupCreateCmd.Flags().StringVarP(&name, "name", "n", "", "name of the database backup")
 	dbBackupCreateCmd.Flags().StringVarP(&schedule, "schedule", "s", "", "schedule of the database backup in the form of cronjob")
 	dbBackupCreateCmd.Flags().IntVarP(&count, "count", "c", 1, "number of backups to keep")
-	dbBackupCreateCmd.Flags().StringVarP(&backupType, "type", "t", "scheduled", "set the type of database backup manul/scheduled")
+	dbBackupCreateCmd.Flags().StringVarP(&backupType, "type", "t", "scheduled", "set the type of database backup manual/scheduled")
 
 	dbBackupCreateCmd.MarkFlagRequired("name")