6
6
"flag"
7
7
"fmt"
8
8
"os"
9
+ "strings"
9
10
"time"
10
11
11
12
"github.com/orltom/on-call-schedule/internal/cli"
@@ -19,17 +20,17 @@ var (
19
20
ErrInvalidArgument = errors .New ("invalid value" )
20
21
)
21
22
22
- type Converter int
23
+ type Format int
23
24
24
25
const (
25
- CVS Converter = iota
26
+ CVS Format = iota
26
27
Table
27
28
JSON
28
29
)
29
30
30
31
func RunCreateShiftPlan (arguments []string ) error {
31
- enums := map [string ]Converter {"CVS" : CVS , "Table" : Table , "json" : JSON }
32
- converters := map [Converter ]func () apis.Exporter {
32
+ enums := map [string ]Format {"CVS" : CVS , "Table" : Table , "json" : JSON }
33
+ exporters := map [Format ]func () apis.Exporter {
33
34
Table : func () apis.Exporter {
34
35
return export .NewTableExporter ()
35
36
},
@@ -41,20 +42,22 @@ func RunCreateShiftPlan(arguments []string) error {
41
42
},
42
43
}
43
44
44
- str := new (time.Time )
45
+ start := new (time.Time )
45
46
end := new (time.Time )
47
+ enabledRules := new (string )
46
48
duration := new (int )
47
49
teamFilePath := new (string )
48
- transform := Table
50
+ outputFormat := Table
49
51
var showHelp bool
50
52
51
53
createCommand := flag .NewFlagSet ("create" , flag .ExitOnError )
52
54
createCommand .BoolVar (& showHelp , "h" , false , "help for ocsctl create" )
53
- createCommand .IntVar (duration , "duration" , 7 * 24 , "shift duration in hours. " )
54
- createCommand .Func ("start" , "(required) start time of the schedule plan" , cli .TimeValueVar (str ))
55
+ createCommand .IntVar (duration , "duration" , 7 * 24 , "shift duration in hours" )
56
+ createCommand .Func ("start" , "(required) start time of the schedule plan" , cli .TimeValueVar (start ))
55
57
createCommand .Func ("end" , "(required) end time of the schedule plan" , cli .TimeValueVar (end ))
56
58
createCommand .Func ("team-file" , "(required) path to the file that contain all on-call duties" , cli .FilePathVar (teamFilePath ))
57
- createCommand .Func ("output" , "output format. One of (cvs, table, json)" , cli .EnumValueVar (enums , & transform ))
59
+ createCommand .Func ("output" , "output format. One of (cvs, table, json)" , cli .EnumValueVar (enums , & outputFormat ))
60
+ createCommand .StringVar (enabledRules , "enabled-rules" , "vacation" , "Rule to decide which employee should be on-call for the next shift" )
58
61
createCommand .Usage = func () {
59
62
fmt .Fprintf (os .Stdout , "Create on-call schedule\n " )
60
63
fmt .Fprintf (os .Stdout , "\n Usage\n " )
@@ -74,56 +77,67 @@ func RunCreateShiftPlan(arguments []string) error {
74
77
return nil
75
78
}
76
79
77
- // check that the required flags are set ...
78
- if ! cli .IsFlagPassed (createCommand , "start" ) {
80
+ // validate CLI arguments ...
81
+ if ok , missed := cli .RequiredFlagPassed (createCommand , "start" , "end" , "team-file" ); ! ok {
79
82
createCommand .Usage ()
80
- return fmt .Errorf ("%w: %s" , ErrMissingArguments , "start" )
83
+ return fmt .Errorf ("%w: %s" , ErrMissingArguments , strings . Join ( missed , "," ) )
81
84
}
82
85
83
- if ! cli .IsFlagPassed (createCommand , "end" ) {
84
- createCommand .Usage ()
85
- return fmt .Errorf ("%w: %s" , ErrMissingArguments , "end" )
86
- }
87
-
88
- if ! cli .IsFlagPassed (createCommand , "team-file" ) {
89
- createCommand .Usage ()
90
- return fmt .Errorf ("%w: %s" , ErrMissingArguments , "team-file" )
91
- }
92
-
93
- // validate input data...
94
- if str == end {
95
- createCommand .Usage ()
96
- return ErrInvalidArgument
86
+ // initialize...
87
+ team , err := readTeamFile (* teamFilePath )
88
+ if err != nil {
89
+ return fmt .Errorf ("%w: could not read %s: %w" , ErrInvalidArgument , * teamFilePath , err )
97
90
}
98
91
99
- // initialize and run...
100
- team , err := parse (* teamFilePath )
92
+ rules , err := readRules (* enabledRules )
101
93
if err != nil {
102
- return fmt .Errorf ("%w: invalid team config file : %w" , ErrInvalidArgument , err )
94
+ return fmt .Errorf ("%w: invalid rules : %w" , ErrInvalidArgument , err )
103
95
}
104
96
105
- plan , err := shiftplan .NewDefaultShiftPlanner (team .Employees ).Plan (* str , * end , time .Duration (* duration )* time .Hour )
97
+ // run...
98
+ plan , err := shiftplan .NewShiftPlanner (team .Employees , rules , rules ).Plan (* start , * end , time .Duration (* duration )* time .Hour )
106
99
if err != nil {
107
100
return fmt .Errorf ("can not create on-call schedule: %w" , err )
108
101
}
109
102
110
- if err := converters [ transform ]().Write (plan , os .Stdout ); err != nil {
103
+ if err := exporters [ outputFormat ]().Write (plan , os .Stdout ); err != nil {
111
104
return fmt .Errorf ("unexpecting error: %w" , err )
112
105
}
113
106
114
107
return nil
115
108
}
116
109
117
- func parse (path string ) (apis.Team , error ) {
110
+ func readTeamFile (path string ) (apis.Team , error ) {
118
111
content , err := os .ReadFile (path )
119
112
if err != nil {
120
113
return apis.Team {}, fmt .Errorf ("could not read file '%s': %w" , path , err )
121
114
}
122
115
123
116
var team apis.Team
124
117
if err := json .Unmarshal (content , & team ); err != nil {
125
- return apis.Team {}, fmt .Errorf ("could not pars json file '%s': %w" , path , err )
118
+ return apis.Team {}, fmt .Errorf ("could not parse json file '%s': %w" , path , err )
126
119
}
127
120
128
121
return team , nil
129
122
}
123
+
124
+ func readRules (value string ) ([]apis.Rule , error ) {
125
+ var rules []apis.Rule
126
+ for _ , s := range strings .Split (value , "," ) {
127
+ switch strings .ToLower (s ) {
128
+ case "vacation" :
129
+ rules = append (rules , shiftplan .NewNoVacationOverlap ())
130
+ case "minimumoneshiftgap" :
131
+ rules = append (rules , shiftplan .NewMinimumWeekGap (1 ))
132
+ case "minimumtwoshiftgap" :
133
+ rules = append (rules , shiftplan .NewMinimumWeekGap (2 ))
134
+ case "minimumthreeshiftgap" :
135
+ rules = append (rules , shiftplan .NewMinimumWeekGap (3 ))
136
+ case "minimumfourshiftgap" :
137
+ rules = append (rules , shiftplan .NewMinimumWeekGap (4 ))
138
+ default :
139
+ return nil , fmt .Errorf ("unknow rule: %s" , s )
140
+ }
141
+ }
142
+ return rules , nil
143
+ }
0 commit comments