@@ -2,8 +2,8 @@ package cmd
22
33import (
44 "context"
5- "errors"
65 "fmt"
6+ "regexp"
77 "strconv"
88 "strings"
99 "time"
@@ -15,6 +15,7 @@ import (
1515 "github.com/Scalingo/cli/detect"
1616 "github.com/Scalingo/cli/utils"
1717 "github.com/Scalingo/go-scalingo/v10"
18+ "github.com/Scalingo/go-utils/errors/v3"
1819)
1920
2021var (
4243
4344 addonName := addonUUIDFromFlags (ctx , c , currentResource , true )
4445 if c .NArg () != 1 {
45- errorQuit (ctx , errors .New ("feature argument should be specified" ))
46+ errorQuit (ctx , errors .New (ctx , "feature argument should be specified" ))
4647 }
4748 feature := c .Args ().First ()
4849 err := db .EnableFeature (ctx , c , currentResource , addonName , feature )
7374
7475 addonName := addonUUIDFromFlags (ctx , c , currentResource , true )
7576 if c .NArg () != 1 {
76- errorQuit (ctx , errors .New ("feature argument should be specified" ))
77+ errorQuit (ctx , errors .New (ctx , "feature argument should be specified" ))
7778 }
7879 feature := c .Args ().First ()
7980 err := db .DisableFeature (ctx , currentResource , addonName , feature )
@@ -115,25 +116,25 @@ var (
115116 scheduleAtFlag := c .String ("schedule-at" )
116117 disable := c .Bool ("unschedule" )
117118 if scheduleAtFlag != "" && disable {
118- errorQuit (ctx , errors .New ("you cannot use both --schedule-at and --unschedule at the same time" ))
119+ errorQuit (ctx , errors .New (ctx , "you cannot use both --schedule-at and --unschedule at the same time" ))
119120 }
120121
121122 if disable {
122123 continueB := askContinue ("Disabling periodic backups will prevent Scalingo from restoring your database in case of data loss or corruption. Backups are a critical safeguard, and we strongly recommend keeping them enabled. Do you want to continue? (yes/no)" )
123124 if ! continueB {
124- errorQuit (ctx , errors .New ("periodic backups are still enabled" ))
125+ errorQuit (ctx , errors .New (ctx , "periodic backups are still enabled" ))
125126 return nil
126127 }
127128
128129 params .Enabled = utils .BoolPtr (false )
129130 }
130131 if scheduleAtFlag != "" {
131132 params .Enabled = utils .BoolPtr (true )
132- scheduleAt , loc , err := parseScheduleAtFlag (scheduleAtFlag )
133+ scheduleAtHour , loc , err := parseScheduleAtFlag (scheduleAtFlag )
133134 if err != nil {
134135 errorQuit (ctx , err )
135136 }
136- localTime := time .Date (1986 , 7 , 22 , scheduleAt , 0 , 0 , 0 , loc )
137+ localTime := time .Date (1986 , 7 , 22 , scheduleAtHour , 0 , 0 , 0 , loc )
137138 hour := localTime .UTC ().Hour ()
138139 params .ScheduledAt = & hour
139140 }
@@ -296,26 +297,39 @@ Only available on ` + fmt.Sprintf("%s", dbUsers.SupportedAddons),
296297)
297298
298299func parseScheduleAtFlag (flag string ) (int , * time.Location , error ) {
299- scheduleAt , err := strconv .Atoi (flag )
300+ scheduleAtHour , err := strconv .Atoi (flag )
300301 if err == nil {
301302 // In this case, the schedule-at flag equals a single number
302- return scheduleAt , time .Local , nil
303+ return scheduleAtHour , time .Local , nil
303304 }
304305
306+ validationError := errors .NewValidationErrorsBuilder ()
307+
305308 // From now on the schedule-at flag is a number and a timezone such as
306309 // "3 Europe/Paris"
307310 s := strings .Split (flag , " " )
308311 if len (s ) < 2 {
309- return - 1 , nil , errors .New ("parse the schedule-at value" )
312+ validationError = validationError .Set ("schedule-at" , "only contains two space-separated fields" )
313+ return - 1 , nil , validationError .Build ()
310314 }
311- scheduleAt , err = strconv .Atoi (s [0 ])
315+ scheduleAtTime := s [0 ]
316+ scheduleAtTimezone := s [1 ]
317+
318+ // If client writes "4:00" or "4h00", we only want to keep "4" in scheduleAtTime
319+ re := regexp .MustCompile (`([:hH].*)|[0]+` )
320+ scheduleAtTime = re .ReplaceAllString (scheduleAtTime , "" )
321+
322+ scheduleAtHour , err = strconv .Atoi (scheduleAtTime )
312323 if err != nil {
313- return - 1 , nil , errors .New ("parse the schedule-at value" )
324+ validationError = validationError .Set ("schedule-at" , "first field must be a digit representing the hour" )
325+ return - 1 , nil , validationError .Build ()
314326 }
315- loc , err := time .LoadLocation (s [1 ])
327+
328+ loc , err := time .LoadLocation (scheduleAtTimezone )
316329 if err != nil {
317- return - 1 , nil , fmt .Errorf ("unknown timezone '%s'" , s [1 ])
330+ validationError = validationError .Set ("schedule-at" , "unknown timezone" + s [1 ])
331+ return - 1 , nil , validationError .Build ()
318332 }
319333
320- return scheduleAt , loc , nil
334+ return scheduleAtHour , loc , nil
321335}
0 commit comments